v2.0.0 ae3e752

helpers_test.go RawHistoryFolder

1package container
2
3import (
4	"strings"
5	"testing"
6
7	"github.com/stretchr/testify/assert"
8)
9
10func TestNormalizeImageRef(t *testing.T) {
11	testCases := []struct {
12		name     string
13		input    string
14		expected string
15	}{
16		{
17			name:     "simple image with tag",
18			input:    "nginx:latest",
19			expected: "docker.io/library/nginx:latest",
20		},
21		{
22			name:     "image without tag",
23			input:    "nginx",
24			expected: "docker.io/library/nginx:latest",
25		},
26		{
27			name:     "registry with image and tag",
28			input:    "registry.example.com/nginx:v1.0",
29			expected: "registry.example.com/nginx:v1.0",
30		},
31		{
32			name:     "dockerhub image with user",
33			input:    "user/repo:tag",
34			expected: "docker.io/user/repo:tag",
35		},
36		{
37			name:     "official library image without tag",
38			input:    "postgres",
39			expected: "docker.io/library/postgres:latest",
40		},
41	}
42
43	for _, tc := range testCases {
44		t.Run(tc.name, func(t *testing.T) {
45			result := normalizeImageRef(tc.input)
46			assert.Equal(t, tc.expected, result)
47		})
48	}
49}
50
51func TestGenerateVolumeName(t *testing.T) {
52	testCases := []struct {
53		name     string
54		prefix   string
55		domain   string
56		path     string
57	}{
58		{
59			name:   "basic volume name",
60			prefix: "gordon",
61			domain: "app.example.com",
62			path:   "/data",
63		},
64		{
65			name:   "complex path",
66			prefix: "test",
67			domain: "my-app.domain.com", 
68			path:   "/var/www/html/uploads",
69		},
70	}
71
72	for _, tc := range testCases {
73		t.Run(tc.name, func(t *testing.T) {
74			result := generateVolumeName(tc.prefix, tc.domain, tc.path)
75			
76			// Check that it starts with prefix
77			assert.True(t, strings.HasPrefix(result, tc.prefix+"-"))
78			
79			// Check that it contains sanitized domain
80			sanitizedDomain := strings.ReplaceAll(strings.ToLower(tc.domain), ".", "-")
81			assert.Contains(t, result, sanitizedDomain)
82			
83			// Volume names should be consistent for same inputs
84			result2 := generateVolumeName(tc.prefix, tc.domain, tc.path)
85			assert.Equal(t, result, result2)
86			
87			// Volume names should be different for different paths
88			result3 := generateVolumeName(tc.prefix, tc.domain, tc.path+"/different")
89			assert.NotEqual(t, result, result3)
90		})
91	}
92}
93
94func TestMergeEnvironmentVariables(t *testing.T) {
95	testCases := []struct {
96		name         string
97		dockerfileEnv []string
98		userEnv      []string
99		expected     []string
100	}{
101		{
102			name:         "user env overrides dockerfile env",
103			dockerfileEnv: []string{"NODE_ENV=development", "PORT=3000"},
104			userEnv:      []string{"NODE_ENV=production", "API_KEY=secret"},
105			expected:     []string{"NODE_ENV=production", "PORT=3000", "API_KEY=secret"},
106		},
107		{
108			name:         "only dockerfile env",
109			dockerfileEnv: []string{"NODE_ENV=development", "PORT=3000"},
110			userEnv:      []string{},
111			expected:     []string{"NODE_ENV=development", "PORT=3000"},
112		},
113		{
114			name:         "only user env",
115			dockerfileEnv: []string{},
116			userEnv:      []string{"API_KEY=secret", "DEBUG=true"},
117			expected:     []string{"API_KEY=secret", "DEBUG=true"},
118		},
119		{
120			name:         "empty environment",
121			dockerfileEnv: []string{},
122			userEnv:      []string{},
123			expected:     []string{},
124		},
125	}
126
127	for _, tc := range testCases {
128		t.Run(tc.name, func(t *testing.T) {
129			result := mergeEnvironmentVariables(tc.dockerfileEnv, tc.userEnv)
130			assert.Equal(t, len(tc.expected), len(result))
131			
132			// Convert to map for easier comparison
133			resultMap := make(map[string]string)
134			for _, env := range result {
135				parts := splitEnvVar(env)
136				if len(parts) == 2 {
137					resultMap[parts[0]] = parts[1]
138				}
139			}
140			
141			expectedMap := make(map[string]string)
142			for _, env := range tc.expected {
143				parts := splitEnvVar(env)
144				if len(parts) == 2 {
145					expectedMap[parts[0]] = parts[1]
146				}
147			}
148			
149			assert.Equal(t, expectedMap, resultMap)
150		})
151	}
152}
153
154// Helper function to split environment variable string
155func splitEnvVar(env string) []string {
156	for i, c := range env {
157		if c == '=' {
158			return []string{env[:i], env[i+1:]}
159		}
160	}
161	return []string{env}
162}
163
164func TestSanitizeDomainForVolume(t *testing.T) {
165	testCases := []struct {
166		name     string
167		input    string
168		expected string
169	}{
170		{
171			name:     "basic domain",
172			input:    "app.example.com",
173			expected: "app-example-com",
174		},
175		{
176			name:     "domain with port",
177			input:    "localhost:3000",
178			expected: "localhost-3000",
179		},
180		{
181			name:     "domain with special chars",
182			input:    "my_app@example.com",
183			expected: "my-app-example-com",
184		},
185		{
186			name:     "uppercase domain",
187			input:    "API.EXAMPLE.COM",
188			expected: "api-example-com",
189		},
190	}
191
192	for _, tc := range testCases {
193		t.Run(tc.name, func(t *testing.T) {
194			result := sanitizeDomainForVolume(tc.input)
195			assert.Equal(t, tc.expected, result)
196		})
197	}
198}

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