package provider import ( "sort" "testing" ) func TestLookupProviderSpec_Hit(t *testing.T) { spec, ok := LookupProviderSpec("deepseek") if !ok { t.Fatalf("LookupProviderSpec(deepseek): expected hit, got miss") } if spec.Name != "deepseek" { t.Errorf("Name = %q, want deepseek", spec.Name) } if spec.DefaultBaseURL != "https://api.deepseek.com" { t.Errorf("DefaultBaseURL = %q, want https://api.deepseek.com", spec.DefaultBaseURL) } if spec.Protocol != ProtocolOpenAIResponses { t.Errorf("Protocol = %q, want %q", spec.Protocol, ProtocolOpenAIResponses) } if len(spec.EnvVars) != 1 || spec.EnvVars[0] != "DEEPSEEK_API_KEY" { t.Errorf("EnvVars = %v, want [DEEPSEEK_API_KEY]", spec.EnvVars) } } func TestLookupProviderSpec_Miss(t *testing.T) { if _, ok := LookupProviderSpec("does-not-exist"); ok { t.Errorf("LookupProviderSpec(does-not-exist): expected miss, got hit") } } func TestAnthropicEnvVarOrder(t *testing.T) { spec, ok := LookupProviderSpec("anthropic") if !ok { t.Fatal("LookupProviderSpec(anthropic): expected hit") } want := []string{"ANTHROPIC_OAUTH_TOKEN", "ANTHROPIC_API_KEY", "CLAUDE_API_KEY"} if len(spec.EnvVars) != len(want) { t.Fatalf("EnvVars = %v, want %v", spec.EnvVars, want) } for i := range want { if spec.EnvVars[i] != want[i] { t.Errorf("EnvVars[%d] = %q, want %q (OAuth must be first)", i, spec.EnvVars[i], want[i]) } } if spec.Protocol != ProtocolAnthropic { t.Errorf("Protocol = %q, want %q", spec.Protocol, ProtocolAnthropic) } } func TestHuggingfaceEnvVar(t *testing.T) { spec, ok := LookupProviderSpec("huggingface") if !ok { t.Fatal("LookupProviderSpec(huggingface): expected hit") } if len(spec.EnvVars) != 1 || spec.EnvVars[0] != "HF_TOKEN" { t.Errorf("EnvVars = %v, want [HF_TOKEN]", spec.EnvVars) } } func TestChineseCloudProviders(t *testing.T) { cases := []struct { name string envVars []string baseURL string }{ {"qianfan", []string{"QIANFAN_API_KEY"}, "https://qianfan.baidubce.com/v2"}, {"volcengine", []string{"ARK_API_KEY", "VOLCENGINE_API_KEY"}, "https://ark.cn-beijing.volces.com/api/v3"}, {"dashscope", []string{"DASHSCOPE_API_KEY"}, "https://dashscope.aliyuncs.com/compatible-mode/v1"}, {"hunyuan", []string{"HUNYUAN_API_KEY"}, "https://api.hunyuan.cloud.tencent.com/v1"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { spec, ok := LookupProviderSpec(tc.name) if !ok { t.Fatalf("LookupProviderSpec(%q): expected hit", tc.name) } if spec.Name != tc.name { t.Errorf("Name = %q, want %q", spec.Name, tc.name) } if spec.DefaultBaseURL != tc.baseURL { t.Errorf("DefaultBaseURL = %q, want %q", spec.DefaultBaseURL, tc.baseURL) } if spec.Protocol != ProtocolOpenAI { t.Errorf("Protocol = %q, want %q", spec.Protocol, ProtocolOpenAI) } if spec.AuthScheme != AuthBearer { t.Errorf("AuthScheme = %q, want %q", spec.AuthScheme, AuthBearer) } if len(spec.EnvVars) != len(tc.envVars) { t.Fatalf("EnvVars = %v, want %v", spec.EnvVars, tc.envVars) } for i := range tc.envVars { if spec.EnvVars[i] != tc.envVars[i] { t.Errorf("EnvVars[%d] = %q, want %q", i, spec.EnvVars[i], tc.envVars[i]) } } }) } } func TestAzureBaseURLEnvVars(t *testing.T) { spec, ok := LookupProviderSpec("azure-openai-responses") if !ok { t.Fatal("LookupProviderSpec(azure-openai-responses): expected hit") } found := false for _, v := range spec.BaseURLEnvVars { if v == "AZURE_OPENAI_BASE_URL" { found = true } } if !found { t.Errorf("BaseURLEnvVars = %v, want to contain AZURE_OPENAI_BASE_URL", spec.BaseURLEnvVars) } } func TestRegistryContainsAllExpectedProviders(t *testing.T) { expected := []string{ "anthropic", "openai", "ant-ling", "deepseek", "nvidia", "google", "groq", "cerebras", "xai", "openrouter", "vercel-ai-gateway", "zai", "zai-coding-cn", "mistral", "minimax", "minimax-cn", "moonshotai", "moonshotai-cn", "huggingface", "fireworks", "together", "opencode", "opencode-go", "kimi-coding", "xiaomi", "xiaomi-token-plan-cn", "xiaomi-token-plan-ams", "xiaomi-token-plan-sgp", "qianfan", "volcengine", "dashscope", "hunyuan", "azure-openai-responses", "amazon-bedrock", "google-vertex", "cloudflare-workers-ai", "cloudflare-ai-gateway", } for _, name := range expected { if _, ok := LookupProviderSpec(name); !ok { t.Errorf("registry missing expected provider %q", name) } } names := ProviderNames() if len(names) != len(expected) { t.Errorf("registry has %d providers, want %d", len(names), len(expected)) } // Every spec must have a name, at least one env var, and a valid protocol. for _, spec := range ProviderSpecs() { if spec.Name == "" { t.Error("found spec with empty Name") } if len(spec.EnvVars) == 0 { t.Errorf("provider %q has no EnvVars", spec.Name) } if spec.Protocol != ProtocolOpenAI && spec.Protocol != ProtocolAnthropic && spec.Protocol != ProtocolOpenAIResponses { t.Errorf("provider %q has invalid Protocol %q", spec.Name, spec.Protocol) } } // No duplicate provider names. seen := make(map[string]bool, len(names)) dupSorted := append([]string(nil), names...) sort.Strings(dupSorted) for _, n := range dupSorted { if seen[n] { t.Errorf("duplicate provider name %q in registry", n) } seen[n] = true } }