64e3fbe035
v2-ci / build (push) Failing after 1m43s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
Adds <summary>, <param>, <typeparam>, and <inheritdoc/> tags to public members surfaced by commentchecker — resolves 5,847 of 5,869 issues (99.6%) across three /fixdocs passes.
147 lines
5.3 KiB
C#
147 lines
5.3 KiB
C#
using Shouldly;
|
|
using Xunit;
|
|
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
|
using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Health;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests.Health;
|
|
|
|
/// <summary>
|
|
/// Tests for <see cref="HostStatusAggregator"/> — the merge + diff logic for the
|
|
/// transport entry plus per-platform probe entries that
|
|
/// <c>IHostConnectivityProbe.GetHostStatuses()</c> surfaces.
|
|
/// </summary>
|
|
public sealed class HostStatusAggregatorTests
|
|
{
|
|
private static HostConnectivityStatus Status(string host, HostState state) =>
|
|
new(host, state, DateTime.UtcNow);
|
|
|
|
/// <summary>Verifies that snapshot is empty when nothing is tracked.</summary>
|
|
[Fact]
|
|
public void Snapshot_Empty_WhenNothingTracked()
|
|
{
|
|
var agg = new HostStatusAggregator();
|
|
agg.Snapshot().ShouldBeEmpty();
|
|
}
|
|
|
|
/// <summary>Verifies that updating a new host fires a change event with Unknown as previous state.</summary>
|
|
[Fact]
|
|
public void Update_NewHost_FiresChange_PreviousIsUnknown()
|
|
{
|
|
var agg = new HostStatusAggregator();
|
|
var captured = new List<HostStatusChangedEventArgs>();
|
|
agg.OnHostStatusChanged += (_, e) => captured.Add(e);
|
|
|
|
agg.Update(Status("PlatformA", HostState.Running));
|
|
|
|
captured.Count.ShouldBe(1);
|
|
captured[0].HostName.ShouldBe("PlatformA");
|
|
captured[0].OldState.ShouldBe(HostState.Unknown);
|
|
captured[0].NewState.ShouldBe(HostState.Running);
|
|
}
|
|
|
|
/// <summary>Verifies that updating to the same state does not fire a change event.</summary>
|
|
[Fact]
|
|
public void Update_SameState_DoesNotFire()
|
|
{
|
|
var agg = new HostStatusAggregator();
|
|
agg.Update(Status("PlatformA", HostState.Running));
|
|
|
|
var captured = new List<HostStatusChangedEventArgs>();
|
|
agg.OnHostStatusChanged += (_, e) => captured.Add(e);
|
|
|
|
agg.Update(Status("PlatformA", HostState.Running));
|
|
|
|
captured.ShouldBeEmpty();
|
|
}
|
|
|
|
/// <summary>Verifies that state transitions fire change events with correct old and new states.</summary>
|
|
[Fact]
|
|
public void Update_StateTransition_FiresChangeWithCorrectPreviousAndNew()
|
|
{
|
|
var agg = new HostStatusAggregator();
|
|
agg.Update(Status("PlatformA", HostState.Running));
|
|
|
|
var captured = new List<HostStatusChangedEventArgs>();
|
|
agg.OnHostStatusChanged += (_, e) => captured.Add(e);
|
|
|
|
agg.Update(Status("PlatformA", HostState.Stopped));
|
|
|
|
captured.Count.ShouldBe(1);
|
|
captured[0].OldState.ShouldBe(HostState.Running);
|
|
captured[0].NewState.ShouldBe(HostState.Stopped);
|
|
}
|
|
|
|
/// <summary>Verifies that snapshot reflects every upserted host.</summary>
|
|
[Fact]
|
|
public void Snapshot_ReflectsEveryUpsertedHost()
|
|
{
|
|
var agg = new HostStatusAggregator();
|
|
agg.Update(Status("Transport", HostState.Running));
|
|
agg.Update(Status("PlatformA", HostState.Running));
|
|
agg.Update(Status("PlatformB", HostState.Stopped));
|
|
|
|
var snap = agg.Snapshot();
|
|
|
|
snap.Count.ShouldBe(3);
|
|
snap.Select(s => s.HostName).OrderBy(x => x).ShouldBe(new[] { "PlatformA", "PlatformB", "Transport" });
|
|
snap.First(s => s.HostName == "PlatformB").State.ShouldBe(HostState.Stopped);
|
|
}
|
|
|
|
/// <summary>Verifies that host name comparison is case-insensitive.</summary>
|
|
[Fact]
|
|
public void Update_HostNameComparison_IsCaseInsensitive()
|
|
{
|
|
var agg = new HostStatusAggregator();
|
|
var captured = new List<HostStatusChangedEventArgs>();
|
|
agg.OnHostStatusChanged += (_, e) => captured.Add(e);
|
|
|
|
agg.Update(Status("PlatformA", HostState.Running));
|
|
agg.Update(Status("platforma", HostState.Stopped)); // same host, different case
|
|
|
|
captured.Count.ShouldBe(2);
|
|
captured[1].OldState.ShouldBe(HostState.Running);
|
|
captured[1].NewState.ShouldBe(HostState.Stopped);
|
|
agg.Snapshot().Count.ShouldBe(1);
|
|
}
|
|
|
|
/// <summary>Verifies that removing a tracked host returns true and drops it from snapshot.</summary>
|
|
[Fact]
|
|
public void Remove_TrackedHost_ReturnsTrue_AndDropsFromSnapshot()
|
|
{
|
|
var agg = new HostStatusAggregator();
|
|
agg.Update(Status("PlatformA", HostState.Running));
|
|
agg.Remove("PlatformA").ShouldBeTrue();
|
|
agg.Snapshot().ShouldBeEmpty();
|
|
}
|
|
|
|
/// <summary>Verifies that removing an unknown host returns false.</summary>
|
|
[Fact]
|
|
public void Remove_UnknownHost_ReturnsFalse()
|
|
{
|
|
var agg = new HostStatusAggregator();
|
|
agg.Remove("Nope").ShouldBeFalse();
|
|
}
|
|
|
|
/// <summary>Verifies that concurrent updates do not corrupt the internal dictionary.</summary>
|
|
[Fact]
|
|
public void ConcurrentUpdates_DoNotCorruptDictionary()
|
|
{
|
|
var agg = new HostStatusAggregator();
|
|
const int threadCount = 8;
|
|
const int updatesPerThread = 250;
|
|
|
|
var tasks = Enumerable.Range(0, threadCount).Select(t => Task.Run(() =>
|
|
{
|
|
for (var i = 0; i < updatesPerThread; i++)
|
|
{
|
|
var hostName = $"Host{(t * updatesPerThread + i) % 32}";
|
|
var state = i % 2 == 0 ? HostState.Running : HostState.Stopped;
|
|
agg.Update(Status(hostName, state));
|
|
}
|
|
})).ToArray();
|
|
|
|
Task.WaitAll(tasks);
|
|
agg.Snapshot().Count.ShouldBeLessThanOrEqualTo(32);
|
|
}
|
|
}
|