From 872cf7e37a4e8150ec47b1a026915622e0c4cbee Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 16 Jul 2026 18:27:59 -0400 Subject: [PATCH] test(secrets): register ISecretResolver in driver-factory resilience tests (Task 10 fix) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The full-suite gate caught a real regression: AddOtOpcUaDriverFactories' registration now resolves ISecretResolver (for Galaxy/OpcUaClient secret: refs, Tasks 7-8), so the two ResilienceInvokerFactoryRegistrationTests that build a minimal container and resolve the invoker factory threw 'No service for ISecretResolver'. The real host always registers it via AddZbSecrets (unconditional, Task 3), and GetRequiredService correctly fails-fast for a genuinely misconfigured host — so the fix is to complete the test container with a stub resolver, matching production composition. Test-only. --- ...esilienceInvokerFactoryRegistrationTests.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/ResilienceInvokerFactoryRegistrationTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/ResilienceInvokerFactoryRegistrationTests.cs index 6d6ec6b6..039b975f 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/ResilienceInvokerFactoryRegistrationTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests/ResilienceInvokerFactoryRegistrationTests.cs @@ -4,6 +4,7 @@ using Xunit; using ZB.MOM.WW.OtOpcUa.Core.Abstractions; using ZB.MOM.WW.OtOpcUa.Core.Resilience; using ZB.MOM.WW.OtOpcUa.Host.Drivers; +using ZB.MOM.WW.Secrets.Abstractions; namespace ZB.MOM.WW.OtOpcUa.Host.IntegrationTests; @@ -24,6 +25,9 @@ public sealed class ResilienceInvokerFactoryRegistrationTests { var services = new ServiceCollection(); services.AddLogging(); + // The driver-factory registration resolves ISecretResolver (Galaxy/OpcUaClient secret: refs); + // the real host always has it via AddZbSecrets (registered unconditionally). Mirror that here. + services.AddSingleton(new StubSecretResolver()); services.AddOtOpcUaDriverFactories(); using var sp = services.BuildServiceProvider(); @@ -38,6 +42,9 @@ public sealed class ResilienceInvokerFactoryRegistrationTests { var services = new ServiceCollection(); services.AddLogging(); + // The driver-factory registration resolves ISecretResolver (Galaxy/OpcUaClient secret: refs); + // the real host always has it via AddZbSecrets (registered unconditionally). Mirror that here. + services.AddSingleton(new StubSecretResolver()); services.AddOtOpcUaDriverFactories(); using var sp = services.BuildServiceProvider(); @@ -54,6 +61,9 @@ public sealed class ResilienceInvokerFactoryRegistrationTests { var services = new ServiceCollection(); services.AddLogging(); + // The driver-factory registration resolves ISecretResolver (Galaxy/OpcUaClient secret: refs); + // the real host always has it via AddZbSecrets (registered unconditionally). Mirror that here. + services.AddSingleton(new StubSecretResolver()); services.AddOtOpcUaDriverFactories(); using var sp = services.BuildServiceProvider(); @@ -65,4 +75,12 @@ public sealed class ResilienceInvokerFactoryRegistrationTests sp.GetRequiredService() .ShouldBeSameAs(sp.GetRequiredService(), "builder must be a singleton"); } + + // Minimal ISecretResolver so AddOtOpcUaDriverFactories' registration (which resolves it for + // Galaxy/OpcUaClient secret: refs) can be built. These tests exercise no secret: refs, so + // returning null for every name is sufficient — the real resolver comes from AddZbSecrets. + private sealed class StubSecretResolver : ISecretResolver + { + public Task GetAsync(SecretName name, CancellationToken ct) => Task.FromResult(null); + } }