test(0145): unit + integration + launcher + claudecode coverage

cmd/devicemesh-mcp/main_test.go (10 tests):
- TestInitialize: JSON-RPC initialize frame → serverInfo + capabilities.
- TestToolsList: tools/list → 16 user-mode entries, cada uno con name +
  inputSchema valido.
- TestToolsCallExec: tools/call name=exec → mock device-agent (httptest)
  recibe capability=shell.exec, MCP response content contiene "hi".
- TestToolsCallInvalidTool: name desconocido → isError o error envelope.
- TestNotificationsInitializedNoResponse: notification (sin id) → cero
  responses.
- TestUserModeFiltersPkgInstall: --mode user oculta pkg.install,
  --mode sudo la expone.
- TestToolsAllowedNarrows: --tools-allowed exec,fs.read → solo 2.
- TestSplitCSV, TestParseMode, TestIsCleanShutdown: helpers.

cmd/devicemesh-mcp/integration_test.go:
- TestIntegrationBinarySubprocess: build el binario en tmp + spawn como
  child via exec.Command + pipe real + secuencia initialize ->
  notifications/initialized -> tools/list -> tools/call. Valida el path
  identico al que usara claude.

devagents/mcp_bridge_test.go (9 tests):
- Disabled paths (nil DM, ExposeViaMCP=false, provider!=claude-code).
- Applied path: /tmp/<agent>-mcp-config.json JSON valido, mode 0600,
  mcpServers.devicemesh con command apuntando al binario fake.
- AllowedTools formato mcp__<server>__<tool>.
- DisableTools=true overrideado a false.
- URLEnv override gana sobre YAML.
- Binary missing → ok=false sin panico.
- BuildClaudeAllowedToolNames default server name.
- ResolveBridgedToolNames respeta mode + ToolsAllowed.
- ShouldExposeViaMCP cubre nil/disabled/default/explicit-true/false.

shell/llm/claudecode_test.go:
- TestBuildClaudeArgs_DisableTools actualizado: solo emite --tools "" cuando
  AllowedTools ESTA vacio. La regla nueva (issue 0145) da precedencia a
  AllowedTools.
- Anadido TestBuildClaudeArgs_DisableToolsButAllowedToolsWins.
- Anadido TestBuildClaudeArgs_MCPConfigPath.

bridge.go fix: cambio NewTool + WithRawInputSchema a NewToolWithRawSchema
porque NewTool inicializa ToolInputSchema.Type="object" por default, lo
cual entra en conflicto con RawInputSchema en MarshalJSON del SDK.

Suite completa pasa con -tags goolm -count=1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-24 18:33:24 +02:00
parent b92a350023
commit d1fd78324b
5 changed files with 962 additions and 14 deletions
+36 -6
View File
@@ -62,23 +62,53 @@ func TestBuildClaudeArgs_AllOptions(t *testing.T) {
}
func TestBuildClaudeArgs_DisableTools(t *testing.T) {
// DisableTools alone (no AllowedTools) → --tools "".
cfg := config.ClaudeCodeCfg{
DisableTools: true,
AllowedTools: []string{"Bash"}, // should be ignored
}
req := coretypes.CompletionRequest{}
args := buildClaudeArgs(cfg, req)
args := buildClaudeArgs(cfg, coretypes.CompletionRequest{})
assertContains(t, args, "--tools", "")
// --allowedTools must NOT appear when disable_tools is set
for _, a := range args {
if a == "--allowedTools" {
t.Error("--allowedTools should not appear when DisableTools=true")
t.Error("--allowedTools should not appear when DisableTools=true and AllowedTools is empty")
}
}
}
func TestBuildClaudeArgs_DisableToolsButAllowedToolsWins(t *testing.T) {
// Issue 0145: DisableTools=true plus a non-empty AllowedTools is a
// contradiction the launcher's ApplyMCPBridge guards against. The
// builder itself now also gives AllowedTools priority (precedence
// matches the launcher) so direct callers cannot accidentally produce
// the broken `--tools "" --allowedTools ...` combo.
cfg := config.ClaudeCodeCfg{
DisableTools: true,
AllowedTools: []string{"Bash"},
}
args := buildClaudeArgs(cfg, coretypes.CompletionRequest{})
for _, a := range args {
if a == "--tools" {
t.Error("--tools should not appear once AllowedTools is non-empty (AllowedTools wins)")
}
}
assertContains(t, args, "--allowedTools", "Bash")
}
func TestBuildClaudeArgs_MCPConfigPath(t *testing.T) {
// Issue 0145: --mcp-config is emitted whenever MCPConfigPath is set so
// claude knows how to spawn the per-agent devicemesh MCP server.
cfg := config.ClaudeCodeCfg{
MCPConfigPath: "/tmp/agent-x-mcp-config.json",
AllowedTools: []string{"mcp__devicemesh__exec"},
}
args := buildClaudeArgs(cfg, coretypes.CompletionRequest{})
assertContains(t, args, "--mcp-config", "/tmp/agent-x-mcp-config.json")
assertContains(t, args, "--allowedTools", "mcp__devicemesh__exec")
}
func TestBuildClaudeArgs_DisallowedTools(t *testing.T) {
cfg := config.ClaudeCodeCfg{
DisallowedTools: []string{"Edit", "Write"},