返回 DeepSeek-Reasonix
proxy_test.go
根目录 / internal / config / proxy_test.go
1 package config
2
3 import (
4 "os"
5 "path/filepath"
6 "testing"
7 )
8
9 func TestDirectProxyHostsFromNoProxyProviders(t *testing.T) {
10 c := Default()
11 c.Providers = append(c.Providers, ProviderEntry{Name: "domestic", Kind: "openai", BaseURL: "https://domestic.example/v1", Model: "chat", NoProxy: true})
12 spec := c.NetworkProxySpec()
13 hasDirectHost := false
14 for _, h := range spec.DirectHosts {
15 if h == "domestic.example" {
16 hasDirectHost = true
17 }
18 if h == "api.deepseek.com" {
19 t.Errorf("DeepSeek works through the proxy and must not be forced direct: %v", spec.DirectHosts)
20 }
21 }
22 if !hasDirectHost {
23 t.Errorf("a no_proxy provider's host should land in DirectHosts, got %v", spec.DirectHosts)
24 }
25 }
26
27 func TestExplicitProxyOverridesProviderNoProxy(t *testing.T) {
28 // An explicit custom proxy (e.g. a mandatory corporate proxy) must apply to
29 // every provider, including no_proxy ones, so it isn't unreachable
30 // behind the proxy (#3635).
31 c := Default()
32 c.Providers = append(c.Providers, ProviderEntry{Name: "domestic", Kind: "openai", BaseURL: "https://domestic.example/v1", Model: "chat", NoProxy: true})
33 c.Network.ProxyMode = "custom"
34 spec := c.NetworkProxySpec()
35 for _, h := range spec.DirectHosts {
36 if h == "domestic.example" {
37 t.Fatalf("custom proxy must not force no_proxy providers direct; DirectHosts = %v", spec.DirectHosts)
38 }
39 }
40 }
41
42 func TestLoadForRootWithoutCredentialsReadOnlyUsesEffectiveProjectProxy(t *testing.T) {
43 home := t.TempDir()
44 project := t.TempDir()
45 t.Setenv("REASONIX_HOME", home)
46 t.Setenv("REASONIX_CREDENTIALS_STORE", "file")
47 const key = "REASONIX_TEST_EFFECTIVE_PROXY_KEY"
48 t.Setenv(key, "inherited-value")
49
50 if err := os.WriteFile(UserConfigPath(), []byte("[network]\nproxy_mode = \"off\"\n"), 0o600); err != nil {
51 t.Fatal(err)
52 }
53 if err := os.WriteFile(filepath.Join(project, ".env"), []byte("PROJECT_PROXY_URL=http://127.0.0.1:9876\n"), 0o600); err != nil {
54 t.Fatal(err)
55 }
56 if err := os.WriteFile(filepath.Join(project, "reasonix.toml"), []byte(`
57 [network]
58 proxy_mode = "custom"
59 proxy_url = "${PROJECT_PROXY_URL}"
60
61 [[providers]]
62 name = "project-provider"
63 kind = "openai"
64 base_url = "https://provider.invalid/v1"
65 model = "model"
66 api_key_env = "`+key+`"
67 `), 0o600); err != nil {
68 t.Fatal(err)
69 }
70 credentials := UserCredentialsPath()
71 if err := os.MkdirAll(filepath.Dir(credentials), 0o700); err != nil {
72 t.Fatal(err)
73 }
74 if err := os.WriteFile(credentials, []byte(key+"=stored-value\n"), 0o600); err != nil {
75 t.Fatal(err)
76 }
77
78 cfg, err := LoadForRootWithoutCredentialsReadOnly(project)
79 if err != nil {
80 t.Fatalf("LoadForRootWithoutCredentialsReadOnly: %v", err)
81 }
82 spec := cfg.NetworkProxySpec()
83 if spec.Mode != "custom" || spec.URL != "http://127.0.0.1:9876" {
84 t.Fatalf("effective proxy = %+v, want project custom proxy with .env expansion", spec)
85 }
86 provider, ok := cfg.Provider("project-provider")
87 if !ok {
88 t.Fatal("project provider missing from effective config")
89 }
90 if provider.resolvedAPIKey != "" {
91 t.Fatal("credential-free load eagerly resolved the provider key")
92 }
93 if got := os.Getenv(key); got != "inherited-value" {
94 t.Fatalf("credential-free load changed process env to %q", got)
95 }
96 }
97
97 lines GO