Ctrl K
ComunidadGuías…

internal/api/home_models_empty_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package api

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gin-gonic/gin"
	"github.com/router-for-me/CLIProxyAPI/v8/internal/home"
	"github.com/router-for-me/CLIProxyAPI/v8/internal/registry"
)

func TestDecodeHomeModelsEmptyCatalog(t *testing.T) {
	for _, raw := range []string{"{}", " { } ", `{"claude":[],"codex-pro":[]}`} {
		entries, errDecode := decodeHomeModels([]byte(raw))
		if errDecode != nil || entries == nil || len(entries) != 0 {
			t.Errorf("decodeHomeModels(%q) = %v, %v, want empty list", raw, entries, errDecode)
		}
	}
	for _, raw := range []string{
		"", "null", "[]", "{bad}", `{"claude":[{}]}`, `{"claude":null}`, `{"error":null}`,
		`{"error":{"type":"internal_error","message":"unavailable"}}`,
		`{"error":[]}`, `{"error":[],"claude":[]}`,
		`{"error":[{"id":"not-a-model"}]}`, `{"error":[],"claude":[{"id":"model-a"}]}`,
	} {
		if _, errDecode := decodeHomeModels([]byte(raw)); errDecode == nil {
			t.Errorf("decodeHomeModels(%q) accepted malformed or error payload", raw)
		}
	}
}

func TestHomeEmptyModelCatalogResponses(t *testing.T) {
	server := newTestServer(t)
	server.cfg.Home.Enabled = true
	engine := gin.New()
	engine.GET("/v1/models", server.unifiedModelsHandler(nil, nil))
	engine.GET("/v1beta/models", server.geminiModelsHandler(nil))
	engine.GET("/v1beta/models/*action", server.geminiGetHandler(nil))
	client := newHomeCatalogClient(t, "{}")
	previousHome := home.Current()
	home.SetCurrent(client)
	t.Cleanup(func() { home.SetCurrent(previousHome) })
	registry.GetGlobalRegistry().RegisterClient("empty-catalog-local", "codex", []*registry.ModelInfo{{ID: "local-only-model"}})
	t.Cleanup(func() { registry.GetGlobalRegistry().UnregisterClient("empty-catalog-local") })

	tests := []struct {
		name    string
		path    string
		headers map[string]string
		field   string
	}{
		{name: "openai", path: "/v1/models", field: "data"},
		{name: "claude", path: "/v1/models", headers: map[string]string{"Anthropic-Version": "2023-06-01"}, field: "data"},
		{name: "codex", path: "/v1/models?client_version=0.153.4", field: "models"},
		{name: "cpa", path: "/v1/models?client_version=cpa", field: "models"},
		{name: "gemini", path: "/v1beta/models", field: "models"},
		{name: "grok", path: "/v1/models", headers: map[string]string{"User-Agent": "grok-shell"}, field: "data"},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			request := httptest.NewRequest(http.MethodGet, test.path, nil)
			request.Header.Set("Authorization", "Bearer scoped-key")
			for key, value := range test.headers {
				request.Header.Set(key, value)
			}
			recorder := httptest.NewRecorder()
			engine.ServeHTTP(recorder, request)
			if recorder.Code != http.StatusOK {
				t.Fatalf("status = %d; body=%s", recorder.Code, recorder.Body.String())
			}
			var payload map[string]json.RawMessage
			if errUnmarshal := json.Unmarshal(recorder.Body.Bytes(), &payload); errUnmarshal != nil {
				t.Fatal(errUnmarshal)
			}
			if string(payload[test.field]) != "[]" {
				t.Fatalf("%s = %s, want []; body=%s", test.field, payload[test.field], recorder.Body.String())
			}
		})
	}
	recorder := httptest.NewRecorder()
	engine.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/v1beta/models/inaccessible-model", nil))
	if recorder.Code != http.StatusNotFound {
		t.Fatalf("inaccessible model status = %d, want 404; body=%s", recorder.Code, recorder.Body.String())
	}
}

func TestHomeModelCatalogErrorsRemainErrors(t *testing.T) {
	server := newTestServer(t)
	server.cfg.Home.Enabled = true
	engine := gin.New()
	engine.GET("/v1/models", server.unifiedModelsHandler(nil, nil))
	for _, test := range []struct {
		name    string
		payload string
		status  int
	}{
		{name: "missing credentials", payload: `{"error":{"type":"no_credentials","message":"Missing API key"}}`, status: http.StatusUnauthorized},
		{name: "invalid credentials", payload: `{"error":{"type":"invalid_credential","message":"Invalid API key"}}`, status: http.StatusUnauthorized},
		{name: "policy failure", payload: `{"error":{"type":"internal_error","message":"Model access service error"}}`, status: http.StatusBadGateway},
		{name: "empty array error", payload: `{"error":[]}`, status: http.StatusBadGateway},
		{name: "error alongside empty section", payload: `{"error":[],"claude":[]}`, status: http.StatusBadGateway},
		{name: "error containing model-shaped records", payload: `{"error":[{"id":"not-a-model"}]}`, status: http.StatusBadGateway},
		{name: "error alongside models", payload: `{"error":[],"claude":[{"id":"model-a"}]}`, status: http.StatusBadGateway},
		{name: "empty response", payload: "", status: http.StatusBadGateway},
		{name: "malformed JSON", payload: "{bad}", status: http.StatusBadGateway},
		{name: "null catalog", payload: "null", status: http.StatusBadGateway},
		{name: "null section", payload: `{"claude":null}`, status: http.StatusBadGateway},
		{name: "missing model IDs", payload: `{"claude":[{}]}`, status: http.StatusBadGateway},
	} {
		t.Run(test.name, func(t *testing.T) {
			client := newHomeCatalogClient(t, test.payload)
			previousHome := home.Current()
			home.SetCurrent(client)
			t.Cleanup(func() { home.SetCurrent(previousHome) })
			recorder := httptest.NewRecorder()
			engine.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/v1/models", nil))
			if recorder.Code != test.status {
				t.Fatalf("status = %d, want %d; body=%s", recorder.Code, test.status, recorder.Body.String())
			}
			var payload map[string]json.RawMessage
			if errUnmarshal := json.Unmarshal(recorder.Body.Bytes(), &payload); errUnmarshal != nil {
				t.Fatal(errUnmarshal)
			}
			if _, exists := payload["error"]; !exists {
				t.Fatalf("expected error response; body=%s", recorder.Body.String())
			}
		})
	}
}