diff --git a/local/compose/create.go b/local/compose/create.go index 7e4f2af8d..cb24cde4e 100644 --- a/local/compose/create.go +++ b/local/compose/create.go @@ -64,10 +64,8 @@ func (s *composeService) Create(ctx context.Context, project *types.Project, opt var observedState Containers observedState, err = s.apiClient.ContainerList(ctx, moby.ContainerListOptions{ - Filters: filters.NewArgs( - projectFilter(project.Name), - ), - All: true, + Filters: filters.NewArgs(projectFilter(project.Name)), + All: true, }) if err != nil { return err diff --git a/local/compose/down.go b/local/compose/down.go index 0bd583ce9..e60912e6b 100644 --- a/local/compose/down.go +++ b/local/compose/down.go @@ -73,11 +73,7 @@ func (s *composeService) Down(ctx context.Context, projectName string, options c } } - networks, err := s.apiClient.NetworkList(ctx, moby.NetworkListOptions{ - Filters: filters.NewArgs( - projectFilter(projectName), - ), - }) + networks, err := s.apiClient.NetworkList(ctx, moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(projectName))}) if err != nil { return err } @@ -137,13 +133,15 @@ func (s *composeService) removeContainers(ctx context.Context, w progress.Writer return eg.Wait() } +func projectFilterListOpt(projectName string) moby.ContainerListOptions { + return moby.ContainerListOptions{ + Filters: filters.NewArgs(projectFilter(projectName)), + All: true, + } +} + func (s *composeService) projectFromContainerLabels(ctx context.Context, projectName string) (*types.Project, error) { - containers, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{ - Filters: filters.NewArgs( - projectFilter(projectName), - ), - All: true, - }) + containers, err := s.apiClient.ContainerList(ctx, projectFilterListOpt(projectName)) if err != nil { return nil, err } diff --git a/local/compose/down_test.go b/local/compose/down_test.go new file mode 100644 index 000000000..7ebf0af9e --- /dev/null +++ b/local/compose/down_test.go @@ -0,0 +1,83 @@ +/* + Copyright 2020 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package compose + +import ( + "context" + "testing" + + "github.com/golang/mock/gomock" + "gotest.tools/v3/assert" + + apitypes "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" + + "github.com/docker/compose-cli/api/compose" + "github.com/docker/compose-cli/local/mocks" +) + +func TestDown(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + api := mocks.NewMockAPIClient(mockCtrl) + tested.apiClient = api + + ctx := context.Background() + api.EXPECT().ContainerList(ctx, projectFilterListOpt(testProject)).Return( + []apitypes.Container{testContainer("service1", "123"), testContainer("service1", "456"), testContainer("service2", "789"), testContainer("service_orphan", "321")}, nil).Times(2) + + api.EXPECT().ContainerStop(ctx, "123", nil).Return(nil) + api.EXPECT().ContainerStop(ctx, "456", nil).Return(nil) + api.EXPECT().ContainerStop(ctx, "789", nil).Return(nil) + + api.EXPECT().ContainerRemove(ctx, "123", apitypes.ContainerRemoveOptions{Force: true}).Return(nil) + api.EXPECT().ContainerRemove(ctx, "456", apitypes.ContainerRemoveOptions{Force: true}).Return(nil) + api.EXPECT().ContainerRemove(ctx, "789", apitypes.ContainerRemoveOptions{Force: true}).Return(nil) + + api.EXPECT().NetworkList(ctx, apitypes.NetworkListOptions{Filters: filters.NewArgs(projectFilter(testProject))}).Return([]apitypes.NetworkResource{{ID: "myProject_default"}}, nil) + + api.EXPECT().NetworkRemove(ctx, "myProject_default").Return(nil) + + err := tested.Down(ctx, testProject, compose.DownOptions{}) + assert.NilError(t, err) +} + +func TestDownRemoveOrphans(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + api := mocks.NewMockAPIClient(mockCtrl) + tested.apiClient = api + + ctx := context.Background() + api.EXPECT().ContainerList(ctx, projectFilterListOpt(testProject)).Return( + []apitypes.Container{testContainer("service1", "123"), testContainer("service2", "789"), testContainer("service_orphan", "321")}, nil).Times(2) + + api.EXPECT().ContainerStop(ctx, "123", nil).Return(nil) + api.EXPECT().ContainerStop(ctx, "789", nil).Return(nil) + api.EXPECT().ContainerStop(ctx, "321", nil).Return(nil) + + api.EXPECT().ContainerRemove(ctx, "123", apitypes.ContainerRemoveOptions{Force: true}).Return(nil) + api.EXPECT().ContainerRemove(ctx, "789", apitypes.ContainerRemoveOptions{Force: true}).Return(nil) + api.EXPECT().ContainerRemove(ctx, "321", apitypes.ContainerRemoveOptions{Force: true}).Return(nil) + + api.EXPECT().NetworkList(ctx, apitypes.NetworkListOptions{Filters: filters.NewArgs(projectFilter(testProject))}).Return([]apitypes.NetworkResource{{ID: "myProject_default"}}, nil) + + api.EXPECT().NetworkRemove(ctx, "myProject_default").Return(nil) + + err := tested.Down(ctx, testProject, compose.DownOptions{RemoveOrphans: true}) + assert.NilError(t, err) +} diff --git a/local/compose/kill_test.go b/local/compose/kill_test.go index bf03f6b09..435ff74c8 100644 --- a/local/compose/kill_test.go +++ b/local/compose/kill_test.go @@ -20,40 +20,36 @@ import ( "context" "testing" - "github.com/compose-spec/compose-go/types" - apitypes "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/filters" - "github.com/golang/mock/gomock" "gotest.tools/v3/assert" + "github.com/compose-spec/compose-go/types" + apitypes "github.com/docker/docker/api/types" + "github.com/docker/compose-cli/api/compose" "github.com/docker/compose-cli/local/mocks" ) -var ( - s = composeService{} - projectListOpts = apitypes.ContainerListOptions{ - Filters: filters.NewArgs(projectFilter("myProject")), - All: true, - } -) +const testProject = "testProject" + +var tested = composeService{} func TestKillAll(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() api := mocks.NewMockAPIClient(mockCtrl) - s.apiClient = api + tested.apiClient = api - project := types.Project{Name: "myProject", Services: []types.ServiceConfig{testService("service1"), testService("service2")}} + project := types.Project{Name: testProject, Services: []types.ServiceConfig{testService("service1"), testService("service2")}} ctx := context.Background() - api.EXPECT().ContainerList(ctx, projectListOpts).Return([]apitypes.Container{testContainer("service1", "123"), testContainer("service1", "456"), testContainer("service2", "789")}, nil) + api.EXPECT().ContainerList(ctx, projectFilterListOpt(testProject)).Return( + []apitypes.Container{testContainer("service1", "123"), testContainer("service1", "456"), testContainer("service2", "789")}, nil) api.EXPECT().ContainerKill(anyCancellableContext(), "123", "").Return(nil) api.EXPECT().ContainerKill(anyCancellableContext(), "456", "").Return(nil) api.EXPECT().ContainerKill(anyCancellableContext(), "789", "").Return(nil) - err := s.Kill(ctx, &project, compose.KillOptions{}) + err := tested.Kill(ctx, &project, compose.KillOptions{}) assert.NilError(t, err) } @@ -61,15 +57,15 @@ func TestKillSignal(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() api := mocks.NewMockAPIClient(mockCtrl) - s.apiClient = api + tested.apiClient = api - project := types.Project{Name: "myProject", Services: []types.ServiceConfig{testService("service1")}} + project := types.Project{Name: testProject, Services: []types.ServiceConfig{testService("service1")}} ctx := context.Background() - api.EXPECT().ContainerList(ctx, projectListOpts).Return([]apitypes.Container{testContainer("service1", "123")}, nil) + api.EXPECT().ContainerList(ctx, projectFilterListOpt(testProject)).Return([]apitypes.Container{testContainer("service1", "123")}, nil) api.EXPECT().ContainerKill(anyCancellableContext(), "123", "SIGTERM").Return(nil) - err := s.Kill(ctx, &project, compose.KillOptions{Signal: "SIGTERM"}) + err := tested.Kill(ctx, &project, compose.KillOptions{Signal: "SIGTERM"}) assert.NilError(t, err) } @@ -81,7 +77,7 @@ func testContainer(service string, id string) apitypes.Container { return apitypes.Container{ ID: id, Names: []string{id}, - Labels: map[string]string{compose.ServiceTag: service}, + Labels: map[string]string{serviceLabel: service, configFilesLabel: "testdata/docker-compose.yml", workingDirLabel: "testdata", projectLabel: testProject}, } } diff --git a/local/compose/ps.go b/local/compose/ps.go index 264f2ecfb..a95cbd84c 100644 --- a/local/compose/ps.go +++ b/local/compose/ps.go @@ -30,10 +30,8 @@ import ( func (s *composeService) Ps(ctx context.Context, projectName string, options compose.PsOptions) ([]compose.ContainerSummary, error) { containers, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{ - Filters: filters.NewArgs( - projectFilter(projectName), - ), - All: options.All, + Filters: filters.NewArgs(projectFilter(projectName)), + All: options.All, }) if err != nil { return nil, err diff --git a/local/compose/testdata/docker-compose.yml b/local/compose/testdata/docker-compose.yml new file mode 100644 index 000000000..4e3e6cb98 --- /dev/null +++ b/local/compose/testdata/docker-compose.yml @@ -0,0 +1,5 @@ +services: + service1: + image: nginx + service2: + image: mysql