@@ -251,41 +251,56 @@ func TestProxyManager_ListModelsHandler(t *testing.T) {
251251}
252252
253253func TestProxyManager_Shutdown (t * testing.T ) {
254- // Test Case 1: Startup failure due to unavailable proxy
255- t .Run ("startup failure with unavailable proxy" , func (t * testing.T ) {
256- // Create configuration with invalid command that will fail immediately
257- modelConfig := ModelConfig {
258- Cmd : "/invalid-command" , // Invalid executable path that will fail to start
259- Proxy : "http://localhost:9991" ,
260- CheckEndpoint : "/health" ,
261- }
262-
263- config := AddDefaultGroupToConfig (Config {
264- HealthCheckTimeout : 15 ,
265- Models : map [string ]ModelConfig {
266- "model1" : modelConfig ,
254+ // make broken model configurations
255+ model1Config := getTestSimpleResponderConfigPort ("model1" , 9991 )
256+ model1Config .Proxy = "http://localhost:10001/"
257+
258+ model2Config := getTestSimpleResponderConfigPort ("model2" , 9992 )
259+ model2Config .Proxy = "http://localhost:10002/"
260+
261+ model3Config := getTestSimpleResponderConfigPort ("model3" , 9993 )
262+ model3Config .Proxy = "http://localhost:10003/"
263+
264+ config := AddDefaultGroupToConfig (Config {
265+ HealthCheckTimeout : 15 ,
266+ Models : map [string ]ModelConfig {
267+ "model1" : model1Config ,
268+ "model2" : model2Config ,
269+ "model3" : model3Config ,
270+ },
271+ LogLevel : "error" ,
272+ Groups : map [string ]GroupConfig {
273+ "test" : {
274+ Swap : false ,
275+ Members : []string {"model1" , "model2" , "model3" },
267276 },
268- LogLevel : "error" ,
269- })
277+ } ,
278+ })
270279
271- proxy := New (config )
272- defer proxy .Shutdown ()
280+ proxy := New (config )
273281
274- // Try to start the model
275- reqBody := `{"model":"model1"}`
276- req := httptest .NewRequest ("POST" , "/v1/chat/completions" , bytes .NewBufferString (reqBody ))
277- w := httptest .NewRecorder ()
278- proxy .ServeHTTP (w , req )
282+ // Start all the processes
283+ var wg sync.WaitGroup
284+ for _ , modelName := range []string {"model1" , "model2" , "model3" } {
285+ wg .Add (1 )
286+ go func (modelName string ) {
287+ defer wg .Done ()
288+ reqBody := fmt .Sprintf (`{"model":"%s"}` , modelName )
289+ req := httptest .NewRequest ("POST" , "/v1/chat/completions" , bytes .NewBufferString (reqBody ))
290+ w := httptest .NewRecorder ()
279291
280- assert .Equal (t , http .StatusBadGateway , w .Code )
281- assert .Contains (t , w .Body .String (), "unable to start process: start() failed: fork/exec /invalid-command: no such file or directory" )
292+ // send a request to trigger the proxy to load ... this should hang waiting for start up
293+ proxy .ServeHTTP (w , req )
294+ assert .Equal (t , http .StatusBadGateway , w .Code )
295+ assert .Contains (t , w .Body .String (), "health check interrupted due to shutdown" )
296+ }(modelName )
297+ }
282298
283- // Verify process is tracked but in failed state
284- processGroup := proxy .findGroupByModelName ("model1" )
285- assert .NotNil (t , processGroup )
286- process := processGroup .processes ["model1" ]
287- assert .Equal (t , StateFailed , process .CurrentState ())
288- })
299+ go func () {
300+ <- time .After (time .Second )
301+ proxy .Shutdown ()
302+ }()
303+ wg .Wait ()
289304}
290305
291306func TestProxyManager_Unload (t * testing.T ) {
@@ -382,8 +397,6 @@ func TestProxyManager_RunningEndpoint(t *testing.T) {
382397 })
383398}
384399
385-
386-
387400func TestProxyManager_AudioTranscriptionHandler (t * testing.T ) {
388401 config := AddDefaultGroupToConfig (Config {
389402 HealthCheckTimeout : 15 ,
@@ -432,6 +445,68 @@ func TestProxyManager_AudioTranscriptionHandler(t *testing.T) {
432445 assert .Equal (t , strconv .Itoa (370 + contentLength ), response ["h_content_length" ])
433446}
434447
448+ // Test useModelName in configuration sends overrides what is sent to upstream
449+ func TestProxyManager_UseModelName (t * testing.T ) {
450+ upstreamModelName := "upstreamModel"
451+
452+ modelConfig := getTestSimpleResponderConfig (upstreamModelName )
453+ modelConfig .UseModelName = upstreamModelName
454+
455+ config := AddDefaultGroupToConfig (Config {
456+ HealthCheckTimeout : 15 ,
457+ Models : map [string ]ModelConfig {
458+ "model1" : modelConfig ,
459+ },
460+ LogLevel : "error" ,
461+ })
462+
463+ proxy := New (config )
464+ defer proxy .StopProcesses ()
465+
466+ requestedModel := "model1"
467+
468+ t .Run ("useModelName over rides requested model: /v1/chat/completions" , func (t * testing.T ) {
469+ reqBody := fmt .Sprintf (`{"model":"%s"}` , requestedModel )
470+ req := httptest .NewRequest ("POST" , "/v1/chat/completions" , bytes .NewBufferString (reqBody ))
471+ w := httptest .NewRecorder ()
472+
473+ proxy .ServeHTTP (w , req )
474+ assert .Equal (t , http .StatusOK , w .Code )
475+ assert .Contains (t , w .Body .String (), upstreamModelName )
476+ })
477+
478+ t .Run ("useModelName over rides requested model: /v1/audio/transcriptions" , func (t * testing.T ) {
479+ // Create a buffer with multipart form data
480+ var b bytes.Buffer
481+ w := multipart .NewWriter (& b )
482+
483+ // Add the model field
484+ fw , err := w .CreateFormField ("model" )
485+ assert .NoError (t , err )
486+ _ , err = fw .Write ([]byte (requestedModel ))
487+ assert .NoError (t , err )
488+
489+ // Add a file field
490+ fw , err = w .CreateFormFile ("file" , "test.mp3" )
491+ assert .NoError (t , err )
492+ _ , err = fw .Write ([]byte ("test" ))
493+ assert .NoError (t , err )
494+ w .Close ()
495+
496+ // Create the request with the multipart form data
497+ req := httptest .NewRequest ("POST" , "/v1/audio/transcriptions" , & b )
498+ req .Header .Set ("Content-Type" , w .FormDataContentType ())
499+ rec := httptest .NewRecorder ()
500+ proxy .ServeHTTP (rec , req )
501+
502+ // Verify the response
503+ assert .Equal (t , http .StatusOK , rec .Code )
504+ var response map [string ]string
505+ err = json .Unmarshal (rec .Body .Bytes (), & response )
506+ assert .NoError (t , err )
507+ assert .Equal (t , upstreamModelName , response ["model" ])
508+ })
509+ }
435510
436511func TestProxyManager_CORSOptionsHandler (t * testing.T ) {
437512 config := AddDefaultGroupToConfig (Config {
@@ -501,69 +576,6 @@ func TestProxyManager_CORSOptionsHandler(t *testing.T) {
501576 }
502577}
503578
504- // Test useModelName in configuration sends overrides what is sent to upstream
505- func TestProxyManager_UseModelName (t * testing.T ) {
506- upstreamModelName := "upstreamModel"
507-
508- modelConfig := getTestSimpleResponderConfig (upstreamModelName )
509- modelConfig .UseModelName = upstreamModelName
510-
511- config := AddDefaultGroupToConfig (Config {
512- HealthCheckTimeout : 15 ,
513- Models : map [string ]ModelConfig {
514- "model1" : modelConfig ,
515- },
516- LogLevel : "error" ,
517- })
518-
519- proxy := New (config )
520- defer proxy .StopProcesses ()
521-
522- requestedModel := "model1"
523-
524- t .Run ("useModelName over rides requested model: /v1/chat/completions" , func (t * testing.T ) {
525- reqBody := fmt .Sprintf (`{"model":"%s"}` , requestedModel )
526- req := httptest .NewRequest ("POST" , "/v1/chat/completions" , bytes .NewBufferString (reqBody ))
527- w := httptest .NewRecorder ()
528-
529- proxy .ServeHTTP (w , req )
530- assert .Equal (t , http .StatusOK , w .Code )
531- assert .Contains (t , w .Body .String (), upstreamModelName )
532- })
533-
534- t .Run ("useModelName over rides requested model: /v1/audio/transcriptions" , func (t * testing.T ) {
535- // Create a buffer with multipart form data
536- var b bytes.Buffer
537- w := multipart .NewWriter (& b )
538-
539- // Add the model field
540- fw , err := w .CreateFormField ("model" )
541- assert .NoError (t , err )
542- _ , err = fw .Write ([]byte (requestedModel ))
543- assert .NoError (t , err )
544-
545- // Add a file field
546- fw , err = w .CreateFormFile ("file" , "test.mp3" )
547- assert .NoError (t , err )
548- _ , err = fw .Write ([]byte ("test" ))
549- assert .NoError (t , err )
550- w .Close ()
551-
552- // Create the request with the multipart form data
553- req := httptest .NewRequest ("POST" , "/v1/audio/transcriptions" , & b )
554- req .Header .Set ("Content-Type" , w .FormDataContentType ())
555- rec := httptest .NewRecorder ()
556- proxy .ServeHTTP (rec , req )
557-
558- // Verify the response
559- assert .Equal (t , http .StatusOK , rec .Code )
560- var response map [string ]string
561- err = json .Unmarshal (rec .Body .Bytes (), & response )
562- assert .NoError (t , err )
563- assert .Equal (t , upstreamModelName , response ["model" ])
564- })
565- }
566-
567579func TestProxyManager_Upstream (t * testing.T ) {
568580 config := AddDefaultGroupToConfig (Config {
569581 HealthCheckTimeout : 15 ,
0 commit comments