mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-14 12:02:27 +08:00
114 lines
5.0 KiB
Go
114 lines
5.0 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestFetchOpenAIAccountModelsOAuthPopulatesPickerFields(t *testing.T) {
|
|
_, calls := newCodexModelsOAuthCacheServer(t, `{"models":[
|
|
{"slug":"new-oauth-model","display_name":"New OAuth Model"},
|
|
{"slug":"gpt-5.6-sol"},
|
|
{"slug":"blank-display-name","display_name":" "},
|
|
{"slug":"gpt-6-astra"}
|
|
]}`)
|
|
gateway := &OpenAIGatewayService{}
|
|
svc := &AccountTestService{openaiGatewayService: gateway}
|
|
account := newCodexModelsTestAccount()
|
|
ctx := context.Background()
|
|
|
|
before, err := gateway.FetchOpenAIModelsList(ctx, account)
|
|
require.NoError(t, err)
|
|
models, err := svc.FetchOpenAIAccountModels(ctx, account)
|
|
require.NoError(t, err)
|
|
require.Greater(t, len(models), 2)
|
|
// Upstream display name wins; a missing one falls back to the local catalog name,
|
|
// then to the raw slug.
|
|
for i, expected := range []struct{ id, displayName string }{
|
|
{id: "new-oauth-model", displayName: "New OAuth Model"},
|
|
{id: "gpt-5.6-sol", displayName: "GPT-5.6 Sol"},
|
|
{id: "blank-display-name", displayName: "blank-display-name"},
|
|
{id: "gpt-6-astra", displayName: "GPT-6 Astra"},
|
|
} {
|
|
require.Equal(t, expected.id, models[i].ID)
|
|
require.Equal(t, expected.displayName, models[i].DisplayName)
|
|
require.Equal(t, "model", models[i].Type)
|
|
}
|
|
ids := make([]string, 0, len(models))
|
|
for _, model := range models {
|
|
ids = append(ids, model.ID)
|
|
}
|
|
require.Contains(t, ids, "gpt-image-2.5-flare")
|
|
require.Contains(t, ids, "gpt-image-2.5-sunburst")
|
|
|
|
after, err := gateway.FetchOpenAIModelsList(ctx, account)
|
|
require.NoError(t, err)
|
|
require.Equal(t, before.Body, after.Body, "picker fields must not change the shared catalog")
|
|
require.Contains(t, string(after.Body), `"display_name":"New OAuth Model"`, "the shared catalog keeps the upstream display name")
|
|
require.EqualValues(t, 1, calls.Load(), "picker must reuse the shared discovery cache")
|
|
}
|
|
|
|
func TestFetchOpenAIAccountModelsAPIKeyPopulatesPickerFields(t *testing.T) {
|
|
gateway := newCodexModelsAPIKeyTestService(&codexModelsHTTPUpstreamStub{do: func(_ *http.Request, _ string, _ int64, _ int) (*http.Response, error) {
|
|
return ordinaryModelsUpstreamResponse(`{"data":[
|
|
{"id":"new-api-model","owned_by":"provider","created":123},
|
|
{"id":"blank-label","display_name":" ","type":""},
|
|
{"id":"named-model","display_name":"Provider Model","type":"model"}
|
|
]}`), nil
|
|
}})
|
|
svc := &AccountTestService{openaiGatewayService: gateway}
|
|
models, err := svc.FetchOpenAIAccountModels(context.Background(), newCodexModelsAPIKeyTestAccount("https://models.example/v1"))
|
|
require.NoError(t, err)
|
|
require.Len(t, models, 3)
|
|
for i, name := range []string{"new-api-model", "blank-label", "Provider Model"} {
|
|
require.Equal(t, name, models[i].DisplayName)
|
|
require.Equal(t, "model", models[i].Type)
|
|
}
|
|
require.Equal(t, "provider", models[0].OwnedBy)
|
|
require.EqualValues(t, 123, models[0].Created)
|
|
require.Equal(t, "named-model", models[2].ID)
|
|
}
|
|
|
|
func TestFetchOpenAIAccountModelsPreservesEmptyCatalog(t *testing.T) {
|
|
gateway := newCodexModelsAPIKeyTestService(&codexModelsHTTPUpstreamStub{do: func(_ *http.Request, _ string, _ int64, _ int) (*http.Response, error) {
|
|
return ordinaryModelsUpstreamResponse(`{"data":[]}`), nil
|
|
}})
|
|
svc := &AccountTestService{openaiGatewayService: gateway}
|
|
models, err := svc.FetchOpenAIAccountModels(context.Background(), newCodexModelsAPIKeyTestAccount("https://models.example/v1"))
|
|
require.NoError(t, err)
|
|
require.Empty(t, models, "an empty upstream catalog must not become a static model list")
|
|
}
|
|
|
|
func TestFetchOpenAIAccountModelsOAuthLabelsLocalImageModelsLikeUpstream(t *testing.T) {
|
|
newCodexModelsOAuthCacheServer(t, `{"models":[{"slug":"gpt-5.6-sol"}]}`)
|
|
svc := &AccountTestService{openaiGatewayService: &OpenAIGatewayService{}}
|
|
account := newCodexModelsTestAccount()
|
|
account.Credentials["model_mapping"] = map[string]any{"gpt-image-2.5-flare": "gpt-image-2.5-flare"}
|
|
models, err := svc.FetchOpenAIAccountModels(context.Background(), account)
|
|
require.NoError(t, err)
|
|
byID := make(map[string]string, len(models))
|
|
for _, model := range models {
|
|
byID[model.ID] = model.DisplayName
|
|
}
|
|
require.Equal(t, "GPT-5.6 Sol", byID["gpt-5.6-sol"], "upstream slug must not be the only label source")
|
|
require.Equal(t, "GPT Image 2.5 Flare", byID["gpt-image-2.5-flare"], "locally added models use the same naming rule")
|
|
}
|
|
|
|
func TestFetchOpenAIAccountModelsOAuthRespectsImageAllowlist(t *testing.T) {
|
|
newCodexModelsOAuthCacheServer(t, `{"models":[{"slug":"gpt-6-astra"}]}`)
|
|
svc := &AccountTestService{openaiGatewayService: &OpenAIGatewayService{}}
|
|
account := newCodexModelsTestAccount()
|
|
account.Credentials["model_mapping"] = map[string]any{"gpt-image-2.5-flare": "gpt-image-2.5-flare"}
|
|
models, err := svc.FetchOpenAIAccountModels(context.Background(), account)
|
|
require.NoError(t, err)
|
|
ids := []string{}
|
|
for _, model := range models {
|
|
ids = append(ids, model.ID)
|
|
}
|
|
require.Contains(t, ids, "gpt-image-2.5-flare")
|
|
require.NotContains(t, ids, "gpt-image-2.5-sunburst")
|
|
}
|