fix(tests): three real failures the integration suite had stopped catching
None of these were fixture absence. Each is a guard that went quietly wrong and then reported the wrong thing. PrimaryGateFailoverTests — per-cluster mesh Phase 6 (a2c5d57f) moved RedundancyStateActor out of WithOtOpcUaControlPlaneSingletons into its own cluster-role-scoped registration, made from Program.cs's DRIVER branch. The harness models a fused admin,driver node but was never updated, so from that commit onward NO node it built spawned the singleton: nothing published redundancy-state, both nodes sat at "role unknown" forever, and the test polled 45s and timed out. The test's own summary calls this its negative control for a broken redundancy-topic subscribe — it fired correctly, at the harness rather than at production. Second time this shape has bitten the harness; the AddOtOpcUaRuntime note a few lines up records the first. DriverProbeRegistrationTests — the expected driver set was a hand-written array kept in sync by comment, and it drifted when Sql (9b5a9687) and Mqtt (f79d13e2) shipped. It failed as "12 where 10 expected", which names neither driver and reads as if the probes were wrong. It also could not catch the direction that matters: a driver type registered with no probe passed silently, because a hand-written list only grows when someone remembers, and this test exists for the case where nobody did. Now derived from DriverTypeNames.All, both directions, plus an explicit case-drift test for the two types whose AdminUI key differs in case from the constant (TwinCat/TwinCAT, Focas/FOCAS) — which the derived tests cannot cover, since they compare the constants to themselves. DriverProbeHandshakeE2eTests.AbCip_Green_AgainstSim — the probe config still used the retired v2 `Tags: [{DeviceHostAddress, TagPath}]` shape, so AbCipDriverOptions.RawTags bound empty, the probe fell through to its @raw_cpu_type system-tag fallback, and ab_server answered ErrorBadParam. The test has therefore spent the whole v3 migration exercising the one path its own comment says it does not exercise. Rewritten to the v3 RawTags shape, and the assertion tightened from ShouldContain("CIP session OK") to an exact match: the probe's two green messages both contain that substring, so the loose form would go green again the moment the config merely reached the controller, whether or not the authored tag resolved. Falsified each: drop the MTConnect probe (2 red, by name), remove the harness singleton registration (back to the 48s "role unknown" timeout), break the RawTags key (back to ErrorBadParam). Host.IntegrationTests 211 passed / 4 skipped / 0 failed, against live fixtures on 10.100.0.35. Still red and NOT addressed here: the AbLegacy integration suite (4 tests). Its fixture is genuinely down, but it hard-fails instead of skipping because the AbCip ControlLogix container holds :44818 — the reachability guard cannot tell "my ab_server" from "someone else's", so SkipReason stays null and SLC500-mode PCCC runs against a ControlLogix. Needs either distinct fixture ports or a family-aware guard; both are shared-infrastructure changes. Claude-Session: https://claude.ai/code/session_015p7wGqy3YpZNCpDzTpGMKo
This commit is contained in:
+17
-2
@@ -178,11 +178,26 @@ public sealed class DriverProbeHandshakeE2eTests
|
||||
// ControlLogix instead returns ErrorNotFound, which the probe classifies as
|
||||
// reachable). Whether the `@raw_cpu_type` system-tag fallback is valid on a real
|
||||
// ControlLogix is a hardware-gated follow-up (AbCipDriverOptions.cs flags it deferred).
|
||||
// ⚠️ The config must use the v3 `RawTags` shape — `[{RawPath, TagConfig, WriteIdempotent,
|
||||
// DeviceName}]`, where the Logix tag path lives inside the TagConfig blob as `tagPath`. This
|
||||
// test passed the retired v2 `Tags: [{DeviceHostAddress, TagPath}]` shape until 2026-08-01, so
|
||||
// AbCipDriverOptions.RawTags bound EMPTY, the probe fell through to its `@raw_cpu_type` system-tag
|
||||
// fallback, and ab_server answered ErrorBadParam. Which is to say it spent that whole time
|
||||
// exercising the one path the comment above says it does not exercise — and reporting it as a
|
||||
// failure of the fixture rather than of the config shape.
|
||||
var result = await new AbCipDriverProbe().ProbeAsync(
|
||||
$"{{\"Devices\":[{{\"HostAddress\":\"ab://{DockerHost}:{AbCipPort}/1,0\"}}]," +
|
||||
$"\"Tags\":[{{\"DeviceHostAddress\":\"ab://{DockerHost}:{AbCipPort}/1,0\",\"TagPath\":\"TestDINT\"}}]}}",
|
||||
$"\"RawTags\":[{{\"RawPath\":\"Plant/AbCip/dev1/TestDINT\"," +
|
||||
$"\"TagConfig\":\"{{\\\"tagPath\\\":\\\"TestDINT\\\",\\\"dataType\\\":\\\"DInt\\\"}}\"," +
|
||||
$"\"WriteIdempotent\":false,\"DeviceName\":\"ab://{DockerHost}:{AbCipPort}/1,0\"}}]}}",
|
||||
Timeout, Ct);
|
||||
result.Ok.ShouldBeTrue($"Probe message: {result.Message}");
|
||||
result.Message!.ShouldContain("CIP session OK");
|
||||
|
||||
// EXACT, not ShouldContain. The probe's two green messages are "CIP session OK" (the tag was
|
||||
// read) and "CIP session OK (controller reachable; probe tag not found)" (the fallback), and
|
||||
// `ShouldContain` matches both — so it would have gone green again the moment the config shape
|
||||
// was merely well-formed enough to reach the controller, whether or not the authored tag was
|
||||
// ever resolved. Reading the authored tag is the entire point of this test.
|
||||
result.Message.ShouldBe("CIP session OK");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user