package provider import ( "context" "encoding/json" "net/http" "net/http/httptest" "testing" "github.com/kami/hexis/internal/domain" ) func newWorkspaceTestServer(t *testing.T, status int, body map[string]any) (*httptest.Server, *WorkspaceMCPProvider) { t.Helper() srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(status) json.NewEncoder(w).Encode(body) })) t.Cleanup(srv.Close) allowlist := ToolAllowlist{Tools: map[string]ToolMapping{ "workspace_tool": {Capability: "ws.do_thing", Risk: "write", ReadOnly: false}, }} return srv, NewWorkspaceMCPProvider(srv.URL, allowlist) } func TestExecute_SucceedsOnPlainResult(t *testing.T) { _, p := newWorkspaceTestServer(t, http.StatusOK, map[string]any{ "summary": "ok", "items": []any{}, "warnings": []any{}, "truncated": false, }) cap := &domain.Capability{Name: "ws.do_thing"} result, err := p.Execute(context.Background(), cap, &domain.ExecuteRequest{}) if err != nil { t.Fatalf("expected no error, got %v", err) } if result == nil { t.Fatal("expected non-nil result") } } // TestExecute_ErrorEnvelopeReportedAsFailure verifies that a 200 response // carrying workspace-mcp's ERROR-coded warning envelope (its convention for // tool-handler exceptions) is treated as a failed execution, not a success. func TestExecute_ErrorEnvelopeReportedAsFailure(t *testing.T) { _, p := newWorkspaceTestServer(t, http.StatusOK, map[string]any{ "summary": "boom", "items": []any{}, "warnings": []any{ map[string]any{"code": "ERROR", "message": "boom"}, }, "truncated": false, }) cap := &domain.Capability{Name: "ws.do_thing"} _, err := p.Execute(context.Background(), cap, &domain.ExecuteRequest{}) if err == nil { t.Fatal("expected error for ERROR-coded warning envelope, got nil") } }