From e44914ecbdedff7beb2d2748ba7dc9fe3b652886 Mon Sep 17 00:00:00 2001 From: George Tsiolis Date: Tue, 10 Feb 2026 19:43:28 +0200 Subject: [PATCH 1/8] Add stop command --- cmd/stop.go | 36 ++++++++++++++ internal/container/start.go | 8 ++++ internal/container/stop.go | 43 +++++++++++++++++ internal/runtime/docker.go | 11 +++++ internal/runtime/runtime.go | 2 + test/integration/start_test.go | 27 +++++++++++ test/integration/stop_test.go | 87 ++++++++++++++++++++++++++++++++++ 7 files changed, 214 insertions(+) create mode 100644 cmd/stop.go create mode 100644 internal/container/stop.go create mode 100644 test/integration/stop_test.go diff --git a/cmd/stop.go b/cmd/stop.go new file mode 100644 index 0000000..02b6791 --- /dev/null +++ b/cmd/stop.go @@ -0,0 +1,36 @@ +package cmd + +import ( + "fmt" + "os" + + "github.com/localstack/lstk/internal/container" + "github.com/localstack/lstk/internal/runtime" + "github.com/spf13/cobra" +) + +var stopCmd = &cobra.Command{ + Use: "stop", + Short: "Stop LocalStack", + Long: "Stop the LocalStack emulator.", + Run: func(cmd *cobra.Command, args []string) { + rt, err := runtime.NewDockerRuntime() + if err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } + + onProgress := func(msg string) { + fmt.Println(msg) + } + + if err := container.Stop(cmd.Context(), rt, onProgress); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + }, +} + +func init() { + rootCmd.AddCommand(stopCmd) +} diff --git a/internal/container/start.go b/internal/container/start.go index feb969e..bd2d21b 100644 --- a/internal/container/start.go +++ b/internal/container/start.go @@ -50,6 +50,14 @@ func Start(ctx context.Context, rt runtime.Runtime, onProgress func(string)) err } for _, config := range containers { + if running, _ := rt.IsRunning(ctx, config.Name); running { + onProgress(fmt.Sprintf("LocalStack is already running")) + return nil + } + + // Remove any existing stopped container with the same name + _ = rt.Remove(ctx, config.Name) + onProgress(fmt.Sprintf("Pulling %s...", config.Image)) progress := make(chan runtime.PullProgress) go func() { diff --git a/internal/container/stop.go b/internal/container/stop.go new file mode 100644 index 0000000..fae1f24 --- /dev/null +++ b/internal/container/stop.go @@ -0,0 +1,43 @@ +package container + +import ( + "context" + "fmt" + "strings" + + "github.com/localstack/lstk/internal/config" + "github.com/localstack/lstk/internal/runtime" +) + +func Stop(ctx context.Context, rt runtime.Runtime, onProgress func(string)) error { + cfg, err := config.Get() + if err != nil { + return fmt.Errorf("failed to get config: %w", err) + } + + for _, c := range cfg.Containers { + name := c.Name() + onProgress(fmt.Sprintf("Stopping %s...", name)) + if err := rt.Stop(ctx, name); err != nil { + return &StopError{Name: name, Err: err} + } + onProgress(fmt.Sprintf("%s stopped", name)) + } + + return nil +} + +type StopError struct { + Name string + Err error +} + +func (e *StopError) Error() string { + msg := e.Err.Error() + + if strings.Contains(msg, "No such container") || strings.Contains(msg, "not found") { + return fmt.Sprintf("%s is not running", e.Name) + } + + return fmt.Sprintf("Failed to stop %s\n%s", e.Name, msg) +} diff --git a/internal/runtime/docker.go b/internal/runtime/docker.go index 59c73bc..739e65f 100644 --- a/internal/runtime/docker.go +++ b/internal/runtime/docker.go @@ -96,6 +96,17 @@ func (d *DockerRuntime) Start(ctx context.Context, config ContainerConfig) (stri return resp.ID, nil } +func (d *DockerRuntime) Stop(ctx context.Context, containerName string) error { + if err := d.client.ContainerStop(ctx, containerName, container.StopOptions{}); err != nil { + return err + } + return d.client.ContainerRemove(ctx, containerName, container.RemoveOptions{}) +} + +func (d *DockerRuntime) Remove(ctx context.Context, containerName string) error { + return d.client.ContainerRemove(ctx, containerName, container.RemoveOptions{}) +} + func (d *DockerRuntime) IsRunning(ctx context.Context, containerID string) (bool, error) { inspect, err := d.client.ContainerInspect(ctx, containerID) if err != nil { diff --git a/internal/runtime/runtime.go b/internal/runtime/runtime.go index 7a95884..caeb6af 100644 --- a/internal/runtime/runtime.go +++ b/internal/runtime/runtime.go @@ -21,6 +21,8 @@ type PullProgress struct { type Runtime interface { PullImage(ctx context.Context, image string, progress chan<- PullProgress) error Start(ctx context.Context, config ContainerConfig) (string, error) + Stop(ctx context.Context, containerName string) error + Remove(ctx context.Context, containerName string) error IsRunning(ctx context.Context, containerID string) (bool, error) Logs(ctx context.Context, containerID string, tail int) (string, error) } diff --git a/test/integration/start_test.go b/test/integration/start_test.go index 2e56786..82e0a80 100644 --- a/test/integration/start_test.go +++ b/test/integration/start_test.go @@ -67,6 +67,33 @@ func TestStartCommandSucceedsWithKeyringToken(t *testing.T) { assert.True(t, inspect.State.Running, "container should be running") } +func TestStartCommandSucceedsWhenAlreadyRunning(t *testing.T) { + requireDocker(t) + authToken := os.Getenv("LOCALSTACK_AUTH_TOKEN") + require.NotEmpty(t, authToken, "LOCALSTACK_AUTH_TOKEN must be set to run this test") + + cleanup() + t.Cleanup(cleanup) + + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) + defer cancel() + + cmd := exec.CommandContext(ctx, binaryPath(), "start") + cmd.Env = append(os.Environ(), "LOCALSTACK_AUTH_TOKEN="+authToken) + output, err := cmd.CombinedOutput() + require.NoError(t, err, "first lstk start failed: %s", output) + + cmd2 := exec.CommandContext(ctx, binaryPath(), "start") + cmd2.Env = append(os.Environ(), "LOCALSTACK_AUTH_TOKEN="+authToken) + output2, err := cmd2.CombinedOutput() + require.NoError(t, err, "second lstk start should succeed: %s", output2) + assert.Contains(t, string(output2), "already running") + + inspect, err := dockerClient.ContainerInspect(ctx, containerName) + require.NoError(t, err, "failed to inspect container") + assert.True(t, inspect.State.Running, "container should still be running") +} + func TestStartCommandFailsWithInvalidToken(t *testing.T) { requireDocker(t) cleanup() diff --git a/test/integration/stop_test.go b/test/integration/stop_test.go new file mode 100644 index 0000000..40e33d8 --- /dev/null +++ b/test/integration/stop_test.go @@ -0,0 +1,87 @@ +package integration_test + +import ( + "context" + "os" + "os/exec" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestStopCommandSucceeds(t *testing.T) { + requireDocker(t) + authToken := os.Getenv("LOCALSTACK_AUTH_TOKEN") + require.NotEmpty(t, authToken, "LOCALSTACK_AUTH_TOKEN must be set to run this test") + + cleanup() + t.Cleanup(cleanup) + + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) + defer cancel() + + startCmd := exec.CommandContext(ctx, binaryPath(), "start") + startCmd.Env = append(os.Environ(), "LOCALSTACK_AUTH_TOKEN="+authToken) + output, err := startCmd.CombinedOutput() + require.NoError(t, err, "lstk start failed: %s", output) + + inspect, err := dockerClient.ContainerInspect(ctx, containerName) + require.NoError(t, err, "failed to inspect container after start") + require.True(t, inspect.State.Running, "container should be running after start") + + stopCmd := exec.CommandContext(ctx, binaryPath(), "stop") + output, err = stopCmd.CombinedOutput() + require.NoError(t, err, "lstk stop failed: %s", output) + + outputStr := string(output) + assert.Contains(t, outputStr, "Stopping", "should show stopping message") + assert.Contains(t, outputStr, "stopped", "should show stopped message") + + _, err = dockerClient.ContainerInspect(ctx, containerName) + assert.Error(t, err, "container should not exist after stop") +} + +func TestStopCommandFailsWhenNotRunning(t *testing.T) { + requireDocker(t) + cleanup() + t.Cleanup(cleanup) + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + cmd := exec.CommandContext(ctx, binaryPath(), "stop") + output, err := cmd.CombinedOutput() + + require.Error(t, err, "expected lstk stop to fail when container not running") + assert.Contains(t, string(output), "is not running") +} + +func TestStopCommandIsIdempotent(t *testing.T) { + requireDocker(t) + authToken := os.Getenv("LOCALSTACK_AUTH_TOKEN") + require.NotEmpty(t, authToken, "LOCALSTACK_AUTH_TOKEN must be set to run this test") + + cleanup() + t.Cleanup(cleanup) + + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) + defer cancel() + + startCmd := exec.CommandContext(ctx, binaryPath(), "start") + startCmd.Env = append(os.Environ(), "LOCALSTACK_AUTH_TOKEN="+authToken) + output, err := startCmd.CombinedOutput() + require.NoError(t, err, "lstk start failed: %s", output) + + stopCmd := exec.CommandContext(ctx, binaryPath(), "stop") + output, err = stopCmd.CombinedOutput() + require.NoError(t, err, "first lstk stop failed: %s", output) + + _, err = dockerClient.ContainerInspect(ctx, containerName) + require.Error(t, err, "container should not exist after first stop") + + stopCmd2 := exec.CommandContext(ctx, binaryPath(), "stop") + output, err = stopCmd2.CombinedOutput() + assert.Error(t, err, "second lstk stop should fail since container already removed") +} From 0408af1c86923c0e0dc0ccd3a3d47c00b2378173 Mon Sep 17 00:00:00 2001 From: George Tsiolis Date: Wed, 11 Feb 2026 21:43:53 +0200 Subject: [PATCH 2/8] Handle errors from container removal in start command --- internal/container/start.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/container/start.go b/internal/container/start.go index bd2d21b..93eb326 100644 --- a/internal/container/start.go +++ b/internal/container/start.go @@ -7,6 +7,7 @@ import ( "net/http" "time" + "github.com/docker/docker/errdefs" "github.com/localstack/lstk/internal/auth" "github.com/localstack/lstk/internal/config" "github.com/localstack/lstk/internal/runtime" @@ -56,7 +57,9 @@ func Start(ctx context.Context, rt runtime.Runtime, onProgress func(string)) err } // Remove any existing stopped container with the same name - _ = rt.Remove(ctx, config.Name) + if err := rt.Remove(ctx, config.Name); err != nil && !errdefs.IsNotFound(err) { + return fmt.Errorf("failed to remove existing container %s: %w", config.Name, err) + } onProgress(fmt.Sprintf("Pulling %s...", config.Image)) progress := make(chan runtime.PullProgress) From 1f8e3ebe0654e4776b38b5bc1a342ba846e4a01c Mon Sep 17 00:00:00 2001 From: George Tsiolis Date: Wed, 11 Feb 2026 21:45:01 +0200 Subject: [PATCH 3/8] Use errdefs.IsNotFound for error checking in stop command --- internal/container/stop.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/internal/container/stop.go b/internal/container/stop.go index fae1f24..c9adec5 100644 --- a/internal/container/stop.go +++ b/internal/container/stop.go @@ -3,8 +3,8 @@ package container import ( "context" "fmt" - "strings" + "github.com/docker/docker/errdefs" "github.com/localstack/lstk/internal/config" "github.com/localstack/lstk/internal/runtime" ) @@ -33,11 +33,8 @@ type StopError struct { } func (e *StopError) Error() string { - msg := e.Err.Error() - - if strings.Contains(msg, "No such container") || strings.Contains(msg, "not found") { + if errdefs.IsNotFound(e.Err) { return fmt.Sprintf("%s is not running", e.Name) } - - return fmt.Sprintf("Failed to stop %s\n%s", e.Name, msg) + return fmt.Sprintf("Failed to stop %s\n%s", e.Name, e.Err.Error()) } From 0601e91cb8a041146a474b2a08604dc0e23fce06 Mon Sep 17 00:00:00 2001 From: George Tsiolis Date: Wed, 11 Feb 2026 21:46:56 +0200 Subject: [PATCH 4/8] Remove "already running" check from start command --- internal/container/start.go | 5 ----- test/integration/start_test.go | 27 --------------------------- 2 files changed, 32 deletions(-) diff --git a/internal/container/start.go b/internal/container/start.go index 93eb326..0fabc70 100644 --- a/internal/container/start.go +++ b/internal/container/start.go @@ -51,11 +51,6 @@ func Start(ctx context.Context, rt runtime.Runtime, onProgress func(string)) err } for _, config := range containers { - if running, _ := rt.IsRunning(ctx, config.Name); running { - onProgress(fmt.Sprintf("LocalStack is already running")) - return nil - } - // Remove any existing stopped container with the same name if err := rt.Remove(ctx, config.Name); err != nil && !errdefs.IsNotFound(err) { return fmt.Errorf("failed to remove existing container %s: %w", config.Name, err) diff --git a/test/integration/start_test.go b/test/integration/start_test.go index 82e0a80..2e56786 100644 --- a/test/integration/start_test.go +++ b/test/integration/start_test.go @@ -67,33 +67,6 @@ func TestStartCommandSucceedsWithKeyringToken(t *testing.T) { assert.True(t, inspect.State.Running, "container should be running") } -func TestStartCommandSucceedsWhenAlreadyRunning(t *testing.T) { - requireDocker(t) - authToken := os.Getenv("LOCALSTACK_AUTH_TOKEN") - require.NotEmpty(t, authToken, "LOCALSTACK_AUTH_TOKEN must be set to run this test") - - cleanup() - t.Cleanup(cleanup) - - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) - defer cancel() - - cmd := exec.CommandContext(ctx, binaryPath(), "start") - cmd.Env = append(os.Environ(), "LOCALSTACK_AUTH_TOKEN="+authToken) - output, err := cmd.CombinedOutput() - require.NoError(t, err, "first lstk start failed: %s", output) - - cmd2 := exec.CommandContext(ctx, binaryPath(), "start") - cmd2.Env = append(os.Environ(), "LOCALSTACK_AUTH_TOKEN="+authToken) - output2, err := cmd2.CombinedOutput() - require.NoError(t, err, "second lstk start should succeed: %s", output2) - assert.Contains(t, string(output2), "already running") - - inspect, err := dockerClient.ContainerInspect(ctx, containerName) - require.NoError(t, err, "failed to inspect container") - assert.True(t, inspect.State.Running, "container should still be running") -} - func TestStartCommandFailsWithInvalidToken(t *testing.T) { requireDocker(t) cleanup() From 5f61b8cffbb98bcacb9b9e30b3fecf803c3405a7 Mon Sep 17 00:00:00 2001 From: George Tsiolis Date: Wed, 11 Feb 2026 21:48:43 +0200 Subject: [PATCH 5/8] Use Docker SDK to create test containers in stop tests --- test/integration/stop_test.go | 41 +++++++++++++++-------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/test/integration/stop_test.go b/test/integration/stop_test.go index 40e33d8..f1e3717 100644 --- a/test/integration/stop_test.go +++ b/test/integration/stop_test.go @@ -2,37 +2,38 @@ package integration_test import ( "context" - "os" "os/exec" "testing" "time" + "github.com/docker/docker/api/types/container" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) +func startTestContainer(t *testing.T, ctx context.Context) { + t.Helper() + resp, err := dockerClient.ContainerCreate(ctx, &container.Config{ + Image: "alpine:latest", + Cmd: []string{"sleep", "infinity"}, + }, nil, nil, nil, containerName) + require.NoError(t, err, "failed to create test container") + err = dockerClient.ContainerStart(ctx, resp.ID, container.StartOptions{}) + require.NoError(t, err, "failed to start test container") +} + func TestStopCommandSucceeds(t *testing.T) { requireDocker(t) - authToken := os.Getenv("LOCALSTACK_AUTH_TOKEN") - require.NotEmpty(t, authToken, "LOCALSTACK_AUTH_TOKEN must be set to run this test") - cleanup() t.Cleanup(cleanup) - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() - startCmd := exec.CommandContext(ctx, binaryPath(), "start") - startCmd.Env = append(os.Environ(), "LOCALSTACK_AUTH_TOKEN="+authToken) - output, err := startCmd.CombinedOutput() - require.NoError(t, err, "lstk start failed: %s", output) - - inspect, err := dockerClient.ContainerInspect(ctx, containerName) - require.NoError(t, err, "failed to inspect container after start") - require.True(t, inspect.State.Running, "container should be running after start") + startTestContainer(t, ctx) stopCmd := exec.CommandContext(ctx, binaryPath(), "stop") - output, err = stopCmd.CombinedOutput() + output, err := stopCmd.CombinedOutput() require.NoError(t, err, "lstk stop failed: %s", output) outputStr := string(output) @@ -60,22 +61,16 @@ func TestStopCommandFailsWhenNotRunning(t *testing.T) { func TestStopCommandIsIdempotent(t *testing.T) { requireDocker(t) - authToken := os.Getenv("LOCALSTACK_AUTH_TOKEN") - require.NotEmpty(t, authToken, "LOCALSTACK_AUTH_TOKEN must be set to run this test") - cleanup() t.Cleanup(cleanup) - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() - startCmd := exec.CommandContext(ctx, binaryPath(), "start") - startCmd.Env = append(os.Environ(), "LOCALSTACK_AUTH_TOKEN="+authToken) - output, err := startCmd.CombinedOutput() - require.NoError(t, err, "lstk start failed: %s", output) + startTestContainer(t, ctx) stopCmd := exec.CommandContext(ctx, binaryPath(), "stop") - output, err = stopCmd.CombinedOutput() + output, err := stopCmd.CombinedOutput() require.NoError(t, err, "first lstk stop failed: %s", output) _, err = dockerClient.ContainerInspect(ctx, containerName) From cdd5997bb07fd7897518636ee6864c3588155aaa Mon Sep 17 00:00:00 2001 From: George Tsiolis Date: Wed, 11 Feb 2026 21:57:43 +0200 Subject: [PATCH 6/8] Fix lint errors --- go.mod | 2 +- internal/container/start.go | 2 +- internal/container/stop.go | 2 +- test/integration/stop_test.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 627f577..ceeb388 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.25.6 require ( github.com/99designs/keyring v1.2.2 + github.com/containerd/errdefs v1.0.0 github.com/docker/docker v28.2.2+incompatible github.com/docker/go-connections v0.5.0 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c @@ -17,7 +18,6 @@ require ( github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/Microsoft/go-winio v0.4.14 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/danieljoos/wincred v1.2.2 // indirect diff --git a/internal/container/start.go b/internal/container/start.go index 0fabc70..73df1d2 100644 --- a/internal/container/start.go +++ b/internal/container/start.go @@ -7,7 +7,7 @@ import ( "net/http" "time" - "github.com/docker/docker/errdefs" + "github.com/containerd/errdefs" "github.com/localstack/lstk/internal/auth" "github.com/localstack/lstk/internal/config" "github.com/localstack/lstk/internal/runtime" diff --git a/internal/container/stop.go b/internal/container/stop.go index c9adec5..c305244 100644 --- a/internal/container/stop.go +++ b/internal/container/stop.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/docker/docker/errdefs" + "github.com/containerd/errdefs" "github.com/localstack/lstk/internal/config" "github.com/localstack/lstk/internal/runtime" ) diff --git a/test/integration/stop_test.go b/test/integration/stop_test.go index f1e3717..e78be38 100644 --- a/test/integration/stop_test.go +++ b/test/integration/stop_test.go @@ -77,6 +77,6 @@ func TestStopCommandIsIdempotent(t *testing.T) { require.Error(t, err, "container should not exist after first stop") stopCmd2 := exec.CommandContext(ctx, binaryPath(), "stop") - output, err = stopCmd2.CombinedOutput() + _, err = stopCmd2.CombinedOutput() assert.Error(t, err, "second lstk stop should fail since container already removed") } From a55d50ac0d96e92d0b907269823003cd1881a2f2 Mon Sep 17 00:00:00 2001 From: George Tsiolis Date: Thu, 12 Feb 2026 14:51:36 +0200 Subject: [PATCH 7/8] Remove custom stop error --- internal/container/stop.go | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/internal/container/stop.go b/internal/container/stop.go index c305244..a4f050d 100644 --- a/internal/container/stop.go +++ b/internal/container/stop.go @@ -4,7 +4,6 @@ import ( "context" "fmt" - "github.com/containerd/errdefs" "github.com/localstack/lstk/internal/config" "github.com/localstack/lstk/internal/runtime" ) @@ -19,22 +18,10 @@ func Stop(ctx context.Context, rt runtime.Runtime, onProgress func(string)) erro name := c.Name() onProgress(fmt.Sprintf("Stopping %s...", name)) if err := rt.Stop(ctx, name); err != nil { - return &StopError{Name: name, Err: err} + return fmt.Errorf("failed to stop %s: %w", name, err) } onProgress(fmt.Sprintf("%s stopped", name)) } return nil } - -type StopError struct { - Name string - Err error -} - -func (e *StopError) Error() string { - if errdefs.IsNotFound(e.Err) { - return fmt.Sprintf("%s is not running", e.Name) - } - return fmt.Sprintf("Failed to stop %s\n%s", e.Name, e.Err.Error()) -} From df555a875a7d84ef66be385c531244f0b02a756a Mon Sep 17 00:00:00 2001 From: George Tsiolis Date: Fri, 13 Feb 2026 16:07:29 +0200 Subject: [PATCH 8/8] Attempt to fix failing tests --- internal/container/stop.go | 4 ++++ test/integration/stop_test.go | 12 +++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/internal/container/stop.go b/internal/container/stop.go index a4f050d..cdac02d 100644 --- a/internal/container/stop.go +++ b/internal/container/stop.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/containerd/errdefs" "github.com/localstack/lstk/internal/config" "github.com/localstack/lstk/internal/runtime" ) @@ -18,6 +19,9 @@ func Stop(ctx context.Context, rt runtime.Runtime, onProgress func(string)) erro name := c.Name() onProgress(fmt.Sprintf("Stopping %s...", name)) if err := rt.Stop(ctx, name); err != nil { + if errdefs.IsNotFound(err) { + return fmt.Errorf("%s is not running", name) + } return fmt.Errorf("failed to stop %s: %w", name, err) } onProgress(fmt.Sprintf("%s stopped", name)) diff --git a/test/integration/stop_test.go b/test/integration/stop_test.go index e78be38..01cad28 100644 --- a/test/integration/stop_test.go +++ b/test/integration/stop_test.go @@ -2,19 +2,29 @@ package integration_test import ( "context" + "io" "os/exec" "testing" "time" "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/image" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) +const testImage = "alpine:latest" + func startTestContainer(t *testing.T, ctx context.Context) { t.Helper() + + reader, err := dockerClient.ImagePull(ctx, testImage, image.PullOptions{}) + require.NoError(t, err, "failed to pull test image") + _, _ = io.Copy(io.Discard, reader) + _ = reader.Close() + resp, err := dockerClient.ContainerCreate(ctx, &container.Config{ - Image: "alpine:latest", + Image: testImage, Cmd: []string{"sleep", "infinity"}, }, nil, nil, nil, containerName) require.NoError(t, err, "failed to create test container")