Refactor RDP proxy handling and update related tests
This commit is contained in:
@@ -0,0 +1,267 @@
|
||||
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,
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user