2.0.0 4803e67

root_test.go RawHistoryFolder

1package cmd
2
3import (
4	"bytes"
5	"os"
6	"path/filepath"
7	"testing"
8
9	"github.com/spf13/cobra"
10	"github.com/spf13/viper"
11	"github.com/stretchr/testify/assert"
12	"github.com/stretchr/testify/require"
13)
14
15func TestRootCommand(t *testing.T) {
16	tests := []struct {
17		name string
18		args []string
19	}{
20		{
21			name: "no arguments shows help",
22			args: []string{},
23		},
24		{
25			name: "help flag",
26			args: []string{"--help"},
27		},
28	}
29
30	for _, tt := range tests {
31		t.Run(tt.name, func(t *testing.T) {
32			// Create new command to avoid state pollution
33			cmd := &cobra.Command{
34				Use:   "gordon",
35				Short: "Gordon - Container Registry & Deployment System",
36				Long: `Gordon is a single-binary application that combines a container registry 
37with an intelligent reverse proxy and automated deployment system.`,
38			}
39
40			cmd.SetArgs(tt.args)
41			
42			var output bytes.Buffer
43			cmd.SetOut(&output)
44			cmd.SetErr(&output)
45
46			// Should not panic
47			assert.NotPanics(t, func() {
48				cmd.Execute()
49			})
50		})
51	}
52}
53
54func TestExecute(t *testing.T) {
55	// Create a temporary config file to avoid config errors
56	tempDir := t.TempDir()
57	configFile := filepath.Join(tempDir, "gordon.toml")
58	
59	configContent := `
60[server]
61port = 8080
62registry_port = 5000
63runtime = "docker"
64
65[logging]
66enabled = false
67
68[routes]
69`
70	err := os.WriteFile(configFile, []byte(configContent), 0644)
71	require.NoError(t, err)
72
73	// Save original values
74	originalArgs := os.Args
75	originalCfgFile := cfgFile
76	
77	// Test with help flag to avoid starting actual server
78	os.Args = []string{"gordon", "--help"}
79	cfgFile = configFile
80
81	// Restore after test
82	defer func() {
83		os.Args = originalArgs
84		cfgFile = originalCfgFile
85		viper.Reset()
86	}()
87
88	// Should not panic
89	assert.NotPanics(t, func() {
90		Execute()
91	})
92}
93
94func TestInitConfig(t *testing.T) {
95	tests := []struct {
96		name           string
97		setupFunc      func(t *testing.T) string // returns temp dir
98		configFile     string
99		configContent  string
100		expectedError  bool
101		shouldFindFile bool
102	}{
103		{
104			name: "explicit config file",
105			setupFunc: func(t *testing.T) string {
106				return t.TempDir()
107			},
108			configFile: "test-gordon.toml",
109			configContent: `
110[server]
111port = 8080
112registry_port = 5000
113runtime = "docker"
114
115[logging]
116enabled = false
117
118[routes]
119`,
120			shouldFindFile: true,
121		},
122		{
123			name: "config file in current directory",
124			setupFunc: func(t *testing.T) string {
125				tempDir := t.TempDir()
126				// Change to temp directory
127				originalDir, _ := os.Getwd()
128				os.Chdir(tempDir)
129				t.Cleanup(func() {
130					os.Chdir(originalDir)
131				})
132				return tempDir
133			},
134			configFile: "gordon.toml",
135			configContent: `
136[server]
137port = 8080
138registry_port = 5000
139runtime = "docker"
140
141[logging]
142enabled = false
143
144[routes]
145`,
146			shouldFindFile: true,
147		},
148	}
149
150	for _, tt := range tests {
151		t.Run(tt.name, func(t *testing.T) {
152			// Reset viper for each test
153			viper.Reset()
154
155			tempDir := tt.setupFunc(t)
156			
157			// Save original values
158			originalCfgFile := cfgFile
159			
160			if tt.configContent != "" {
161				configPath := tt.configFile
162				if !filepath.IsAbs(configPath) {
163					configPath = filepath.Join(tempDir, tt.configFile)
164				}
165				
166				err := os.WriteFile(configPath, []byte(tt.configContent), 0644)
167				require.NoError(t, err)
168				
169				if tt.name == "explicit config file" {
170					cfgFile = configPath
171				}
172			}
173
174			// Restore after test
175			t.Cleanup(func() {
176				cfgFile = originalCfgFile
177				viper.Reset()
178			})
179
180			assert.NotPanics(t, func() {
181				initConfig()
182			})
183
184			if tt.shouldFindFile {
185				assert.NotEmpty(t, viper.ConfigFileUsed())
186			}
187		})
188	}
189}
190
191func TestRootCmdStructure(t *testing.T) {
192	// Test root command basic properties
193	assert.Equal(t, "gordon", rootCmd.Use)
194	assert.Contains(t, rootCmd.Short, "Gordon")
195	assert.Contains(t, rootCmd.Long, "container registry")
196	
197	// Test that persistent flags are set
198	flag := rootCmd.PersistentFlags().Lookup("config")
199	assert.NotNil(t, flag)
200	assert.Equal(t, "config", flag.Name)
201}
202
203func TestRootCmdSubcommands(t *testing.T) {
204	// Check that expected subcommands are registered
205	commands := rootCmd.Commands()
206	
207	commandNames := make([]string, len(commands))
208	for i, cmd := range commands {
209		commandNames[i] = cmd.Name()
210	}
211
212	// Should have start and reload commands
213	assert.Contains(t, commandNames, "start")
214	assert.Contains(t, commandNames, "reload")
215}
216
217func TestConfigFileFlag(t *testing.T) {
218	tempDir := t.TempDir()
219	configFile := filepath.Join(tempDir, "test-config.toml")
220	
221	configContent := `
222[server]
223port = 9999
224registry_port = 6000
225runtime = "docker"
226
227[logging]
228enabled = false
229
230[routes]
231`
232	err := os.WriteFile(configFile, []byte(configContent), 0644)
233	require.NoError(t, err)
234
235	// Reset viper and cfgFile
236	viper.Reset()
237	originalCfgFile := cfgFile
238	
239	defer func() {
240		cfgFile = originalCfgFile
241		viper.Reset()
242	}()
243
244	// Test setting config file via flag
245	cfgFile = configFile
246	
247	assert.NotPanics(t, func() {
248		initConfig()
249	})
250
251	// Should use the specified config file
252	assert.Equal(t, configFile, viper.ConfigFileUsed())
253}
254
255func TestRootCmdHelp(t *testing.T) {
256	var output bytes.Buffer
257	rootCmd.SetOut(&output)
258	rootCmd.SetArgs([]string{"--help"})
259	
260	err := rootCmd.Execute()
261	assert.NoError(t, err)
262	
263	helpOutput := output.String()
264	assert.Contains(t, helpOutput, "Gordon")
265	assert.Contains(t, helpOutput, "container registry")
266	assert.Contains(t, helpOutput, "Available Commands:")
267	assert.Contains(t, helpOutput, "start")
268	assert.Contains(t, helpOutput, "reload")
269}

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