package webingress import ( "context" "encoding/json" "net/http" "testing" ) func TestAdminRuntimeDispatcherReturnsHealthAndManifest(t *testing.T) { dispatcher := AdminRuntimeDispatcher{Now: fixedEnvelopeNow} health, err := dispatcher.HandleFabricRequest(context.Background(), FabricRequest{ Method: http.MethodGet, Path: "/readyz", Scope: "platform", ServiceClass: "platform_admin", }) if err != nil { t.Fatalf("health: %v", err) } if health.StatusCode != http.StatusOK { t.Fatalf("health = %+v", health) } manifest, err := dispatcher.HandleFabricRequest(context.Background(), FabricRequest{ Method: http.MethodGet, Path: "/platform-admin/ui-manifest", Scope: "platform", ServiceClass: "platform_admin", }) if err != nil { t.Fatalf("manifest: %v", err) } var payload AdminRuntimeJSONResponse if err := json.Unmarshal(manifest.Body, &payload); err != nil { t.Fatalf("decode manifest: %v", err) } if manifest.StatusCode != http.StatusOK || payload.SchemaVersion != AdminRuntimeResponseSchema || payload.Status != "ready" || payload.Reason != "ui_manifest_ready" || payload.Manifest["schema_version"] != "rap.web_ingress.ui_manifest.v1" || payload.Manifest["mutation_enabled"] != false { t.Fatalf("payload = %+v status=%d", payload, manifest.StatusCode) } } func TestAdminRuntimeDispatcherBlocksMutationsAndUnknownProjection(t *testing.T) { dispatcher := AdminRuntimeDispatcher{Now: fixedEnvelopeNow} mutation, err := dispatcher.HandleFabricRequest(context.Background(), FabricRequest{ Method: http.MethodPost, Path: "/platform-admin/nodes", Scope: "platform", ServiceClass: "platform_admin", }) if err != nil { t.Fatalf("mutation: %v", err) } var mutationPayload AdminRuntimeJSONResponse if err := json.Unmarshal(mutation.Body, &mutationPayload); err != nil { t.Fatalf("decode mutation: %v", err) } if mutation.StatusCode != http.StatusForbidden || mutationPayload.Reason != "control_api_mutation_binding_not_implemented" { t.Fatalf("mutation payload = %+v status=%d", mutationPayload, mutation.StatusCode) } projection, err := dispatcher.HandleFabricRequest(context.Background(), FabricRequest{ Method: http.MethodGet, Path: "/platform-admin/nodes", Scope: "platform", ServiceClass: "platform_admin", }) if err != nil { t.Fatalf("projection: %v", err) } var projectionPayload AdminRuntimeJSONResponse if err := json.Unmarshal(projection.Body, &projectionPayload); err != nil { t.Fatalf("decode projection: %v", err) } if projection.StatusCode != http.StatusNotImplemented || projectionPayload.Reason != "control_api_projection_binding_not_implemented" { t.Fatalf("projection payload = %+v status=%d", projectionPayload, projection.StatusCode) } } func TestAdminRuntimeDispatcherRejectsInvalidScopeClassPair(t *testing.T) { dispatcher := AdminRuntimeDispatcher{ProjectionClient: &recordingProjectionClient{}, Now: fixedEnvelopeNow} response, err := dispatcher.HandleFabricRequest(context.Background(), FabricRequest{ Method: http.MethodGet, Path: "/platform-admin/ui-manifest", Scope: "organization", ServiceClass: "platform_admin", }) if err != nil { t.Fatalf("projection: %v", err) } var payload AdminRuntimeJSONResponse if err := json.Unmarshal(response.Body, &payload); err != nil { t.Fatalf("decode response: %v", err) } if response.StatusCode != http.StatusForbidden || payload.Reason != "admin_runtime_scope_rejected" { t.Fatalf("payload = %+v status=%d", payload, response.StatusCode) } } func TestAdminRuntimeDispatcherUsesControlAPIProjectionClientForReadRequests(t *testing.T) { client := &recordingProjectionClient{ response: ControlAPIProjectionResponse{ SchemaVersion: ControlAPIProjectionResponseSchema, Status: "ready", StatusCode: http.StatusOK, Headers: map[string]string{"X-RAP-Projection": "control-api", "Set-Cookie": "blocked"}, Body: json.RawMessage(`{"schema_version":"control.projection.v1","ok":true}`), }, } dispatcher := AdminRuntimeDispatcher{ProjectionClient: client, Now: fixedEnvelopeNow} response, err := dispatcher.HandleFabricRequest(context.Background(), FabricRequest{ Method: http.MethodGet, Path: "/platform-admin/nodes", Query: "limit=10", Host: "admin.example.test", Scope: "platform", ServiceClass: "platform_admin", }) if err != nil { t.Fatalf("projection: %v", err) } if response.StatusCode != http.StatusOK || response.Headers.Get("X-RAP-Projection") != "control-api" || response.Headers.Get("Set-Cookie") != "" || string(response.Body) != `{"schema_version":"control.projection.v1","ok":true}` { t.Fatalf("response = %+v body=%s", response, string(response.Body)) } if client.request.Path != "/platform-admin/nodes" || client.request.Query != "limit=10" || client.request.Scope != "platform" || client.request.ServiceClass != "platform_admin" { t.Fatalf("request = %+v", client.request) } } func TestAdminRuntimeDispatcherReportsProjectionClientFailure(t *testing.T) { dispatcher := AdminRuntimeDispatcher{ProjectionClient: failingProjectionClient{}, Now: fixedEnvelopeNow} response, err := dispatcher.HandleFabricRequest(context.Background(), FabricRequest{ Method: http.MethodGet, Path: "/platform-admin/nodes", Scope: "platform", ServiceClass: "platform_admin", }) if err != nil { t.Fatalf("projection: %v", err) } var payload AdminRuntimeJSONResponse if err := json.Unmarshal(response.Body, &payload); err != nil { t.Fatalf("decode response: %v", err) } if response.StatusCode != http.StatusBadGateway || payload.Reason != "control_api_projection_failed" { t.Fatalf("payload = %+v status=%d", payload, response.StatusCode) } } func TestAdminRuntimeDispatcherRejectsInvalidProjectionResponseSchema(t *testing.T) { dispatcher := AdminRuntimeDispatcher{ ProjectionClient: &recordingProjectionClient{ response: ControlAPIProjectionResponse{ SchemaVersion: "wrong.schema", Status: "ready", StatusCode: http.StatusOK, Body: json.RawMessage(`{"ok":true}`), }, }, Now: fixedEnvelopeNow, } response, err := dispatcher.HandleFabricRequest(context.Background(), FabricRequest{ Method: http.MethodGet, Path: "/platform-admin/nodes", Scope: "platform", ServiceClass: "platform_admin", }) if err != nil { t.Fatalf("projection: %v", err) } var payload AdminRuntimeJSONResponse if err := json.Unmarshal(response.Body, &payload); err != nil { t.Fatalf("decode response: %v", err) } if response.StatusCode != http.StatusBadGateway || payload.Reason != "control_api_projection_invalid_response" { t.Fatalf("payload = %+v status=%d", payload, response.StatusCode) } } type recordingProjectionClient struct { request ControlAPIProjectionRequest response ControlAPIProjectionResponse } func (c *recordingProjectionClient) Project(_ context.Context, request ControlAPIProjectionRequest) (ControlAPIProjectionResponse, error) { c.request = request return c.response, nil } type failingProjectionClient struct{} func (failingProjectionClient) Project(context.Context, ControlAPIProjectionRequest) (ControlAPIProjectionResponse, error) { return ControlAPIProjectionResponse{}, errTestProjectionFailure{} } type errTestProjectionFailure struct{} func (errTestProjectionFailure) Error() string { return "projection failed" }