Files
superidou 5759c1862e AI Gateway Go 0.10.0 源码快照 + 旗舰版需求规划报告
M0-M7 已完成:核心网关(身份/RBAC/TOTP/OIDC/SAML/Provider/配额/路由/内容策略/审计/定价)+ 资源市场(MCP/Skills/数字员工)。
含 22 个 PostgreSQL 迁移、管理端/门户端前端源码、OpenAPI 契约、部署 compose。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-12 11:45:54 +08:00

80 lines
3.4 KiB
Go

package runtime
import (
"encoding/base64"
"encoding/json"
"io"
"log/slog"
"testing"
"time"
"aigateway.local/core/internal/gateway"
"aigateway.local/core/internal/provider"
provideropenai "aigateway.local/core/internal/provider/openai"
)
func TestBuildRuntimeAdapter(t *testing.T) {
key := base64.StdEncoding.EncodeToString(make([]byte, 32))
cipher, err := provider.NewCredentialCipher(key, 1)
if err != nil {
t.Fatal(err)
}
encrypted, version, err := cipher.Encrypt([]byte(`{"api_key":"upstream-secret"}`))
if err != nil {
t.Fatal(err)
}
fallback, _ := provideropenai.New("https://fallback.example", "")
resolver := NewResolver(nil, cipher, fallback, time.Second, slog.New(slog.NewTextHandler(io.Discard, nil)))
resolved, defaultProvider, err := resolver.build(provider.Record{
Code: "primary", Adapter: "openai-compatible", BaseURL: "https://upstream.example/v1",
EncryptedCredentials: encrypted, CredentialKEKVersion: version,
Capabilities: []string{"chat", "models"}, Config: json.RawMessage(`{"default":true}`), Revision: 3,
})
if err != nil {
t.Fatal(err)
}
if resolved.Code != "primary" || resolved.Revision != 3 || !resolved.Capabilities[provider.CapabilityChat] || !defaultProvider {
t.Fatalf("unexpected resolved adapter: %#v, default=%v", resolved, defaultProvider)
}
}
func TestModelRouteUsesConditionsPriorityAndExplicitProvider(t *testing.T) {
first, _ := provideropenai.New("https://first.example", "")
second, _ := provideropenai.New("https://second.example", "")
resolver := &Resolver{}
resolver.snapshot.Store(&snapshot{
adapters: map[string]gateway.ResolvedAdapter{
"first": {Code: "first", Adapter: first}, "second": {Code: "second", Adapter: second},
},
routes: map[string][]compiledRoute{"public-chat": {
{providerCode: "first", targetModel: "model-a", weight: 100, priority: 10},
{providerCode: "second", targetModel: "model-b", weight: 100, priority: 20, conditions: routeConditions{Endpoints: []string{"/v1/chat/completions"}}},
}},
knownModels: map[string]bool{"public-chat": true},
})
result, err := resolver.ResolveModelRoute(gateway.ModelRouteQuery{Model: "public-chat", Endpoint: "/v1/chat/completions", Seed: "request-1"})
if err != nil || !result.Matched || result.Code != "second" || result.TargetModel != "model-b" {
t.Fatalf("unexpected priority route: %#v %v", result, err)
}
result, err = resolver.ResolveModelRoute(gateway.ModelRouteQuery{ProviderCode: "first", Model: "public-chat", Endpoint: "/v1/chat/completions", Seed: "request-1"})
if err != nil || !result.Matched || result.Code != "first" {
t.Fatalf("explicit provider was not respected: %#v %v", result, err)
}
result, err = resolver.ResolveModelRoute(gateway.ModelRouteQuery{ProviderCode: "second", Model: "public-chat", Endpoint: "/v1/embeddings", Seed: "request-1"})
if err != nil || result.Matched || !result.Known {
t.Fatalf("known alias with unmatched conditions must fail closed: %#v %v", result, err)
}
}
func TestResolverStartsWithEnvironmentFallback(t *testing.T) {
fallback, _ := provideropenai.New("https://fallback.example", "")
resolver := NewResolver(nil, nil, fallback, time.Second, slog.New(slog.NewTextHandler(io.Discard, nil)))
resolved, err := resolver.Resolve("")
if err != nil || resolved.Code != "environment" {
t.Fatalf("fallback resolve: %#v %v", resolved, err)
}
if _, err := resolver.Resolve("missing"); err == nil {
t.Fatal("unknown provider must be rejected")
}
}