返回 DeepSeek-Reasonix
deepseek_protocol_migration_test.go
根目录 / internal / boot / deepseek_protocol_migration_test.go
1 package boot
2
3 import (
4 "context"
5 "os"
6 "path/filepath"
7 "strings"
8 "testing"
9
10 "reasonix/internal/config"
11 "reasonix/internal/event"
12 )
13
14 func TestBuildScopesMalformedConfigDeepSeekMigrationWarningToNonDesktopFrontends(t *testing.T) {
15 tests := []struct {
16 name string
17 statsSource string
18 handleWarnings bool
19 wantNotice bool
20 }{
21 {name: "desktop accepts persistent config warning", statsSource: "desktop", handleWarnings: true},
22 {name: "desktop without warning handler keeps boot warning", statsSource: "desktop", wantNotice: true},
23 {name: "CLI keeps boot warning", statsSource: "cli", wantNotice: true},
24 }
25 for _, tt := range tests {
26 t.Run(tt.name, func(t *testing.T) {
27 home := isolateConfigHome(t)
28 t.Setenv("REASONIX_HOME", filepath.Join(home, "reasonix-home"))
29 userPath := config.UserConfigPath()
30 if err := os.MkdirAll(filepath.Dir(userPath), 0o700); err != nil {
31 t.Fatal(err)
32 }
33 raw := `[[providers]]
34 name = "deepseek-flash"
35 kind = "openai"
36 base_url = "https://api.deepseek.com"
37 model = "deepseek-v4-flash"
38 api_key_env = "DEEPSEEK_API_KEY"
39
40 [[plugins]]
41 name = "windows-mcp"
42 command = "C:\Users\reasonix\mcp.exe"
43 `
44 if err := os.WriteFile(userPath, []byte(raw), 0o600); err != nil {
45 t.Fatal(err)
46 }
47
48 var notices []event.Event
49 sink := event.FuncSink(func(e event.Event) {
50 if e.Kind == event.Notice {
51 notices = append(notices, e)
52 }
53 })
54 var handledWarnings []string
55 opts := Options{Sink: sink, WorkspaceRoot: t.TempDir(), StatsSource: tt.statsSource}
56 if tt.handleWarnings {
57 opts.OnConfigLoadWarnings = func(warnings []string) bool {
58 handledWarnings = append([]string(nil), warnings...)
59 return true
60 }
61 }
62 ctrl, err := Build(context.Background(), opts)
63 if err != nil {
64 t.Fatalf("Build: %v", err)
65 }
66 ctrl.Close()
67
68 var migrationNotice *event.Event
69 for i := range notices {
70 if notices[i].Text == "DeepSeek protocol migration did not complete." {
71 migrationNotice = &notices[i]
72 break
73 }
74 }
75 if got := migrationNotice != nil; got != tt.wantNotice {
76 t.Fatalf("migration notice present = %v, want %v; notices=%+v", got, tt.wantNotice, notices)
77 }
78 if got := len(handledWarnings) > 0; got != tt.handleWarnings {
79 t.Fatalf("config warnings handled = %v, want %v; warnings=%v", got, tt.handleWarnings, handledWarnings)
80 }
81 if migrationNotice != nil &&
82 (migrationNotice.Level != event.LevelWarn || !strings.Contains(migrationNotice.Detail, "toml:")) {
83 t.Fatalf("migration notice lost parse diagnostics: %+v", *migrationNotice)
84 }
85 next, err := os.ReadFile(userPath)
86 if err != nil {
87 t.Fatal(err)
88 }
89 if string(next) != raw {
90 t.Fatalf("build rewrote malformed config:\n%s", next)
91 }
92 })
93 }
94 }
95
96 func TestBuildDeliversProjectConfigWarningsWithoutDeepSeekMigrationError(t *testing.T) {
97 home := isolateConfigHome(t)
98 t.Setenv("REASONIX_HOME", filepath.Join(home, "reasonix-home"))
99 workspace := t.TempDir()
100 projectPath := filepath.Join(workspace, "reasonix.toml")
101 raw := `[[plugins]]
102 name = "windows-mcp"
103 command = "C:\Users\reasonix\mcp.exe"
104 `
105 if err := os.WriteFile(projectPath, []byte(raw), 0o600); err != nil {
106 t.Fatal(err)
107 }
108
109 var handledWarnings []string
110 var notices []event.Event
111 ctrl, err := Build(context.Background(), Options{
112 WorkspaceRoot: workspace,
113 StatsSource: "desktop",
114 Sink: event.FuncSink(func(e event.Event) {
115 if e.Kind == event.Notice {
116 notices = append(notices, e)
117 }
118 }),
119 OnConfigLoadWarnings: func(warnings []string) bool {
120 handledWarnings = append([]string(nil), warnings...)
121 return true
122 },
123 })
124 if err != nil {
125 t.Fatalf("Build: %v", err)
126 }
127 ctrl.Close()
128
129 if len(handledWarnings) == 0 || !strings.Contains(strings.Join(handledWarnings, "\n"), "project config") {
130 t.Fatalf("project config warnings were not delivered: %v", handledWarnings)
131 }
132 for _, notice := range notices {
133 if notice.Text == "DeepSeek protocol migration did not complete." {
134 t.Fatalf("project config damage produced an unrelated migration notice: %+v", notice)
135 }
136 }
137 next, err := os.ReadFile(projectPath)
138 if err != nil {
139 t.Fatal(err)
140 }
141 if string(next) != raw {
142 t.Fatalf("build rewrote malformed project config:\n%s", next)
143 }
144 }
145
145 lines GO