| 333 | } |
| 334 | |
| 335 | func TestOpenAI_KeyFailoverConfig(t *testing.T) { |
| 336 | t.Parallel() |
| 337 | |
| 338 | pool, err := keypool.New([]string{"k0", "k1"}, quartz.NewMock(t)) |
| 339 | require.NoError(t, err) |
| 340 | |
| 341 | p := NewOpenAI(config.OpenAI{KeyPool: pool}) |
| 342 | |
| 343 | cfg := p.KeyFailoverConfig(slog.Make()) |
| 344 | |
| 345 | assert.Same(t, pool, cfg.Pool, "Pool must be wired from the provider config") |
| 346 | assert.Equal(t, config.ProviderOpenAI, cfg.ProviderName, "ProviderName must match the provider name") |
| 347 | require.NotNil(t, cfg.IsBYOK) |
| 348 | require.NotNil(t, cfg.InjectAuthKey) |
| 349 | require.NotNil(t, cfg.BuildKeyPoolResponse) |
| 350 | |
| 351 | t.Run("IsBYOK", func(t *testing.T) { |
| 352 | t.Parallel() |
| 353 | cases := []struct { |
| 354 | name string |
| 355 | headers map[string]string |
| 356 | want bool |
| 357 | }{ |
| 358 | { |
| 359 | name: "no_auth_headers", |
| 360 | headers: nil, |
| 361 | want: false, |
| 362 | }, |
| 363 | { |
| 364 | name: "non_auth_header", |
| 365 | headers: map[string]string{"Content-Type": "application/json"}, |
| 366 | want: false, |
| 367 | }, |
| 368 | { |
| 369 | name: "authorization_only", |
| 370 | headers: map[string]string{"Authorization": "Bearer user-token"}, |
| 371 | want: true, |
| 372 | }, |
| 373 | { |
| 374 | name: "x_api_key_only", |
| 375 | headers: map[string]string{"X-Api-Key": "user-key"}, |
| 376 | want: false, |
| 377 | }, |
| 378 | { |
| 379 | name: "both_headers_set", |
| 380 | headers: map[string]string{ |
| 381 | "Authorization": "Bearer user-token", |
| 382 | "X-Api-Key": "user-key", |
| 383 | }, |
| 384 | want: true, |
| 385 | }, |
| 386 | } |
| 387 | for _, tc := range cases { |
| 388 | t.Run(tc.name, func(t *testing.T) { |
| 389 | t.Parallel() |
| 390 | r := httptest.NewRequest(http.MethodPost, "/", nil) |
| 391 | for k, v := range tc.headers { |
| 392 | r.Header.Set(k, v) |