From dbfc34cb6dafe9f2fc6620ccdeaede93a6892b92 Mon Sep 17 00:00:00 2001 From: Dai Ha Date: Tue, 22 Sep 2026 12:11:28 +0700 Subject: [PATCH] fleetd #612 B2 fixup: cover the symmetric FleetApp daemon-drop mutation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per ticket comment 17525: my second independent mutation on FleetdAssembly.java:518 survived — new FleetApp(memberHerdr, memberHerdr, ...) (dropping the LEAD client instead of the member one) left both existing FleetdAssemblyFleetAppTest cases green. That is the symmetric form of the CB-185 defect (/healthz green while the LEAD daemon is down), and the guard this PR deletes would have caught it: its positive assertion required the exact pair "new FleetApp(herdr, memberHerdr, workers,", which does not survive either daemon being dropped. Adds healthzGoesRedWhenTheLeadDaemonIsDownEvenThoughTheMemberIsUp, symmetric to the existing member-down case. Proven red today: reverting FleetdAssembly.java:518 to "new FleetApp(memberHerdr, memberHerdr, workers, ..." and running only FleetdAssemblyFleetAppTest gives Tests run: 3, Failures: 1 — the new case fails ("expected: <503> but was: <200>", body has no "member" key); the other two cases stay green. Reverted, git diff --stat empty, file touched, re-ran: Tests run: 3, Failures: 0. Full mvn -o test: Tests run: 1884, Failures: 7 (same 7 B1/B3-scope failures as before this fixup; 1884 = 1883 + 1 new case). --- .../fleet/FleetdAssemblyFleetAppTest.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/fleetd/src/test/java/dev/ltms/fleet/FleetdAssemblyFleetAppTest.java b/fleetd/src/test/java/dev/ltms/fleet/FleetdAssemblyFleetAppTest.java index 1372c22..ba2b8c3 100644 --- a/fleetd/src/test/java/dev/ltms/fleet/FleetdAssemblyFleetAppTest.java +++ b/fleetd/src/test/java/dev/ltms/fleet/FleetdAssemblyFleetAppTest.java @@ -40,6 +40,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals; * FleetAppTwoDaemonTest} already proves {@code FleetApp} itself merges/gates correctly given two * clients; the gap this pins is that the assembly actually passes it two. * + *

Both directions, not just one (fleetd #612 issue comment 17525): the deleted + * guard's positive assertion required the exact pair {@code "new FleetApp(herdr, memberHerdr, + * workers,"}, which does not survive EITHER daemon being dropped. An earlier version of this class + * only proved the member-dropped direction, which left {@code new FleetApp(memberHerdr, + * memberHerdr, ...)} — the symmetric bug, {@code /healthz} green while the LEAD daemon is down — + * an undetected regression. {@link #healthzGoesRedWhenTheLeadDaemonIsDownEvenThoughTheMemberIsUp} + * closes that. + * *

Unlike the {@code ConnectionIdentity} half of CB-185 ({@code * FleetdAssemblyConnectionIdentityTest}), {@code /healthz} needs no caller identity at all, so * this test can bind {@link FleetdRuntime#app()} to a REAL ephemeral port (exactly {@code @@ -206,4 +214,24 @@ class FleetdAssemblyFleetAppTest { assertEquals(200, get(port, "/healthz").statusCode()); } + + /** + * The symmetric pin (fleetd #612 issue comment 17525): the LEAD daemon is down; the MEMBER + * daemon is healthy. If the assembly built {@code FleetApp} with only the member client + * (dropping {@code herdr} — the mirror of the bug above, {@code new FleetApp(memberHerdr, + * memberHerdr, ...)}), the down LEAD is invisible and {@code /healthz} stays 200. Without this + * case the pair above is one-directional and does not cover the deleted guard's positive + * assertion (it required BOTH {@code herdr,} and {@code memberHerdr,} in that order). + */ + @Test + void healthzGoesRedWhenTheLeadDaemonIsDownEvenThoughTheMemberIsUp(@TempDir Path dir) throws Exception { + FakeHerdr lead = new FakeHerdr().healthy(false); + FakeHerdr member = new FakeHerdr(); + + int port = assembleAndBind(dir, lead, member); + + HttpResponse res = get(port, "/healthz"); + assertEquals(503, res.statusCode(), + "a down LEAD daemon must not be masked by a healthy member: " + res.body()); + } }