fix(e2e): require every listed entry for the service to match state

RequireEventuallyServiceState succeeded on the first NDJSON entry for
the service matching the expected state, without checking any
remaining entries. During a recreation window compose ps can list two
containers for the same (scale: 1) service simultaneously (old and
new); the old one could still read "running" while the new one is
"starting", passing the poll prematurely on stale state.

Track whether any entry for the service was seen, and only succeed
once every one of them matches -- fail (poll.Continue) on the first
mismatch instead.

(docker-agent review on #14228)

Signed-off-by: Nicolas De Loof <[email protected]>
This commit is contained in:
Nicolas De Loof
2026-09-16 14:31:15 +02:00
committed by Guillaume Lours
parent c1fe57b62a
commit e64f64bf87
+9 -3
View File
@@ -64,7 +64,9 @@ func RequireEventuallyServiceState(t testing.TB, cli *CLI, service string, state
// --format=json prints one JSON object per line (NDJSON), not a
// single object or array: a scaled service, or a transient window
// during recreation where the old and new containers are both
// listed, means more than one line for the requested service.
// listed, means more than one line for the requested service — every
// one of them must reach the expected state, not just the first.
var found bool
for _, line := range strings.Split(strings.TrimSpace(psRes.Stdout()), "\n") {
if line == "" {
continue
@@ -76,10 +78,14 @@ func RequireEventuallyServiceState(t testing.TB, cli *CLI, service string, state
if svc, _ := entry["Service"].(string); !strings.EqualFold(svc, service) {
continue
}
if current, _ := entry["State"].(string); strings.EqualFold(current, state) {
return poll.Success()
found = true
if current, _ := entry["State"].(string); !strings.EqualFold(current, state) {
return poll.Continue("service %q not in state %q yet (got %q): %s", service, state, current, psRes.Stdout())
}
}
if found {
return poll.Success()
}
return poll.Continue("service %q not in state %q yet: %s", service, state, psRes.Stdout())
}
poll.WaitOn(t, check, poll.WithDelay(250*time.Millisecond), poll.WithTimeout(15*time.Second))