1+ package cmd
2+
3+ import (
4+ "os"
5+ "path/filepath"
6+ "testing"
7+
8+ "github.com/spf13/cobra"
9+ "github.com/spf13/viper"
10+ "github.com/stretchr/testify/assert"
11+ "github.com/stretchr/testify/require"
12+ )
13+
14+ func TestRootCommand (t * testing.T ) {
15+ tests := []struct {
16+ name string
17+ args []string
18+ expect string
19+ wantErr bool
20+ }{
21+ {
22+ name : "no arguments shows help" ,
23+ args : []string {},
24+ wantErr : false ,
25+ },
26+ {
27+ name : "help flag" ,
28+ args : []string {"--help" },
29+ wantErr : false ,
30+ },
31+ {
32+ name : "invalid command" ,
33+ args : []string {"invalid" },
34+ wantErr : true ,
35+ },
36+ }
37+
38+ for _ , tt := range tests {
39+ t .Run (tt .name , func (t * testing.T ) {
40+ testRootCmd := rootcmd
41+ testRootCmd .SetArgs (tt .args )
42+
43+ err := testRootCmd .Execute ()
44+ if tt .wantErr {
45+ assert .Error (t , err )
46+ } else {
47+ assert .NoError (t , err )
48+ }
49+ })
50+ }
51+ }
52+
53+ func TestRootCommandProperties (t * testing.T ) {
54+ assert .Equal (t , "ocfcore" , rootcmd .Use )
55+ assert .Equal (t , "ocfcore" , rootcmd .Short )
56+ assert .Empty (t , rootcmd .Long )
57+ assert .NotNil (t , rootcmd .PersistentPreRunE )
58+ assert .NotNil (t , rootcmd .Run )
59+ }
60+
61+ func TestInitConfig (t * testing.T ) {
62+ tests := []struct {
63+ name string
64+ setup func ()
65+ cleanup func ()
66+ expectError bool
67+ }{
68+ {
69+ name : "valid config file" ,
70+ setup : func () {
71+ tempDir := t .TempDir ()
72+ cfgFile = filepath .Join (tempDir , "config.yaml" )
73+
74+ // Create a valid config file
75+ content := `
76+ port: "8080"
77+ name: "test-node"
78+ tcpport: "43905"
79+ udpport: "59820"
80+ `
81+ err := os .WriteFile (cfgFile , []byte (content ), 0644 )
82+ require .NoError (t , err )
83+ },
84+ cleanup : func () {
85+ cfgFile = ""
86+ },
87+ expectError : false ,
88+ },
89+ {
90+ name : "no config file uses defaults" ,
91+ setup : func () {
92+ cfgFile = ""
93+ // Set up a fake home directory
94+ home := t .TempDir ()
95+ os .Setenv ("HOME" , home )
96+ },
97+ cleanup : func () {
98+ cfgFile = ""
99+ os .Unsetenv ("HOME" )
100+ },
101+ expectError : false ,
102+ },
103+ {
104+ name : "invalid config file path" ,
105+ setup : func () {
106+ cfgFile = "/nonexistent/path/config.yaml"
107+ },
108+ cleanup : func () {
109+ cfgFile = ""
110+ },
111+ expectError : false , // Should use defaults
112+ },
113+ }
114+
115+ for _ , tt := range tests {
116+ t .Run (tt .name , func (t * testing.T ) {
117+ tt .setup ()
118+ defer tt .cleanup ()
119+
120+ // Reset viper state
121+ viper .Reset ()
122+
123+ cmd := & cobra.Command {}
124+ err := initConfig (cmd )
125+
126+ if tt .expectError {
127+ assert .Error (t , err )
128+ } else {
129+ assert .NoError (t , err )
130+ }
131+ })
132+ }
133+ }
134+
135+ func TestInitConfigDefaults (t * testing.T ) {
136+ // Reset viper state
137+ viper .Reset ()
138+
139+ // Create a temporary home directory
140+ tempHome := t .TempDir ()
141+ os .Setenv ("HOME" , tempHome )
142+ defer os .Unsetenv ("HOME" )
143+
144+ cfgFile = ""
145+ cmd := & cobra.Command {}
146+ err := initConfig (cmd )
147+ require .NoError (t , err )
148+
149+ // Test that default values are set
150+ assert .Equal (t , "8092" , viper .GetString ("port" ))
151+ assert .Equal (t , "relay" , viper .GetString ("name" ))
152+ assert .Equal (t , "43905" , viper .GetString ("tcpport" ))
153+ assert .Equal (t , "59820" , viper .GetString ("udpport" ))
154+ assert .Equal (t , "24h" , viper .GetString ("crdt.tombstone_retention" ))
155+ assert .Equal (t , "1h" , viper .GetString ("crdt.tombstone_compaction_interval" ))
156+ assert .Equal (t , 512 , viper .GetInt ("crdt.tombstone_compaction_batch" ))
157+ }
158+
159+ func TestInitConfigFlagBinding (t * testing.T ) {
160+ // Reset viper state
161+ viper .Reset ()
162+
163+ tempHome := t .TempDir ()
164+ os .Setenv ("HOME" , tempHome )
165+ defer os .Unsetenv ("HOME" )
166+
167+ cfgFile = ""
168+
169+ // Create a command with various flag types
170+ cmd := & cobra.Command {}
171+ cmd .Flags ().Bool ("test-bool" , true , "test bool flag" )
172+ cmd .Flags ().String ("test-string" , "default" , "test string flag" )
173+ cmd .Flags ().Int ("test-int" , 42 , "test int flag" )
174+ cmd .Flags ().StringSlice ("test-slice" , []string {"a" , "b" }, "test slice flag" )
175+
176+ // Simulate flag changes
177+ cmd .Flags ().Set ("test-bool" , "false" )
178+ cmd .Flags ().Set ("test-string" , "custom" )
179+ cmd .Flags ().Set ("test-int" , "100" )
180+ cmd .Flags ().Set ("test-slice" , "x,y,z" )
181+
182+ err := initConfig (cmd )
183+ require .NoError (t , err )
184+
185+ // Verify that flag values are bound to viper
186+ assert .Equal (t , false , viper .GetBool ("test-bool" ))
187+ assert .Equal (t , "custom" , viper .GetString ("test-string" ))
188+ assert .Equal (t , 100 , viper .GetInt ("test-int" ))
189+ assert .Equal (t , []string {"x" , "y" , "z" }, viper .GetStringSlice ("test-slice" ))
190+ }
191+
192+ func TestExecute (t * testing.T ) {
193+ tests := []struct {
194+ name string
195+ args []string
196+ setup func ()
197+ wantErr bool
198+ }{
199+ {
200+ name : "execute with no args" ,
201+ args : []string {},
202+ wantErr : false , // Shows help, no error
203+ },
204+ {
205+ name : "execute help" ,
206+ args : []string {"--help" },
207+ wantErr : false ,
208+ },
209+ {
210+ name : "execute with config file" ,
211+ args : []string {"--config" , "/tmp/test.yaml" },
212+ setup : func () {
213+ // Create a dummy config file
214+ err := os .WriteFile ("/tmp/test.yaml" , []byte ("port: 8080" ), 0644 )
215+ if err != nil {
216+ t .Skip ("Cannot create test config file" )
217+ }
218+ },
219+ wantErr : false ,
220+ },
221+ }
222+
223+ for _ , tt := range tests {
224+ t .Run (tt .name , func (t * testing.T ) {
225+ if tt .setup != nil {
226+ tt .setup ()
227+ }
228+
229+ // Create a test command instead of using the global Execute function
230+ // to avoid os.Exit complications
231+ testCmd := rootcmd
232+ testCmd .SetArgs (tt .args )
233+
234+ err := testCmd .Execute ()
235+ if tt .wantErr {
236+ assert .Error (t , err )
237+ } else {
238+ assert .NoError (t , err )
239+ }
240+ })
241+ }
242+ }
243+
244+ func TestInitFunction (t * testing.T ) {
245+ // Test that the init function properly sets up flags
246+ // This is tested indirectly by checking that the root command has the expected flags
247+
248+ flags := rootcmd .PersistentFlags ()
249+ assert .NotNil (t , flags .Lookup ("config" ))
250+
251+ // Check that subcommands are added
252+ assert .Contains (t , rootcmd .Commands (), startCmd )
253+ assert .Contains (t , rootcmd .Commands (), initCmd )
254+ assert .Contains (t , rootcmd .Commands (), versionCmd )
255+ assert .Contains (t , rootcmd .Commands (), updateCmd )
256+ }
257+
258+ func TestRootCommandHelpFunctionality (t * testing.T ) {
259+ // Test that the root command's Run function properly calls Help()
260+ cmd := rootcmd
261+ cmd .SetArgs ([]string {})
262+
263+ // This should not panic and should show help
264+ err := cmd .Execute ()
265+ assert .NoError (t , err )
266+ }
267+
268+ func TestConfigFileVariable (t * testing.T ) {
269+ // Test that cfgFile variable can be set and retrieved
270+ testFile := "/test/config.yaml"
271+ cfgFile = testFile
272+ assert .Equal (t , testFile , cfgFile )
273+
274+ // Reset for other tests
275+ cfgFile = ""
276+ }
0 commit comments