@@ -2,8 +2,13 @@ package server
2
2
3
3
import (
4
4
"fmt"
5
+ "os"
6
+ "strings"
5
7
"testing"
6
8
9
+ "github.com/spf13/cobra"
10
+ "github.com/spf13/viper"
11
+ "github.com/stretchr/testify/assert"
7
12
"github.com/stretchr/testify/require"
8
13
)
9
14
@@ -83,3 +88,206 @@ func TestParseAgentType(t *testing.T) {
83
88
require .Error (t , err )
84
89
})
85
90
}
91
+
92
+ // Test helper to isolate viper config between tests
93
+ func isolateViper (t * testing.T ) {
94
+ // Save current state
95
+ oldConfig := viper .AllSettings ()
96
+
97
+ // Reset viper
98
+ viper .Reset ()
99
+
100
+ // Clear AGENTAPI_ env vars
101
+ var agentapiEnvs []string
102
+ for _ , env := range os .Environ () {
103
+ if strings .HasPrefix (env , "AGENTAPI_" ) {
104
+ parts := strings .SplitN (env , "=" , 2 )
105
+ agentapiEnvs = append (agentapiEnvs , parts [0 ])
106
+ if err := os .Unsetenv (parts [0 ]); err != nil {
107
+ t .Fatalf ("Failed to unset env var %s: %v" , parts [0 ], err )
108
+ }
109
+ }
110
+ }
111
+
112
+ t .Cleanup (func () {
113
+ // Restore state
114
+ viper .Reset ()
115
+ for key , value := range oldConfig {
116
+ viper .Set (key , value )
117
+ }
118
+
119
+ // Restore env vars
120
+ for _ , key := range agentapiEnvs {
121
+ if val := os .Getenv (key ); val != "" {
122
+ if err := os .Setenv (key , val ); err != nil {
123
+ t .Fatalf ("Failed to set env var %s: %v" , key , err )
124
+ }
125
+ }
126
+ }
127
+ })
128
+ }
129
+
130
+ // Test configuration values via ServerCmd execution
131
+ func TestServerCmd_AllArgs_Defaults (t * testing.T ) {
132
+ tests := []struct {
133
+ name string
134
+ flag string
135
+ expected any
136
+ getter func () any
137
+ }{
138
+ {"type default" , FlagType , "" , func () any { return viper .GetString (FlagType ) }},
139
+ {"port default" , FlagPort , 3284 , func () any { return viper .GetInt (FlagPort ) }},
140
+ {"print-openapi default" , FlagPrintOpenAPI , false , func () any { return viper .GetBool (FlagPrintOpenAPI ) }},
141
+ {"chat-base-path default" , FlagChatBasePath , "/chat" , func () any { return viper .GetString (FlagChatBasePath ) }},
142
+ {"term-width default" , FlagTermWidth , uint16 (80 ), func () any { return viper .GetUint16 (FlagTermWidth ) }},
143
+ {"term-height default" , FlagTermHeight , uint16 (1000 ), func () any { return viper .GetUint16 (FlagTermHeight ) }},
144
+ }
145
+
146
+ for _ , tt := range tests {
147
+ t .Run (tt .name , func (t * testing.T ) {
148
+ isolateViper (t )
149
+ serverCmd := CreateServerCmd ()
150
+ cmd := & cobra.Command {}
151
+ cmd .AddCommand (serverCmd )
152
+
153
+ // Execute with no args to get defaults
154
+ serverCmd .SetArgs ([]string {"--help" }) // Use help to avoid actual execution
155
+ if err := serverCmd .Execute (); err != nil {
156
+ t .Fatalf ("Failed to execute server command: %v" , err )
157
+ }
158
+
159
+ assert .Equal (t , tt .expected , tt .getter ())
160
+ })
161
+ }
162
+ }
163
+
164
+ func TestServerCmd_AllEnvVars (t * testing.T ) {
165
+ tests := []struct {
166
+ name string
167
+ envVar string
168
+ envValue string
169
+ expected any
170
+ getter func () any
171
+ }{
172
+ {"AGENTAPI_TYPE" , "AGENTAPI_TYPE" , "claude" , "claude" , func () any { return viper .GetString (FlagType ) }},
173
+ {"AGENTAPI_PORT" , "AGENTAPI_PORT" , "8080" , 8080 , func () any { return viper .GetInt (FlagPort ) }},
174
+ {"AGENTAPI_PRINT_OPENAPI" , "AGENTAPI_PRINT_OPENAPI" , "true" , true , func () any { return viper .GetBool (FlagPrintOpenAPI ) }},
175
+ {"AGENTAPI_CHAT_BASE_PATH" , "AGENTAPI_CHAT_BASE_PATH" , "/api" , "/api" , func () any { return viper .GetString (FlagChatBasePath ) }},
176
+ {"AGENTAPI_TERM_WIDTH" , "AGENTAPI_TERM_WIDTH" , "120" , uint16 (120 ), func () any { return viper .GetUint16 (FlagTermWidth ) }},
177
+ {"AGENTAPI_TERM_HEIGHT" , "AGENTAPI_TERM_HEIGHT" , "500" , uint16 (500 ), func () any { return viper .GetUint16 (FlagTermHeight ) }},
178
+ }
179
+
180
+ for _ , tt := range tests {
181
+ t .Run (tt .name , func (t * testing.T ) {
182
+ isolateViper (t )
183
+ t .Setenv (tt .envVar , tt .envValue )
184
+
185
+ serverCmd := CreateServerCmd ()
186
+ cmd := & cobra.Command {}
187
+ cmd .AddCommand (serverCmd )
188
+
189
+ serverCmd .SetArgs ([]string {"--help" })
190
+ if err := serverCmd .Execute (); err != nil {
191
+ t .Fatalf ("Failed to execute server command: %v" , err )
192
+ }
193
+
194
+ assert .Equal (t , tt .expected , tt .getter ())
195
+ })
196
+ }
197
+ }
198
+
199
+ func TestServerCmd_ArgsPrecedenceOverEnv (t * testing.T ) {
200
+ tests := []struct {
201
+ name string
202
+ envVar string
203
+ envValue string
204
+ args []string
205
+ expected any
206
+ getter func () any
207
+ }{
208
+ {
209
+ "type: CLI overrides env" ,
210
+ "AGENTAPI_TYPE" , "goose" ,
211
+ []string {"--type" , "claude" },
212
+ "claude" ,
213
+ func () any { return viper .GetString (FlagType ) },
214
+ },
215
+ {
216
+ "port: CLI overrides env" ,
217
+ "AGENTAPI_PORT" , "8080" ,
218
+ []string {"--port" , "9090" },
219
+ 9090 ,
220
+ func () any { return viper .GetInt (FlagPort ) },
221
+ },
222
+ {
223
+ "print-openapi: CLI overrides env" ,
224
+ "AGENTAPI_PRINT_OPENAPI" , "false" ,
225
+ []string {"--print-openapi" },
226
+ true ,
227
+ func () any { return viper .GetBool (FlagPrintOpenAPI ) },
228
+ },
229
+ {
230
+ "chat-base-path: CLI overrides env" ,
231
+ "AGENTAPI_CHAT_BASE_PATH" , "/env-path" ,
232
+ []string {"--chat-base-path" , "/cli-path" },
233
+ "/cli-path" ,
234
+ func () any { return viper .GetString (FlagChatBasePath ) },
235
+ },
236
+ {
237
+ "term-width: CLI overrides env" ,
238
+ "AGENTAPI_TERM_WIDTH" , "100" ,
239
+ []string {"--term-width" , "150" },
240
+ uint16 (150 ),
241
+ func () any { return viper .GetUint16 (FlagTermWidth ) },
242
+ },
243
+ {
244
+ "term-height: CLI overrides env" ,
245
+ "AGENTAPI_TERM_HEIGHT" , "500" ,
246
+ []string {"--term-height" , "600" },
247
+ uint16 (600 ),
248
+ func () any { return viper .GetUint16 (FlagTermHeight ) },
249
+ },
250
+ }
251
+
252
+ for _ , tt := range tests {
253
+ t .Run (tt .name , func (t * testing.T ) {
254
+ isolateViper (t )
255
+ t .Setenv (tt .envVar , tt .envValue )
256
+
257
+ // Mock execution to test arg parsing without running server
258
+ args := append (tt .args , "--help" )
259
+ serverCmd := CreateServerCmd ()
260
+ serverCmd .SetArgs (args )
261
+ if err := serverCmd .Execute (); err != nil {
262
+ t .Fatalf ("Failed to execute server command: %v" , err )
263
+ }
264
+
265
+ assert .Equal (t , tt .expected , tt .getter ())
266
+ })
267
+ }
268
+ }
269
+
270
+ func TestMixed_ConfigurationScenarios (t * testing.T ) {
271
+ t .Run ("some env, some cli, some defaults" , func (t * testing.T ) {
272
+ isolateViper (t )
273
+
274
+ // Set some env vars
275
+ t .Setenv ("AGENTAPI_TYPE" , "goose" )
276
+ t .Setenv ("AGENTAPI_TERM_WIDTH" , "120" )
277
+
278
+ // Set some CLI args
279
+ serverCmd := CreateServerCmd ()
280
+ serverCmd .SetArgs ([]string {"--port" , "9999" , "--print-openapi" , "--help" })
281
+ if err := serverCmd .Execute (); err != nil {
282
+ t .Fatalf ("Failed to execute server command: %v" , err )
283
+ }
284
+
285
+ // Verify mixed configuration
286
+ assert .Equal (t , "goose" , viper .GetString (FlagType )) // from env
287
+ assert .Equal (t , 9999 , viper .GetInt (FlagPort )) // from CLI
288
+ assert .Equal (t , true , viper .GetBool (FlagPrintOpenAPI )) // from CLI
289
+ assert .Equal (t , "/chat" , viper .GetString (FlagChatBasePath )) // default
290
+ assert .Equal (t , uint16 (120 ), viper .GetUint16 (FlagTermWidth )) // from env
291
+ assert .Equal (t , uint16 (1000 ), viper .GetUint16 (FlagTermHeight )) // default
292
+ })
293
+ }
0 commit comments