v2.31.0-dev2 4b72742

routes_test.go RawHistoryFolder

1package cli
2
3import (
4	"testing"
5
6	"github.com/bnema/gordon/internal/adapters/in/cli/remote"
7	"github.com/bnema/gordon/internal/adapters/in/cli/ui/components"
8	"github.com/stretchr/testify/assert"
9)
10
11func TestTruncateImage(t *testing.T) {
12	tests := []struct {
13		name     string
14		image    string
15		maxLen   int
16		expected string
17	}{
18		// Basic cases - no truncation needed
19		{
20			name:     "short image fits",
21			image:    "nginx:latest",
22			maxLen:   20,
23			expected: "nginx:latest",
24		},
25		{
26			name:     "exact fit",
27			image:    "nginx:latest",
28			maxLen:   12,
29			expected: "nginx:latest",
30		},
31
32		// Regular tag truncation
33		{
34			name:     "truncate long tag with ellipsis",
35			image:    "registry.test.com/test:v1234567890",
36			maxLen:   30,
37			expected: "registry.test.com/test:v123...",
38		},
39		{
40			name:     "truncate very long image",
41			image:    "registry.example.com/organization/project/image:v1.2.3-beta.4",
42			maxLen:   35,
43			expected: "registry.example.com/organizatio...",
44		},
45
46		// Digest truncation
47		{
48			name:     "digest shortened to 12 chars",
49			image:    "myapp@sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4",
50			maxLen:   50,
51			expected: "myapp@sha256:a3ed95caeb02",
52		},
53		{
54			name:     "digest truncated with ellipsis when too long",
55			image:    "registry.example.com/org/app@sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4",
56			maxLen:   35,
57			expected: "registry.example.com/org/app@sha...",
58		},
59		{
60			name:     "short digest fits",
61			image:    "app@sha256:abc123",
62			maxLen:   30,
63			expected: "app@sha256:abc123",
64		},
65
66		// Edge cases
67		{
68			name:     "maxLen zero returns empty",
69			image:    "nginx:latest",
70			maxLen:   0,
71			expected: "",
72		},
73		{
74			name:     "maxLen negative returns empty",
75			image:    "nginx:latest",
76			maxLen:   -1,
77			expected: "",
78		},
79		{
80			name:     "maxLen 3 or less - no ellipsis",
81			image:    "nginx:latest",
82			maxLen:   3,
83			expected: "ngi",
84		},
85		{
86			name:     "maxLen 4 - truncate with ellipsis",
87			image:    "nginx:latest",
88			maxLen:   4,
89			expected: "n...",
90		},
91		{
92			name:     "empty image",
93			image:    "",
94			maxLen:   10,
95			expected: "",
96		},
97	}
98
99	for _, tt := range tests {
100		t.Run(tt.name, func(t *testing.T) {
101			result := truncateImage(tt.image, tt.maxLen)
102			assert.Equal(t, tt.expected, result)
103		})
104	}
105}
106
107func TestHTTPHealthToStatus(t *testing.T) {
108	tests := []struct {
109		name     string
110		health   *remote.RouteHealth
111		expected components.Status
112	}{
113		{
114			name:     "nil health returns unknown",
115			health:   nil,
116			expected: components.StatusUnknown,
117		},
118		{
119			name:     "zero status no error returns unknown",
120			health:   &remote.RouteHealth{HTTPStatus: 0},
121			expected: components.StatusUnknown,
122		},
123		{
124			name:     "zero status with error returns error",
125			health:   &remote.RouteHealth{HTTPStatus: 0, Error: "connection refused"},
126			expected: components.StatusError,
127		},
128		{
129			name:     "200 returns success",
130			health:   &remote.RouteHealth{HTTPStatus: 200},
131			expected: components.StatusSuccess,
132		},
133		{
134			name:     "301 returns success",
135			health:   &remote.RouteHealth{HTTPStatus: 301},
136			expected: components.StatusSuccess,
137		},
138		{
139			name:     "500 returns error",
140			health:   &remote.RouteHealth{HTTPStatus: 500},
141			expected: components.StatusError,
142		},
143		{
144			name:     "404 returns error",
145			health:   &remote.RouteHealth{HTTPStatus: 404},
146			expected: components.StatusError,
147		},
148		{
149			name:     "100 informational returns error",
150			health:   &remote.RouteHealth{HTTPStatus: 100},
151			expected: components.StatusError,
152		},
153	}
154
155	for _, tt := range tests {
156		t.Run(tt.name, func(t *testing.T) {
157			result := httpHealthToStatus(tt.health)
158			assert.Equal(t, tt.expected, result)
159		})
160	}
161}
162
163func TestGroupRoutesByNetwork(t *testing.T) {
164	routes := []remote.RouteInfo{
165		{Domain: "alpha.dev", Network: "gordon-alpha-dev"},
166		{Domain: "beta.dev", Network: "gordon-shared"},
167		{Domain: "gamma.dev", Network: "gordon-shared"},
168		{Domain: "delta.dev", Network: "gordon-delta-dev"},
169	}
170
171	groups, solo := groupRoutesByNetwork(routes)
172
173	assert.Len(t, solo, 2)
174	assert.Equal(t, "alpha.dev", solo[0].Domain)
175	assert.Equal(t, "delta.dev", solo[1].Domain)
176
177	assert.Len(t, groups, 1)
178	assert.Equal(t, "shared", groups[0].name)
179	assert.Len(t, groups[0].routes, 2)
180}
181
182func TestStripNetworkPrefix(t *testing.T) {
183	tests := []struct {
184		network  string
185		expected string
186	}{
187		{"gordon-shared-services", "shared-services"},
188		{"gordon-my-app-dev", "my-app-dev"},
189		{"custom-network", "custom-network"},
190		{"gordon-", ""},
191		{"", ""},
192	}
193
194	for _, tt := range tests {
195		t.Run(tt.network, func(t *testing.T) {
196			assert.Equal(t, tt.expected, stripNetworkPrefix(tt.network))
197		})
198	}
199}

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