1package container
2
3import (
4 "testing"
5
6 "github.com/stretchr/testify/assert"
7 "github.com/stretchr/testify/mock"
8
9 "github.com/bnema/gordon/internal/boundaries/out/mocks"
10 "github.com/bnema/gordon/internal/domain"
11)
12
13func TestService_ListRoutesWithDetails(t *testing.T) {
14 runtime := mocks.NewMockContainerRuntime(t)
15 svc := NewService(runtime, nil, nil, nil, Config{NetworkPrefix: "gordon"}, nil)
16 ctx := testContext()
17
18 svc.containers["app.example.com"] = &domain.Container{
19 ID: "container-1",
20 Image: "registry/app:latest",
21 Status: "running",
22 Labels: map[string]string{
23 domain.LabelImage: "app:latest",
24 },
25 }
26
27 runtime.EXPECT().GetContainerNetwork(mock.Anything, "container-1").Return("gordon-app-example-com", nil)
28 // getAllAttachments calls GetContainerNetwork for each attachment
29 runtime.EXPECT().GetContainerNetwork(mock.Anything, "attach-1").Return("gordon-app-example-com", nil)
30 runtime.EXPECT().GetContainerNetwork(mock.Anything, "attach-2").Return("gordon-other-example-com", nil)
31 runtime.EXPECT().ListContainers(mock.Anything, true).Return([]*domain.Container{
32 {
33 ID: "attach-1",
34 Name: "gordon-app-example-com-postgres",
35 Image: "postgres:15",
36 Status: "running",
37 Labels: map[string]string{
38 domain.LabelAttachment: "true",
39 domain.LabelAttachedTo: "app.example.com",
40 domain.LabelImage: "postgres:15",
41 },
42 },
43 {
44 ID: "attach-2",
45 Name: "gordon-other-redis",
46 Image: "redis:7",
47 Status: "running",
48 Labels: map[string]string{
49 domain.LabelAttachment: "true",
50 domain.LabelAttachedTo: "other.example.com",
51 domain.LabelImage: "redis:7",
52 },
53 },
54 {
55 ID: "other",
56 Name: "gordon-other",
57 Image: "busybox",
58 Status: "running",
59 Labels: map[string]string{
60 domain.LabelAttachment: "false",
61 },
62 },
63 }, nil)
64
65 results := svc.ListRoutesWithDetails(ctx)
66
67 assert.Len(t, results, 1)
68 assert.Equal(t, "app.example.com", results[0].Domain)
69 assert.Equal(t, "app:latest", results[0].Image)
70 assert.Equal(t, "container-1", results[0].ContainerID)
71 assert.Equal(t, "running", results[0].ContainerStatus)
72 assert.Equal(t, "gordon-app-example-com", results[0].Network)
73 if assert.Len(t, results[0].Attachments, 1) {
74 assert.Equal(t, "postgres", results[0].Attachments[0].Name)
75 assert.Equal(t, "postgres:15", results[0].Attachments[0].Image)
76 assert.Equal(t, "attach-1", results[0].Attachments[0].ContainerID)
77 assert.Equal(t, "gordon-app-example-com", results[0].Attachments[0].Network)
78 }
79}
80
81func TestService_ListRoutesWithDetails_Empty(t *testing.T) {
82 runtime := mocks.NewMockContainerRuntime(t)
83 svc := NewService(runtime, nil, nil, nil, Config{NetworkPrefix: "gordon"}, nil)
84 ctx := testContext()
85
86 // getAllAttachments is called even with empty containers
87 runtime.EXPECT().ListContainers(mock.Anything, true).Return([]*domain.Container{}, nil)
88
89 results := svc.ListRoutesWithDetails(ctx)
90
91 assert.Empty(t, results)
92}
93
94func TestService_ListRoutesWithDetails_NetworkError(t *testing.T) {
95 runtime := mocks.NewMockContainerRuntime(t)
96 svc := NewService(runtime, nil, nil, nil, Config{NetworkPrefix: "gordon"}, nil)
97 ctx := testContext()
98
99 svc.containers["app.example.com"] = &domain.Container{
100 ID: "container-1",
101 Image: "app:latest",
102 Status: "running",
103 }
104
105 runtime.EXPECT().GetContainerNetwork(mock.Anything, "container-1").Return("", assert.AnError)
106 runtime.EXPECT().ListContainers(mock.Anything, true).Return([]*domain.Container{}, nil)
107
108 results := svc.ListRoutesWithDetails(ctx)
109
110 assert.Len(t, results, 1)
111 assert.Equal(t, "", results[0].Network)
112}
113
114func TestService_ListAttachments(t *testing.T) {
115 runtime := mocks.NewMockContainerRuntime(t)
116 svc := NewService(runtime, nil, nil, nil, Config{}, nil)
117 ctx := testContext()
118
119 runtime.EXPECT().ListContainers(mock.Anything, true).Return([]*domain.Container{
120 {
121 ID: "attach-1",
122 Name: "gordon-app-example-com-postgres",
123 Image: "postgres:15",
124 Status: "running",
125 Labels: map[string]string{
126 domain.LabelAttachment: "true",
127 domain.LabelAttachedTo: "app.example.com",
128 domain.LabelImage: "postgres:15",
129 },
130 },
131 {
132 ID: "attach-2",
133 Name: "gordon-other-redis",
134 Image: "redis:7",
135 Status: "running",
136 Labels: map[string]string{
137 domain.LabelAttachment: "true",
138 domain.LabelAttachedTo: "other.example.com",
139 domain.LabelImage: "redis:7",
140 },
141 },
142 }, nil)
143 runtime.EXPECT().GetContainerNetwork(mock.Anything, "attach-1").Return("gordon-app-example-com", nil)
144
145 attachments := svc.ListAttachments(ctx, "app.example.com")
146
147 assert.Len(t, attachments, 1)
148 assert.Equal(t, "postgres", attachments[0].Name)
149 assert.Equal(t, "postgres:15", attachments[0].Image)
150 assert.Equal(t, "attach-1", attachments[0].ContainerID)
151 assert.Equal(t, "gordon-app-example-com", attachments[0].Network)
152}
153
154func TestService_ListNetworks(t *testing.T) {
155 runtime := mocks.NewMockContainerRuntime(t)
156 svc := NewService(runtime, nil, nil, nil, Config{NetworkPrefix: "gordon"}, nil)
157 ctx := testContext()
158
159 runtime.EXPECT().ListNetworks(mock.Anything).Return([]*domain.NetworkInfo{
160 {Name: "gordon-app", Labels: map[string]string{domain.LabelManaged: "true"}},
161 {Name: "bridge"},
162 {Name: "gordon-shared", Labels: map[string]string{domain.LabelManaged: "true"}},
163 {Name: "gordon-unmanaged"},
164 }, nil)
165
166 networks, err := svc.ListNetworks(ctx)
167
168 assert.NoError(t, err)
169 assert.Len(t, networks, 2)
170 assert.Equal(t, "gordon-app", networks[0].Name)
171 assert.Equal(t, "gordon-shared", networks[1].Name)
172 assert.NotContains(t, []string{networks[0].Name, networks[1].Name}, "gordon-unmanaged")
173}