diff --git a/fleetd/src/test/java/dev/ltms/fleet/inject/BackendOutageFlowTest.java b/fleetd/src/test/java/dev/ltms/fleet/inject/BackendOutageFlowTest.java index c82ed4e..cf2b1ea 100644 --- a/fleetd/src/test/java/dev/ltms/fleet/inject/BackendOutageFlowTest.java +++ b/fleetd/src/test/java/dev/ltms/fleet/inject/BackendOutageFlowTest.java @@ -2,6 +2,7 @@ package dev.ltms.fleet.inject; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import dev.ltms.fleet.Fleetd; import dev.ltms.fleet.config.FleetConfig; import dev.ltms.fleet.guard.SubscriptionGuard; import dev.ltms.fleet.herdr.AgentControl; @@ -146,40 +147,16 @@ class BackendOutageFlowTest { pushLoop = new ReplyPushLoop(registry, new AgentControl(leadClient), inbox, scheduler, 3, 50); AtomicReference pushLoopRef = new AtomicReference<>(pushLoop); - // --- mirrors Fleetd.main's backendErrorSink lambda EXACTLY: (1) mark BACKEND_ERROR, - // (2) resolve profile/credential via the roster, fail-loud + notify unmapped-target, - // (3) record in BackendOutagePolicy, (4) on a NEW incident, notify the lead. ------------ - BackendErrorSink backendErrorSink = (target, matchedLine, reason) -> { - sessions.onBackendError(target, reason); + // fleetd #248 follow-up: this used to be a 30-line hand-copy of Fleetd.main's + // backendErrorSink lambda, with a comment promising it mirrored production "EXACTLY". + // That promise is exactly the problem: a copy proves the copy. Editing or deleting the + // real sink left this whole flow test green, because it never touched the real sink. + // #248 made Fleetd.backendErrorSink public precisely so a cross-package test could + // drive the real object, so this now calls it. Every assertion below is about + // production code again. + BackendErrorSink backendErrorSink = + Fleetd.backendErrorSink(sessions, () -> profiles, outagePolicy, pushLoopRef::get); - String profileName = sessions.roster().stream() - .filter(session -> target.equals(session.terminalId())) - .findFirst() - .map(MemberSession::profile) - .orElse(null); - FleetConfig.Profile profile = profileName == null ? null : profiles.get(profileName); - if (profile == null) { - ReplyPushLoop loop = pushLoopRef.get(); - if (loop != null) { - loop.onBackendTargetUnmapped(target, reason); - } - return; - } - String credentialId = profile.effectiveCredentialId(); - Optional incident = outagePolicy.record(credentialId, target, reason); - incident.ifPresent(inc -> { - List affectedProfiles = profiles.values().stream() - .filter(p -> credentialId.equals(p.effectiveCredentialId())) - .map(FleetConfig.Profile::profile) - .sorted() - .toList(); - ReplyPushLoop loop = pushLoopRef.get(); - if (loop != null) { - loop.onBackendIncident(inc.id(), inc.targets(), credentialId, affectedProfiles, - (int) inc.remainingCoolOffSeconds()); - } - }); - }; BackendErrorPatternLookup patterns = target -> Pattern.compile("(?i)503 Service Unavailable"); resolver = new CompletionResolver(new AgentControl(herdr), rendezvous, ExhaustedPatternLookup.none(), ExhaustionSink.none(), patterns, backendErrorSink);