1package config
2
3import (
4 "os"
5 "path/filepath"
6 "testing"
7
8 "charm.land/catwalk/pkg/catwalk"
9 "github.com/charmbracelet/crush/internal/env"
10 "github.com/stretchr/testify/require"
11)
12
13func TestIsDockerMCPEnabled(t *testing.T) {
14 t.Parallel()
15
16 t.Run("returns false when MCP is nil", func(t *testing.T) {
17 t.Parallel()
18 cfg := &Config{
19 MCP: nil,
20 }
21 require.False(t, cfg.IsDockerMCPEnabled())
22 })
23
24 t.Run("returns false when docker mcp not configured", func(t *testing.T) {
25 t.Parallel()
26 cfg := &Config{
27 MCP: make(map[string]MCPConfig),
28 }
29 require.False(t, cfg.IsDockerMCPEnabled())
30 })
31
32 t.Run("returns true when docker mcp is configured", func(t *testing.T) {
33 t.Parallel()
34 cfg := &Config{
35 MCP: map[string]MCPConfig{
36 DockerMCPName: {
37 Type: MCPStdio,
38 Command: "docker",
39 },
40 },
41 }
42 require.True(t, cfg.IsDockerMCPEnabled())
43 })
44}
45
46func TestEnableDockerMCP(t *testing.T) {
47 t.Parallel()
48
49 t.Run("adds docker mcp to config", func(t *testing.T) {
50 t.Parallel()
51
52 // Create a temporary directory for config.
53 tmpDir := t.TempDir()
54 configPath := filepath.Join(tmpDir, "crush.json")
55
56 cfg := &Config{
57 MCP: make(map[string]MCPConfig),
58 dataConfigDir: configPath,
59 resolver: NewShellVariableResolver(env.New()),
60 knownProviders: []catwalk.Provider{},
61 }
62
63 // Only run this test if docker mcp is available.
64 if !IsDockerMCPAvailable() {
65 t.Skip("Docker MCP not available, skipping test")
66 }
67
68 err := cfg.EnableDockerMCP()
69 require.NoError(t, err)
70
71 // Check in-memory config.
72 require.True(t, cfg.IsDockerMCPEnabled())
73 mcpConfig, exists := cfg.MCP[DockerMCPName]
74 require.True(t, exists)
75 require.Equal(t, MCPStdio, mcpConfig.Type)
76 require.Equal(t, "docker", mcpConfig.Command)
77 require.Equal(t, []string{"mcp", "gateway", "run"}, mcpConfig.Args)
78 require.False(t, mcpConfig.Disabled)
79
80 // Check persisted config.
81 data, err := os.ReadFile(configPath)
82 require.NoError(t, err)
83 require.Contains(t, string(data), "docker")
84 require.Contains(t, string(data), "gateway")
85 })
86
87 t.Run("fails when docker mcp not available", func(t *testing.T) {
88 t.Parallel()
89
90 // Create a temporary directory for config.
91 tmpDir := t.TempDir()
92 configPath := filepath.Join(tmpDir, "crush.json")
93
94 cfg := &Config{
95 MCP: make(map[string]MCPConfig),
96 dataConfigDir: configPath,
97 resolver: NewShellVariableResolver(env.New()),
98 knownProviders: []catwalk.Provider{},
99 }
100
101 // Skip if docker mcp is actually available.
102 if IsDockerMCPAvailable() {
103 t.Skip("Docker MCP is available, skipping unavailable test")
104 }
105
106 err := cfg.EnableDockerMCP()
107 require.Error(t, err)
108 require.Contains(t, err.Error(), "docker mcp is not available")
109 })
110}
111
112func TestDisableDockerMCP(t *testing.T) {
113 t.Parallel()
114
115 t.Run("removes docker mcp from config", func(t *testing.T) {
116 t.Parallel()
117
118 // Create a temporary directory for config.
119 tmpDir := t.TempDir()
120 configPath := filepath.Join(tmpDir, "crush.json")
121
122 cfg := &Config{
123 MCP: map[string]MCPConfig{
124 DockerMCPName: {
125 Type: MCPStdio,
126 Command: "docker",
127 Args: []string{"mcp", "gateway", "run"},
128 Disabled: false,
129 },
130 },
131 dataConfigDir: configPath,
132 resolver: NewShellVariableResolver(env.New()),
133 knownProviders: []catwalk.Provider{},
134 }
135
136 // Verify it's enabled first.
137 require.True(t, cfg.IsDockerMCPEnabled())
138
139 err := cfg.DisableDockerMCP()
140 require.NoError(t, err)
141
142 // Check in-memory config.
143 require.False(t, cfg.IsDockerMCPEnabled())
144 _, exists := cfg.MCP[DockerMCPName]
145 require.False(t, exists)
146 })
147
148 t.Run("does nothing when MCP is nil", func(t *testing.T) {
149 t.Parallel()
150
151 cfg := &Config{
152 MCP: nil,
153 dataConfigDir: t.TempDir() + "/crush.json",
154 resolver: NewShellVariableResolver(env.New()),
155 knownProviders: []catwalk.Provider{},
156 }
157
158 err := cfg.DisableDockerMCP()
159 require.NoError(t, err)
160 })
161}