From 09c98d7e3d29b46d5e36831c66fa80a32a94a241 Mon Sep 17 00:00:00 2001 From: Elizabeth Worstell Date: Wed, 22 Jul 2026 15:37:35 -0700 Subject: [PATCH] fix(test): tolerate docker container creation races in s3clienttest Parallel test packages race to create the shared MinIO container. The loser's "docker start" can run before the winner's creation finishes registering the container, failing with "No such container". Retry the run/start cycle until the container is up or a deadline passes. Amp-Thread-ID: https://ampcode.com/threads/T-019f8b6a-3778-7200-a3b4-c24b84edd973 Co-authored-by: Amp --- .../s3client/s3clienttest/s3clienttest.go | 47 ++++++++++++------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/internal/s3client/s3clienttest/s3clienttest.go b/internal/s3client/s3clienttest/s3clienttest.go index 71ecb693..75f8f0a8 100644 --- a/internal/s3client/s3clienttest/s3clienttest.go +++ b/internal/s3client/s3clienttest/s3clienttest.go @@ -119,25 +119,38 @@ func Client(t *testing.T) *minio.Client { return client } +// startContainer starts the shared MinIO container, tolerating races with +// other test processes doing the same: a "name already in use" failure means +// another process is creating the container, but "docker start" on it can +// still fail with "No such container" until that creation finishes +// registering, so keep retrying until the container is up or the deadline +// passes. func startContainer(t *testing.T) { t.Helper() - cmd := exec.CommandContext(t.Context(), "docker", "run", "-d", - "--name", containerName, - "-p", Port+":9000", - "-e", "MINIO_ROOT_USER="+Username, - "-e", "MINIO_ROOT_PASSWORD="+Password, - "minio/minio", "server", "/data", - ) - output, err := cmd.CombinedOutput() - if err == nil { - return - } - if !strings.Contains(string(output), "already in use") { - t.Fatalf("failed to start minio container: %v\n%s", err, output) - } - // Container exists but may be stopped — try restarting it. - if restartOut, restartErr := exec.CommandContext(t.Context(), "docker", "start", containerName).CombinedOutput(); restartErr != nil { - t.Fatalf("failed to restart existing minio container: %v\n%s", restartErr, restartOut) + deadline := time.Now().Add(30 * time.Second) + for { + cmd := exec.CommandContext(t.Context(), "docker", "run", "-d", + "--name", containerName, + "-p", Port+":9000", + "-e", "MINIO_ROOT_USER="+Username, + "-e", "MINIO_ROOT_PASSWORD="+Password, + "minio/minio", "server", "/data", + ) + output, err := cmd.CombinedOutput() + if err == nil { + return + } + if !strings.Contains(string(output), "already in use") { + t.Fatalf("failed to start minio container: %v\n%s", err, output) + } + // Container exists but may be stopped — try restarting it. + if _, restartErr := exec.CommandContext(t.Context(), "docker", "start", containerName).CombinedOutput(); restartErr == nil { + return + } + if time.Now().After(deadline) { + t.Fatalf("timed out waiting for minio container: %v\n%s", err, output) + } + time.Sleep(200 * time.Millisecond) } }