diff --git a/modules/compose/compose_api.go b/modules/compose/compose_api.go index 0aa97fa9e4..0156e7e2a4 100644 --- a/modules/compose/compose_api.go +++ b/modules/compose/compose_api.go @@ -50,7 +50,7 @@ func (io IgnoreOrphans) applyToStackUp(co *api.CreateOptions, _ *api.StartOption co.IgnoreOrphans = bool(io) } -// RemoveOrphans will cleanup containers that are not declared on the compose model but own the same labels +// RemoveOrphans will clean up containers that are not declared on the compose model but own the same labels type RemoveOrphans bool func (ro RemoveOrphans) applyToStackUp(o *stackUpOptions) { @@ -68,6 +68,12 @@ func (w Wait) applyToStackUp(o *stackUpOptions) { o.Wait = bool(w) } +type RemoveVolumes bool + +func (ro RemoveVolumes) applyToStackDown(o *stackDownOptions) { + o.Volumes = bool(ro) +} + // RemoveImages used by services type RemoveImages uint8 diff --git a/modules/compose/compose_api_test.go b/modules/compose/compose_api_test.go index 40539a969f..310685b7cf 100644 --- a/modules/compose/compose_api_test.go +++ b/modules/compose/compose_api_test.go @@ -3,7 +3,10 @@ package compose import ( "context" "fmt" + "github.com/docker/docker/api/types/filters" + "github.com/google/uuid" "hash/fnv" + "path/filepath" "testing" "time" @@ -12,8 +15,16 @@ import ( "github.com/testcontainers/testcontainers-go/wait" ) +const ( + simpleCompose = "docker-compose-simple.yml" + complexCompose = "docker-compose-complex.yml" + composeWithVolume = "docker-compose-volume.yml" + testResourcesPackage = "testresources" +) + func TestDockerComposeAPI(t *testing.T) { - compose, err := NewDockerCompose("./testresources/docker-compose-simple.yml") + path := filepath.Join(testResourcesPackage, simpleCompose) + compose, err := NewDockerCompose(path) assert.NoError(t, err, "NewDockerCompose()") t.Cleanup(func() { @@ -27,7 +38,8 @@ func TestDockerComposeAPI(t *testing.T) { } func TestDockerComposeAPIStrategyForInvalidService(t *testing.T) { - compose, err := NewDockerCompose("./testresources/docker-compose-simple.yml") + path := filepath.Join(testResourcesPackage, simpleCompose) + compose, err := NewDockerCompose(path) assert.NoError(t, err, "NewDockerCompose()") t.Cleanup(func() { @@ -52,7 +64,8 @@ func TestDockerComposeAPIStrategyForInvalidService(t *testing.T) { } func TestDockerComposeAPIWithWaitLogStrategy(t *testing.T) { - compose, err := NewDockerCompose("./testresources/docker-compose-complex.yml") + path := filepath.Join(testResourcesPackage, complexCompose) + compose, err := NewDockerCompose(path) assert.NoError(t, err, "NewDockerCompose()") t.Cleanup(func() { @@ -76,7 +89,8 @@ func TestDockerComposeAPIWithWaitLogStrategy(t *testing.T) { } func TestDockerComposeAPIWithRunServices(t *testing.T) { - compose, err := NewDockerCompose("./testresources/docker-compose-complex.yml") + path := filepath.Join(testResourcesPackage, complexCompose) + compose, err := NewDockerCompose(path) assert.NoError(t, err, "NewDockerCompose()") t.Cleanup(func() { @@ -102,7 +116,8 @@ func TestDockerComposeAPIWithRunServices(t *testing.T) { } func TestDockerComposeAPIWithWaitForService(t *testing.T) { - compose, err := NewDockerCompose("./testresources/docker-compose-simple.yml") + path := filepath.Join(testResourcesPackage, simpleCompose) + compose, err := NewDockerCompose(path) assert.NoError(t, err, "NewDockerCompose()") t.Cleanup(func() { @@ -128,7 +143,8 @@ func TestDockerComposeAPIWithWaitForService(t *testing.T) { } func TestDockerComposeAPIWithWaitHTTPStrategy(t *testing.T) { - compose, err := NewDockerCompose("./testresources/docker-compose-simple.yml") + path := filepath.Join(testResourcesPackage, simpleCompose) + compose, err := NewDockerCompose(path) assert.NoError(t, err, "NewDockerCompose()") t.Cleanup(func() { @@ -154,7 +170,8 @@ func TestDockerComposeAPIWithWaitHTTPStrategy(t *testing.T) { } func TestDockerComposeAPIWithContainerName(t *testing.T) { - compose, err := NewDockerCompose("./testresources/docker-compose-container-name.yml") + path := filepath.Join(testResourcesPackage, "docker-compose-container-name.yml") + compose, err := NewDockerCompose(path) assert.NoError(t, err, "NewDockerCompose()") t.Cleanup(func() { @@ -180,7 +197,8 @@ func TestDockerComposeAPIWithContainerName(t *testing.T) { } func TestDockerComposeAPIWithWaitStrategy_NoExposedPorts(t *testing.T) { - compose, err := NewDockerCompose("./testresources/docker-compose-no-exposed-ports.yml") + path := filepath.Join(testResourcesPackage, "docker-compose-no-exposed-ports.yml") + compose, err := NewDockerCompose(path) assert.NoError(t, err, "NewDockerCompose()") t.Cleanup(func() { @@ -203,7 +221,8 @@ func TestDockerComposeAPIWithWaitStrategy_NoExposedPorts(t *testing.T) { } func TestDockerComposeAPIWithMultipleWaitStrategies(t *testing.T) { - compose, err := NewDockerCompose("./testresources/docker-compose-complex.yml") + path := filepath.Join(testResourcesPackage, complexCompose) + compose, err := NewDockerCompose(path) assert.NoError(t, err, "NewDockerCompose()") t.Cleanup(func() { @@ -228,7 +247,8 @@ func TestDockerComposeAPIWithMultipleWaitStrategies(t *testing.T) { } func TestDockerComposeAPIWithFailedStrategy(t *testing.T) { - compose, err := NewDockerCompose("./testresources/docker-compose-simple.yml") + path := filepath.Join(testResourcesPackage, simpleCompose) + compose, err := NewDockerCompose(path) assert.NoError(t, err, "NewDockerCompose()") t.Cleanup(func() { @@ -256,7 +276,8 @@ func TestDockerComposeAPIWithFailedStrategy(t *testing.T) { } func TestDockerComposeAPIComplex(t *testing.T) { - compose, err := NewDockerCompose("./testresources/docker-compose-complex.yml") + path := filepath.Join(testResourcesPackage, complexCompose) + compose, err := NewDockerCompose(path) assert.NoError(t, err, "NewDockerCompose()") t.Cleanup(func() { @@ -278,7 +299,9 @@ func TestDockerComposeAPIComplex(t *testing.T) { func TestDockerComposeAPIWithEnvironment(t *testing.T) { identifier := testNameHash(t.Name()) - compose, err := NewDockerComposeWith(WithStackFiles("./testresources/docker-compose-simple.yml"), identifier) + path := filepath.Join(testResourcesPackage, simpleCompose) + + compose, err := NewDockerComposeWith(WithStackFiles(path), identifier) assert.NoError(t, err, "NewDockerCompose()") t.Cleanup(func() { @@ -310,9 +333,9 @@ func TestDockerComposeAPIWithEnvironment(t *testing.T) { func TestDockerComposeAPIWithMultipleComposeFiles(t *testing.T) { composeFiles := ComposeStackFiles{ - "testresources/docker-compose-simple.yml", - "testresources/docker-compose-postgres.yml", - "testresources/docker-compose-override.yml", + filepath.Join(testResourcesPackage, simpleCompose), + filepath.Join(testResourcesPackage, "docker-compose-postgres.yml"), + filepath.Join(testResourcesPackage, "docker-compose-override.yml"), } identifier := testNameHash(t.Name()) @@ -351,7 +374,8 @@ func TestDockerComposeAPIWithMultipleComposeFiles(t *testing.T) { } func TestDockerComposeAPIWithVolume(t *testing.T) { - compose, err := NewDockerCompose("./testresources/docker-compose-volume.yml") + path := filepath.Join(testResourcesPackage, composeWithVolume) + compose, err := NewDockerCompose(path) assert.NoError(t, err, "NewDockerCompose()") t.Cleanup(func() { @@ -365,8 +389,34 @@ func TestDockerComposeAPIWithVolume(t *testing.T) { assert.NoError(t, err, "compose.Up()") } +func TestDockerComposeAPIVolumesDeletedOnDown(t *testing.T) { + path := filepath.Join(testResourcesPackage, composeWithVolume) + identifier := uuid.New().String() + stackFiles := WithStackFiles(path) + compose, err := NewDockerComposeWith(stackFiles, StackIdentifier(identifier)) + assert.NoError(t, err, "NewDockerCompose()") + + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + + err = compose.Up(ctx, Wait(true)) + assert.NoError(t, err, "compose.Up()") + + err = compose.Down(context.Background(), RemoveOrphans(true), RemoveVolumes(true), RemoveImagesLocal) + assert.NoError(t, err, "compose.Down()") + + volumeListFilters := filters.NewArgs() + // the "mydata" identifier comes from the "testresources/docker-compose-volume.yml" file + volumeListFilters.Add("name", fmt.Sprintf("%s_mydata", identifier)) + volumeList, err := compose.dockerClient.VolumeList(ctx, volumeListFilters) + assert.NoError(t, err, "compose.dockerClient.VolumeList()") + + assert.Equal(t, 0, len(volumeList.Volumes), "Volumes are not cleaned up") +} + func TestDockerComposeAPIWithBuild(t *testing.T) { - compose, err := NewDockerCompose("./testresources/docker-compose-build.yml") + path := filepath.Join(testResourcesPackage, "docker-compose-build.yml") + compose, err := NewDockerCompose(path) assert.NoError(t, err, "NewDockerCompose()") t.Cleanup(func() { @@ -384,7 +434,8 @@ func TestDockerComposeAPIWithBuild(t *testing.T) { } func TestDockerComposeApiWithWaitForShortLifespanService(t *testing.T) { - compose, err := NewDockerCompose("./testresources/docker-compose-short-lifespan.yml") + path := filepath.Join(testResourcesPackage, "docker-compose-short-lifespan.yml") + compose, err := NewDockerCompose(path) assert.NoError(t, err, "NewDockerCompose()") t.Cleanup(func() { diff --git a/modules/compose/go.mod b/modules/compose/go.mod index 08a8c2854a..32bd91c2ae 100644 --- a/modules/compose/go.mod +++ b/modules/compose/go.mod @@ -51,7 +51,7 @@ require ( github.com/cenkalti/backoff/v4 v4.2.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/containerd/console v1.0.3 // indirect - github.com/containerd/containerd v1.6.18 // indirect + github.com/containerd/containerd v1.6.19 // indirect github.com/containerd/continuity v0.3.0 // indirect github.com/containerd/ttrpc v1.1.0 // indirect github.com/containerd/typeurl v1.0.2 // indirect diff --git a/modules/compose/go.sum b/modules/compose/go.sum index 7a1fc3008c..db6f4a2d1e 100644 --- a/modules/compose/go.sum +++ b/modules/compose/go.sum @@ -71,7 +71,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= -github.com/Microsoft/hcsshim v0.9.6 h1:VwnDOgLeoi2du6dAznfmspNqTiwczvjv4K7NxuY9jsY= +github.com/Microsoft/hcsshim v0.9.7 h1:mKNHW/Xvv1aFH87Jb6ERDzXTJTLPlmzfZ28VBFD/bfg= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= @@ -154,8 +154,8 @@ github.com/compose-spec/compose-go v1.12.0/go.mod h1:0/X/dTehChV+KBB696nOOl+HYzK github.com/containerd/cgroups v1.0.4 h1:jN/mbWBEaz+T1pi5OFtnkQ+8qnmEbAr1Oo1FRm5B0dA= github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= -github.com/containerd/containerd v1.6.18 h1:qZbsLvmyu+Vlty0/Ex5xc0z2YtKpIsb5n45mAMI+2Ns= -github.com/containerd/containerd v1.6.18/go.mod h1:1RdCUu95+gc2v9t3IL+zIlpClSmew7/0YS8O5eQZrOw= +github.com/containerd/containerd v1.6.19 h1:F0qgQPrG0P2JPgwpxWxYavrVeXAG0ezUIB9Z/4FTUAU= +github.com/containerd/containerd v1.6.19/go.mod h1:HZCDMn4v/Xl2579/MvtOC2M206i+JJ6VxFWU/NetrGY= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/containerd/fifo v1.0.0 h1:6PirWBr9/L7GDamKr+XM0IeUFXu5mf3M/BPpH9gaLBU=