返回 DeepSeek-Reasonix
mcp_remove_oauth_test.go
根目录 / desktop / mcp_remove_oauth_test.go
1 package main
2
3 import (
4 "errors"
5 "fmt"
6 "os"
7 "path/filepath"
8 "testing"
9
10 "reasonix/internal/config"
11 "reasonix/internal/control"
12 "reasonix/internal/plugin"
13 )
14
15 func TestRemoveMCPServerReconcilesOAuthState(t *testing.T) {
16 for _, keepFallback := range []bool{false, true} {
17 t.Run(fmt.Sprintf("keep-fallback-%v", keepFallback), func(t *testing.T) {
18 isolateDesktopUserDirs(t)
19 root, name, resource := robustTempDir(t), "shared", "https://mcp.example.test/mcp"
20 t.Chdir(root)
21 if keepFallback {
22 cfg := config.LoadForEdit(config.UserConfigPath())
23 cfg.Plugins = []config.PluginEntry{{Name: name, Type: "http", URL: resource}}
24 if err := cfg.SaveTo(config.UserConfigPath()); err != nil {
25 t.Fatal(err)
26 }
27 }
28 project := fmt.Sprintf("[[plugins]]\nname = %q\ntype = \"http\"\nurl = %q\n", name, resource)
29 if err := os.WriteFile(filepath.Join(root, "reasonix.toml"), []byte(project), 0o644); err != nil {
30 t.Fatal(err)
31 }
32 stateDir := plugin.MCPStateDir(config.ReasonixHomeDir(), root, name)
33 if err := os.MkdirAll(stateDir, 0o700); err != nil {
34 t.Fatal(err)
35 }
36 statePath := filepath.Join(stateDir, "oauth.json")
37 if err := os.WriteFile(statePath, fmt.Appendf(nil, `{"version":1,"resource":%q,"access_token":"private"}`, resource), 0o600); err != nil {
38 t.Fatal(err)
39 }
40
41 app := NewApp()
42 app.setTestCtrl(control.New(control.Options{Host: plugin.NewHost(), WorkspaceRoot: root}), "")
43 defer app.activeCtrl().Close()
44 app.activeTab().WorkspaceRoot = root
45 if err := app.RemoveMCPServer(name); err != nil {
46 t.Fatal(err)
47 }
48 _, statErr := os.Stat(statePath)
49 if keepFallback && statErr != nil || !keepFallback && !errors.Is(statErr, os.ErrNotExist) {
50 t.Fatalf("OAuth state after removal: keep=%v err=%v", keepFallback, statErr)
51 }
52 })
53 }
54 }
55
56 func TestRemoveMCPServerReconcilesOAuthStateAcrossWorkspaceRuntimes(t *testing.T) {
57 isolateDesktopUserDirs(t)
58 activeRoot, otherRoot := robustTempDir(t), robustTempDir(t)
59 name, resource := "shared", "https://mcp.example.test/mcp"
60 t.Chdir(activeRoot)
61 project := fmt.Sprintf("[[plugins]]\nname = %q\ntype = \"http\"\nurl = %q\n", name, resource)
62 if err := os.WriteFile(filepath.Join(activeRoot, "reasonix.toml"), []byte(project), 0o644); err != nil {
63 t.Fatal(err)
64 }
65 for _, root := range []string{activeRoot, otherRoot} {
66 stateDir := plugin.MCPStateDir(config.ReasonixHomeDir(), root, name)
67 if err := os.MkdirAll(stateDir, 0o700); err != nil {
68 t.Fatal(err)
69 }
70 statePath := filepath.Join(stateDir, "oauth.json")
71 if err := os.WriteFile(statePath, fmt.Appendf(nil, `{"version":1,"resource":%q,"access_token":"private"}`, resource), 0o600); err != nil {
72 t.Fatal(err)
73 }
74 }
75
76 app := NewApp()
77 active := control.New(control.Options{Host: plugin.NewHost(), WorkspaceRoot: activeRoot})
78 app.setTestCtrl(active, "")
79 defer active.Close()
80 app.activeTab().WorkspaceRoot = activeRoot
81 app.tabs["other"] = &WorkspaceTab{ID: "other", WorkspaceRoot: otherRoot}
82 if err := app.RemoveMCPServer(name); err != nil {
83 t.Fatal(err)
84 }
85 for _, root := range []string{activeRoot, otherRoot} {
86 statePath := filepath.Join(plugin.MCPStateDir(config.ReasonixHomeDir(), root, name), "oauth.json")
87 if _, err := os.Stat(statePath); !errors.Is(err, os.ErrNotExist) {
88 t.Fatalf("OAuth state for workspace %q still exists: %v", root, err)
89 }
90 }
91 }
92
92 lines GO