fix(mtconnect): a delivered /sample chunk clears an unanswered-write degradation (review r2 N-5)
Coordinator ruling: a delivered chunk proves the Agent is alive (the analogue of OpcUaClient's good keep-alive), so TryMarkStreamDelivered - generation-checked under _subscriptionLock - also clears _writeDegraded. The degradation no longer sticks forever on a subscription-only driver. Test: unanswered write -> Degraded, stays Degraded with nothing else happening (positive control), the next chunk -> Healthy; red with the clear removed. Round-2 doc text corrected. Refs #743 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
This commit is contained in:
+10
-10
@@ -167,11 +167,12 @@ public sealed class MTConnectBatchedWriteTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// r1 N-5: stream evidence does not clear an unanswered write — neither a delivered /sample chunk nor a read
|
||||
/// served from the live pump index. The next answered write does (the positive control).
|
||||
/// r2 N-5 (coordinator ruling): on a subscription-only driver an unanswered write degrades, and the next delivered
|
||||
/// /sample chunk restores Healthy (a delivered chunk proves the Agent is alive). Positive control: with no chunk
|
||||
/// it stays Degraded.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task Stream_evidence_does_not_clear_an_unanswered_write_but_an_answered_write_does()
|
||||
public async Task A_delivered_chunk_clears_an_unanswered_write_and_without_one_it_stays_degraded()
|
||||
{
|
||||
var (driver, client) = await WritableAsync();
|
||||
try
|
||||
@@ -181,20 +182,19 @@ public sealed class MTConnectBatchedWriteTests
|
||||
client.WriteFailure = new HttpRequestException("connection refused");
|
||||
await driver.WriteAsync([new WriteRequest(PosRaw, 9.5)], Ct);
|
||||
driver.GetHealth().State.ShouldBe(DriverState.Degraded);
|
||||
|
||||
// Positive control: nothing else happens — it stays Degraded (no read, no write, no chunk).
|
||||
var currentCalls = client.CurrentCallCount;
|
||||
driver.GetHealth().State.ShouldBe(DriverState.Degraded);
|
||||
client.CurrentCallCount.ShouldBe(currentCalls);
|
||||
|
||||
await client.PumpAsync(MTConnectPumpGenerationChunks.Pos(113, 118, "2.5")).WaitAsync(TimeSpan.FromSeconds(30), Ct);
|
||||
(await driver.ReadAsync([PosRaw], Ct)).Single().StatusCode.ShouldBe(Good);
|
||||
client.CurrentCallCount.ShouldBe(currentCalls, "the read was served from the live index");
|
||||
|
||||
driver.GetHealth().State.ShouldBe(DriverState.Degraded, "stream evidence is not an answer to the write");
|
||||
|
||||
client.WriteFailure = null;
|
||||
await driver.WriteAsync([new WriteRequest(PosRaw, 3.5)], Ct);
|
||||
driver.GetHealth().State.ShouldBe(DriverState.Healthy);
|
||||
driver.GetHealth().State.ShouldBe(DriverState.Healthy, "a delivered chunk proves the Agent is alive");
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.WriteFailure = null;
|
||||
await driver.ShutdownAsync(CancellationToken.None);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user