From e04e81b1789831f6c9d2f66373b306c1991a4302 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Sat, 3 Jan 2026 16:38:11 -0500 Subject: [PATCH] test(datasync): add integration tests for BranchDevEtl Add integration tests for the Branch development ETL pipeline: - BranchDevEtlTests with tests for pipeline creation and execution - Tests verify pipeline creates correctly and loads data from cache files - Added appsettings.json with local connection string and cache directory - Added necessary packages (Configuration.Json, SqlClient, Dapper) Tests require local SQL Server and CACHED_DB_FILES directory with branch.json.zstd to pass; tests silently skip if resources unavailable. --- .../DevEtl/BranchDevEtlTests.cs | 177 ++++++++++++++++++ .../JdeScoping.DataSync.Tests.csproj | 8 + .../appsettings.json | 8 + 3 files changed, 193 insertions(+) create mode 100644 NEW/tests/JdeScoping.DataSync.Tests/DevEtl/BranchDevEtlTests.cs create mode 100644 NEW/tests/JdeScoping.DataSync.Tests/appsettings.json diff --git a/NEW/tests/JdeScoping.DataSync.Tests/DevEtl/BranchDevEtlTests.cs b/NEW/tests/JdeScoping.DataSync.Tests/DevEtl/BranchDevEtlTests.cs new file mode 100644 index 0000000..1e49f40 --- /dev/null +++ b/NEW/tests/JdeScoping.DataSync.Tests/DevEtl/BranchDevEtlTests.cs @@ -0,0 +1,177 @@ +using Dapper; +using JdeScoping.DataAccess; +using JdeScoping.DataAccess.Interfaces; +using JdeScoping.DataSync.DevEtl; +using Microsoft.Data.SqlClient; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging.Abstractions; +using NSubstitute; +using Shouldly; + +namespace JdeScoping.DataSync.Tests.DevEtl; + +/// +/// Integration tests for Branch development ETL. +/// Requires: Local SQL Server, CACHED_DB_FILES directory with branch.json.zstd +/// +public class BranchDevEtlTests : IAsyncLifetime +{ + private readonly string _connectionString; + private readonly string _cacheDirectory; + private readonly IDbConnectionFactory _connectionFactory; + + public BranchDevEtlTests() + { + // Load configuration + var config = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: true) + .AddEnvironmentVariables() + .Build(); + + _connectionString = config.GetConnectionString("LotFinder") + ?? throw new InvalidOperationException("LotFinder connection string not configured."); + + _cacheDirectory = config["DevEtl:CacheDirectory"] + ?? "/Users/dohertj2/Desktop/JdeScopingTool/CACHED_DB_FILES"; + + _connectionFactory = new DbConnectionFactory(config, NullLogger.Instance); + } + + public async Task InitializeAsync() + { + // Ensure Branch table is empty before test + await using var connection = new SqlConnection(_connectionString); + await connection.OpenAsync(); + await connection.ExecuteAsync("TRUNCATE TABLE dbo.Branch"); + } + + public Task DisposeAsync() => Task.CompletedTask; + + [Fact] + public void Create_ReturnsValidPipeline() + { + // Arrange + var cacheFilePath = Path.Combine(_cacheDirectory, BranchDevEtl.CacheFileName); + if (!File.Exists(cacheFilePath)) + { + // Skip test if cache file doesn't exist + return; + } + + // Act + var pipeline = BranchDevEtl.Create(_connectionFactory, cacheFilePath); + + // Assert + pipeline.ShouldNotBeNull(); + pipeline.PipelineName.ShouldBe("Branch_Dev"); + } + + [Fact] + public async Task Execute_LoadsBranchData() + { + // Arrange + var cacheFilePath = Path.Combine(_cacheDirectory, BranchDevEtl.CacheFileName); + if (!File.Exists(cacheFilePath)) + { + // Skip test if cache file doesn't exist + return; + } + + var pipeline = BranchDevEtl.Create(_connectionFactory, cacheFilePath); + + // Act + var result = await pipeline.ExecuteAsync(); + + // Assert + result.Success.ShouldBeTrue(result.Error?.Message ?? "Pipeline should succeed"); + result.TotalRows.ShouldBeGreaterThan(0, "Should load at least one row"); + + // Verify data in database + await using var connection = new SqlConnection(_connectionString); + await connection.OpenAsync(); + var count = await connection.ExecuteScalarAsync("SELECT COUNT(*) FROM dbo.Branch"); + + count.ShouldBe((int)result.TotalRows, "Database row count should match pipeline result"); + } + + [Fact] + public async Task Registry_RunAsync_LoadsBranch() + { + // Arrange + if (!Directory.Exists(_cacheDirectory)) + { + // Skip test if cache directory doesn't exist + return; + } + + var registry = new DevEtlRegistry(_connectionFactory, _cacheDirectory); + + // Act + var result = await registry.RunAsync("Branch"); + + // Assert + result.Success.ShouldBeTrue(result.Error?.Message ?? "Pipeline should succeed"); + result.TotalRows.ShouldBeGreaterThan(0); + } + + [Fact] + public void Create_WithNullConnectionFactory_ThrowsArgumentNullException() + { + // Arrange + var cacheFilePath = Path.Combine(_cacheDirectory, BranchDevEtl.CacheFileName); + + // Act & Assert + Should.Throw(() => BranchDevEtl.Create(null!, cacheFilePath)); + } + + [Fact] + public void Create_WithEmptyCacheFilePath_ThrowsArgumentException() + { + // Arrange + var mockFactory = Substitute.For(); + + // Act & Assert + Should.Throw(() => BranchDevEtl.Create(mockFactory, string.Empty)); + } + + [Fact] + public void Create_WithNonExistentCacheFile_ThrowsFileNotFoundException() + { + // Arrange + var mockFactory = Substitute.For(); + var nonExistentPath = "/nonexistent/path/branch.json.zstd"; + + // Act & Assert + Should.Throw(() => BranchDevEtl.Create(mockFactory, nonExistentPath)); + } + + [Fact] + public void DevEtlRegistry_WithNonExistentCacheDirectory_ThrowsDirectoryNotFoundException() + { + // Arrange + var mockFactory = Substitute.For(); + var nonExistentPath = "/nonexistent/cache/directory"; + + // Act & Assert + Should.Throw(() => new DevEtlRegistry(mockFactory, nonExistentPath)); + } + + [Fact] + public void DevEtlRegistry_GetAvailableTables_IncludesBranch() + { + // Arrange + if (!Directory.Exists(_cacheDirectory)) + { + return; + } + + var registry = new DevEtlRegistry(_connectionFactory, _cacheDirectory); + + // Act + var tables = registry.GetAvailableTables().ToList(); + + // Assert + tables.ShouldContain("Branch"); + } +} diff --git a/NEW/tests/JdeScoping.DataSync.Tests/JdeScoping.DataSync.Tests.csproj b/NEW/tests/JdeScoping.DataSync.Tests/JdeScoping.DataSync.Tests.csproj index 352d954..7dfd001 100644 --- a/NEW/tests/JdeScoping.DataSync.Tests/JdeScoping.DataSync.Tests.csproj +++ b/NEW/tests/JdeScoping.DataSync.Tests/JdeScoping.DataSync.Tests.csproj @@ -25,6 +25,10 @@ + + + + @@ -36,4 +40,8 @@ + + + + diff --git a/NEW/tests/JdeScoping.DataSync.Tests/appsettings.json b/NEW/tests/JdeScoping.DataSync.Tests/appsettings.json new file mode 100644 index 0000000..865fbd9 --- /dev/null +++ b/NEW/tests/JdeScoping.DataSync.Tests/appsettings.json @@ -0,0 +1,8 @@ +{ + "ConnectionStrings": { + "LotFinder": "Server=localhost,1434;Database=ScopingTool;User Id=scopingapp;Password=Sc0ping@pp_Dev#2024;TrustServerCertificate=true" + }, + "DevEtl": { + "CacheDirectory": "/Users/dohertj2/Desktop/JdeScopingTool/CACHED_DB_FILES" + } +}