213 lines
7.4 KiB
Go
213 lines
7.4 KiB
Go
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" }
|