fix(communication): DebugStreamService drops the session on an InstanceNotFound snapshot (review 2026-10-21 03/M-3)
This commit is contained in:
@@ -169,6 +169,61 @@ public class DebugStreamServiceTests : TestKit
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Verifies that an InstanceNotFound snapshot does not leave a registered session behind (review 2026-10-21 03/M-3).</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task StartStreamAsync_InstanceNotFoundSnapshot_DoesNotRegisterASession()
|
||||
{
|
||||
var instance = new Instance("Site1.Pump01") { Id = 7, SiteId = 3 };
|
||||
var site = new Site("Site One", "site-1")
|
||||
{
|
||||
Id = 3,
|
||||
GrpcNodeAAddress = "http://localhost:5100",
|
||||
GrpcNodeBAddress = "http://localhost:5200"
|
||||
};
|
||||
|
||||
var instanceRepo = Substitute.For<ITemplateEngineRepository>();
|
||||
instanceRepo.GetInstanceByIdAsync(7, Arg.Any<CancellationToken>()).Returns(instance);
|
||||
var siteRepo = Substitute.For<ISiteRepository>();
|
||||
siteRepo.GetSiteByIdAsync(3, Arg.Any<CancellationToken>()).Returns(site);
|
||||
|
||||
var services = new ServiceCollection();
|
||||
services.AddScoped(_ => instanceRepo);
|
||||
services.AddScoped(_ => siteRepo);
|
||||
using var provider = services.BuildServiceProvider();
|
||||
|
||||
var commProbe = CreateTestProbe();
|
||||
var commService = new CommunicationService(
|
||||
Options.Create(new CommunicationOptions()),
|
||||
NullLogger<CommunicationService>.Instance);
|
||||
commService.SetCommunicationActor(commProbe.Ref);
|
||||
|
||||
using var grpcFactory = new Grpc.MockSiteStreamGrpcClientFactory(
|
||||
new Grpc.MockSiteStreamGrpcClient());
|
||||
using var service = new DebugStreamService(
|
||||
commService, provider, grpcFactory, NullLogger<DebugStreamService>.Instance);
|
||||
service.SetActorSystem(Sys);
|
||||
|
||||
var startTask = service.StartStreamAsync(instanceId: 7, onEvent: _ => { }, onTerminated: () => { });
|
||||
commProbe.ExpectMsg<SiteEnvelope>(TimeSpan.FromSeconds(5));
|
||||
var bridgeActor = commProbe.LastSender;
|
||||
Watch(bridgeActor);
|
||||
|
||||
bridgeActor.Tell(new ZB.MOM.WW.ScadaBridge.Commons.Messages.DebugView.DebugViewSnapshot(
|
||||
"Site1.Pump01",
|
||||
new List<ZB.MOM.WW.ScadaBridge.Commons.Messages.Streaming.AttributeValueChanged>(),
|
||||
new List<ZB.MOM.WW.ScadaBridge.Commons.Messages.Streaming.AlarmStateChanged>(),
|
||||
DateTimeOffset.UtcNow,
|
||||
InstanceNotFound: true));
|
||||
var session = await startTask;
|
||||
|
||||
// The caller still sees the flag, but the bridge actor has stopped itself — the
|
||||
// service must not keep a live-looking session for it (keepalives to a dead actor).
|
||||
Assert.True(session.InitialSnapshot.InstanceNotFound);
|
||||
Assert.Equal(0, service.SessionCount);
|
||||
ExpectTerminated(bridgeActor, TimeSpan.FromSeconds(3));
|
||||
}
|
||||
|
||||
// --- single-endpoint sites ---
|
||||
|
||||
/// <summary>Verifies that a single-endpoint site uses its sole address for both node slots.</summary>
|
||||
|
||||
Reference in New Issue
Block a user