fix(runtime): diagnostics Name stays the string instance id; order-tolerant write-cap test (A6 follow-through)
DriverInstanceDiagnostics.Name carries the string driver-instance id (what /hosts, telemetry and the artifact key on) and DriverInstanceId the DB row Guid; the wire record has no slot for the authored display name. The write-cap test asserts entry order per slot pair instead of completion order of two concurrent writes. Refs #731 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
This commit is contained in:
@@ -115,7 +115,7 @@ else
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Driver</th>
|
||||
<th>Driver instance</th>
|
||||
<th>Row id</th>
|
||||
<th>State</th>
|
||||
<th class="numeric">Connected devices</th>
|
||||
|
||||
@@ -2540,15 +2540,17 @@ public sealed class DriverHostActor : ReceiveActor, IWithTimers, IWithUnboundedS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// One child's diagnostics row. Device counts come from the driver's host statuses when it is an
|
||||
/// <c>IHostConnectivityProbe</c> (Running = connected; Stopped/Faulted = faulted; Unknown = neither);
|
||||
/// a single-host driver counts as one device, connected while it reports Healthy or Degraded and
|
||||
/// faulted while it reports Faulted. A child that has not published yet reports "Connecting" (or
|
||||
/// "Stubbed") with its spawn time as the last change.
|
||||
/// One child's diagnostics row. <c>Name</c> carries the string driver-instance id — the identity every
|
||||
/// other surface (/hosts, telemetry, the artifact) keys on — and <c>DriverInstanceId</c> the DB row Guid;
|
||||
/// the wire record has no slot for the authored display name. Device counts come from the driver's host
|
||||
/// statuses when it is an <c>IHostConnectivityProbe</c> (Running = connected; Stopped/Faulted = faulted;
|
||||
/// Unknown = neither); a single-host driver counts as one device, connected while it reports Healthy or
|
||||
/// Degraded and faulted while it reports Faulted. A child that has not published yet reports
|
||||
/// "Connecting" (or "Stubbed") with its spawn time as the last change.
|
||||
/// </summary>
|
||||
private static DriverInstanceDiagnostics ToDiagnostics(string driverInstanceId, ChildEntry entry, ChildHealthRecord? health)
|
||||
{
|
||||
var name = string.IsNullOrEmpty(entry.Spec.Name) ? driverInstanceId : entry.Spec.Name;
|
||||
var name = driverInstanceId;
|
||||
if (entry.Stubbed)
|
||||
return new DriverInstanceDiagnostics(entry.Spec.DriverInstanceRowId, name, "Stubbed", 0, 0, entry.SpawnedUtc);
|
||||
if (health is null)
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@ namespace ZB.MOM.WW.OtOpcUa.Runtime.Tests.Drivers;
|
||||
/// <summary>
|
||||
/// Review 02 U1: <c>GetDiagnostics</c> answered a placeholder — <c>Guid.Empty</c>, "Spawned", zero devices and
|
||||
/// "now" for every child, in every behaviour — so the snapshot looked live and said nothing. It now carries
|
||||
/// each child's row id, authored name, last-published health state, device counts and last change time.
|
||||
/// each child's row id, instance id, last-published health state, device counts and last change time.
|
||||
/// </summary>
|
||||
public sealed class DriverHostActorDiagnosticsTests : RuntimeActorTestBase
|
||||
{
|
||||
@@ -39,7 +39,7 @@ public sealed class DriverHostActorDiagnosticsTests : RuntimeActorTestBase
|
||||
snapshot.RunningFromCache.ShouldBeFalse();
|
||||
var driver = snapshot.Drivers.ShouldHaveSingleItem();
|
||||
driver.DriverInstanceId.ShouldBe(rowId, "the real row id, not Guid.Empty");
|
||||
driver.Name.ShouldBe("Line1-Modbus", "the authored name, not the instance id");
|
||||
driver.Name.ShouldBe(DriverId, "the string instance id every other surface keys on");
|
||||
driver.State.ShouldBe("Healthy");
|
||||
driver.ConnectedDevices.ShouldBe(1);
|
||||
driver.FaultedDevices.ShouldBe(0);
|
||||
|
||||
+9
-1
@@ -96,7 +96,12 @@ public sealed class DriverInstanceActorConcurrentWriteTests : RuntimeActorTestBa
|
||||
driver.ReleaseWrites();
|
||||
var results = await Task.WhenAll(asks);
|
||||
results.ShouldAllBe(r => r.Success);
|
||||
driver.Writes.Select(w => w.FullReference).ShouldBe(new[] { "tag-0", "tag-1", "tag-2", "tag-3" });
|
||||
// Entry order: the first two slots went to the first two writes (in either order — they are
|
||||
// concurrent), the queued pair entered only after a slot freed, in queue order.
|
||||
var entered = driver.EnteredRefs;
|
||||
entered.Count.ShouldBe(4);
|
||||
entered.Take(2).ShouldBe(new[] { "tag-0", "tag-1" }, ignoreOrder: true);
|
||||
entered.Skip(2).ShouldBe(new[] { "tag-2", "tag-3" });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -129,6 +134,7 @@ public sealed class DriverInstanceActorConcurrentWriteTests : RuntimeActorTestBa
|
||||
{
|
||||
private readonly StubHandle _handle = new();
|
||||
private readonly ConcurrentQueue<WriteRequest> _writes = new();
|
||||
private readonly ConcurrentQueue<string> _enteredRefs = new();
|
||||
private TaskCompletionSource _release = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
private int _entered;
|
||||
private int _inside;
|
||||
@@ -138,6 +144,7 @@ public sealed class DriverInstanceActorConcurrentWriteTests : RuntimeActorTestBa
|
||||
public bool HoldWrites { get; init; }
|
||||
|
||||
public IReadOnlyList<WriteRequest> Writes => _writes.ToArray();
|
||||
public IReadOnlyList<string> EnteredRefs => _enteredRefs.ToArray();
|
||||
public int WritesEntered => Volatile.Read(ref _entered);
|
||||
public int MaxConcurrentWrites => Volatile.Read(ref _maxInside);
|
||||
|
||||
@@ -154,6 +161,7 @@ public sealed class DriverInstanceActorConcurrentWriteTests : RuntimeActorTestBa
|
||||
public async Task<IReadOnlyList<WriteResult>> WriteAsync(IReadOnlyList<WriteRequest> writes, CancellationToken cancellationToken)
|
||||
{
|
||||
Interlocked.Increment(ref _entered);
|
||||
foreach (var w in writes) _enteredRefs.Enqueue(w.FullReference);
|
||||
var inside = Interlocked.Increment(ref _inside);
|
||||
int seen;
|
||||
while (inside > (seen = Volatile.Read(ref _maxInside)))
|
||||
|
||||
Reference in New Issue
Block a user