2.0.0 4803e67

factory_test.go RawHistoryFolder

1package container
2
3import (
4	"context"
5	"os"
6	"path/filepath"
7	"strings"
8	"testing"
9
10	"github.com/stretchr/testify/assert"
11	"github.com/stretchr/testify/require"
12
13	"gordon/internal/config"
14)
15
16func TestCreateRuntime(t *testing.T) {
17	ctx := context.Background()
18	
19	tests := []struct {
20		name           string
21		config         *config.Config
22		expectError    bool
23		expectedError  string
24	}{
25		{
26			name: "docker runtime",
27			config: &config.Config{
28				Server: config.ServerConfig{
29					Runtime:    "docker",
30					SocketPath: "/var/run/docker.sock",
31				},
32			},
33			expectError: true, // Will fail because Docker isn't running in test
34		},
35		{
36			name: "podman runtime",
37			config: &config.Config{
38				Server: config.ServerConfig{
39					Runtime:    "podman",
40					SocketPath: "/run/user/1000/podman/podman.sock",
41				},
42			},
43			expectError: true, // Will fail because Podman isn't running in test
44		},
45		{
46			name: "auto runtime",
47			config: &config.Config{
48				Server: config.ServerConfig{
49					Runtime: "auto",
50				},
51			},
52			expectError: false, // May succeed if runtime is available
53		},
54		{
55			name: "invalid runtime",
56			config: &config.Config{
57				Server: config.ServerConfig{
58					Runtime: "invalid",
59				},
60			},
61			expectError:   true,
62			expectedError: "unsupported runtime",
63		},
64	}
65
66	for _, tt := range tests {
67		t.Run(tt.name, func(t *testing.T) {
68			runtime, err := CreateRuntime(ctx, tt.config)
69			
70			if tt.name == "auto runtime" {
71				// Auto runtime may succeed or fail depending on environment
72				if err != nil {
73					assert.Nil(t, runtime)
74				} else {
75					assert.NotNil(t, runtime)
76				}
77			} else if tt.expectError {
78				assert.Error(t, err)
79				if tt.expectedError != "" {
80					assert.Contains(t, err.Error(), tt.expectedError)
81				}
82				assert.Nil(t, runtime)
83			} else {
84				assert.NoError(t, err)
85				assert.NotNil(t, runtime)
86			}
87		})
88	}
89}
90
91func TestGetSocketPath(t *testing.T) {
92	tests := []struct {
93		name         string
94		configPath   string
95		setupEnv     func()
96		cleanupEnv   func()
97		expected     string
98	}{
99		{
100			name:       "with provided config path",
101			configPath: "/custom/docker.sock",
102			setupEnv:   func() {},
103			cleanupEnv: func() {},
104			expected:   "/custom/docker.sock",
105		},
106		{
107			name:       "with CONTAINER_HOST env var",
108			configPath: "",
109			setupEnv: func() {
110				os.Setenv("CONTAINER_HOST", "/env/container.sock")
111			},
112			cleanupEnv: func() {
113				os.Unsetenv("CONTAINER_HOST")
114			},
115			expected: "/env/container.sock",
116		},
117		{
118			name:       "no config or env - returns empty",
119			configPath: "",
120			setupEnv: func() {
121				os.Unsetenv("CONTAINER_HOST")
122			},
123			cleanupEnv: func() {},
124			expected:   "",
125		},
126	}
127
128	for _, tt := range tests {
129		t.Run(tt.name, func(t *testing.T) {
130			tt.setupEnv()
131			defer tt.cleanupEnv()
132			
133			result := getSocketPath(tt.configPath)
134			assert.Equal(t, tt.expected, result)
135		})
136	}
137}
138
139func TestCreateAutoRuntime(t *testing.T) {
140	ctx := context.Background()
141	
142	// Test that createAutoRuntime tries different runtimes
143	runtime, err := createAutoRuntime(ctx, "")
144	// In test environment, this may succeed or fail depending on available runtimes
145	if err != nil {
146		// If it fails, should be because no runtime is available
147		assert.Nil(t, runtime)
148		assert.Contains(t, err.Error(), "no container runtime available")
149	} else {
150		// If it succeeds, should return a runtime
151		assert.NotNil(t, runtime)
152	}
153}
154
155func TestCreateDockerRuntime(t *testing.T) {
156	ctx := context.Background()
157	
158	tests := []struct {
159		name        string
160		socketPath  string
161		expectError bool
162	}{
163		{
164			name:        "default docker socket",
165			socketPath:  "/var/run/docker.sock",
166			expectError: true, // Will fail because Docker isn't running
167		},
168		{
169			name:        "custom socket path",
170			socketPath:  "/custom/docker.sock",
171			expectError: true, // Will fail because socket doesn't exist
172		},
173	}
174
175	for _, tt := range tests {
176		t.Run(tt.name, func(t *testing.T) {
177			runtime, err := createDockerRuntime(ctx, tt.socketPath)
178			
179			if tt.expectError {
180				assert.Error(t, err)
181				assert.Nil(t, runtime)
182			} else {
183				assert.NoError(t, err)
184				assert.NotNil(t, runtime)
185			}
186		})
187	}
188}
189
190func TestCreatePodmanRuntime(t *testing.T) {
191	ctx := context.Background()
192	
193	tests := []struct {
194		name        string
195		socketPath  string
196		rootless    bool
197		expectError bool
198	}{
199		{
200			name:        "custom podman socket",
201			socketPath:  "/custom/podman.sock",
202			rootless:    false,
203			expectError: true, // Will fail because socket doesn't exist
204		},
205		{
206			name:        "rootless podman socket",
207			socketPath:  "/custom/podman.sock", 
208			rootless:    true,
209			expectError: true, // Will fail because socket doesn't exist
210		},
211	}
212
213	for _, tt := range tests {
214		t.Run(tt.name, func(t *testing.T) {
215			runtime, err := createPodmanRuntime(ctx, tt.socketPath, tt.rootless)
216			
217			if tt.expectError {
218				assert.Error(t, err)
219				assert.Nil(t, runtime)
220			} else {
221				assert.NoError(t, err)
222				assert.NotNil(t, runtime)
223			}
224		})
225	}
226}
227
228func TestDetectRuntimeType(t *testing.T) {
229	tests := []struct {
230		name       string
231		socketPath string
232		expected   RuntimeType
233	}{
234		{
235			name:       "docker socket",
236			socketPath: "/var/run/docker.sock",
237			expected:   RuntimeDocker,
238		},
239		{
240			name:       "docker unix socket",
241			socketPath: "unix:///var/run/docker.sock",
242			expected:   RuntimeDocker,
243		},
244		{
245			name:       "podman socket",
246			socketPath: "/run/podman/podman.sock",
247			expected:   RuntimePodman,
248		},
249		{
250			name:       "rootless podman socket",
251			socketPath: "/run/user/1000/podman/podman.sock",
252			expected:   RuntimePodmanRootless,
253		},
254		{
255			name:       "unknown socket defaults to docker",
256			socketPath: "/unknown/socket.sock",
257			expected:   RuntimeDocker,
258		},
259	}
260
261	for _, tt := range tests {
262		t.Run(tt.name, func(t *testing.T) {
263			result := detectRuntimeType(tt.socketPath)
264			assert.Equal(t, tt.expected, result)
265		})
266	}
267}
268
269func TestGetDefaultSocketPaths(t *testing.T) {
270	paths := getDefaultSocketPaths()
271	
272	// Should return common socket paths
273	assert.True(t, len(paths) > 0)
274	
275	// Should contain at least one Docker socket path
276	found := false
277	for _, path := range paths {
278		if strings.Contains(path, "docker") {
279			found = true
280			break
281		}
282	}
283	assert.True(t, found, "Should contain a Docker socket path")
284}
285
286func TestGetDefaultPodmanSocket(t *testing.T) {
287	socket := getDefaultPodmanSocket(false) // Regular mode
288	
289	// Should return a valid path
290	assert.NotEmpty(t, socket)
291	
292	// Should contain "podman" in the path
293	assert.Contains(t, socket, "podman")
294	
295	// Test rootless mode
296	rootlessSocket := getDefaultPodmanSocket(true)
297	assert.NotEmpty(t, rootlessSocket)
298	assert.Contains(t, rootlessSocket, "podman")
299}
300
301func TestGetAvailableRuntimes(t *testing.T) {
302	runtimes := GetAvailableRuntimes()
303	
304	// Should return a slice of runtime info
305	assert.IsType(t, []RuntimeInfo{}, runtimes)
306	
307	// Should not be empty
308	assert.True(t, len(runtimes) > 0)
309	
310	// Each runtime should have basic info
311	for _, rt := range runtimes {
312		assert.NotEmpty(t, rt.Type)
313		assert.NotEmpty(t, rt.SocketPath)
314		// Version may be empty if runtime not actually available
315	}
316}
317
318// Test socket existence checking (private function behavior via public interface)
319func TestSocketExistenceChecking(t *testing.T) {
320	ctx := context.Background()
321	
322	// Create a temporary socket file
323	tmpDir := t.TempDir()
324	socketPath := filepath.Join(tmpDir, "test.sock")
325	
326	// Create an empty file to simulate a socket
327	file, err := os.Create(socketPath)
328	require.NoError(t, err)
329	file.Close()
330	
331	// Test with existing file (won't be a real socket, but tests file existence)
332	_, err = createDockerRuntime(ctx, socketPath)
333	// This will still fail because it's not a real Docker socket, but for a different reason
334	assert.Error(t, err)
335	// Error should not be about file not existing
336	assert.NotContains(t, err.Error(), "no such file")
337}

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