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