docker_mcp_test.go

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