Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ func SetRegion(r string) {
region = r
}

// SetGraphqlEndpointForTesting overrides the GraphQL endpoint URL and
// returns a function that restores the prior value. Intended only for
// tests that need to point the api package at an httptest.Server from a
// different test package (notably ui flow tests that drive a tea.Cmd which
// internally calls into api). Production code MUST NOT call this.
func SetGraphqlEndpointForTesting(url string) (restore func()) {
prev := graphqlEndpoint
graphqlEndpoint = url
return func() { graphqlEndpoint = prev }
}

// NavItem is a navigable node in the APS Manufacturing Data Model hierarchy.
type NavItem struct {
ID string
Expand Down
8 changes: 4 additions & 4 deletions fusion/mcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,16 +158,16 @@ func (c *Client) ActiveHubProjects(ctx context.Context) ([]HubProject, error) {
if tr == nil || len(tr.Content) == 0 {
return nil, errors.New("fusion MCP: empty projects response")
}
// success:false payloads (with or without an error string) are caught
// upstream by parseToolErrorText in callTool and surfaced as an error
// from c.invoke above, so we only reach this point on a success path —
// no need for a per-method success guard here.
var payload struct {
Success *bool `json:"success"`
Projects []HubProject `json:"projects"`
}
if err := json.Unmarshal([]byte(tr.Content[0].Text), &payload); err != nil {
return nil, fmt.Errorf("fusion MCP: decoding projects: %w", err)
}
if payload.Success != nil && !*payload.Success {
return nil, errors.New("fusion MCP: projects query failed")
}
return payload.Projects, nil
}

Expand Down
13 changes: 5 additions & 8 deletions fusion/mcp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,14 +346,11 @@ func TestActiveHubProjects_SuccessFalse(t *testing.T) {
if err == nil {
t.Fatal("ActiveHubProjects: expected error for success:false, got nil")
}
// Subtlety: callTool's parseToolErrorText branch fires first on success:false
// payloads, surfacing them as "tool reported failure" before the per-method
// "projects query failed" branch in ActiveHubProjects ever runs. Either
// message indicates the failure was caught — assert on either to remain
// resilient to whichever guard short-circuits first.
msg := err.Error()
if !strings.Contains(msg, "projects query failed") && !strings.Contains(msg, "tool reported failure") {
t.Errorf("ActiveHubProjects: error %q does not contain \"projects query failed\" or \"tool reported failure\"", msg)
// callTool's parseToolErrorText catches {success:false} (no error field)
// and surfaces it as "tool reported failure". The per-method success
// guard in ActiveHubProjects was removed because it was unreachable.
if msg := err.Error(); !strings.Contains(msg, "tool reported failure") {
t.Errorf("ActiveHubProjects: error %q does not contain %q", msg, "tool reported failure")
}
}

Expand Down
Loading
Loading