package config_test import ( "os" "path/filepath" "strings" "testing" "iop/packages/go/config" ) // --- S01: Overlay resolution, rejection, and legacy alias normalization --- func TestProtocolProfileOverlayResolution(t *testing.T) { catalog := map[string]config.ProtocolProfileConf{ "base": { Driver: config.ProtocolDriverOpenAIChat, BaseURL: "https://api.example.com/v1", Operations: map[string]string{ "models": "/models", }, Auth: config.ProtocolAuthConf{Header: "Authorization", Scheme: "Bearer"}, Capabilities: []string{"models", "chat"}, }, "overlay": { Base: "base", Operations: map[string]string{ "chat_completions": "/chat/completions", }, Capabilities: []string{"models", "chat", "streaming"}, }, } resolved, err := config.ResolveProtocolProfile("overlay", "", catalog) if err != nil { t.Fatalf("ResolveProtocolProfile: %v", err) } if resolved.ID != "overlay" { t.Errorf("ID = %q, want %q", resolved.ID, "overlay") } if resolved.Driver != config.ProtocolDriverOpenAIChat { t.Errorf("Driver = %q, want %q", resolved.Driver, config.ProtocolDriverOpenAIChat) } if resolved.BaseURL != "https://api.example.com/v1" { t.Errorf("BaseURL = %q, want inherited value", resolved.BaseURL) } if _, ok := resolved.Operations["models"]; !ok { t.Errorf("expected inherited operation models") } if _, ok := resolved.Operations["chat_completions"]; !ok { t.Errorf("expected overlay operation chat_completions") } if len(resolved.Capabilities) != 3 { t.Errorf("Capabilities = %v, want 3", resolved.Capabilities) } } func TestProtocolProfileOverlayDeepCopyImmutability(t *testing.T) { baseOps := map[string]string{"models": "/models"} catalog := map[string]config.ProtocolProfileConf{ "base": { Driver: config.ProtocolDriverOpenAIChat, BaseURL: "https://api.example.com/v1", Operations: baseOps, Auth: config.ProtocolAuthConf{Header: "Authorization", Scheme: "Bearer"}, Capabilities: []string{"models", "chat"}, }, "overlay": { Base: "base", Operations: map[string]string{"chat_completions": "/chat/completions"}, }, } resolved, err := config.ResolveProtocolProfile("overlay", "", catalog) if err != nil { t.Fatalf("ResolveProtocolProfile: %v", err) } // Mutate the resolved snapshot and verify the catalog is unaffected. resolved.Operations["injected"] = "/injected" if _, ok := catalog["base"].Operations["injected"]; ok { t.Error("mutating resolved profile affected catalog base") } if _, ok := catalog["overlay"].Operations["injected"]; ok { t.Error("mutating resolved profile affected catalog overlay") } } func TestProtocolProfileOverlayRejected(t *testing.T) { t.Run("cycle", func(t *testing.T) { catalog := map[string]config.ProtocolProfileConf{ "a": {Base: "b", Driver: config.ProtocolDriverOpenAIChat, BaseURL: "https://a/v1", Operations: map[string]string{"models": "/m"}, Capabilities: []string{"chat"}}, "b": {Base: "a", Driver: config.ProtocolDriverOpenAIChat, BaseURL: "https://b/v1", Operations: map[string]string{"models": "/m"}, Capabilities: []string{"chat"}}, } _, err := config.ResolveProtocolProfile("a", "", catalog) if err == nil || !strings.Contains(err.Error(), "cycle") { t.Fatalf("expected cycle error, got %v", err) } }) t.Run("unknown_base", func(t *testing.T) { catalog := map[string]config.ProtocolProfileConf{ "overlay": {Base: "nonexistent", Driver: config.ProtocolDriverOpenAIChat, BaseURL: "https://a/v1", Operations: map[string]string{"models": "/m"}, Capabilities: []string{"chat"}}, } _, err := config.ResolveProtocolProfile("overlay", "", catalog) if err == nil || !strings.Contains(err.Error(), "unknown") { t.Fatalf("expected unknown base error, got %v", err) } }) t.Run("conflicting_driver", func(t *testing.T) { catalog := map[string]config.ProtocolProfileConf{ "base": {Driver: config.ProtocolDriverOpenAIChat, BaseURL: "https://a/v1", Operations: map[string]string{"models": "/m"}, Capabilities: []string{"chat"}}, "overlay": {Base: "base", Driver: config.ProtocolDriverAnthropicMessages, BaseURL: "https://a/v1", Operations: map[string]string{"models": "/m", "messages": "/msg"}, Capabilities: []string{"messages"}}, } _, err := config.ResolveProtocolProfile("overlay", "", catalog) if err == nil || !strings.Contains(err.Error(), "driver") { t.Fatalf("expected driver conflict error, got %v", err) } }) t.Run("invalid_operation", func(t *testing.T) { catalog := map[string]config.ProtocolProfileConf{ "bad": {Driver: config.ProtocolDriverOpenAIChat, BaseURL: "https://a/v1", Operations: map[string]string{"messages": "/msg"}, Capabilities: []string{"chat"}}, } _, err := config.ResolveProtocolProfile("bad", "", catalog) if err == nil || !strings.Contains(err.Error(), "messages") { t.Fatalf("expected invalid operation error, got %v", err) } }) t.Run("invalid_auth_header", func(t *testing.T) { catalog := map[string]config.ProtocolProfileConf{ "bad": {Driver: config.ProtocolDriverOpenAIChat, BaseURL: "https://a/v1", Operations: map[string]string{"models": "/m", "chat_completions": "/chat"}, Auth: config.ProtocolAuthConf{Header: ""}, Capabilities: []string{"models", "chat"}}, } _, err := config.ResolveProtocolProfile("bad", "", catalog) if err == nil || !strings.Contains(err.Error(), "auth") { t.Fatalf("expected auth validation error, got %v", err) } }) t.Run("empty_capabilities", func(t *testing.T) { catalog := map[string]config.ProtocolProfileConf{ "bad": {Driver: config.ProtocolDriverOpenAIChat, BaseURL: "https://a/v1", Operations: map[string]string{"models": "/m"}, Capabilities: []string{}}, } _, err := config.ResolveProtocolProfile("bad", "", catalog) if err == nil || !strings.Contains(err.Error(), "capabilities") { t.Fatalf("expected capabilities error, got %v", err) } }) t.Run("malformed_absolute_url", func(t *testing.T) { catalog := map[string]config.ProtocolProfileConf{ "bad": {Driver: config.ProtocolDriverOpenAIChat, BaseURL: "https://a/v1", Operations: map[string]string{"models": "://not-a-url"}, Capabilities: []string{"chat"}}, } _, err := config.ResolveProtocolProfile("bad", "", catalog) if err == nil || !strings.Contains(err.Error(), "operation") { t.Fatalf("expected URL validation error, got %v", err) } }) t.Run("absolute_url_without_host", func(t *testing.T) { catalog := map[string]config.ProtocolProfileConf{ "bad": { Driver: config.ProtocolDriverOpenAIChat, BaseURL: "https://a/v1", Operations: map[string]string{"chat_completions": "https:///v1/chat/completions"}, Auth: config.ProtocolAuthConf{Header: "Authorization", Scheme: "Bearer"}, Capabilities: []string{"chat"}, }, } _, err := config.ResolveProtocolProfile("bad", "", catalog) if err == nil || !strings.Contains(err.Error(), "absolute http(s) URL") { t.Fatalf("expected absolute URL host validation error, got %v", err) } }) t.Run("relative_path_no_leading_slash", func(t *testing.T) { catalog := map[string]config.ProtocolProfileConf{ "bad": {Driver: config.ProtocolDriverOpenAIChat, BaseURL: "https://a/v1", Operations: map[string]string{"models": "models"}, Capabilities: []string{"chat"}}, } _, err := config.ResolveProtocolProfile("bad", "", catalog) if err == nil || !strings.Contains(err.Error(), "leading") { t.Fatalf("expected leading slash error, got %v", err) } }) } func TestLegacyProviderAliasProfileNormalization(t *testing.T) { cases := []struct { legacyType string wantID string }{ {"vllm", "openai"}, {"openai_api", "openai"}, {"openai_compat", "openai"}, {"vllm-mlx", "openai"}, {"lemonade", "openai"}, {"sglang", "openai"}, {"seulgivibe_claude", "seulgi_messages"}, {"seulgivibe_openai", "seulgi_chat"}, {"ollama", ""}, {"cli", ""}, {"unknown_type", ""}, } for _, c := range cases { got := config.LegacyProviderTypeToProfile(c.legacyType) if got != c.wantID { t.Errorf("LegacyProviderTypeToProfile(%q) = %q, want %q", c.legacyType, got, c.wantID) } } } func TestLegacyProviderAliasResolvesToBuiltIn(t *testing.T) { // No explicit selector: legacy type should normalize to the built-in. resolved, err := config.ResolveProtocolProfile("", "vllm", config.BuiltInProtocolProfiles) if err != nil { t.Fatalf("ResolveProtocolProfile: %v", err) } if resolved.ID != "openai" { t.Errorf("ID = %q, want %q", resolved.ID, "openai") } if resolved.Driver != config.ProtocolDriverOpenAIChat { t.Errorf("Driver = %q, want %q", resolved.Driver, config.ProtocolDriverOpenAIChat) } } func TestExplicitProfilePrecedenceOverLegacyType(t *testing.T) { // Explicit selector should win over legacy type mapping. resolved, err := config.ResolveProtocolProfile("anthropic", "vllm", config.BuiltInProtocolProfiles) if err != nil { t.Fatalf("ResolveProtocolProfile: %v", err) } if resolved.ID != "anthropic" { t.Errorf("ID = %q, want %q", resolved.ID, "anthropic") } if resolved.Driver != config.ProtocolDriverAnthropicMessages { t.Errorf("Driver = %q, want %q", resolved.Driver, config.ProtocolDriverAnthropicMessages) } } func TestProtocolProfileMultiLevelOverlay(t *testing.T) { catalog := map[string]config.ProtocolProfileConf{ "l1": { Driver: config.ProtocolDriverOpenAIChat, BaseURL: "https://l1/v1", Operations: map[string]string{"models": "/models"}, Auth: config.ProtocolAuthConf{Header: "Authorization", Scheme: "Bearer"}, Capabilities: []string{"models", "chat"}, }, "l2": { Base: "l1", BaseURL: "https://l2/v1", Operations: map[string]string{"chat_completions": "/chat/completions"}, }, "l3": { Base: "l2", Capabilities: []string{"models", "chat", "streaming"}, }, } resolved, err := config.ResolveProtocolProfile("l3", "", catalog) if err != nil { t.Fatalf("ResolveProtocolProfile: %v", err) } if resolved.BaseURL != "https://l2/v1" { t.Errorf("BaseURL = %q, want %q", resolved.BaseURL, "https://l2/v1") } if _, ok := resolved.Operations["models"]; !ok { t.Error("expected inherited operation models") } if _, ok := resolved.Operations["chat_completions"]; !ok { t.Error("expected inherited operation chat_completions") } if len(resolved.Capabilities) != 3 { t.Errorf("Capabilities = %v, want 3", resolved.Capabilities) } } func TestProtocolProfileCustomOverlay(t *testing.T) { catalog := map[string]config.ProtocolProfileConf{ "openai": config.BuiltInProtocolProfiles["openai"], "my-proxy": { Base: "openai", BaseURL: "https://my-proxy.example.invalid/v1", }, } resolved, err := config.ResolveProtocolProfile("my-proxy", "", catalog) if err != nil { t.Fatalf("ResolveProtocolProfile: %v", err) } if resolved.BaseURL != "https://my-proxy.example.invalid/v1" { t.Errorf("BaseURL = %q, want overridden value", resolved.BaseURL) } if resolved.ID != "my-proxy" { t.Errorf("ID = %q, want %q", resolved.ID, "my-proxy") } } // --- S03: Built-in catalog admission --- func TestBuiltInProtocolProfileCatalog(t *testing.T) { expectedIDs := []string{ "anthropic", "gemini", "glm", "glm_coding", "grok", "kimi", "minimax_chat", "minimax_messages", "mimo_chat", "mimo_messages", "openai", "seulgi_chat", "seulgi_messages", } for _, id := range expectedIDs { if _, ok := config.BuiltInProtocolProfiles[id]; !ok { t.Fatalf("built-in profile %q not found", id) } resolved, err := config.ResolveProtocolProfile(id, "", config.BuiltInProtocolProfiles) if err != nil { t.Fatalf("ResolveProtocolProfile(%q): %v", id, err) } if resolved.ID != id { t.Errorf("profile %q: ID = %q, want %q", id, resolved.ID, id) } if resolved.Base != "" { t.Errorf("profile %q: Base should be empty in concrete snapshot, got %q", id, resolved.Base) } } // Verify all expected IDs are present for _, id := range expectedIDs { if _, ok := config.BuiltInProtocolProfiles[id]; !ok { t.Errorf("expected built-in profile %q", id) } } } func TestBuiltInProtocolProfileOperations(t *testing.T) { t.Run("openai_has_chat_completions", func(t *testing.T) { r, err := config.ResolveProtocolProfile("openai", "", config.BuiltInProtocolProfiles) if err != nil { t.Fatal(err) } if _, ok := r.Operations["chat_completions"]; !ok { t.Error("openai should declare chat_completions") } if _, ok := r.Operations["responses"]; !ok { t.Error("openai should declare responses") } }) t.Run("anthropic_has_messages", func(t *testing.T) { r, err := config.ResolveProtocolProfile("anthropic", "", config.BuiltInProtocolProfiles) if err != nil { t.Fatal(err) } if _, ok := r.Operations["messages"]; !ok { t.Error("anthropic should declare messages") } if _, ok := r.Operations["chat_completions"]; ok { t.Error("anthropic should NOT declare chat_completions") } }) t.Run("seulgi_messages_has_messages", func(t *testing.T) { r, err := config.ResolveProtocolProfile("seulgi_messages", "", config.BuiltInProtocolProfiles) if err != nil { t.Fatal(err) } if _, ok := r.Operations["messages"]; !ok { t.Error("seulgi_messages should declare messages") } }) t.Run("seulgi_chat_has_chat_completions", func(t *testing.T) { r, err := config.ResolveProtocolProfile("seulgi_chat", "", config.BuiltInProtocolProfiles) if err != nil { t.Fatal(err) } if _, ok := r.Operations["chat_completions"]; !ok { t.Error("seulgi_chat should declare chat_completions") } }) } func TestBuiltInProtocolProfileURLs(t *testing.T) { t.Run("anthropic_absolute_path", func(t *testing.T) { r, err := config.ResolveProtocolProfile("anthropic", "", config.BuiltInProtocolProfiles) if err != nil { t.Fatal(err) } url, err := r.ResolveOperationURL("messages") if err != nil { t.Fatal(err) } if !strings.HasSuffix(url, "/v1/messages") { t.Errorf("expected /v1/messages suffix, got %q", url) } }) t.Run("gemini_v1beta_openai", func(t *testing.T) { r, err := config.ResolveProtocolProfile("gemini", "", config.BuiltInProtocolProfiles) if err != nil { t.Fatal(err) } url, err := r.ResolveOperationURL("chat_completions") if err != nil { t.Fatal(err) } if !strings.HasSuffix(url, "/v1beta/openai/chat/completions") { t.Errorf("expected /v1beta/openai/chat/completions suffix, got %q", url) } }) t.Run("glm_api_paas_v4", func(t *testing.T) { r, err := config.ResolveProtocolProfile("glm", "", config.BuiltInProtocolProfiles) if err != nil { t.Fatal(err) } url, err := r.ResolveOperationURL("chat_completions") if err != nil { t.Fatal(err) } if !strings.HasSuffix(url, "/api/paas/v4/chat/completions") { t.Errorf("expected /api/paas/v4/chat/completions suffix, got %q", url) } }) t.Run("glm_coding_api_coding_paas_v4", func(t *testing.T) { r, err := config.ResolveProtocolProfile("glm_coding", "", config.BuiltInProtocolProfiles) if err != nil { t.Fatal(err) } url, err := r.ResolveOperationURL("chat_completions") if err != nil { t.Fatal(err) } if !strings.HasSuffix(url, "/api/coding/paas/v4/chat/completions") { t.Errorf("expected /api/coding/paas/v4/chat/completions suffix, got %q", url) } }) t.Run("glm_coding_models_url", func(t *testing.T) { r, err := config.ResolveProtocolProfile("glm_coding", "", config.BuiltInProtocolProfiles) if err != nil { t.Fatal(err) } url, err := r.ResolveOperationURL("models") if err != nil { t.Fatal(err) } if !strings.HasSuffix(url, "/api/coding/paas/v4/models") { t.Errorf("expected /api/coding/paas/v4/models suffix, got %q", url) } }) } func TestProtocolProfileUnsupportedOperationRejected(t *testing.T) { r, err := config.ResolveProtocolProfile("anthropic", "", config.BuiltInProtocolProfiles) if err != nil { t.Fatal(err) } _, err = r.ResolveOperationURL("chat_completions") if err == nil || !strings.Contains(err.Error(), "not supported") { t.Fatalf("expected unsupported operation error, got %v", err) } } func TestProtocolProfileResolveOperationURLAbsolute(t *testing.T) { catalog := map[string]config.ProtocolProfileConf{ "custom": { Driver: config.ProtocolDriverOpenAIChat, BaseURL: "https://base.example.com/v1", Operations: map[string]string{ "models": "https://override.example.com/v1/models", "chat_completions": "/chat/completions", }, Auth: config.ProtocolAuthConf{Header: "Authorization", Scheme: "Bearer"}, Capabilities: []string{"models", "chat"}, }, } r, err := config.ResolveProtocolProfile("custom", "", catalog) if err != nil { t.Fatal(err) } url, err := r.ResolveOperationURL("models") if err != nil { t.Fatal(err) } if url != "https://override.example.com/v1/models" { t.Errorf("expected absolute URL unchanged, got %q", url) } } func TestProtocolProfileClone(t *testing.T) { r, err := config.ResolveProtocolProfile("openai", "", config.BuiltInProtocolProfiles) if err != nil { t.Fatal(err) } clone := r.Clone() if clone.ID != r.ID { t.Errorf("ID mismatch: %q vs %q", clone.ID, r.ID) } clone.Operations["injected"] = "/injected" if _, ok := r.Operations["injected"]; ok { t.Error("clone mutation affected original") } } func TestProtocolProfileProviderEndpointOverlay(t *testing.T) { cfg, err := loadProtocolProfileYAML(t, ` nodes: - id: node-profile providers: - id: provider-profile type: vllm category: api endpoint: http://127.0.0.1:18080/v1/ base_url: http://127.0.0.1:18081/ignored models: [upstream-model] models: - id: canonical-model providers: provider-profile: upstream-model `) if err != nil { t.Fatalf("LoadEdge: %v", err) } profile := cfg.Nodes[0].Providers[0].RuntimeProfile if profile == nil || profile.BaseURL != "http://127.0.0.1:18080/v1" { t.Fatalf("runtime profile base_url = %#v", profile) } url, err := profile.ResolveOperationURL(string(config.OperationChatCompletions)) if err != nil || url != "http://127.0.0.1:18080/v1/chat/completions" { t.Fatalf("resolved chat URL = %q, err=%v", url, err) } fresh := config.BuiltInProtocolProfileCatalog()["openai"] if fresh.BaseURL != "https://api.openai.com/v1" { t.Fatalf("provider endpoint mutated built-in: %q", fresh.BaseURL) } rootCfg, err := loadProtocolProfileYAML(t, ` nodes: - id: node-root providers: - id: provider-root type: lemonade category: api endpoint: http://127.0.0.1:18082 models: [upstream-model] models: - id: root-model providers: {provider-root: upstream-model} `) if err != nil { t.Fatalf("LoadEdge root endpoint: %v", err) } rootProfile := rootCfg.Nodes[0].Providers[0].RuntimeProfile if rootProfile == nil || rootProfile.BaseURL != "http://127.0.0.1:18082/v1" { t.Fatalf("root endpoint did not retain profile prefix: %#v", rootProfile) } } func TestProtocolProfileCatalogCollisionRejected(t *testing.T) { _, err := loadProtocolProfileYAML(t, ` protocol_profiles: openai: driver: openai_chat base_url: https://collision.example.invalid/v1 operations: {chat_completions: /chat/completions} auth: {header: Authorization, scheme: Bearer} capabilities: [chat] `) if err == nil || !strings.Contains(err.Error(), "reserved") { t.Fatalf("expected reserved built-in collision error, got %v", err) } } func TestProtocolProfileCapabilityMatrixRejected(t *testing.T) { base := config.ProtocolProfileConf{ Driver: config.ProtocolDriverOpenAIChat, BaseURL: "https://matrix.example.invalid/v1", Operations: map[string]string{"chat_completions": "/chat/completions"}, Auth: config.ProtocolAuthConf{Header: "Authorization", Scheme: "Bearer"}, Capabilities: []string{"chat"}, } for _, tc := range []struct { name string edit func(*config.ProtocolProfileConf) want string }{ {name: "unknown_capability", edit: func(p *config.ProtocolProfileConf) { p.Capabilities = append(p.Capabilities, "telepathy") }, want: "not recognized"}, {name: "operation_without_capability", edit: func(p *config.ProtocolProfileConf) { p.Operations["models"] = "/models" }, want: "requires capability"}, {name: "wrong_driver_operation", edit: func(p *config.ProtocolProfileConf) { p.Operations["messages"] = "/messages" }, want: "not supported"}, {name: "raw_header_with_scheme", edit: func(p *config.ProtocolProfileConf) { p.Auth = config.ProtocolAuthConf{Header: "X-Api-Key", Scheme: "Bearer"} }, want: "raw credential"}, {name: "authorization_without_bearer", edit: func(p *config.ProtocolProfileConf) { p.Auth.Scheme = "Token" }, want: "Bearer"}, } { t.Run(tc.name, func(t *testing.T) { profile := base profile.Operations = map[string]string{"chat_completions": "/chat/completions"} profile.Capabilities = append([]string(nil), base.Capabilities...) tc.edit(&profile) _, err := config.ResolveProtocolProfile("bad", "", map[string]config.ProtocolProfileConf{"bad": profile}) if err == nil || !strings.Contains(err.Error(), tc.want) { t.Fatalf("expected %q error, got %v", tc.want, err) } }) } } func TestProtocolProfileChatOnlyTokenCounter(t *testing.T) { base := func(profile, counter string) string { return ` nodes: - id: node-counter providers: - id: provider-counter type: openai_api category: api profile: ` + profile + ` endpoint: http://127.0.0.1:18080/v1 models: [upstream-model] models: - id: canonical-model providers: provider-counter: upstream-model token_counter: ` + counter } if _, err := loadProtocolProfileYAML(t, base("openai", " mode: deterministic\n")); err != nil { t.Fatalf("Chat deterministic counter: %v", err) } for _, tc := range []struct { name, profile, counter, want string }{ {name: "messages", profile: "anthropic", counter: " mode: deterministic\n", want: "Chat-only"}, {name: "estimate_range", profile: "openai", counter: " mode: estimate\n per_1k_input: 1001\n", want: "between 1 and 1000"}, {name: "deterministic_parameter", profile: "openai", counter: " mode: deterministic\n per_1k_input: 250\n", want: "must be 0"}, } { t.Run(tc.name, func(t *testing.T) { _, err := loadProtocolProfileYAML(t, base(tc.profile, tc.counter)) if err == nil || !strings.Contains(err.Error(), tc.want) { t.Fatalf("expected %q error, got %v", tc.want, err) } }) } _, err := loadProtocolProfileYAML(t, ` protocol_profiles: responses_custom: driver: openai_responses base_url: https://responses.example.invalid/v1 operations: {responses: /responses} auth: {header: Authorization, scheme: Bearer} capabilities: [responses] nodes: - id: node-responses-counter providers: - id: responses-counter type: openai_api category: api profile: responses_custom models: [upstream-response] models: - id: canonical-response providers: {responses-counter: upstream-response} token_counter: {mode: deterministic} `) if err == nil || !strings.Contains(err.Error(), "Chat-only") { t.Fatalf("expected Responses profile token-counter rejection, got %v", err) } } func TestBuiltInProtocolProfileCatalogImmutable(t *testing.T) { first := config.BuiltInProtocolProfileCatalog() openai := first["openai"] openai.Operations[string(config.OperationChatCompletions)] = "/mutated" openai.Capabilities[0] = "mutated" first["openai"] = openai fresh := config.BuiltInProtocolProfileCatalog()["openai"] if fresh.Operations[string(config.OperationChatCompletions)] != "/chat/completions" || fresh.Capabilities[0] == "mutated" { t.Fatalf("built-in catalog mutation leaked: %+v", fresh) } } // TestProtocolProfileHeaderValidation covers the RFC 9110 field-name token // grammar independently from Go's permissive MIME canonicalization helpers. func TestProtocolProfileHeaderValidation(t *testing.T) { validProfile := func(header string) config.ProtocolProfileConf { return config.ProtocolProfileConf{ Driver: config.ProtocolDriverOpenAIChat, BaseURL: "https://example.invalid/v1", Operations: map[string]string{"chat_completions": "/chat/completions"}, Auth: config.ProtocolAuthConf{Header: header}, Capabilities: []string{"chat"}, } } for _, tc := range []struct { name, header string valid bool }{ {name: "token_punctuation", header: "X!#$%&'*+-.^_`|~Key", valid: true}, {name: "empty", header: ""}, {name: "leading_space", header: " X-Key"}, {name: "trailing_space", header: "X-Key "}, {name: "embedded_space", header: "X Key"}, {name: "colon", header: "X:Key"}, {name: "tab", header: "X\tKey"}, {name: "control", header: "X\x01Key"}, {name: "non_ascii", header: "X-Kéy"}, {name: "separator", header: "X(Key)"}, } { t.Run(tc.name, func(t *testing.T) { profile := validProfile(tc.header) _, err := config.ResolveProtocolProfile("header-test", "", map[string]config.ProtocolProfileConf{"header-test": profile}) if tc.valid && err != nil { t.Fatalf("valid header rejected: %v", err) } if !tc.valid && (err == nil || !strings.Contains(err.Error(), "auth")) { t.Fatalf("invalid header %q was not rejected: %v", tc.header, err) } }) } } // TestProtocolProfileBuiltInAuthMatrix is intentionally literal so catalog // drift cannot update the expected values by sharing production data. MiniMax // and MiMo Anthropic-compatible auth was rechecked against official provider // documentation on 2026-08-01: // https://platform.minimax.io/docs/token-plan/other-tools // https://mimo.mi.com/docs/en-US/quick-start/summary/first-api-call func TestProtocolProfileBuiltInAuthMatrix(t *testing.T) { type wantAuth struct{ header, scheme string } want := map[string]wantAuth{ "openai": {"Authorization", "Bearer"}, "gemini": {"Authorization", "Bearer"}, "anthropic": {"x-api-key", ""}, "glm": {"Authorization", "Bearer"}, "glm_coding": {"Authorization", "Bearer"}, "kimi": {"Authorization", "Bearer"}, "minimax_chat": {"Authorization", "Bearer"}, "minimax_messages": {"Authorization", "Bearer"}, "mimo_chat": {"Authorization", "Bearer"}, "mimo_messages": {"api-key", ""}, "grok": {"Authorization", "Bearer"}, "seulgi_chat": {"Authorization", "Bearer"}, "seulgi_messages": {"x-api-key", ""}, } if len(config.BuiltInProtocolProfiles) != len(want) { t.Fatalf("built-in profile count = %d, want %d", len(config.BuiltInProtocolProfiles), len(want)) } for id, expected := range want { resolved, err := config.ResolveProtocolProfile(id, "", config.BuiltInProtocolProfiles) if err != nil { t.Fatalf("ResolveProtocolProfile(%q): %v", id, err) } if resolved.Auth.Header != expected.header || resolved.Auth.Scheme != expected.scheme { t.Errorf("%s auth = {%q %q}, want {%q %q}", id, resolved.Auth.Header, resolved.Auth.Scheme, expected.header, expected.scheme) } } } // TestBuiltInGLMProtocolProfiles asserts that both GLM profiles carry the // expected capabilities, lack Responses, and expose only models+chat operations. // Official docs rechecked on 2026-08-02: // https://docs.z.ai/api-reference/introduction // https://docs.z.ai/api-reference/llm/chat-completion // https://docs.z.ai/scenario-example/develop-tools/others func TestBuiltInGLMProtocolProfiles(t *testing.T) { for _, id := range []string{"glm", "glm_coding"} { t.Run(id, func(t *testing.T) { r, err := config.ResolveProtocolProfile(id, "", config.BuiltInProtocolProfiles) if err != nil { t.Fatal(err) } for _, want := range []string{"models", "chat", "streaming", "tool_calling"} { if !r.HasCapability(want) { t.Errorf("%s: missing capability %q", id, want) } } if r.HasCapability("responses") { t.Errorf("%s: must not advertise responses capability", id) } if _, ok := r.Operations[string(config.OperationResponses)]; ok { t.Errorf("%s: must not declare responses operation", id) } for _, op := range []config.ProtocolOperation{config.OperationModels, config.OperationChatCompletions} { if _, ok := r.Operations[string(op)]; !ok { t.Errorf("%s: missing operation %q", id, op) } } }) } } // TestGLMProfilesRemainDistinctThroughProviderPoolConfig loads a provider-pool // mapping with two distinct external model IDs that route to two distinct // provider IDs and two distinct GLM profiles, then asserts no cross-mapping // and both map to the same upstream model. // Official endpoint distinction rechecked on 2026-08-02: // https://docs.z.ai/scenario-example/develop-tools/others func TestGLMProfilesRemainDistinctThroughProviderPoolConfig(t *testing.T) { tmpDir := t.TempDir() yaml := ` models: - id: "glm-5.1-api" providers: glm-api: "glm-5.1" - id: "glm-5.1-coding" providers: glm-coding: "glm-5.1" nodes: - id: "node-glm" providers: - id: "glm-api" type: "openai_api" category: "api" profile: "glm" endpoint: "https://api.z.ai/api/paas/v4" models: ["glm-5.1"] capacity: 1 - id: "glm-coding" type: "openai_api" category: "api" profile: "glm_coding" endpoint: "https://api.z.ai/api/coding/paas/v4" models: ["glm-5.1"] capacity: 1 ` path := filepath.Join(tmpDir, "edge.yaml") if err := os.WriteFile(path, []byte(yaml), 0o600); err != nil { t.Fatalf("write: %v", err) } cfg, err := config.LoadEdge(path) if err != nil { t.Fatalf("LoadEdge: %v", err) } if len(cfg.Models) != 2 { t.Fatalf("expected 2 models, got %d", len(cfg.Models)) } if len(cfg.Nodes) != 1 { t.Fatalf("expected 1 node, got %d", len(cfg.Nodes)) } if len(cfg.Nodes[0].Providers) != 2 { t.Fatalf("expected 2 providers, got %d", len(cfg.Nodes[0].Providers)) } var apiProv, codingProv *config.NodeProviderConf for i := range cfg.Nodes[0].Providers { p := &cfg.Nodes[0].Providers[i] if p.ID == "glm-api" { apiProv = p } else if p.ID == "glm-coding" { codingProv = p } } if apiProv == nil { t.Fatal("glm-api provider missing") } if codingProv == nil { t.Fatal("glm-coding provider missing") } if apiProv.Profile != "glm" { t.Errorf("glm-api profile = %q, want %q", apiProv.Profile, "glm") } if codingProv.Profile != "glm_coding" { t.Errorf("glm-coding profile = %q, want %q", codingProv.Profile, "glm_coding") } if len(cfg.Models[0].Providers) != 1 { t.Fatalf("glm-5.1-api: expected 1 provider mapping, got %d", len(cfg.Models[0].Providers)) } if len(cfg.Models[1].Providers) != 1 { t.Fatalf("glm-5.1-coding: expected 1 provider mapping, got %d", len(cfg.Models[1].Providers)) } if cfg.Models[0].Providers["glm-api"] != "glm-5.1" { t.Errorf("glm-5.1-api provider served = %q, want %q", cfg.Models[0].Providers["glm-api"], "glm-5.1") } if cfg.Models[1].Providers["glm-coding"] != "glm-5.1" { t.Errorf("glm-5.1-coding provider served = %q, want %q", cfg.Models[1].Providers["glm-coding"], "glm-5.1") } // Resolved runtime profiles must be distinct. apiProfile, err := config.ResolveProtocolProfile("glm", "", config.BuiltInProtocolProfiles) if err != nil { t.Fatal(err) } codingProfile, err := config.ResolveProtocolProfile("glm_coding", "", config.BuiltInProtocolProfiles) if err != nil { t.Fatal(err) } if apiProfile.BaseURL == codingProfile.BaseURL { t.Errorf("glm and glm_coding must resolve to different base URLs, both got %q", apiProfile.BaseURL) } } func TestProtocolProfileAdapterBackingResolution(t *testing.T) { cfg, err := loadProtocolProfileYAML(t, ` nodes: - id: node-backed adapters: openai_compat_instances: - name: upstream enabled: true provider: lemonade endpoint: http://127.0.0.1:18080 providers: - id: profile-provider type: lemonade category: api adapter: upstream profile: openai models: [served] capacity: 1 models: - id: canonical providers: {profile-provider: served} `) if err != nil { t.Fatalf("LoadEdge: %v", err) } profile := cfg.Nodes[0].Providers[0].RuntimeProfile if profile == nil || profile.BaseURL != "http://127.0.0.1:18080/v1" { t.Fatalf("backing endpoint was not applied: %#v", profile) } } func TestProtocolProfileAdapterBackingRejected(t *testing.T) { for _, tc := range []struct { name, adapters, ref, want string }{ {name: "missing", ref: "missing", adapters: " openai_compat_instances: []", want: "missing"}, {name: "disabled", ref: "backing", adapters: " openai_compat_instances:\n - {name: backing, enabled: false, endpoint: http://127.0.0.1:1}", want: "disabled"}, {name: "ambiguous", ref: "backing", adapters: " vllm_instances:\n - {name: backing, enabled: true, endpoint: http://127.0.0.1:1}\n openai_compat_instances:\n - {name: backing, enabled: true, endpoint: http://127.0.0.1:2}", want: "ambiguous"}, } { t.Run(tc.name, func(t *testing.T) { _, err := loadProtocolProfileYAML(t, ` nodes: - id: node-bad-backing adapters: `+tc.adapters+` providers: - id: profile-provider type: openai_compat category: api adapter: `+tc.ref+` profile: openai models: [served] capacity: 1 `) if err == nil || !strings.Contains(err.Error(), tc.want) || !strings.Contains(err.Error(), "profile-provider") || !strings.Contains(err.Error(), tc.ref) { t.Fatalf("expected contextual %q error, got %v", tc.want, err) } }) } } func loadProtocolProfileYAML(t *testing.T, contents string) (*config.EdgeConfig, error) { t.Helper() path := filepath.Join(t.TempDir(), "edge.yaml") if err := os.WriteFile(path, []byte(contents), 0o600); err != nil { t.Fatalf("write config: %v", err) } return config.LoadEdge(path) }