using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; namespace ScadaLink.DeploymentManager.Tests; /// /// DeploymentManager-008: DeploymentManagerOptions must be resolvable via the /// Options pattern and bindable to the "ScadaLink:DeploymentManager" /// configuration section. The component itself does not depend on /// IConfiguration (enforced by Host's OptionsTests) — the Host binds the /// section; AddDeploymentManager only guarantees IOptions resolvability. /// public class ServiceCollectionExtensionsTests { [Fact] public void AddDeploymentManager_RegistersResolvableOptions_WithDefaults() { var services = new ServiceCollection(); services.AddDeploymentManager(); using var provider = services.BuildServiceProvider(); var options = provider.GetRequiredService>().Value; // No section bound -> the option-class defaults are retained. Assert.Equal(TimeSpan.FromSeconds(5), options.OperationLockTimeout); } [Fact] public void AddDeploymentManager_OptionsBindToConfigurationSection_AsTheHostWires() { // Mirrors the Host wiring: the Host calls Configure // against OptionsSection, then AddDeploymentManager(). var configuration = new ConfigurationBuilder() .AddInMemoryCollection(new Dictionary { ["ScadaLink:DeploymentManager:OperationLockTimeout"] = "00:00:09", ["ScadaLink:DeploymentManager:ArtifactDeploymentTimeoutPerSite"] = "00:03:00" }) .Build(); var services = new ServiceCollection(); services.Configure( configuration.GetSection(ServiceCollectionExtensions.OptionsSection)); services.AddDeploymentManager(); using var provider = services.BuildServiceProvider(); var options = provider.GetRequiredService>().Value; Assert.Equal(TimeSpan.FromSeconds(9), options.OperationLockTimeout); Assert.Equal(TimeSpan.FromMinutes(3), options.ArtifactDeploymentTimeoutPerSite); } [Fact] public void OptionsSection_MatchesTheConventionalComponentSectionPath() { Assert.Equal("ScadaLink:DeploymentManager", ServiceCollectionExtensions.OptionsSection); } // CentralUI-006: the deployment-status notifier must be a singleton so the // scoped DeploymentService and the Central UI's scoped Blazor page share // one instance — without that, a push notification raised by the service // would never reach the page's subscription. [Fact] public void AddDeploymentManager_RegistersDeploymentStatusNotifier_AsSingleton() { var services = new ServiceCollection(); services.AddLogging(); services.AddDeploymentManager(); using var provider = services.BuildServiceProvider(); var fromRoot = provider.GetRequiredService(); using var scope = provider.CreateScope(); var fromScope = scope.ServiceProvider.GetRequiredService(); Assert.IsType(fromRoot); Assert.Same(fromRoot, fromScope); } }