Files
jdescopingtool/NEW/tests/JdeScoping.DataAccess.Tests/DbConnectionFactoryTests.cs
T
Joseph Doherty bfc1c8064a refactor(securestore): store entire connection strings in SecureStore
Eliminates placeholder substitution (${KEY}) in favor of storing complete
connection strings as single encrypted values. SecureStore now auto-creates
entries for all connection strings defined in appsettings. ConfigManager
editor reads/writes values directly to SecureStore.
2026-01-23 14:44:04 -05:00

236 lines
7.5 KiB
C#

using JdeScoping.Core.Interfaces;
using JdeScoping.DataAccess.Exceptions;
using Microsoft.Extensions.Logging;
using NSubstitute;
using Shouldly;
using Xunit;
namespace JdeScoping.DataAccess.Tests;
/// <summary>
/// Unit tests for DbConnectionFactory.
/// Connection strings are retrieved from ISecureStoreService.
/// </summary>
public class DbConnectionFactoryTests
{
private readonly ISecureStoreService _secureStore;
private readonly ILogger<DbConnectionFactory> _logger;
public DbConnectionFactoryTests()
{
_secureStore = Substitute.For<ISecureStoreService>();
_logger = Substitute.For<ILogger<DbConnectionFactory>>();
}
#region Constructor Tests
[Fact]
public void Constructor_NullSecureStore_ThrowsArgumentNullException()
{
// Act & Assert
Should.Throw<ArgumentNullException>(() => new DbConnectionFactory(null!, _logger))
.ParamName.ShouldBe("secureStore");
}
[Fact]
public void Constructor_NullLogger_ThrowsArgumentNullException()
{
// Act & Assert
Should.Throw<ArgumentNullException>(() => new DbConnectionFactory(_secureStore, null!))
.ParamName.ShouldBe("logger");
}
[Fact]
public void Constructor_ValidParameters_CreatesInstance()
{
// Act
var factory = new DbConnectionFactory(_secureStore, _logger);
// Assert
factory.ShouldNotBeNull();
}
#endregion
#region CreateLotFinderConnectionAsync Tests
[Fact]
public async Task CreateLotFinderConnectionAsync_MissingConnectionString_ThrowsConnectionException()
{
// Arrange
_secureStore.Get("LotFinder").Returns((string?)null);
var factory = new DbConnectionFactory(_secureStore, _logger);
// Act & Assert
var ex = await Should.ThrowAsync<ConnectionException>(
async () => await factory.CreateLotFinderConnectionAsync());
ex.DataSource.ShouldBe("LotFinder");
ex.Message.ShouldContain("Connection string not found");
}
[Fact]
public async Task CreateLotFinderConnectionAsync_EmptyConnectionString_ThrowsConnectionException()
{
// Arrange
_secureStore.Get("LotFinder").Returns(string.Empty);
var factory = new DbConnectionFactory(_secureStore, _logger);
// Act & Assert
var ex = await Should.ThrowAsync<ConnectionException>(
async () => await factory.CreateLotFinderConnectionAsync());
ex.DataSource.ShouldBe("LotFinder");
ex.Message.ShouldContain("Connection string not found");
}
[Fact]
public async Task CreateLotFinderConnectionAsync_InvalidConnectionString_ThrowsConnectionException()
{
// Arrange
_secureStore.Get("LotFinder").Returns("Invalid connection string");
var factory = new DbConnectionFactory(_secureStore, _logger);
// Act & Assert
var ex = await Should.ThrowAsync<ConnectionException>(
async () => await factory.CreateLotFinderConnectionAsync());
ex.DataSource.ShouldBe("LotFinder");
ex.Message.ShouldContain("Failed to open connection");
ex.InnerException.ShouldNotBeNull();
}
[Fact]
public async Task CreateLotFinderConnectionAsync_CancellationRequested_ThrowsOperationCanceledException()
{
// Arrange
_secureStore.Get("LotFinder").Returns("Server=test;Database=test;");
var factory = new DbConnectionFactory(_secureStore, _logger);
using var cts = new CancellationTokenSource();
cts.Cancel();
// Act & Assert
await Should.ThrowAsync<OperationCanceledException>(
async () => await factory.CreateLotFinderConnectionAsync(cts.Token));
}
#endregion
#region CreateJdeConnectionAsync Tests
[Fact]
public async Task CreateJdeConnectionAsync_MissingConnectionString_ThrowsConnectionException()
{
// Arrange
_secureStore.Get("JDE").Returns((string?)null);
var factory = new DbConnectionFactory(_secureStore, _logger);
// Act & Assert
var ex = await Should.ThrowAsync<ConnectionException>(
async () => await factory.CreateJdeConnectionAsync());
ex.DataSource.ShouldBe("JDE");
ex.Message.ShouldContain("Connection string not found");
}
[Fact]
public async Task CreateJdeConnectionAsync_InvalidConnectionString_ThrowsConnectionException()
{
// Arrange
_secureStore.Get("JDE").Returns("Invalid oracle connection");
var factory = new DbConnectionFactory(_secureStore, _logger);
// Act & Assert
var ex = await Should.ThrowAsync<ConnectionException>(
async () => await factory.CreateJdeConnectionAsync());
ex.DataSource.ShouldBe("JDE");
ex.Message.ShouldContain("Failed to open connection");
}
#endregion
#region CreateJdeStageConnectionAsync Tests
[Fact]
public async Task CreateJdeStageConnectionAsync_MissingConnectionString_ThrowsConnectionException()
{
// Arrange
_secureStore.Get("JDEStage").Returns((string?)null);
var factory = new DbConnectionFactory(_secureStore, _logger);
// Act & Assert
var ex = await Should.ThrowAsync<ConnectionException>(
async () => await factory.CreateJdeStageConnectionAsync());
ex.DataSource.ShouldBe("JDEStage");
ex.Message.ShouldContain("Connection string not found");
}
#endregion
#region CreateCmsConnectionAsync Tests
[Fact]
public async Task CreateCmsConnectionAsync_MissingConnectionString_ThrowsConnectionException()
{
// Arrange
_secureStore.Get("CMS").Returns((string?)null);
var factory = new DbConnectionFactory(_secureStore, _logger);
// Act & Assert
var ex = await Should.ThrowAsync<ConnectionException>(
async () => await factory.CreateCmsConnectionAsync());
ex.DataSource.ShouldBe("CMS");
ex.Message.ShouldContain("Connection string not found");
}
[Fact]
public async Task CreateCmsConnectionAsync_InvalidConnectionString_ThrowsConnectionException()
{
// Arrange
_secureStore.Get("CMS").Returns("Invalid oracle connection");
var factory = new DbConnectionFactory(_secureStore, _logger);
// Act & Assert
var ex = await Should.ThrowAsync<ConnectionException>(
async () => await factory.CreateCmsConnectionAsync());
ex.DataSource.ShouldBe("CMS");
ex.Message.ShouldContain("Failed to open connection");
}
#endregion
#region Logging Tests
[Fact]
public async Task CreateLotFinderConnectionAsync_InvalidConnection_LogsError()
{
// Arrange
_secureStore.Get("LotFinder").Returns("Invalid connection string");
var factory = new DbConnectionFactory(_secureStore, _logger);
// Act
try
{
await factory.CreateLotFinderConnectionAsync();
}
catch (ConnectionException)
{
// Expected
}
// Assert - verify error logging was called (at least once - there may also be debug logs)
_logger.Received().Log(
LogLevel.Error,
Arg.Any<EventId>(),
Arg.Any<object>(),
Arg.Any<Exception>(),
Arg.Any<Func<object, Exception?, string>>());
}
#endregion
}