From 1038683c5838669606cf5a97a9cd904ee9fd7966 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Sun, 17 May 2026 06:46:47 -0400 Subject: [PATCH] test(integration): repair IntegrationTests harness and stale API-key test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ScadaLinkWebApplicationFactory removed the AkkaHostedService SINGLETON, not just its IHostedService registration, so IClusterNodeProvider's factory (Program.cs) could not resolve it — 10 tests failed at host build. Now removes only the factory-registered IHostedService descriptors and keeps the singleton. - Configure an LDAP service account so ResolveUserDnAsync does search-then-bind against GLAuth (whose DN layout the no-service-account fallback DN never matched), fixing LoginEndpoint_WithValidLdapCredentials. - IntegrationSurfaceTests: ApiKeyValidator now matches keys by HMAC hash over GetAllApiKeysAsync (ConfigurationDatabase-012); the test mocked the removed GetApiKeyByValueAsync path. Suite now 64/64. --- .../IntegrationSurfaceTests.cs | 4 +++- .../ScadaLinkWebApplicationFactory.cs | 20 ++++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/tests/ScadaLink.IntegrationTests/IntegrationSurfaceTests.cs b/tests/ScadaLink.IntegrationTests/IntegrationSurfaceTests.cs index 7c3dfb0..c5b4080 100644 --- a/tests/ScadaLink.IntegrationTests/IntegrationSurfaceTests.cs +++ b/tests/ScadaLink.IntegrationTests/IntegrationSurfaceTests.cs @@ -33,7 +33,9 @@ public class IntegrationSurfaceTests TimeoutSeconds = 30 }; - repository.GetApiKeyByValueAsync("key-value-123").Returns(key); + // ConfigurationDatabase-012: the validator fetches every key and matches + // the candidate by HMAC hash in constant time (no secret-equality lookup). + repository.GetAllApiKeysAsync().Returns(new List { key }); repository.GetMethodByNameAsync("getStatus").Returns(method); repository.GetApprovedKeysForMethodAsync(10).Returns(new List { key }); diff --git a/tests/ScadaLink.IntegrationTests/ScadaLinkWebApplicationFactory.cs b/tests/ScadaLink.IntegrationTests/ScadaLinkWebApplicationFactory.cs index a3e34ee..fe977b5 100644 --- a/tests/ScadaLink.IntegrationTests/ScadaLinkWebApplicationFactory.cs +++ b/tests/ScadaLink.IntegrationTests/ScadaLinkWebApplicationFactory.cs @@ -43,6 +43,12 @@ public class ScadaLinkWebApplicationFactory : WebApplicationFactory ["ScadaLink__Security__LdapUseTls"] = "false", ["ScadaLink__Security__AllowInsecureLdap"] = "true", ["ScadaLink__Security__LdapSearchBase"] = "dc=scadalink,dc=local", + // GLAuth places users at cn=,ou=,ou=users,dc=... — the + // no-service-account fallback DN (uid=,dc=...) does not match, + // so a service account is configured to enable search-then-bind: + // resolve the user's real DN by (uid=) lookup, then bind it. + ["ScadaLink__Security__LdapServiceAccountDn"] = "cn=admin,ou=SCADA-Admins,ou=users,dc=scadalink,dc=local", + ["ScadaLink__Security__LdapServiceAccountPassword"] = "password", }; foreach (var (key, value) in envVars) @@ -74,14 +80,14 @@ public class ScadaLinkWebApplicationFactory : WebApplicationFactory services.AddDbContext(options => options.UseInMemoryDatabase($"ScadaLink_IntegrationTests_{Guid.NewGuid()}")); - // Remove AkkaHostedService to avoid Akka.NET remoting DNS resolution in tests. - // It registers as both a singleton and a hosted service via factory. - var akkaDescriptors = services - .Where(d => - d.ServiceType == typeof(AkkaHostedService) || - (d.ServiceType == typeof(IHostedService) && d.ImplementationFactory != null)) + // Remove the factory-registered IHostedService registrations so + // Akka.NET remoting / DNS resolution never starts in tests — but + // keep the AkkaHostedService SINGLETON resolvable: IClusterNodeProvider + // (and other services) depend on it via GetRequiredService. + var hostedServiceDescriptors = services + .Where(d => d.ServiceType == typeof(IHostedService) && d.ImplementationFactory != null) .ToList(); - foreach (var d in akkaDescriptors) + foreach (var d in hostedServiceDescriptors) services.Remove(d); }); }