detached baeff58

test: cover route details and networks

commit
baeff58ad3969a0a5951df2b59dac4f43cb206f6
author
brice · · 2026-01-17 11:28 UTC
parent
6108d0e
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +232 -0
A internal/adapters/out/docker/network_test.go +70 -0
@@ -0,0 +1,70 @@
1+package docker
2+
3+import (
4+ "context"
5+ "net/http"
6+ "net/http/httptest"
7+ "strings"
8+ "testing"
9+
10+ "github.com/docker/docker/client"
11+ "github.com/stretchr/testify/assert"
12+)
13+
14+func TestRuntime_GetContainerNetwork(t *testing.T) {
15+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
16+ assert.Equal(t, http.MethodGet, r.Method)
17+ assert.Equal(t, "/v1.41/containers/abc123/json", r.URL.Path)
18+ w.Header().Set("Content-Type", "application/json")
19+ _, _ = w.Write([]byte(`{
20+ "NetworkSettings": {
21+ "Networks": {
22+ "bridge": {"IPAddress": "172.17.0.2"},
23+ "gordon-app": {"IPAddress": "172.18.0.2"}
24+ }
25+ }
26+ }`))
27+ }))
28+ defer server.Close()
29+
30+ host := strings.TrimPrefix(server.URL, "http://")
31+ cli, err := client.NewClientWithOpts(client.WithHost("tcp://"+host), client.WithVersion("1.41"), client.WithHTTPClient(server.Client()))
32+ if err != nil {
33+ t.Fatalf("failed to create docker client: %v", err)
34+ }
35+
36+ runtime := NewRuntimeWithClient(cli)
37+ network, err := runtime.GetContainerNetwork(context.Background(), "abc123")
38+
39+ assert.NoError(t, err)
40+ assert.Equal(t, "gordon-app", network)
41+}
42+
43+func TestRuntime_GetContainerNetwork_Fallback(t *testing.T) {
44+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
45+ assert.Equal(t, http.MethodGet, r.Method)
46+ assert.Equal(t, "/v1.41/containers/abc123/json", r.URL.Path)
47+ w.Header().Set("Content-Type", "application/json")
48+ _, _ = w.Write([]byte(`{
49+ "NetworkSettings": {
50+ "Networks": {
51+ "bridge": {"IPAddress": "172.17.0.2"},
52+ "custom": {"IPAddress": "172.18.0.2"}
53+ }
54+ }
55+ }`))
56+ }))
57+ defer server.Close()
58+
59+ host := strings.TrimPrefix(server.URL, "http://")
60+ cli, err := client.NewClientWithOpts(client.WithHost("tcp://"+host), client.WithVersion("1.41"), client.WithHTTPClient(server.Client()))
61+ if err != nil {
62+ t.Fatalf("failed to create docker client: %v", err)
63+ }
64+
65+ runtime := NewRuntimeWithClient(cli)
66+ network, err := runtime.GetContainerNetwork(context.Background(), "abc123")
67+
68+ assert.NoError(t, err)
69+ assert.Equal(t, "bridge", network)
70+}
@@ -0,0 +1,70 @@
1+package docker
2+
3+import (
4+ "context"
5+ "net/http"
6+ "net/http/httptest"
7+ "strings"
8+ "testing"
9+
10+ "github.com/docker/docker/client"
11+ "github.com/stretchr/testify/assert"
12+)
13+
14+func TestRuntime_GetContainerNetwork(t *testing.T) {
15+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
16+ assert.Equal(t, http.MethodGet, r.Method)
17+ assert.Equal(t, "/v1.41/containers/abc123/json", r.URL.Path)
18+ w.Header().Set("Content-Type", "application/json")
19+ _, _ = w.Write([]byte(`{
20+ "NetworkSettings": {
21+ "Networks": {
22+ "bridge": {"IPAddress": "172.17.0.2"},
23+ "gordon-app": {"IPAddress": "172.18.0.2"}
24+ }
25+ }
26+ }`))
27+ }))
28+ defer server.Close()
29+
30+ host := strings.TrimPrefix(server.URL, "http://")
31+ cli, err := client.NewClientWithOpts(client.WithHost("tcp://"+host), client.WithVersion("1.41"), client.WithHTTPClient(server.Client()))
32+ if err != nil {
33+ t.Fatalf("failed to create docker client: %v", err)
34+ }
35+
36+ runtime := NewRuntimeWithClient(cli)
37+ network, err := runtime.GetContainerNetwork(context.Background(), "abc123")
38+
39+ assert.NoError(t, err)
40+ assert.Equal(t, "gordon-app", network)
41+}
42+
43+func TestRuntime_GetContainerNetwork_Fallback(t *testing.T) {
44+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
45+ assert.Equal(t, http.MethodGet, r.Method)
46+ assert.Equal(t, "/v1.41/containers/abc123/json", r.URL.Path)
47+ w.Header().Set("Content-Type", "application/json")
48+ _, _ = w.Write([]byte(`{
49+ "NetworkSettings": {
50+ "Networks": {
51+ "bridge": {"IPAddress": "172.17.0.2"},
52+ "custom": {"IPAddress": "172.18.0.2"}
53+ }
54+ }
55+ }`))
56+ }))
57+ defer server.Close()
58+
59+ host := strings.TrimPrefix(server.URL, "http://")
60+ cli, err := client.NewClientWithOpts(client.WithHost("tcp://"+host), client.WithVersion("1.41"), client.WithHTTPClient(server.Client()))
61+ if err != nil {
62+ t.Fatalf("failed to create docker client: %v", err)
63+ }
64+
65+ runtime := NewRuntimeWithClient(cli)
66+ network, err := runtime.GetContainerNetwork(context.Background(), "abc123")
67+
68+ assert.NoError(t, err)
69+ assert.Equal(t, "bridge", network)
70+}
A internal/usecase/container/routes_test.go +162 -0
@@ -0,0 +1,162 @@
1+package container
2+
3+import (
4+ "testing"
5+
6+ "github.com/stretchr/testify/assert"
7+ "github.com/stretchr/testify/mock"
8+
9+ "gordon/internal/boundaries/out/mocks"
10+ "gordon/internal/domain"
11+)
12+
13+func TestService_ListRoutesWithDetails(t *testing.T) {
14+ runtime := mocks.NewMockContainerRuntime(t)
15+ svc := NewService(runtime, nil, nil, nil, Config{NetworkPrefix: "gordon"})
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+ runtime.EXPECT().ListContainers(mock.Anything, true).Return([]*domain.Container{
29+ {
30+ ID: "attach-1",
31+ Name: "gordon-app-example-com-postgres",
32+ Image: "postgres:15",
33+ Status: "running",
34+ Labels: map[string]string{
35+ domain.LabelAttachment: "true",
36+ domain.LabelAttachedTo: "app.example.com",
37+ domain.LabelImage: "postgres:15",
38+ },
39+ },
40+ {
41+ ID: "attach-2",
42+ Name: "gordon-other-redis",
43+ Image: "redis:7",
44+ Status: "running",
45+ Labels: map[string]string{
46+ domain.LabelAttachment: "true",
47+ domain.LabelAttachedTo: "other.example.com",
48+ domain.LabelImage: "redis:7",
49+ },
50+ },
51+ {
52+ ID: "other",
53+ Name: "gordon-other",
54+ Image: "busybox",
55+ Status: "running",
56+ Labels: map[string]string{
57+ domain.LabelAttachment: "false",
58+ },
59+ },
60+ }, nil)
61+
62+ results := svc.ListRoutesWithDetails(ctx)
63+
64+ assert.Len(t, results, 1)
65+ assert.Equal(t, "app.example.com", results[0].Domain)
66+ assert.Equal(t, "app:latest", results[0].Image)
67+ assert.Equal(t, "container-1", results[0].ContainerID)
68+ assert.Equal(t, "running", results[0].ContainerStatus)
69+ assert.Equal(t, "gordon-app-example-com", results[0].Network)
70+ if assert.Len(t, results[0].Attachments, 1) {
71+ assert.Equal(t, "postgres", results[0].Attachments[0].Name)
72+ assert.Equal(t, "postgres:15", results[0].Attachments[0].Image)
73+ assert.Equal(t, "attach-1", results[0].Attachments[0].ContainerID)
74+ }
75+}
76+
77+func TestService_ListRoutesWithDetails_Empty(t *testing.T) {
78+ runtime := mocks.NewMockContainerRuntime(t)
79+ svc := NewService(runtime, nil, nil, nil, Config{NetworkPrefix: "gordon"})
80+ ctx := testContext()
81+
82+ results := svc.ListRoutesWithDetails(ctx)
83+
84+ assert.Empty(t, results)
85+}
86+
87+func TestService_ListRoutesWithDetails_NetworkError(t *testing.T) {
88+ runtime := mocks.NewMockContainerRuntime(t)
89+ svc := NewService(runtime, nil, nil, nil, Config{NetworkPrefix: "gordon"})
90+ ctx := testContext()
91+
92+ svc.containers["app.example.com"] = &domain.Container{
93+ ID: "container-1",
94+ Image: "app:latest",
95+ Status: "running",
96+ }
97+
98+ runtime.EXPECT().GetContainerNetwork(mock.Anything, "container-1").Return("", assert.AnError)
99+ runtime.EXPECT().ListContainers(mock.Anything, true).Return([]*domain.Container{}, nil)
100+
101+ results := svc.ListRoutesWithDetails(ctx)
102+
103+ assert.Len(t, results, 1)
104+ assert.Equal(t, "", results[0].Network)
105+}
106+
107+func TestService_ListAttachments(t *testing.T) {
108+ runtime := mocks.NewMockContainerRuntime(t)
109+ svc := NewService(runtime, nil, nil, nil, Config{})
110+ ctx := testContext()
111+
112+ runtime.EXPECT().ListContainers(mock.Anything, true).Return([]*domain.Container{
113+ {
114+ ID: "attach-1",
115+ Name: "gordon-app-example-com-postgres",
116+ Image: "postgres:15",
117+ Status: "running",
118+ Labels: map[string]string{
119+ domain.LabelAttachment: "true",
120+ domain.LabelAttachedTo: "app.example.com",
121+ domain.LabelImage: "postgres:15",
122+ },
123+ },
124+ {
125+ ID: "attach-2",
126+ Name: "gordon-other-redis",
127+ Image: "redis:7",
128+ Status: "running",
129+ Labels: map[string]string{
130+ domain.LabelAttachment: "true",
131+ domain.LabelAttachedTo: "other.example.com",
132+ domain.LabelImage: "redis:7",
133+ },
134+ },
135+ }, nil)
136+
137+ attachments := svc.ListAttachments(ctx, "app.example.com")
138+
139+ assert.Len(t, attachments, 1)
140+ assert.Equal(t, "postgres", attachments[0].Name)
141+ assert.Equal(t, "postgres:15", attachments[0].Image)
142+ assert.Equal(t, "attach-1", attachments[0].ContainerID)
143+}
144+
145+func TestService_ListNetworks(t *testing.T) {
146+ runtime := mocks.NewMockContainerRuntime(t)
147+ svc := NewService(runtime, nil, nil, nil, Config{NetworkPrefix: "gordon"})
148+ ctx := testContext()
149+
150+ runtime.EXPECT().ListNetworks(mock.Anything).Return([]*domain.NetworkInfo{
151+ {Name: "gordon-app"},
152+ {Name: "bridge"},
153+ {Name: "gordon-shared"},
154+ }, nil)
155+
156+ networks, err := svc.ListNetworks(ctx)
157+
158+ assert.NoError(t, err)
159+ assert.Len(t, networks, 2)
160+ assert.Equal(t, "gordon-app", networks[0].Name)
161+ assert.Equal(t, "gordon-shared", networks[1].Name)
162+}
@@ -0,0 +1,162 @@
1+package container
2+
3+import (
4+ "testing"
5+
6+ "github.com/stretchr/testify/assert"
7+ "github.com/stretchr/testify/mock"
8+
9+ "gordon/internal/boundaries/out/mocks"
10+ "gordon/internal/domain"
11+)
12+
13+func TestService_ListRoutesWithDetails(t *testing.T) {
14+ runtime := mocks.NewMockContainerRuntime(t)
15+ svc := NewService(runtime, nil, nil, nil, Config{NetworkPrefix: "gordon"})
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+ runtime.EXPECT().ListContainers(mock.Anything, true).Return([]*domain.Container{
29+ {
30+ ID: "attach-1",
31+ Name: "gordon-app-example-com-postgres",
32+ Image: "postgres:15",
33+ Status: "running",
34+ Labels: map[string]string{
35+ domain.LabelAttachment: "true",
36+ domain.LabelAttachedTo: "app.example.com",
37+ domain.LabelImage: "postgres:15",
38+ },
39+ },
40+ {
41+ ID: "attach-2",
42+ Name: "gordon-other-redis",
43+ Image: "redis:7",
44+ Status: "running",
45+ Labels: map[string]string{
46+ domain.LabelAttachment: "true",
47+ domain.LabelAttachedTo: "other.example.com",
48+ domain.LabelImage: "redis:7",
49+ },
50+ },
51+ {
52+ ID: "other",
53+ Name: "gordon-other",
54+ Image: "busybox",
55+ Status: "running",
56+ Labels: map[string]string{
57+ domain.LabelAttachment: "false",
58+ },
59+ },
60+ }, nil)
61+
62+ results := svc.ListRoutesWithDetails(ctx)
63+
64+ assert.Len(t, results, 1)
65+ assert.Equal(t, "app.example.com", results[0].Domain)
66+ assert.Equal(t, "app:latest", results[0].Image)
67+ assert.Equal(t, "container-1", results[0].ContainerID)
68+ assert.Equal(t, "running", results[0].ContainerStatus)
69+ assert.Equal(t, "gordon-app-example-com", results[0].Network)
70+ if assert.Len(t, results[0].Attachments, 1) {
71+ assert.Equal(t, "postgres", results[0].Attachments[0].Name)
72+ assert.Equal(t, "postgres:15", results[0].Attachments[0].Image)
73+ assert.Equal(t, "attach-1", results[0].Attachments[0].ContainerID)
74+ }
75+}
76+
77+func TestService_ListRoutesWithDetails_Empty(t *testing.T) {
78+ runtime := mocks.NewMockContainerRuntime(t)
79+ svc := NewService(runtime, nil, nil, nil, Config{NetworkPrefix: "gordon"})
80+ ctx := testContext()
81+
82+ results := svc.ListRoutesWithDetails(ctx)
83+
84+ assert.Empty(t, results)
85+}
86+
87+func TestService_ListRoutesWithDetails_NetworkError(t *testing.T) {
88+ runtime := mocks.NewMockContainerRuntime(t)
89+ svc := NewService(runtime, nil, nil, nil, Config{NetworkPrefix: "gordon"})
90+ ctx := testContext()
91+
92+ svc.containers["app.example.com"] = &domain.Container{
93+ ID: "container-1",
94+ Image: "app:latest",
95+ Status: "running",
96+ }
97+
98+ runtime.EXPECT().GetContainerNetwork(mock.Anything, "container-1").Return("", assert.AnError)
99+ runtime.EXPECT().ListContainers(mock.Anything, true).Return([]*domain.Container{}, nil)
100+
101+ results := svc.ListRoutesWithDetails(ctx)
102+
103+ assert.Len(t, results, 1)
104+ assert.Equal(t, "", results[0].Network)
105+}
106+
107+func TestService_ListAttachments(t *testing.T) {
108+ runtime := mocks.NewMockContainerRuntime(t)
109+ svc := NewService(runtime, nil, nil, nil, Config{})
110+ ctx := testContext()
111+
112+ runtime.EXPECT().ListContainers(mock.Anything, true).Return([]*domain.Container{
113+ {
114+ ID: "attach-1",
115+ Name: "gordon-app-example-com-postgres",
116+ Image: "postgres:15",
117+ Status: "running",
118+ Labels: map[string]string{
119+ domain.LabelAttachment: "true",
120+ domain.LabelAttachedTo: "app.example.com",
121+ domain.LabelImage: "postgres:15",
122+ },
123+ },
124+ {
125+ ID: "attach-2",
126+ Name: "gordon-other-redis",
127+ Image: "redis:7",
128+ Status: "running",
129+ Labels: map[string]string{
130+ domain.LabelAttachment: "true",
131+ domain.LabelAttachedTo: "other.example.com",
132+ domain.LabelImage: "redis:7",
133+ },
134+ },
135+ }, nil)
136+
137+ attachments := svc.ListAttachments(ctx, "app.example.com")
138+
139+ assert.Len(t, attachments, 1)
140+ assert.Equal(t, "postgres", attachments[0].Name)
141+ assert.Equal(t, "postgres:15", attachments[0].Image)
142+ assert.Equal(t, "attach-1", attachments[0].ContainerID)
143+}
144+
145+func TestService_ListNetworks(t *testing.T) {
146+ runtime := mocks.NewMockContainerRuntime(t)
147+ svc := NewService(runtime, nil, nil, nil, Config{NetworkPrefix: "gordon"})
148+ ctx := testContext()
149+
150+ runtime.EXPECT().ListNetworks(mock.Anything).Return([]*domain.NetworkInfo{
151+ {Name: "gordon-app"},
152+ {Name: "bridge"},
153+ {Name: "gordon-shared"},
154+ }, nil)
155+
156+ networks, err := svc.ListNetworks(ctx)
157+
158+ assert.NoError(t, err)
159+ assert.Len(t, networks, 2)
160+ assert.Equal(t, "gordon-app", networks[0].Name)
161+ assert.Equal(t, "gordon-shared", networks[1].Name)
162+}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close