package webingress import ( "context" "encoding/json" "errors" "net/http" "testing" "github.com/example/remote-access-platform/agents/rap-node-agent/internal/mesh" ) func TestMeshEnvelopeSenderSendsSignedEnvelopeOverReliableFabricRuntime(t *testing.T) { runtime := &recordingReliableRuntime{ result: mesh.FabricChannelRuntimeResult{ Channel: mesh.FabricChannel{RouteID: "route-fast", TargetNode: "node-runtime"}, BytesSent: 123, FramesSent: 1, AcksReceived: 1, }, } sender := MeshEnvelopeSender{ Runtime: runtime, RouteSet: testWebIngressRouteSet(), ClusterID: "cluster-1", SourceNodeID: "node-ingress", TargetKind: mesh.FabricChannelTargetPool, TargetID: "pool-admin-runtime", ChannelID: "channel-web-1", Now: fixedEnvelopeNow, } envelope := SignedFabricServiceChannelEnvelope{ SchemaVersion: "rap.web_ingress.signed_fabric_service_channel_envelope.v1", Envelope: FabricServiceChannelEnvelope{ SchemaVersion: FabricServiceChannelEnvelopeSchema, Scope: "platform", ServiceClass: "platform_admin", }, Signature: FabricEnvelopeSignature{KeyID: "node-key", Alg: "ed25519", Signature: "sig"}, } response, err := sender.Send(context.Background(), envelope) if err != nil { t.Fatalf("send: %v", err) } if response.StatusCode != http.StatusAccepted || response.Headers.Get("Content-Type") != "application/json" { t.Fatalf("response = %+v", response) } if runtime.spec.ChannelID != "channel-web-1" || runtime.spec.ClusterID != "cluster-1" || runtime.spec.SourceNodeID != "node-ingress" || runtime.spec.TargetID != "pool-admin-runtime" || runtime.spec.TargetKind != mesh.FabricChannelTargetPool || runtime.spec.TrafficClass != "control" || runtime.spec.StickyKey != "platform:platform_admin" { t.Fatalf("spec = %+v", runtime.spec) } if runtime.routeSet.TargetID != "pool-admin-runtime" || len(runtime.payloads) != 1 { t.Fatalf("route/payload = %+v payloads=%d", runtime.routeSet, len(runtime.payloads)) } var delivered SignedFabricServiceChannelEnvelope if err := json.Unmarshal(runtime.payloads[0], &delivered); err != nil { t.Fatalf("decode delivered envelope: %v", err) } if delivered.Signature.Signature != "sig" || delivered.Envelope.ServiceClass != "platform_admin" { t.Fatalf("delivered = %+v", delivered) } var body MeshEnvelopeDeliveryResponse if err := json.Unmarshal(response.Body, &body); err != nil { t.Fatalf("decode response: %v", err) } if body.SchemaVersion != "rap.web_ingress.mesh_envelope_delivery_response.v1" || body.Status != "accepted" || body.RouteID != "route-fast" || body.AcksReceived != 1 { t.Fatalf("body = %+v", body) } } func TestMeshEnvelopeSenderReturnsRuntimeHTTPResponse(t *testing.T) { runtime := &recordingRequestResponseRuntime{ result: mesh.FabricChannelRequestResponseResult{ FabricChannelRuntimeResult: mesh.FabricChannelRuntimeResult{ Channel: mesh.FabricChannel{RouteID: "route-runtime", TargetNode: "node-runtime"}, BytesSent: 123, BytesRecv: 16, FramesSent: 1, FramesRecv: 1, AcksReceived: 1, }, ResponsePayload: []byte(`{"payload":{"schema_version":"rap.web_ingress.fabric_runtime_response.v1","status_code":201,"headers":{"X-RAP-Runtime":["ok"],"Set-Cookie":["blocked"]},"body_b64":"eyJvayI6dHJ1ZX0="}}`), }, } sender := MeshEnvelopeSender{ ResponseRuntime: runtime, RouteSet: testWebIngressRouteSet(), ClusterID: "cluster-1", SourceNodeID: "node-ingress", TargetKind: mesh.FabricChannelTargetPool, TargetID: "pool-admin-runtime", ChannelID: "channel-web-1", Now: fixedEnvelopeNow, } response, err := sender.Send(context.Background(), SignedFabricServiceChannelEnvelope{ SchemaVersion: "rap.web_ingress.signed_fabric_service_channel_envelope.v1", Envelope: FabricServiceChannelEnvelope{SchemaVersion: FabricServiceChannelEnvelopeSchema, Scope: "platform", ServiceClass: "platform_admin"}, Signature: FabricEnvelopeSignature{KeyID: "node-key", Alg: "ed25519", Signature: "sig"}, }) if err != nil { t.Fatalf("send: %v", err) } if response.StatusCode != http.StatusCreated || response.Headers.Get("X-RAP-Runtime") != "ok" || response.Headers.Get("Set-Cookie") != "" || string(response.Body) != `{"ok":true}` { t.Fatalf("response = %+v body=%s", response, string(response.Body)) } if runtime.spec.ChannelID != "channel-web-1" || len(runtime.payload) == 0 { t.Fatalf("runtime spec=%+v payload=%s", runtime.spec, string(runtime.payload)) } } func TestMeshEnvelopeSenderReportsWrappedRuntimeError(t *testing.T) { sender := MeshEnvelopeSender{ ResponseRuntime: &recordingRequestResponseRuntime{ result: mesh.FabricChannelRequestResponseResult{ResponsePayload: []byte(`{"error":"runtime unavailable"}`)}, }, RouteSet: testWebIngressRouteSet(), ClusterID: "cluster-1", SourceNodeID: "node-ingress", TargetID: "pool-admin-runtime", ChannelID: "channel-web-1", } _, err := sender.Send(context.Background(), SignedFabricServiceChannelEnvelope{ Envelope: FabricServiceChannelEnvelope{Scope: "platform", ServiceClass: "platform_admin"}, }) if !errors.Is(err, ErrMeshEnvelopeRuntimeRequired) { t.Fatalf("err = %v", err) } } func TestMeshEnvelopeSenderFallsBackToDeliveryAckForNonHTTPRuntimePayload(t *testing.T) { runtime := &recordingRequestResponseRuntime{ result: mesh.FabricChannelRequestResponseResult{ FabricChannelRuntimeResult: mesh.FabricChannelRuntimeResult{ Channel: mesh.FabricChannel{RouteID: "route-runtime", TargetNode: "node-runtime"}, BytesSent: 123, FramesSent: 1, AcksReceived: 1, }, ResponsePayload: []byte(`{"not":"http"}`), }, } sender := MeshEnvelopeSender{ ResponseRuntime: runtime, RouteSet: testWebIngressRouteSet(), ClusterID: "cluster-1", SourceNodeID: "node-ingress", TargetID: "pool-admin-runtime", ChannelID: "channel-web-1", } response, err := sender.Send(context.Background(), SignedFabricServiceChannelEnvelope{ Envelope: FabricServiceChannelEnvelope{Scope: "platform", ServiceClass: "platform_admin"}, }) if err != nil { t.Fatalf("send: %v", err) } if response.StatusCode != http.StatusAccepted { t.Fatalf("response = %+v", response) } var body MeshEnvelopeDeliveryResponse if err := json.Unmarshal(response.Body, &body); err != nil { t.Fatalf("decode response: %v", err) } if body.Status != "accepted" || body.RouteID != "route-runtime" { t.Fatalf("body = %+v", body) } } func TestMeshEnvelopeSenderReportsRuntimeRouteAndIdentityErrors(t *testing.T) { _, err := (MeshEnvelopeSender{}).Send(context.Background(), SignedFabricServiceChannelEnvelope{}) if !errors.Is(err, ErrMeshEnvelopeRuntimeRequired) { t.Fatalf("runtime error = %v", err) } _, err = (MeshEnvelopeSender{ Runtime: &recordingReliableRuntime{}, ClusterID: "cluster-1", SourceNodeID: "node-ingress", TargetID: "pool-admin-runtime", }).Send(context.Background(), SignedFabricServiceChannelEnvelope{}) if !errors.Is(err, ErrMeshEnvelopeRouteRequired) { t.Fatalf("route error = %v", err) } _, err = (MeshEnvelopeSender{ Runtime: &recordingReliableRuntime{}, RouteSet: testWebIngressRouteSet(), }).Send(context.Background(), SignedFabricServiceChannelEnvelope{}) if !errors.Is(err, ErrMeshEnvelopeIdentityInvalid) { t.Fatalf("identity error = %v", err) } } func TestMeshEnvelopeSenderPropagatesReliableRuntimeFailure(t *testing.T) { sendErr := errors.New("send failed") _, err := (MeshEnvelopeSender{ Runtime: &recordingReliableRuntime{err: sendErr}, RouteSet: testWebIngressRouteSet(), ClusterID: "cluster-1", SourceNodeID: "node-ingress", TargetID: "pool-admin-runtime", }).Send(context.Background(), SignedFabricServiceChannelEnvelope{}) if !errors.Is(err, sendErr) { t.Fatalf("send error = %v", err) } } type recordingReliableRuntime struct { spec mesh.FabricChannelSpec routeSet mesh.FabricRouteSet payloads [][]byte result mesh.FabricChannelRuntimeResult err error } type recordingRequestResponseRuntime struct { spec mesh.FabricChannelSpec routeSet mesh.FabricRouteSet payload []byte result mesh.FabricChannelRequestResponseResult err error } func (r *recordingRequestResponseRuntime) SendRequestResponse(_ context.Context, spec mesh.FabricChannelSpec, routeSet mesh.FabricRouteSet, payload []byte) (mesh.FabricChannelRequestResponseResult, error) { r.spec = spec r.routeSet = routeSet r.payload = payload if r.err != nil { return mesh.FabricChannelRequestResponseResult{}, r.err } return r.result, nil } func (r *recordingReliableRuntime) SendReliable(_ context.Context, spec mesh.FabricChannelSpec, routeSet mesh.FabricRouteSet, payloads [][]byte) (mesh.FabricChannelRuntimeResult, error) { r.spec = spec r.routeSet = routeSet r.payloads = payloads if r.err != nil { return mesh.FabricChannelRuntimeResult{}, r.err } return r.result, nil } func testWebIngressRouteSet() mesh.FabricRouteSet { return mesh.FabricRouteSet{ Primary: mesh.FabricRoute{ RouteID: "route-fast", ClusterID: "cluster-1", SourceNodeID: "node-ingress", DestinationNodeID: "node-runtime", PoolID: "pool-admin-runtime", Healthy: true, Capacity: 100, }, } }