Files
rdp-proxy/agents/rap-node-agent/internal/webingress/admin_runtime_test.go
T

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" }