From c59a3160d04bb7efd7baddd6d8aff74eb491995a Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Wed, 7 Jan 2026 00:54:11 -0500 Subject: [PATCH] feat(dataaccess): add GIW connection factory method Add CreateGiwConnectionAsync to IDbConnectionFactory and DbConnectionFactory for connecting to the GIW Oracle database. This connection is needed for the StatusCode data sync pipeline. - Reuses existing CreateOracleConnectionAsync helper with "GIW" data source - Follows same pattern as JDE, JDEStage, and CMS connections - Includes 4 unit tests covering missing/empty/invalid connection strings --- .../DbConnectionFactory.cs | 6 ++ .../Interfaces/IDbConnectionFactory.cs | 7 ++ .../DbConnectionFactoryGiwTests.cs | 83 +++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 NEW/tests/JdeScoping.DataAccess.Tests/DbConnectionFactoryGiwTests.cs diff --git a/NEW/src/JdeScoping.DataAccess/DbConnectionFactory.cs b/NEW/src/JdeScoping.DataAccess/DbConnectionFactory.cs index ced9acb..68dfb95 100644 --- a/NEW/src/JdeScoping.DataAccess/DbConnectionFactory.cs +++ b/NEW/src/JdeScoping.DataAccess/DbConnectionFactory.cs @@ -87,6 +87,12 @@ public class DbConnectionFactory : IDbConnectionFactory return await CreateOracleConnectionAsync("CMS", ct).ConfigureAwait(false); } + /// + public async Task CreateGiwConnectionAsync(CancellationToken ct = default) + { + return await CreateOracleConnectionAsync("GIW", ct).ConfigureAwait(false); + } + private async Task CreateOracleConnectionAsync(string dataSource, CancellationToken ct) { var connectionString = _configuration.GetConnectionString(dataSource); diff --git a/NEW/src/JdeScoping.DataAccess/Interfaces/IDbConnectionFactory.cs b/NEW/src/JdeScoping.DataAccess/Interfaces/IDbConnectionFactory.cs index 0ed415d..6035822 100644 --- a/NEW/src/JdeScoping.DataAccess/Interfaces/IDbConnectionFactory.cs +++ b/NEW/src/JdeScoping.DataAccess/Interfaces/IDbConnectionFactory.cs @@ -35,4 +35,11 @@ public interface IDbConnectionFactory /// Cancellation token. /// An open Oracle connection. Caller is responsible for disposal. Task CreateCmsConnectionAsync(CancellationToken ct = default); + + /// + /// Creates and opens a connection to the GIW Oracle database (for StatusCode sync). + /// + /// Cancellation token. + /// An open Oracle connection. Caller is responsible for disposal. + Task CreateGiwConnectionAsync(CancellationToken ct = default); } diff --git a/NEW/tests/JdeScoping.DataAccess.Tests/DbConnectionFactoryGiwTests.cs b/NEW/tests/JdeScoping.DataAccess.Tests/DbConnectionFactoryGiwTests.cs new file mode 100644 index 0000000..6bd8f82 --- /dev/null +++ b/NEW/tests/JdeScoping.DataAccess.Tests/DbConnectionFactoryGiwTests.cs @@ -0,0 +1,83 @@ +using JdeScoping.DataAccess.Exceptions; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using NSubstitute; +using Shouldly; +using Xunit; + +namespace JdeScoping.DataAccess.Tests; + +/// +/// Unit tests for DbConnectionFactory GIW connection support. +/// +public class DbConnectionFactoryGiwTests +{ + private readonly IConfiguration _configuration; + private readonly ILogger _logger; + + public DbConnectionFactoryGiwTests() + { + _configuration = Substitute.For(); + _logger = Substitute.For>(); + } + + [Fact] + public async Task CreateGiwConnectionAsync_MissingConnectionString_ThrowsConnectionException() + { + // Arrange + _configuration.GetConnectionString("GIW").Returns((string?)null); + var factory = new DbConnectionFactory(_configuration, _logger); + + // Act & Assert + var ex = await Should.ThrowAsync( + async () => await factory.CreateGiwConnectionAsync()); + + ex.DataSource.ShouldBe("GIW"); + ex.Message.ShouldContain("Connection string not found"); + } + + [Fact] + public async Task CreateGiwConnectionAsync_EmptyConnectionString_ThrowsConnectionException() + { + // Arrange + _configuration.GetConnectionString("GIW").Returns(string.Empty); + var factory = new DbConnectionFactory(_configuration, _logger); + + // Act & Assert + var ex = await Should.ThrowAsync( + async () => await factory.CreateGiwConnectionAsync()); + + ex.DataSource.ShouldBe("GIW"); + ex.Message.ShouldContain("Connection string not found"); + } + + [Fact] + public async Task CreateGiwConnectionAsync_InvalidConnectionString_ThrowsConnectionException() + { + // Arrange + _configuration.GetConnectionString("GIW").Returns("Invalid oracle connection"); + var factory = new DbConnectionFactory(_configuration, _logger); + + // Act & Assert + var ex = await Should.ThrowAsync( + async () => await factory.CreateGiwConnectionAsync()); + + ex.DataSource.ShouldBe("GIW"); + ex.Message.ShouldContain("Failed to open connection"); + ex.InnerException.ShouldNotBeNull(); + } + + [Fact] + public async Task CreateGiwConnectionAsync_CancellationRequested_ThrowsOperationCanceledException() + { + // Arrange + _configuration.GetConnectionString("GIW").Returns("User Id=test;Password=test;Data Source=test"); + var factory = new DbConnectionFactory(_configuration, _logger); + using var cts = new CancellationTokenSource(); + cts.Cancel(); + + // Act & Assert + await Should.ThrowAsync( + async () => await factory.CreateGiwConnectionAsync(cts.Token)); + } +}