Skip to content
This repository was archived by the owner on Nov 27, 2023. It is now read-only.

Commit f52bdc5

Browse files
authored
Merge pull request #1281 from gtardif/compose_unittests
More Local Compose unit tests
2 parents b39208e + d720eb6 commit f52bdc5

File tree

13 files changed

+2129
-64
lines changed

13 files changed

+2129
-64
lines changed

local/compose/compose.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ import (
3333
)
3434

3535
// NewComposeService create a local implementation of the compose.Service API
36-
func NewComposeService(apiClient *client.Client) compose.Service {
36+
func NewComposeService(apiClient client.APIClient) compose.Service {
3737
return &composeService{apiClient: apiClient}
3838
}
3939

4040
type composeService struct {
41-
apiClient *client.Client
41+
apiClient client.APIClient
4242
}
4343

4444
func (s *composeService) Up(ctx context.Context, project *types.Project, options compose.UpOptions) error {

local/compose/containers.go

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -70,20 +70,6 @@ func (containers Containers) filter(predicate containerPredicate) Containers {
7070
return filtered
7171
}
7272

73-
// split return Containers with elements to match and those not to match predicate
74-
func (containers Containers) split(predicate containerPredicate) (Containers, Containers) {
75-
var right Containers
76-
var left Containers
77-
for _, c := range containers {
78-
if predicate(c) {
79-
right = append(right, c)
80-
} else {
81-
left = append(left, c)
82-
}
83-
}
84-
return right, left
85-
}
86-
8773
func (containers Containers) names() []string {
8874
var names []string
8975
for _, c := range containers {

local/compose/create.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,8 @@ func (s *composeService) Create(ctx context.Context, project *types.Project, opt
6464

6565
var observedState Containers
6666
observedState, err = s.apiClient.ContainerList(ctx, moby.ContainerListOptions{
67-
Filters: filters.NewArgs(
68-
projectFilter(project.Name),
69-
),
70-
All: true,
67+
Filters: filters.NewArgs(projectFilter(project.Name)),
68+
All: true,
7169
})
7270
if err != nil {
7371
return err

local/compose/down.go

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -57,27 +57,23 @@ func (s *composeService) Down(ctx context.Context, projectName string, options c
5757
}
5858

5959
err = InReverseDependencyOrder(ctx, options.Project, func(c context.Context, service types.ServiceConfig) error {
60-
serviceContainers, others := containers.split(isService(service.Name))
60+
serviceContainers := containers.filter(isService(service.Name))
6161
err := s.removeContainers(ctx, w, serviceContainers)
62-
containers = others
6362
return err
6463
})
6564
if err != nil {
6665
return err
6766
}
6867

69-
if options.RemoveOrphans && len(containers) > 0 {
70-
err := s.removeContainers(ctx, w, containers)
68+
orphans := containers.filter(isNotService(options.Project.ServiceNames()...))
69+
if options.RemoveOrphans && len(orphans) > 0 {
70+
err := s.removeContainers(ctx, w, orphans)
7171
if err != nil {
7272
return err
7373
}
7474
}
7575

76-
networks, err := s.apiClient.NetworkList(ctx, moby.NetworkListOptions{
77-
Filters: filters.NewArgs(
78-
projectFilter(projectName),
79-
),
80-
})
76+
networks, err := s.apiClient.NetworkList(ctx, moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(projectName))})
8177
if err != nil {
8278
return err
8379
}
@@ -137,13 +133,15 @@ func (s *composeService) removeContainers(ctx context.Context, w progress.Writer
137133
return eg.Wait()
138134
}
139135

136+
func projectFilterListOpt(projectName string) moby.ContainerListOptions {
137+
return moby.ContainerListOptions{
138+
Filters: filters.NewArgs(projectFilter(projectName)),
139+
All: true,
140+
}
141+
}
142+
140143
func (s *composeService) projectFromContainerLabels(ctx context.Context, projectName string) (*types.Project, error) {
141-
containers, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{
142-
Filters: filters.NewArgs(
143-
projectFilter(projectName),
144-
),
145-
All: true,
146-
})
144+
containers, err := s.apiClient.ContainerList(ctx, projectFilterListOpt(projectName))
147145
if err != nil {
148146
return nil, err
149147
}

local/compose/down_test.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
Copyright 2020 Docker Compose CLI authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package compose
18+
19+
import (
20+
"context"
21+
"testing"
22+
23+
"github.com/golang/mock/gomock"
24+
"gotest.tools/v3/assert"
25+
26+
apitypes "github.com/docker/docker/api/types"
27+
"github.com/docker/docker/api/types/filters"
28+
29+
"github.com/docker/compose-cli/api/compose"
30+
"github.com/docker/compose-cli/local/mocks"
31+
)
32+
33+
func TestDown(t *testing.T) {
34+
mockCtrl := gomock.NewController(t)
35+
defer mockCtrl.Finish()
36+
api := mocks.NewMockAPIClient(mockCtrl)
37+
tested.apiClient = api
38+
39+
ctx := context.Background()
40+
api.EXPECT().ContainerList(ctx, projectFilterListOpt(testProject)).Return(
41+
[]apitypes.Container{testContainer("service1", "123"), testContainer("service1", "456"), testContainer("service2", "789"), testContainer("service_orphan", "321")}, nil).Times(2)
42+
43+
api.EXPECT().ContainerStop(ctx, "123", nil).Return(nil)
44+
api.EXPECT().ContainerStop(ctx, "456", nil).Return(nil)
45+
api.EXPECT().ContainerStop(ctx, "789", nil).Return(nil)
46+
47+
api.EXPECT().ContainerRemove(ctx, "123", apitypes.ContainerRemoveOptions{Force: true}).Return(nil)
48+
api.EXPECT().ContainerRemove(ctx, "456", apitypes.ContainerRemoveOptions{Force: true}).Return(nil)
49+
api.EXPECT().ContainerRemove(ctx, "789", apitypes.ContainerRemoveOptions{Force: true}).Return(nil)
50+
51+
api.EXPECT().NetworkList(ctx, apitypes.NetworkListOptions{Filters: filters.NewArgs(projectFilter(testProject))}).Return([]apitypes.NetworkResource{{ID: "myProject_default"}}, nil)
52+
53+
api.EXPECT().NetworkRemove(ctx, "myProject_default").Return(nil)
54+
55+
err := tested.Down(ctx, testProject, compose.DownOptions{})
56+
assert.NilError(t, err)
57+
}
58+
59+
func TestDownRemoveOrphans(t *testing.T) {
60+
mockCtrl := gomock.NewController(t)
61+
defer mockCtrl.Finish()
62+
api := mocks.NewMockAPIClient(mockCtrl)
63+
tested.apiClient = api
64+
65+
ctx := context.Background()
66+
api.EXPECT().ContainerList(ctx, projectFilterListOpt(testProject)).Return(
67+
[]apitypes.Container{testContainer("service1", "123"), testContainer("service2", "789"), testContainer("service_orphan", "321")}, nil).Times(2)
68+
69+
api.EXPECT().ContainerStop(ctx, "123", nil).Return(nil)
70+
api.EXPECT().ContainerStop(ctx, "789", nil).Return(nil)
71+
api.EXPECT().ContainerStop(ctx, "321", nil).Return(nil)
72+
73+
api.EXPECT().ContainerRemove(ctx, "123", apitypes.ContainerRemoveOptions{Force: true}).Return(nil)
74+
api.EXPECT().ContainerRemove(ctx, "789", apitypes.ContainerRemoveOptions{Force: true}).Return(nil)
75+
api.EXPECT().ContainerRemove(ctx, "321", apitypes.ContainerRemoveOptions{Force: true}).Return(nil)
76+
77+
api.EXPECT().NetworkList(ctx, apitypes.NetworkListOptions{Filters: filters.NewArgs(projectFilter(testProject))}).Return([]apitypes.NetworkResource{{ID: "myProject_default"}}, nil)
78+
79+
api.EXPECT().NetworkRemove(ctx, "myProject_default").Return(nil)
80+
81+
err := tested.Down(ctx, testProject, compose.DownOptions{RemoveOrphans: true})
82+
assert.NilError(t, err)
83+
}

local/compose/kill_test.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
Copyright 2020 Docker Compose CLI authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package compose
18+
19+
import (
20+
"context"
21+
"testing"
22+
23+
"github.com/golang/mock/gomock"
24+
"gotest.tools/v3/assert"
25+
26+
"github.com/compose-spec/compose-go/types"
27+
apitypes "github.com/docker/docker/api/types"
28+
29+
"github.com/docker/compose-cli/api/compose"
30+
"github.com/docker/compose-cli/local/mocks"
31+
)
32+
33+
const testProject = "testProject"
34+
35+
var tested = composeService{}
36+
37+
func TestKillAll(t *testing.T) {
38+
mockCtrl := gomock.NewController(t)
39+
defer mockCtrl.Finish()
40+
api := mocks.NewMockAPIClient(mockCtrl)
41+
tested.apiClient = api
42+
43+
project := types.Project{Name: testProject, Services: []types.ServiceConfig{testService("service1"), testService("service2")}}
44+
45+
ctx := context.Background()
46+
api.EXPECT().ContainerList(ctx, projectFilterListOpt(testProject)).Return(
47+
[]apitypes.Container{testContainer("service1", "123"), testContainer("service1", "456"), testContainer("service2", "789")}, nil)
48+
api.EXPECT().ContainerKill(anyCancellableContext(), "123", "").Return(nil)
49+
api.EXPECT().ContainerKill(anyCancellableContext(), "456", "").Return(nil)
50+
api.EXPECT().ContainerKill(anyCancellableContext(), "789", "").Return(nil)
51+
52+
err := tested.Kill(ctx, &project, compose.KillOptions{})
53+
assert.NilError(t, err)
54+
}
55+
56+
func TestKillSignal(t *testing.T) {
57+
mockCtrl := gomock.NewController(t)
58+
defer mockCtrl.Finish()
59+
api := mocks.NewMockAPIClient(mockCtrl)
60+
tested.apiClient = api
61+
62+
project := types.Project{Name: testProject, Services: []types.ServiceConfig{testService("service1")}}
63+
64+
ctx := context.Background()
65+
api.EXPECT().ContainerList(ctx, projectFilterListOpt(testProject)).Return([]apitypes.Container{testContainer("service1", "123")}, nil)
66+
api.EXPECT().ContainerKill(anyCancellableContext(), "123", "SIGTERM").Return(nil)
67+
68+
err := tested.Kill(ctx, &project, compose.KillOptions{Signal: "SIGTERM"})
69+
assert.NilError(t, err)
70+
}
71+
72+
func testService(name string) types.ServiceConfig {
73+
return types.ServiceConfig{Name: name}
74+
}
75+
76+
func testContainer(service string, id string) apitypes.Container {
77+
return apitypes.Container{
78+
ID: id,
79+
Names: []string{id},
80+
Labels: containerLabels(service),
81+
}
82+
}
83+
84+
func containerLabels(service string) map[string]string {
85+
return map[string]string{serviceLabel: service, configFilesLabel: "testdata/docker-compose.yml", workingDirLabel: "testdata", projectLabel: testProject}
86+
}
87+
88+
func anyCancellableContext() gomock.Matcher {
89+
ctxWithCancel, cancel := context.WithCancel(context.Background())
90+
cancel()
91+
return gomock.AssignableToTypeOf(ctxWithCancel)
92+
}

local/compose/ls.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,23 @@ func combinedStatus(statuses []string) string {
8484
}
8585
return result
8686
}
87+
88+
func groupContainerByLabel(containers []moby.Container, labelName string) (map[string][]moby.Container, []string, error) {
89+
containersByLabel := map[string][]moby.Container{}
90+
keys := []string{}
91+
for _, c := range containers {
92+
label, ok := c.Labels[labelName]
93+
if !ok {
94+
return nil, nil, fmt.Errorf("No label %q set on container %q of compose project", labelName, c.ID)
95+
}
96+
labelContainers, ok := containersByLabel[label]
97+
if !ok {
98+
labelContainers = []moby.Container{}
99+
keys = append(keys, label)
100+
}
101+
labelContainers = append(labelContainers, c)
102+
containersByLabel[label] = labelContainers
103+
}
104+
sort.Strings(keys)
105+
return containersByLabel, keys, nil
106+
}

local/compose/ps.go

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package compose
1919
import (
2020
"context"
2121
"fmt"
22-
"sort"
2322

2423
moby "github.com/docker/docker/api/types"
2524
"github.com/docker/docker/api/types/filters"
@@ -30,10 +29,8 @@ import (
3029

3130
func (s *composeService) Ps(ctx context.Context, projectName string, options compose.PsOptions) ([]compose.ContainerSummary, error) {
3231
containers, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{
33-
Filters: filters.NewArgs(
34-
projectFilter(projectName),
35-
),
36-
All: options.All,
32+
Filters: filters.NewArgs(projectFilter(projectName)),
33+
All: options.All,
3734
})
3835
if err != nil {
3936
return nil, err
@@ -83,23 +80,3 @@ func (s *composeService) Ps(ctx context.Context, projectName string, options com
8380
}
8481
return summary, eg.Wait()
8582
}
86-
87-
func groupContainerByLabel(containers []moby.Container, labelName string) (map[string][]moby.Container, []string, error) {
88-
containersByLabel := map[string][]moby.Container{}
89-
keys := []string{}
90-
for _, c := range containers {
91-
label, ok := c.Labels[labelName]
92-
if !ok {
93-
return nil, nil, fmt.Errorf("No label %q set on container %q of compose project", labelName, c.ID)
94-
}
95-
labelContainers, ok := containersByLabel[label]
96-
if !ok {
97-
labelContainers = []moby.Container{}
98-
keys = append(keys, label)
99-
}
100-
labelContainers = append(labelContainers, c)
101-
containersByLabel[label] = labelContainers
102-
}
103-
sort.Strings(keys)
104-
return containersByLabel, keys, nil
105-
}

0 commit comments

Comments
 (0)