fix(external-system-gateway): resolve ExternalSystemGateway-011 — name-keyed repository lookups replace fetch-all-then-filter on the call hot path

This commit is contained in:
Joseph Doherty
2026-05-17 00:02:45 -04:00
parent 1e2e7d2e7c
commit a55502254e
10 changed files with 448 additions and 131 deletions

View File

@@ -14,10 +14,25 @@ public class DatabaseGatewayTests
{
private readonly IExternalSystemRepository _repository = Substitute.For<IExternalSystemRepository>();
/// <summary>
/// Configures the repository substitute for the name-keyed connection-resolution
/// path used by <c>DatabaseGateway</c> (ExternalSystemGateway-011). A <c>null</c>
/// connection models a "not found" — the substitute returns <c>null</c> by default,
/// so no stub is needed for the absent entity.
/// </summary>
private void StubConnection(DatabaseConnectionDefinition? connection)
{
if (connection != null)
{
_repository.GetDatabaseConnectionByNameAsync(connection.Name, Arg.Any<CancellationToken>())
.Returns(connection);
}
}
[Fact]
public async Task GetConnection_NotFound_Throws()
{
_repository.GetAllDatabaseConnectionsAsync().Returns(new List<DatabaseConnectionDefinition>());
StubConnection(connection: null);
var gateway = new DatabaseGateway(
_repository,
@@ -31,8 +46,7 @@ public class DatabaseGatewayTests
public async Task CachedWrite_NoStoreAndForward_Throws()
{
var conn = new DatabaseConnectionDefinition("testDb", "Server=localhost;Database=test") { Id = 1 };
_repository.GetAllDatabaseConnectionsAsync()
.Returns(new List<DatabaseConnectionDefinition> { conn });
StubConnection(conn);
var gateway = new DatabaseGateway(
_repository,
@@ -46,7 +60,7 @@ public class DatabaseGatewayTests
[Fact]
public async Task CachedWrite_ConnectionNotFound_Throws()
{
_repository.GetAllDatabaseConnectionsAsync().Returns(new List<DatabaseConnectionDefinition>());
StubConnection(connection: null);
var gateway = new DatabaseGateway(
_repository,
@@ -67,8 +81,7 @@ public class DatabaseGatewayTests
MaxRetries = 5,
RetryDelay = TimeSpan.FromSeconds(12),
};
_repository.GetAllDatabaseConnectionsAsync(Arg.Any<CancellationToken>())
.Returns(new List<DatabaseConnectionDefinition> { conn });
StubConnection(conn);
var dbName = $"EsgCachedWrite_{Guid.NewGuid():N}";
var connStr = $"Data Source={dbName};Mode=Memory;Cache=Shared";
@@ -108,8 +121,7 @@ public class DatabaseGatewayTests
MaxRetries = 0,
RetryDelay = TimeSpan.FromSeconds(3),
};
_repository.GetAllDatabaseConnectionsAsync(Arg.Any<CancellationToken>())
.Returns(new List<DatabaseConnectionDefinition> { conn });
StubConnection(conn);
var dbName = $"EsgCachedWriteZero_{Guid.NewGuid():N}";
var connStr = $"Data Source={dbName};Mode=Memory;Cache=Shared";
@@ -153,7 +165,7 @@ public class DatabaseGatewayTests
[Fact]
public async Task DeliverBuffered_ConnectionNoLongerExists_ReturnsFalseSoMessageParks()
{
_repository.GetAllDatabaseConnectionsAsync().Returns(new List<DatabaseConnectionDefinition>());
StubConnection(connection: null);
var gateway = new DatabaseGateway(_repository, NullLogger<DatabaseGateway>.Instance);
var message = new ScadaLink.StoreAndForward.StoreAndForwardMessage
@@ -176,7 +188,7 @@ public class DatabaseGatewayTests
public async Task GetConnection_OpenFails_DisposesConnectionBeforeRethrowing()
{
var conn = new DatabaseConnectionDefinition("testDb", "Server=localhost;Database=test") { Id = 1 };
_repository.GetAllDatabaseConnectionsAsync().Returns(new List<DatabaseConnectionDefinition> { conn });
StubConnection(conn);
var fake = new ThrowingDbConnection();
var gateway = new ConnectionFactoryStubGateway(_repository, fake);