81b07ce027
- Create JdeScoping.DataSync.Dev for sandbox testing ETL code - Create JdeScoping.DataSync.Dev.Tests for associated tests - Move 22 source files and 8 test files - Update namespaces from DevEtl to Dev - Add both projects to solution
178 lines
5.7 KiB
C#
178 lines
5.7 KiB
C#
using Dapper;
|
|
using JdeScoping.DataAccess;
|
|
using JdeScoping.DataAccess.Interfaces;
|
|
using JdeScoping.DataSync.Dev;
|
|
using Microsoft.Data.SqlClient;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using NSubstitute;
|
|
using Shouldly;
|
|
|
|
namespace JdeScoping.DataSync.Dev.Tests;
|
|
|
|
/// <summary>
|
|
/// Integration tests for Branch development ETL.
|
|
/// Requires: Local SQL Server, CACHED_DB_FILES directory with branch.json.zstd
|
|
/// </summary>
|
|
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("LotFinderDB")
|
|
?? throw new InvalidOperationException("LotFinderDB connection string not configured.");
|
|
|
|
_cacheDirectory = config["DevEtl:CacheDirectory"]
|
|
?? Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "..", "..", "..", "CACHED_DB_FILES");
|
|
|
|
_connectionFactory = new DbConnectionFactory(config, NullLogger<DbConnectionFactory>.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<int>("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<ArgumentNullException>(() => BranchDevEtl.Create(null!, cacheFilePath));
|
|
}
|
|
|
|
[Fact]
|
|
public void Create_WithEmptyCacheFilePath_ThrowsArgumentException()
|
|
{
|
|
// Arrange
|
|
var mockFactory = Substitute.For<IDbConnectionFactory>();
|
|
|
|
// Act & Assert
|
|
Should.Throw<ArgumentException>(() => BranchDevEtl.Create(mockFactory, string.Empty));
|
|
}
|
|
|
|
[Fact]
|
|
public void Create_WithNonExistentCacheFile_ThrowsFileNotFoundException()
|
|
{
|
|
// Arrange
|
|
var mockFactory = Substitute.For<IDbConnectionFactory>();
|
|
var nonExistentPath = "/nonexistent/path/branch.json.zstd";
|
|
|
|
// Act & Assert
|
|
Should.Throw<FileNotFoundException>(() => BranchDevEtl.Create(mockFactory, nonExistentPath));
|
|
}
|
|
|
|
[Fact]
|
|
public void DevEtlRegistry_WithNonExistentCacheDirectory_ThrowsDirectoryNotFoundException()
|
|
{
|
|
// Arrange
|
|
var mockFactory = Substitute.For<IDbConnectionFactory>();
|
|
var nonExistentPath = "/nonexistent/cache/directory";
|
|
|
|
// Act & Assert
|
|
Should.Throw<DirectoryNotFoundException>(() => 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");
|
|
}
|
|
}
|