using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; namespace ZB.MOM.WW.ScadaBridge.HealthMonitoring.Tests; /// /// M2.16 (#30) idempotency regression — code-review finding on commit d81f747. /// /// uses a /// factory-lambda overload of AddHostedService, which sets only /// ImplementationFactory and leaves ImplementationType null. The original /// ImplementationType == guard was therefore a silent no-op: a second call would spin /// up a second (two timers both polling). /// The fix uses a private marker singleton whose ServiceType is always set. /// /// public class AddSiteEventLogHealthMetricsBridgeTests { [Fact] public void AddSiteEventLogHealthMetricsBridge_IsIdempotent_DoesNotDoubleRegister_HostedService() { // M2.16 (#30): calling the bridge method twice must register exactly one // SiteEventLogFailureCountReporter. Without the marker-type guard the // ImplementationType == check was a no-op for factory-lambda registrations, // so the second call would have added a second hosted service (two timers). var services = new ServiceCollection(); services.AddSingleton(); services.AddSingleton(typeof(ILogger<>), typeof(NullLogger<>)); services.AddHealthMonitoring(); Func> factory = _ => () => 0L; services.AddSiteEventLogHealthMetricsBridge(factory); services.AddSiteEventLogHealthMetricsBridge(factory); // Count IHostedService descriptors whose factory produces a // SiteEventLogFailureCountReporter. Because it is factory-registered, // ImplementationType is null — we count by resolving and checking type. using var provider = services.BuildServiceProvider(); var reporters = provider.GetServices() .OfType() .ToList(); Assert.Single(reporters); } }