10 Commits
Author SHA1 Message Date
Nicolas De Loof c74f6f8cb6 test(e2e): deflake the three state/stream race suspects
Three tests failed 9 CI runs across 5 branches this week, all on
asynchronous-observation races, none reproducible locally:

- RequireServiceState asserted on a single `compose ps` snapshot; the
  daemon reports state transitions asynchronously from everything else
  a test observes (TestUpDependenciesNotStopped saw 'created' while
  the container's logs were already flowing). It now polls until the
  state converges (15s bound).
- TestAttachRestart counted restart log lines in a snapshot taken as
  soon as the third exit notice appeared; exit notices come from the
  events monitor while log lines come from the re-attached logs
  stream — two channels with no ordering between them. The count is
  now awaited like the exit notices already were; a genuinely lost
  line still fails, by timeout.
- TestUpExitCodeFromContainerKilled ran a full up+abort cycle under a
  60s ceiling, once exceeded on a loaded oldstable runner; raised to
  120s.

Signed-off-by: Nicolas De Loof <[email protected]>
2026-09-22 14:45:23 +02:00
Nicolas De Loof e64f64bf87 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]>
2026-09-16 14:31:15 +02:00
Nicolas De Loof c1fe57b62a fix(e2e): parse compose ps --format=json as NDJSON
`--format=json` prints one JSON object per line, not a single object:
RequireEventuallyServiceState's json.Unmarshal into a single map broke
as soon as more than one container was listed for the service (a
scaled service, or the transient window during recreation where the
old and new containers are both listed) -- every poll iteration
reported "invalid JSON" and the function always timed out instead of
detecting the actual state.

Scan stdout line by line, matching entries by Service, and succeed as
soon as one reaches the expected state. Also check the exit code
before parsing so a real `compose ps` failure is reported as such
instead of a misleading "invalid JSON" message.

(docker-agent review on #14228)

Signed-off-by: Nicolas De Loof <[email protected]>
2026-09-16 14:31:15 +02:00
Nicolas De Loof 5c11397e58 test(e2e): wait on state, not on an unsynchronized log line
TestAttachRestart and TestUpDependenciesNotStopped each flaked on an
assertion checked exactly once, right after an unrelated signal on a
different channel to the daemon:

- TestAttachRestart counted "failing-1  | world" immediately after a
  WaitForCondition on "failing-1 exited with code 1" reached 3. The
  exited status comes from the /events stream; the log line comes
  from a separate /logs?follow=1 connection (followStartedContainers
  in pkg/compose/up.go). Nothing orders one relative to the other, so
  the last restart's log line can still be in flight the instant the
  3rd exited is observed.

- TestUpDependenciesNotStopped called RequireServiceState right after
  seeing "hello app" in the attached log stream. That line reaching
  the test is no guarantee the daemon-reported container state (read
  via a fresh `compose ps` in a brand new process) has caught up yet.

Neither is a compose bug: `ps`/ContainerList and the log stream are
independent channels with no cross-channel ordering guarantee from
the engine, and compose does not cache container state. Both tests
now poll for the actual condition instead of using a log line as a
proxy for it: TestAttachRestart gets a second, bounded
WaitForCondition on the log count, and TestUpDependenciesNotStopped
uses a new RequireEventuallyServiceState (pkg/e2e/assert.go) that
polls `compose ps` instead of checking it once.

Signed-off-by: Nicolas De Loof <[email protected]>
2026-09-16 14:31:15 +02:00
Nicolas De Loof 24059c688c chore: explicit, unique, greppable names for internal identifiers
Rename-only change, no behavior difference, no exported identifier
renamed (only parameter names of a few exported functions, which are
not part of the Go API).

- names that hide what a value is: parameters holding a *name* or *ID*
  while named like the object — project→projectName, service→serviceName,
  container→containerID — so string vs struct is readable at every call
  site without opening the signature
- misleading receivers: monitor methods used c (reads as
  client/container/CLI) → m; jsonWriter used p while its ttyWriter
  sibling uses w → w
- cryptic abbreviations with non-trivial scope: nw (meant both
  network.Summary and types.NetworkConfig) → network/networkConfig,
  svc → service/serviceName/serviceCopy, oc/ocs → observedContainer(s),
  cnts → serviceContainers, cnx → attachResponse
- container.Summary loop variables unified on ctr (was a c/ctr mix);
  fillBindMounts also dropped its p/s/m single-letters, one of which
  was shadowed by a loop variable of a different type
- option-struct identifiers unified on options (opts remains only for
  variadic functional options); ambiguous ones get a precise name
  (bindOptions, networkCreateOptions, projectOptionsFns)

Signed-off-by: Nicolas De Loof <[email protected]>
2026-08-20 11:17:11 +02:00
Sebastiaan van Stijn 92a7ac1fa2 fix mixed assertion libraries in tests
Before this, assertion libraries were mixed, sometimes
even in the same file.

    git grep -l '"gotest.tools/v3/' | wc -l
    75
    git grep -l '"github.com/stretchr/testify' | wc -l
    24

Signed-off-by: Sebastiaan van Stijn <[email protected]>
2026-03-31 17:32:51 +02:00
zjumathcode 13d70b1c11 refactor: replace interface{} with any for clarity and modernization
Signed-off-by: zjumathcode <[email protected]>
2025-12-02 08:41:49 +01:00
Milas Bowman 407a0d5b53 up: fix various race/deadlock conditions on exit (#10934)
If running `up` in foreground mode (i.e. not `-d`),
when exiting via `Ctrl-C`, Compose stops all the
services it launched directly as part of that `up`
command.

In one of the E2E tests (`TestUpDependenciesNotStopped`),
this was occasionally flaking because the stop
behavior was racy: the return might not block on
the stop operation because it gets added to the
error group in a goroutine. As a result, it was
possible for no services to get terminated on exit.

There were a few other related pieces here that
I uncovered and tried to fix while stressing this.
For example, the printer could cause a deadlock if
an event was sent to it after it stopped.

Also, an error group wasn't really appropriate here;
each goroutine is a different operation for printing,
signal-handling, etc. If one part fails, we don't
actually want printing to stop, for example. This has
been switched to a `multierror.Group`, which has the
same API but coalesces errors instead of canceling a
context the moment the first one fails and returning
that single error.

Signed-off-by: Milas Bowman <[email protected]>
2023-08-31 10:47:14 -04:00
Nicolas De Loof 1054792b47 align docker compose ps with docker CLI to support --format
Signed-off-by: Nicolas De Loof <[email protected]>
2023-08-25 16:36:45 +02:00
Milas Bowman 765c071c89 up: do not stop dependency containers (#9701)
This keeps parity with v1, where only the containers explicitly
passed to `up` are torn down when `Ctrl-C` is hit, so any
dependencies that got launched (or orphan containers hanging
around) should not be touched.

Fixes #9696.

Signed-off-by: Milas Bowman <[email protected]>
2022-08-02 15:25:59 -04:00