Skip to content
Open
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: 7 additions & 4 deletions platform-api/internal/server/overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"log/slog"
"net/http"
"sort"
"strings"

"github.com/wso2/api-platform/platform-api/internal/router"
)
Expand Down Expand Up @@ -56,10 +57,12 @@ func installCoreRoutes(
}
if len(unknown) > 0 {
sort.Strings(unknown)
p := unknown[0]
return fmt.Errorf("plugin %q declared a route override for %q, which is not a core route "+
"(patterns are matched exactly, including method and path; %d override(s) unmatched)",
overrides[p].plugin, p, len(unknown))
claims := make([]string, 0, len(unknown))
for _, pattern := range unknown {
claims = append(claims, fmt.Sprintf("plugin %q -> %q", overrides[pattern].plugin, pattern))
}
return fmt.Errorf("%d route override(s) name a pattern that is not a core route: %s",
len(unknown), strings.Join(claims, "; "))
}

// A duplicate pattern can now only come from a plugin route registered on
Expand Down
32 changes: 32 additions & 0 deletions platform-api/internal/server/overrides_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,38 @@ func TestInstallCoreRoutes_UnknownPatternAbortsStartup(t *testing.T) {
}
}

// One unmatched pattern per error would mean fixing a typo, restarting, and
// finding the next one — so the error names every unmatched override at once,
// each paired with the plugin that claimed it and ordered by pattern. The whole
// message is compared: a claim listing the wrong plugin, or claims in map order,
// is exactly what the operator reading it cannot afford.
func TestInstallCoreRoutes_UnknownPatternErrorNamesEveryOverride(t *testing.T) {
cloud := &overridePlugin{
fakePlugin: &fakePlugin{name: "cloud", spec: specWithScopes},
overrides: []pdk.RouteOverride{
{Pattern: "GET /api/v1/gateways/{gatewayId}", Wrap: passthrough},
{Pattern: "GET /api/v0.9/gateways/{id}", Wrap: passthrough},
},
}
audit := &overridePlugin{
fakePlugin: &fakePlugin{name: "audit", spec: specWithScopes},
overrides: []pdk.RouteOverride{{Pattern: "POST /api/v0.9/gateways", Wrap: passthrough}},
}

_, err := startup(t, coreRecorder(map[string]int{}), cloud, audit)
if err == nil {
t.Fatal("expected startup to abort, got nil error")
}

want := `3 route override(s) name a pattern that is not a core route: ` +
`plugin "cloud" -> "GET /api/v0.9/gateways/{id}"; ` +
`plugin "cloud" -> "GET /api/v1/gateways/{gatewayId}"; ` +
`plugin "audit" -> "POST /api/v0.9/gateways"`
if err.Error() != want {
t.Fatalf("error message mismatch\n got: %s\nwant: %s", err.Error(), want)
}
}

// Two decorators on one route would have to be ordered by something no plugin
// author can see, so this is a startup error naming both claimants.
func TestInitPlugins_TwoPluginsClaimingOnePatternAbortStartup(t *testing.T) {
Expand Down
Loading