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;
///
/// Integration tests for FunctionCode development ETL.
///
public class FunctionCodeDevEtlTests : IAsyncLifetime
{
private readonly string _connectionString;
private readonly string _cacheDirectory;
private readonly IDbConnectionFactory _connectionFactory;
public FunctionCodeDevEtlTests()
{
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.Instance);
}
public async Task InitializeAsync()
{
await using var connection = new SqlConnection(_connectionString);
await connection.OpenAsync();
await connection.ExecuteAsync("TRUNCATE TABLE dbo.FunctionCode");
}
public Task DisposeAsync() => Task.CompletedTask;
[Fact]
public void Create_ReturnsValidPipeline()
{
var cacheFilePath = Path.Combine(_cacheDirectory, FunctionCodeDevEtl.CacheFileName);
if (!File.Exists(cacheFilePath)) return;
var pipeline = FunctionCodeDevEtl.Create(_connectionFactory, cacheFilePath);
pipeline.ShouldNotBeNull();
pipeline.PipelineName.ShouldBe("FunctionCode_Dev");
}
[Fact]
public async Task Execute_LoadsData()
{
var cacheFilePath = Path.Combine(_cacheDirectory, FunctionCodeDevEtl.CacheFileName);
if (!File.Exists(cacheFilePath)) return;
var pipeline = FunctionCodeDevEtl.Create(_connectionFactory, cacheFilePath);
var result = await pipeline.ExecuteAsync();
result.Success.ShouldBeTrue(result.Error?.Message ?? "Pipeline should succeed");
result.TotalRows.ShouldBeGreaterThan(0);
await using var connection = new SqlConnection(_connectionString);
await connection.OpenAsync();
var count = await connection.ExecuteScalarAsync("SELECT COUNT(*) FROM dbo.FunctionCode");
count.ShouldBe((int)result.TotalRows);
}
[Fact]
public async Task Registry_RunAsync_LoadsTable()
{
if (!Directory.Exists(_cacheDirectory)) return;
var registry = new DevEtlRegistry(_connectionFactory, _cacheDirectory);
var result = await registry.RunAsync("FunctionCode");
result.Success.ShouldBeTrue(result.Error?.Message ?? "Pipeline should succeed");
result.TotalRows.ShouldBeGreaterThan(0);
}
[Fact]
public void Create_WithNullConnectionFactory_ThrowsArgumentNullException()
{
var cacheFilePath = Path.Combine(_cacheDirectory, FunctionCodeDevEtl.CacheFileName);
Should.Throw(() => FunctionCodeDevEtl.Create(null!, cacheFilePath));
}
}