using Akka.Actor; using Akka.TestKit.Xunit2; using Microsoft.Extensions.DependencyInjection; using NSubstitute; using ScadaLink.Commons.Interfaces.Repositories; using ScadaLink.Communication.Actors; namespace ScadaLink.Communication.Tests; /// /// Regression tests for Communication-004 — coordinator actors must declare an /// explicit Resume supervision strategy per the CLAUDE.md decision /// ("Resume for coordinator actors"). A child fault under the default /// (Restart) strategy would wipe a child's in-memory state; the long-lived /// coordinators own per-site ClusterClients and must not silently discard /// their children on a transient fault. /// public class CoordinatorSupervisionTests : TestKit { /// /// Test-only subclass that exposes the protected /// so the configured directive can be asserted directly. /// private sealed class CentralCommunicationActorProbe : CentralCommunicationActor { public CentralCommunicationActorProbe(IServiceProvider sp, ISiteClientFactory factory) : base(sp, factory) { } public SupervisorStrategy GetSupervisorStrategy() => SupervisorStrategy(); } /// /// Test-only subclass that exposes the protected . /// private sealed class SiteCommunicationActorProbe : SiteCommunicationActor { public SiteCommunicationActorProbe(string siteId, CommunicationOptions options, IActorRef dm) : base(siteId, options, dm) { } public SupervisorStrategy GetSupervisorStrategy() => SupervisorStrategy(); } private static IServiceProvider EmptyServiceProvider() { var mockRepo = Substitute.For(); mockRepo.GetAllSitesAsync(Arg.Any()) .Returns(new List()); var services = new ServiceCollection(); services.AddScoped(_ => mockRepo); return services.BuildServiceProvider(); } [Fact] public void CentralCommunicationActor_SupervisorStrategy_IsResume() { var sp = EmptyServiceProvider(); var factory = Substitute.For(); var actorRef = new Akka.TestKit.TestActorRef( Sys, Props.Create(() => new CentralCommunicationActorProbe(sp, factory))); var strategy = actorRef.UnderlyingActor.GetSupervisorStrategy(); var oneForOne = Assert.IsType(strategy); var directive = oneForOne.Decider.Decide(new InvalidOperationException("transient child fault")); Assert.Equal(Directive.Resume, directive); } [Fact] public void SiteCommunicationActor_SupervisorStrategy_IsResume() { var dmProbe = CreateTestProbe(); var actorRef = new Akka.TestKit.TestActorRef( Sys, Props.Create(() => new SiteCommunicationActorProbe("site1", new CommunicationOptions(), dmProbe.Ref))); var strategy = actorRef.UnderlyingActor.GetSupervisorStrategy(); var oneForOne = Assert.IsType(strategy); var directive = oneForOne.Decider.Decide(new InvalidOperationException("transient child fault")); Assert.Equal(Directive.Resume, directive); } }