返回 DeepSeek-Reasonix
official_provider_access_install_test.go
根目录 / desktop / official_provider_access_install_test.go
1 package main
2
3 import (
4 "os"
5 "path/filepath"
6 "strings"
7 "testing"
8
9 "reasonix/internal/config"
10 )
11
12 func TestAddOfficialProviderAccessUsesDesktopLanguagePricing(t *testing.T) {
13 // Desktop language is display-only; newly installed official DeepSeek
14 // templates freeze the default USD list-price table (billing_currency).
15 isolateDesktopUserDirs(t)
16 if err := os.MkdirAll(filepath.Dir(config.UserConfigPath()), 0o755); err != nil {
17 t.Fatalf("mkdir config dir: %v", err)
18 }
19 if err := os.WriteFile(config.UserConfigPath(), []byte(`
20 [desktop]
21 language = "zh"
22 `), 0o644); err != nil {
23 t.Fatalf("write config: %v", err)
24 }
25
26 if _, err := NewApp().AddOfficialProviderAccess("deepseek", ""); err != nil {
27 t.Fatalf("AddOfficialProviderAccess: %v", err)
28 }
29 cfg := config.LoadForEdit(config.UserConfigPath())
30 p, ok := cfg.Provider("deepseek")
31 if !ok {
32 t.Fatal("deepseek provider not saved")
33 }
34 flash := p.Prices["deepseek-v4-flash"]
35 pro := p.Prices["deepseek-v4-pro"]
36 if flash == nil || flash.Output != 1.2 || flash.Currency != "$" {
37 t.Fatalf("flash price = %+v, want frozen USD official table", flash)
38 }
39 if pro == nil || pro.Output != 3.96 || pro.Currency != "$" {
40 t.Fatalf("pro price = %+v, want frozen USD official table", pro)
41 }
42 if got := cfg.ResolveDisplayCurrency(); got != "" {
43 t.Fatalf("display currency = %q, want unresolved auto", got)
44 }
45 }
46
47 func TestAddOfficialProviderAccessPreservesExistingOfficialCustomization(t *testing.T) {
48 isolateDesktopUserDirs(t)
49 if err := os.MkdirAll(filepath.Dir(config.UserConfigPath()), 0o755); err != nil {
50 t.Fatalf("mkdir config dir: %v", err)
51 }
52 if err := os.WriteFile(config.UserConfigPath(), []byte(`
53 [[providers]]
54 name = "deepseek"
55 kind = "openai"
56 base_url = "https://api.deepseek.com/v1"
57 models = ["deepseek-v4-flash"]
58 default = "deepseek-v4-flash"
59 api_key_env = "MY_DEEPSEEK_KEY"
60 headers = { X-Route = "official-custom" }
61 `), 0o644); err != nil {
62 t.Fatalf("write config: %v", err)
63 }
64
65 if _, err := NewApp().AddOfficialProviderAccess("deepseek", ""); err != nil {
66 t.Fatalf("AddOfficialProviderAccess: %v", err)
67 }
68 cfg := config.LoadForEditWithoutCredentials(config.UserConfigPath())
69 p, ok := cfg.Provider("deepseek")
70 if !ok {
71 t.Fatal("deepseek provider not saved")
72 }
73 if p.Kind != "openai" || p.BaseURL != "https://api.deepseek.com/v1" || p.APIKeyEnv != "MY_DEEPSEEK_KEY" || p.Headers["X-Route"] != "official-custom" {
74 t.Fatalf("existing official customization was overwritten: %+v", p)
75 }
76 if !providerAccessSet(cfg.Desktop.ProviderAccess)["deepseek"] {
77 t.Fatalf("provider_access missing preserved DeepSeek provider: %+v", cfg.Desktop.ProviderAccess)
78 }
79 }
80
81 func TestAddOfficialProviderAccessRepairsCatalogWithoutResettingOfficialTransport(t *testing.T) {
82 isolateDesktopUserDirs(t)
83 if err := os.MkdirAll(filepath.Dir(config.UserConfigPath()), 0o755); err != nil {
84 t.Fatalf("mkdir config dir: %v", err)
85 }
86 if err := os.WriteFile(config.UserConfigPath(), []byte(`
87 [[providers]]
88 name = "deepseek"
89 kind = "openai"
90 base_url = "https://api.deepseek.com/v1"
91 api_key_env = "MY_DEEPSEEK_KEY"
92 headers = { X-Route = "official-custom" }
93 `), 0o644); err != nil {
94 t.Fatalf("write config: %v", err)
95 }
96
97 if _, err := NewApp().AddOfficialProviderAccess("deepseek", "test-key"); err != nil {
98 t.Fatalf("AddOfficialProviderAccess: %v", err)
99 }
100 cfg := config.LoadForEditWithoutCredentials(config.UserConfigPath())
101 p, ok := cfg.Provider("deepseek")
102 if !ok {
103 t.Fatal("deepseek provider not saved")
104 }
105 if p.Kind != "openai" || p.BaseURL != "https://api.deepseek.com/v1" || p.APIKeyEnv == "MY_DEEPSEEK_KEY" || p.Headers["X-Route"] != "official-custom" {
106 t.Fatalf("official transport customization was overwritten: %+v", p)
107 }
108 if got := p.ModelList(); len(got) != 3 || got[0] != "deepseek-v4-flash" || got[1] != "deepseek-v4-pro" || got[2] != "deepseek-v4-flash-vision-exp" {
109 t.Fatalf("repaired model catalog = %v, want official Flash/Pro/vision models", got)
110 }
111 if !config.CredentialStored(p.APIKeyEnv) || config.CredentialStored("MY_DEEPSEEK_KEY") || config.CredentialStored("DEEPSEEK_API_KEY") {
112 t.Fatal("credential was not saved exclusively under the new connection reference")
113 }
114 }
115
116 func TestAddOfficialProviderAccessRetargetsLegacyDeepSeekReferences(t *testing.T) {
117 isolateDesktopUserDirs(t)
118 if err := os.MkdirAll(filepath.Dir(config.UserConfigPath()), 0o755); err != nil {
119 t.Fatalf("mkdir config dir: %v", err)
120 }
121 if err := os.WriteFile(config.UserConfigPath(), []byte(`
122 default_model = "deepseek-flash"
123
124 [agent]
125 planner_model = "deepseek-pro"
126 subagent_model = "deepseek-flash/custom-flash"
127 subagent_models = { vision = "deepseek-pro/custom-pro", keep = "other/model" }
128
129 [[providers]]
130 name = "deepseek-flash"
131 kind = "openai"
132 base_url = "https://api.deepseek.com"
133 api_key_env = "DEEPSEEK_API_KEY"
134 `), 0o644); err != nil {
135 t.Fatalf("write config: %v", err)
136 }
137
138 if _, err := NewApp().AddOfficialProviderAccess("deepseek", ""); err != nil {
139 t.Fatalf("AddOfficialProviderAccess: %v", err)
140 }
141 cfg := config.LoadForEditWithoutCredentials(config.UserConfigPath())
142 if cfg.DefaultModel != "deepseek/deepseek-v4-flash" || cfg.Agent.PlannerModel != "deepseek/deepseek-v4-pro" ||
143 cfg.Agent.SubagentModel != "deepseek/custom-flash" || cfg.Agent.SubagentModels["vision"] != "deepseek/custom-pro" ||
144 cfg.Agent.SubagentModels["keep"] != "other/model" {
145 t.Fatalf("legacy DeepSeek references were not retargeted: default=%q planner=%q subagent=%q skills=%v",
146 cfg.DefaultModel, cfg.Agent.PlannerModel, cfg.Agent.SubagentModel, cfg.Agent.SubagentModels)
147 }
148 }
149
150 func TestAddOfficialProviderAccessRejectsSameNameCustomEndpointBeforeSavingKey(t *testing.T) {
151 isolateDesktopUserDirs(t)
152 if err := os.MkdirAll(filepath.Dir(config.UserConfigPath()), 0o755); err != nil {
153 t.Fatalf("mkdir config dir: %v", err)
154 }
155 if err := os.WriteFile(config.UserConfigPath(), []byte(`
156 [[providers]]
157 name = "deepseek"
158 kind = "openai"
159 base_url = "https://proxy.example.invalid/v1"
160 models = ["deepseek-v4-flash"]
161 default = "deepseek-v4-flash"
162 api_key_env = "DEEPSEEK_API_KEY"
163 `), 0o644); err != nil {
164 t.Fatalf("write config: %v", err)
165 }
166
167 _, err := NewApp().AddOfficialProviderAccess("deepseek", "test-key")
168 if err == nil || !strings.Contains(err.Error(), "already belongs to a custom endpoint") {
169 t.Fatalf("AddOfficialProviderAccess error = %v, want same-name custom endpoint rejection", err)
170 }
171 if data, readErr := os.ReadFile(config.UserCredentialsPath()); readErr == nil && strings.Contains(string(data), "DEEPSEEK_API_KEY") {
172 t.Fatalf("credential was saved before provider name conflict rejection:\n%s", data)
173 }
174 cfg := config.LoadForEditWithoutCredentials(config.UserConfigPath())
175 p, ok := cfg.Provider("deepseek")
176 if !ok || p.BaseURL != "https://proxy.example.invalid/v1" {
177 t.Fatalf("same-name custom provider changed after rejection: %+v", p)
178 }
179 }
180
180 lines GO