diff --git a/fleetd/src/test/java/dev/ltms/fleet/FleetdBackendQuarantineWiringTest.java b/fleetd/src/test/java/dev/ltms/fleet/FleetdBackendQuarantineWiringTest.java new file mode 100644 index 0000000..98d9c6e --- /dev/null +++ b/fleetd/src/test/java/dev/ltms/fleet/FleetdBackendQuarantineWiringTest.java @@ -0,0 +1,65 @@ +package dev.ltms.fleet; + +import java.nio.file.Files; +import java.nio.file.Path; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * fleetd #466 follow-up: {@code Fleetd.main} builds the daemon's one {@code BackendQuarantine} + * from {@link dev.ltms.fleet.placement.BackendQuarantine#withEscalation(java.util.function.LongSupplier, + * long)} — the escalating factory — rather than the plain two-argument constructor, which is still a + * flat cooldown (kept for backward compatibility, see that class's doc). {@code + * BackendQuarantineTest} proves {@code withEscalation} itself escalates, is ceilinged, and resets; + * it says nothing about which one {@code main} actually calls. + * + *
Measured directly: reverting {@code main} to {@code new BackendQuarantine(System::nanoTime, + * TimeUnit.SECONDS.toNanos(cfg.quarantineCooldownSeconds()))} — the pre-#466 flat call — compiles + * with 0 errors and leaves the entire 1608-test suite (including every {@code BackendQuarantineTest} + * case) green, because no other test constructs its {@code BackendQuarantine} through {@code main}; + * every one of them builds its own instance directly. That silent regression is exactly the shape + * {@link FleetdLeadSeatWiringTest} and {@link FleetdCompletionResolverWiringTest} already guard + * against for their own constructor arguments — this is the same class of gap for fleetd #466's + * factory choice, following their approach. + * + *
This test checks source text, not runtime behaviour. It never constructs a {@code + * BackendQuarantine} and never runs {@code main} — a green result here proves only that the exact + * text {@code main} calls {@code BackendQuarantine.withEscalation(...)} rather than the flat + * constructor. It does not prove that call actually executes at startup (no test here starts the + * daemon), and it does not prove the escalation reaches a real backend or credential — only + * {@code BackendQuarantineTest} proves the factory's own behaviour, and only a live daemon proves + * the wiring runs. + */ +class FleetdBackendQuarantineWiringTest { + + private static String fleetdSource() throws Exception { + return Files.readString(Path.of("src/main/java/dev/ltms/fleet/Fleetd.java")); + } + + @Test + @DisplayName("[SOURCE TEXT] main's BackendQuarantine local is still built from BackendQuarantine.withEscalation(...)") + void mainStillWiresTheEscalatingQuarantineFactory() throws Exception { + String source = fleetdSource(); + assertTrue(source.contains( + "BackendQuarantine quarantine = BackendQuarantine.withEscalation(System::nanoTime,\n" + + " TimeUnit.SECONDS.toNanos(cfg.quarantineCooldownSeconds()));"), + "Fleetd.main's BackendQuarantine local must still be built from " + + "BackendQuarantine.withEscalation(System::nanoTime, " + + "TimeUnit.SECONDS.toNanos(cfg.quarantineCooldownSeconds())). Reverting to the flat " + + "two-argument constructor (fleetd #466's measured regression) compiles with 0 errors " + + "and leaves the whole suite green, including every BackendQuarantineTest case that " + + "proves the escalation itself works — this source check is what must go red instead. " + + "A reverted daemon would go back to retrying a weekly subscription limit on every " + + "flat ~30-minute cooldown, about 336 times across the week."); + + // Negative form of the same check: the pre-#466 flat call, if it ever reappears at this + // declaration, must not be mistaken for the escalating one by a looser positive-only check. + assertFalse(source.contains( + "BackendQuarantine quarantine = new BackendQuarantine(System::nanoTime,\n" + + " TimeUnit.SECONDS.toNanos(cfg.quarantineCooldownSeconds()));"), + "main's BackendQuarantine local must never regress to the flat two-argument constructor"); + } +}