返回 DeepSeek-Reasonix
provider_settings_probe_test.go
根目录 / desktop / provider_settings_probe_test.go
1 package main
2
3 import (
4 "encoding/json"
5 "fmt"
6 "net/http"
7 "net/http/httptest"
8 "os"
9 "path/filepath"
10 "testing"
11
12 "reasonix/internal/config"
13 )
14
15 func TestProviderDraftProbesDoNotPersistCredentialsOrConfiguration(t *testing.T) {
16 isolateDesktopUserDirs(t)
17 const keyEnv = "REASONIX_DRAFT_PROBE_TEST_KEY"
18 if _, err := config.SetCredential(keyEnv, "saved-key"); err != nil {
19 t.Fatal(err)
20 }
21 t.Setenv(keyEnv, "process-key")
22 revision := config.CredentialStoreRevision()
23 cachePath := filepath.Join(config.CacheDir(), "model-capabilities-v2.json")
24 beforeCache, _ := os.ReadFile(cachePath)
25 var paths []string
26 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
27 paths = append(paths, r.URL.Path)
28 if r.Header.Get("Authorization") != "Bearer draft-key" {
29 http.Error(w, "wrong credential", http.StatusUnauthorized)
30 return
31 }
32 if r.URL.Path == "/v1/models" {
33 fmt.Fprint(w, `{"data":[{"id":"draft-model"}]}`)
34 return
35 }
36 if r.URL.Path != "/exact/chat" {
37 http.NotFound(w, r)
38 return
39 }
40 var body map[string]any
41 if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
42 t.Error(err)
43 return
44 }
45 if body["model"] != "draft-model" || body["tools"] != nil {
46 t.Errorf("unexpected probe model/tools: %v", body)
47 }
48 messages, _ := body["messages"].([]any)
49 if len(messages) != 1 || messages[0].(map[string]any)["role"] != "user" {
50 t.Errorf("probe includes session/system context: %v", messages)
51 }
52 w.Header().Set("Content-Type", "text/event-stream")
53 fmt.Fprint(w, "data: {\"choices\":[{\"index\":0,\"delta\":{\"content\":\"OK\"}}]}\n\ndata: [DONE]\n\n")
54 }))
55 defer srv.Close()
56 p := ProviderView{Name: "draft-only", Kind: "openai", BaseURL: srv.URL + "/v1", RequestURL: srv.URL + "/exact/chat", APIKeyEnv: keyEnv, Models: []string{"draft-model"}}
57 a := NewApp()
58 catalog, err := a.FetchProviderModelCatalogDraft(p, "draft-key")
59 if err != nil || len(catalog) != 1 || catalog[0].Model != "draft-model" {
60 t.Fatalf("draft catalog: %v, %v", catalog, err)
61 }
62 if err := a.TestProviderModel(p, "draft-model", "draft-key"); err != nil {
63 t.Fatal(err)
64 }
65 if err := a.TestProviderModel(p, "unlisted-model", "draft-key"); err == nil {
66 t.Fatal("unlisted model should be rejected before network access")
67 }
68 afterCache, _ := os.ReadFile(cachePath)
69 if string(beforeCache) != string(afterCache) {
70 t.Fatal("draft credentials polluted the saved capability cache")
71 }
72 if len(paths) != 2 {
73 t.Fatalf("unexpected requests: %v", paths)
74 }
75 if os.Getenv(keyEnv) != "process-key" || config.CredentialStoreRevision() != revision {
76 t.Fatal("probe changed process environment or stored credentials")
77 }
78 cfg, err := config.LoadForRootWithoutCredentialsReadOnly("")
79 if err != nil {
80 t.Fatal(err)
81 }
82 if _, exists := cfg.Provider(p.Name); exists {
83 t.Fatal("probe persisted the draft provider")
84 }
85 }
86
87 func TestProviderModelProbeReportsHTTPFailure(t *testing.T) {
88 isolateDesktopUserDirs(t)
89 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
90 http.Error(w, `{"error":{"message":"invalid credential"}}`, http.StatusUnauthorized)
91 }))
92 defer srv.Close()
93 err := NewApp().TestProviderModel(ProviderView{Name: "probe", Kind: "openai", BaseURL: srv.URL, Models: []string{"model"}}, "model", "bad-key")
94 if err == nil {
95 t.Fatal("failed authentication reported as successful")
96 }
97 }
98
99 func TestConfiguredModelInfoUsesPerModelOverrides(t *testing.T) {
100 vision := true
101 cfg := &config.Config{Providers: []config.ProviderEntry{{
102 Name: "custom", Kind: "openai", BaseURL: "https://example.test/v1",
103 Models: []string{"model-a", "model-b"}, ContextWindow: 32768,
104 ModelOverrides: map[string]config.ProviderModelOverride{"model-b": {ContextWindow: 65536, Vision: &vision}},
105 }}}
106 first := configuredModelInfo(cfg, "custom", "model-a", false)
107 second := configuredModelInfo(cfg, "custom", "model-b", true)
108 if first.ContextWindow != 32768 || first.Vision || second.ContextWindow != 65536 || !second.Vision || !second.Current {
109 t.Fatalf("model menu metadata disagrees with per-model configuration: %+v, %+v", first, second)
110 }
111 }
112
112 lines GO