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

@@ -76,6 +76,94 @@ public class ExternalSystemRepositoryTests : IDisposable
{
Assert.Throws<ArgumentNullException>(() => new ExternalSystemRepository(null!));
}
// ── ExternalSystemGateway-011: name-keyed repository lookups ──
[Fact]
public async Task GetExternalSystemByName_ReturnsMatchingRow()
{
await _repository.AddExternalSystemAsync(
new ExternalSystemDefinition("Alpha", "https://alpha.test", "ApiKey"));
await _repository.AddExternalSystemAsync(
new ExternalSystemDefinition("Beta", "https://beta.test", "Basic"));
await _repository.SaveChangesAsync();
var loaded = await _repository.GetExternalSystemByNameAsync("Beta");
Assert.NotNull(loaded);
Assert.Equal("Beta", loaded!.Name);
Assert.Equal("https://beta.test", loaded.EndpointUrl);
}
[Fact]
public async Task GetExternalSystemByName_MissingName_ReturnsNull()
{
await _repository.AddExternalSystemAsync(
new ExternalSystemDefinition("Alpha", "https://alpha.test", "ApiKey"));
await _repository.SaveChangesAsync();
Assert.Null(await _repository.GetExternalSystemByNameAsync("DoesNotExist"));
}
[Fact]
public async Task GetMethodByName_ReturnsMethodScopedToParentSystem()
{
var sysA = new ExternalSystemDefinition("SysA", "https://a.test", "ApiKey");
var sysB = new ExternalSystemDefinition("SysB", "https://b.test", "ApiKey");
await _repository.AddExternalSystemAsync(sysA);
await _repository.AddExternalSystemAsync(sysB);
await _repository.SaveChangesAsync();
// Same method name on two different systems — the lookup must be scoped.
await _repository.AddExternalSystemMethodAsync(
new ExternalSystemMethod("getData", "GET", "/a") { ExternalSystemDefinitionId = sysA.Id });
await _repository.AddExternalSystemMethodAsync(
new ExternalSystemMethod("getData", "POST", "/b") { ExternalSystemDefinitionId = sysB.Id });
await _repository.SaveChangesAsync();
var method = await _repository.GetMethodByNameAsync(sysB.Id, "getData");
Assert.NotNull(method);
Assert.Equal(sysB.Id, method!.ExternalSystemDefinitionId);
Assert.Equal("POST", method.HttpMethod);
Assert.Equal("/b", method.Path);
}
[Fact]
public async Task GetMethodByName_MissingMethod_ReturnsNull()
{
var sys = new ExternalSystemDefinition("SysA", "https://a.test", "ApiKey");
await _repository.AddExternalSystemAsync(sys);
await _repository.SaveChangesAsync();
Assert.Null(await _repository.GetMethodByNameAsync(sys.Id, "noSuchMethod"));
}
[Fact]
public async Task GetDatabaseConnectionByName_ReturnsMatchingRow()
{
await _repository.AddDatabaseConnectionAsync(
new DatabaseConnectionDefinition("Plant", "Server=plant;Database=p;"));
await _repository.AddDatabaseConnectionAsync(
new DatabaseConnectionDefinition("Historian", "Server=hist;Database=h;"));
await _repository.SaveChangesAsync();
var loaded = await _repository.GetDatabaseConnectionByNameAsync("Historian");
Assert.NotNull(loaded);
Assert.Equal("Historian", loaded!.Name);
Assert.Equal("Server=hist;Database=h;", loaded.ConnectionString);
}
[Fact]
public async Task GetDatabaseConnectionByName_MissingName_ReturnsNull()
{
await _repository.AddDatabaseConnectionAsync(
new DatabaseConnectionDefinition("Plant", "Server=plant;Database=p;"));
await _repository.SaveChangesAsync();
Assert.Null(await _repository.GetDatabaseConnectionByNameAsync("DoesNotExist"));
}
}
public class NotificationRepositoryTests : IDisposable