92 lines
3.7 KiB
C#
92 lines
3.7 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using ArchestrA.MxAccess;
|
|
using Shouldly;
|
|
using Xunit;
|
|
using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Host.Backend;
|
|
using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Host.Backend.Galaxy;
|
|
using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Host.Backend.MxAccess;
|
|
using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Host.Sta;
|
|
using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Shared.Contracts;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Host.Tests;
|
|
|
|
[Trait("Category", "Unit")]
|
|
public sealed class HostStatusPushTests
|
|
{
|
|
/// <summary>
|
|
/// PR 8 — when MxAccessClient.ConnectionStateChanged fires false→true→false,
|
|
/// MxAccessGalaxyBackend raises OnHostStatusChanged once per transition with
|
|
/// HostName=ClientName, RuntimeStatus="Running"/"Stopped", and a timestamp.
|
|
/// This is the gateway-level signal; per-platform ScanState probes are deferred.
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task ConnectionStateChanged_raises_OnHostStatusChanged_with_gateway_name()
|
|
{
|
|
using var pump = new StaPump("Test.Sta");
|
|
await pump.WaitForStartedAsync();
|
|
var proxy = new FakeProxy();
|
|
var mx = new MxAccessClient(pump, proxy, "GatewayClient", new MxAccessClientOptions { AutoReconnect = false });
|
|
using var backend = new MxAccessGalaxyBackend(
|
|
new GalaxyRepository(new GalaxyRepositoryOptions { ConnectionString = "Server=.;Database=ZB;Integrated Security=True;" }),
|
|
mx,
|
|
historian: null);
|
|
|
|
var notifications = new ConcurrentQueue<HostConnectivityStatus>();
|
|
backend.OnHostStatusChanged += (_, s) => notifications.Enqueue(s);
|
|
|
|
await mx.ConnectAsync();
|
|
await mx.DisconnectAsync();
|
|
|
|
notifications.Count.ShouldBe(2);
|
|
notifications.TryDequeue(out var first).ShouldBeTrue();
|
|
first!.HostName.ShouldBe("GatewayClient");
|
|
first.RuntimeStatus.ShouldBe("Running");
|
|
first.LastObservedUtcUnixMs.ShouldBeGreaterThan(0);
|
|
|
|
notifications.TryDequeue(out var second).ShouldBeTrue();
|
|
second!.HostName.ShouldBe("GatewayClient");
|
|
second.RuntimeStatus.ShouldBe("Stopped");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Dispose_unsubscribes_so_post_dispose_state_changes_do_not_fire_events()
|
|
{
|
|
using var pump = new StaPump("Test.Sta");
|
|
await pump.WaitForStartedAsync();
|
|
var proxy = new FakeProxy();
|
|
var mx = new MxAccessClient(pump, proxy, "GatewayClient", new MxAccessClientOptions { AutoReconnect = false });
|
|
var backend = new MxAccessGalaxyBackend(
|
|
new GalaxyRepository(new GalaxyRepositoryOptions { ConnectionString = "Server=.;Database=ZB;Integrated Security=True;" }),
|
|
mx,
|
|
historian: null);
|
|
|
|
var count = 0;
|
|
backend.OnHostStatusChanged += (_, _) => Interlocked.Increment(ref count);
|
|
|
|
await mx.ConnectAsync();
|
|
count.ShouldBe(1);
|
|
|
|
backend.Dispose();
|
|
await mx.DisconnectAsync();
|
|
|
|
count.ShouldBe(1); // no second notification after Dispose
|
|
}
|
|
|
|
private sealed class FakeProxy : IMxProxy
|
|
{
|
|
private int _next = 1;
|
|
public int Register(string _) => 42;
|
|
public void Unregister(int _) { }
|
|
public int AddItem(int _, string __) => Interlocked.Increment(ref _next);
|
|
public void RemoveItem(int _, int __) { }
|
|
public void AdviseSupervisory(int _, int __) { }
|
|
public void UnAdviseSupervisory(int _, int __) { }
|
|
public void Write(int _, int __, object ___, int ____) { }
|
|
public event MxDataChangeHandler? OnDataChange { add { } remove { } }
|
|
public event MxWriteCompleteHandler? OnWriteComplete { add { } remove { } }
|
|
}
|
|
}
|