package config import ( "strings" "testing" "time" ) func TestLoadConfigFromEnvAndArgs(t *testing.T) { cfg, err := Load([]string{"-node-name", "node-b"}, map[string]string{ "RAP_CLUSTER_ID": "cluster-1", "RAP_CLUSTER_AUTHORITY_PUBLIC_KEY": "public-key-b64", "RAP_CLUSTER_AUTHORITY_FINGERPRINT": "rap-ca-ed25519-test", "RAP_JOIN_TOKEN": "join-token", "RAP_NODE_NAME": "node-a", "RAP_NODE_STATE_DIR": "/tmp/rap-node", "RAP_WORKLOAD_SUPERVISION_ENABLED": "true", "RAP_WEB_INGRESS_RUNTIME_ENABLED": "true", "RAP_WEB_INGRESS_SIGNING_PRIVATE_KEY": " private-key-b64 ", "RAP_WEB_INGRESS_SIGNING_KEY_ID": " web-key-1 ", "RAP_WEB_INGRESS_TRUSTED_KEYS_JSON": ` {"web-key-1":"public-key-b64"} `, "RAP_WEB_INGRESS_RUNTIME_SERVICE_CLASSES": " platform_admin, cluster_admin ", "RAP_HEARTBEAT_INTERVAL_SECONDS": "7", "RAP_ENROLLMENT_POLL_INTERVAL_SECONDS": "3", "RAP_ENROLLMENT_POLL_TIMEOUT_SECONDS": "30", "RAP_FABRIC_RUNTIME_ENABLED": "true", "RAP_MESH_PRODUCTION_FORWARDING_ENABLED": "true", "RAP_VPN_FABRIC_SESSION_TRANSPORT_ENABLED": "true", "RAP_MESH_QUIC_FABRIC_ENABLED": "true", "RAP_MESH_QUIC_FABRIC_LISTEN_ADDR": ":19443", "RAP_VPN_FABRIC_SESSION_STREAM_SHARDS": "6", "RAP_VPN_FABRIC_QUIC_MAX_STREAMS_PER_CONN": "24", "RAP_VPN_FABRIC_QUIC_IDLE_TTL_SECONDS": "120", "RAP_MESH_PRODUCTION_OBSERVATION_SINK_CAPACITY": "5", "RAP_FABRIC_LISTEN_ADDR": "127.0.0.1:19001", "RAP_FABRIC_LISTEN_PORT_MODE": "auto", "RAP_FABRIC_LISTEN_AUTO_PORT_START": "19010", "RAP_FABRIC_LISTEN_AUTO_PORT_END": "19020", "RAP_MESH_ADVERTISE_ENDPOINT": "quic://node-a.example.test:19443/", "RAP_MESH_ADVERTISE_ENDPOINTS_JSON": `[{"endpoint_id":"node-a-lan","address":"10.10.0.20:19001"}]`, "RAP_FABRIC_REGISTRY_RECORDS_JSON": ` [{"schema":"rap.fabric.registry.gossip_record.v1","service_class":"control-api"}] `, "RAP_MESH_ADVERTISE_TRANSPORT": "direct_quic", "RAP_MESH_CONNECTIVITY_MODE": "outbound_only", "RAP_MESH_NAT_TYPE": "symmetric", "RAP_MESH_SITE_ID": "home", "RAP_MESH_LOCALITY_GROUP_ID": "home-lan", "RAP_MESH_NAT_GROUP_ID": "nat-a", "RAP_MESH_STUN_REFLEXIVE_ENDPOINT": "quic://203.0.113.20:19443/", "RAP_MESH_STUN_SERVER": "stun.example.test:3478", "RAP_MESH_RELAY_NODE_ID": "node-r", "RAP_MESH_RELAY_ENDPOINT": "quic://node-r.example.test:19443/", "RAP_MESH_REGION": "eu", "RAP_MESH_SYNTHETIC_CONFIG": "/tmp/rap-node/mesh-synthetic.json", "RAP_MESH_PEER_ENDPOINTS_JSON": `{"node-b":"quic://127.0.0.1:19002"}`, "RAP_MESH_SYNTHETIC_ROUTES_JSON": `[{"route_id":"route-1"}]`, "RAP_REMOTE_WORKSPACE_REAL_ADAPTER_ENABLED": "true", "RAP_REMOTE_WORKSPACE_REAL_ADAPTER_COMMAND": " /opt/rap/bin/rdp-worker ", "RAP_REMOTE_WORKSPACE_REAL_ADAPTER_ARGS_JSON": ` ["--future-probe"] `, "RAP_REMOTE_WORKSPACE_REAL_ADAPTER_WORKDIR": " /var/lib/rap-node-agent/rdp-worker ", }) if err != nil { t.Fatalf("load config: %v", err) } if cfg.NodeName != "node-b" { t.Fatalf("NodeName = %q", cfg.NodeName) } if cfg.ClusterAuthorityPublicKey != "public-key-b64" || cfg.ClusterAuthorityFingerprint != "rap-ca-ed25519-test" { t.Fatalf("unexpected cluster authority pin config: %+v", cfg) } if cfg.HeartbeatInterval != 7*time.Second { t.Fatalf("HeartbeatInterval = %s", cfg.HeartbeatInterval) } if cfg.EnrollmentPollInterval != 3*time.Second || cfg.EnrollmentPollTimeout != 30*time.Second { t.Fatalf("unexpected enrollment polling config: %+v", cfg) } if !cfg.WorkloadSupervisionEnabled { t.Fatal("WorkloadSupervisionEnabled = false, want true") } if !cfg.WebIngressRuntimeEnabled { t.Fatal("WebIngressRuntimeEnabled = false, want true") } if cfg.WebIngressSigningPrivateKey != "private-key-b64" || cfg.WebIngressSigningKeyID != "web-key-1" || cfg.WebIngressTrustedKeysJSON != `{"web-key-1":"public-key-b64"}` || cfg.WebIngressRuntimeServiceClasses != "platform_admin, cluster_admin" { t.Fatalf("unexpected web ingress key config: %+v", cfg) } if !cfg.FabricRuntimeEnabled { t.Fatal("FabricRuntimeEnabled = false, want true") } if !cfg.MeshProductionForwardingEnabled { t.Fatal("MeshProductionForwardingEnabled = false, want true") } if !cfg.VPNFabricSessionTransportEnabled { t.Fatal("VPNFabricSessionTransportEnabled = false, want true") } if !cfg.MeshQUICFabricEnabled || cfg.MeshQUICFabricListenAddr != ":19443" { t.Fatalf("unexpected QUIC fabric config: %+v", cfg) } if cfg.VPNFabricSessionStreamShards != 6 { t.Fatalf("VPNFabricSessionStreamShards = %d, want 6", cfg.VPNFabricSessionStreamShards) } if cfg.VPNFabricQUICMaxStreamsPerConn != 24 { t.Fatalf("VPNFabricQUICMaxStreamsPerConn = %d, want 24", cfg.VPNFabricQUICMaxStreamsPerConn) } if cfg.VPNFabricQUICIdleTTL != 120*time.Second { t.Fatalf("VPNFabricQUICIdleTTL = %s, want 120s", cfg.VPNFabricQUICIdleTTL) } if cfg.MeshProductionObservationSinkCapacity != 5 { t.Fatalf("MeshProductionObservationSinkCapacity = %d, want 5", cfg.MeshProductionObservationSinkCapacity) } if cfg.FabricListenAddr != "127.0.0.1:19001" { t.Fatalf("FabricListenAddr = %q", cfg.FabricListenAddr) } if cfg.FabricListenPortMode != "auto" || cfg.FabricListenAutoPortStart != 19010 || cfg.FabricListenAutoPortEnd != 19020 { t.Fatalf("unexpected fabric listen port config: %+v", cfg) } if cfg.MeshAdvertiseEndpoint != "quic://node-a.example.test:19443" || cfg.MeshAdvertiseEndpointsJSON == "" || cfg.FabricRegistryRecordsJSON != `[{"schema":"rap.fabric.registry.gossip_record.v1","service_class":"control-api"}]` || cfg.MeshAdvertiseTransport != "direct_quic" || cfg.MeshConnectivityMode != "outbound_only" || cfg.MeshNATType != "symmetric" || cfg.MeshSiteID != "home" || cfg.MeshLocalityGroupID != "home-lan" || cfg.MeshNATGroupID != "nat-a" || cfg.MeshSTUNReflexiveEndpoint != "quic://203.0.113.20:19443" || cfg.MeshSTUNServer != "stun.example.test:3478" || cfg.MeshRelayNodeID != "node-r" || cfg.MeshRelayEndpoint != "quic://node-r.example.test:19443" || cfg.MeshRegion != "eu" { t.Fatalf("unexpected mesh advertise config: %+v", cfg) } if cfg.MeshSyntheticConfigPath != "/tmp/rap-node/mesh-synthetic.json" { t.Fatalf("MeshSyntheticConfigPath = %q", cfg.MeshSyntheticConfigPath) } if cfg.MeshPeerEndpointsJSON == "" || cfg.MeshSyntheticRoutesJSON == "" { t.Fatalf("mesh live synthetic config was not loaded: %+v", cfg) } if !cfg.RemoteWorkspaceRealAdapterEnabled || cfg.RemoteWorkspaceRealAdapterCommand != "/opt/rap/bin/rdp-worker" || cfg.RemoteWorkspaceRealAdapterArgsJSON != `["--future-probe"]` || cfg.RemoteWorkspaceRealAdapterWorkDir != "/var/lib/rap-node-agent/rdp-worker" { t.Fatalf("unexpected remote workspace real adapter config: %+v", cfg) } } func TestLoadConfigLoadsLocalityGroup(t *testing.T) { cfg, err := Load(nil, map[string]string{ "RAP_NODE_NAME": "node-a", "RAP_FABRIC_REGISTRY_RECORDS_JSON": `[{"schema":"rap.fabric.registry.gossip_record.v1"}]`, "RAP_MESH_LOCALITY_GROUP_ID": "home-lan", }) if err != nil { t.Fatalf("load config: %v", err) } if cfg.MeshLocalityGroupID != "home-lan" { t.Fatalf("unexpected locality group: %+v", cfg) } } func TestLoadConfigDefaultsEnrollmentPollingToNoTimeout(t *testing.T) { cfg, err := Load(nil, map[string]string{ "RAP_NODE_NAME": "node-a", "RAP_FABRIC_REGISTRY_RECORDS_JSON": `[{"schema":"rap.fabric.registry.gossip_record.v1"}]`, }) if err != nil { t.Fatalf("load config: %v", err) } if cfg.EnrollmentPollTimeout != 0 { t.Fatalf("EnrollmentPollTimeout = %s, want no timeout", cfg.EnrollmentPollTimeout) } if cfg.RemoteWorkspaceRealAdapterEnabled || cfg.RemoteWorkspaceRealAdapterCommand != "" || cfg.RemoteWorkspaceRealAdapterArgsJSON != "" || cfg.RemoteWorkspaceRealAdapterWorkDir != "" { t.Fatalf("real adapter config should default disabled and empty: %+v", cfg) } if cfg.WebIngressRuntimeEnabled { t.Fatalf("web ingress runtime should default disabled: %+v", cfg) } } func TestLoadConfigRequiresFabricBootstrap(t *testing.T) { _, err := Load([]string{ "--node-name", "node-a", "--state-dir", t.TempDir(), "--fabric-registry-records-json", `[{"schema":"rap.fabric.registry.gossip_record.v1"}]`, }, map[string]string{}) if err != nil { t.Fatalf("load config: %v", err) } } func TestLoadConfigRejectsMissingFabricBootstrap(t *testing.T) { _, err := Load([]string{ "--node-name", "node-a", "--state-dir", t.TempDir(), }, map[string]string{}) if err == nil || !strings.Contains(err.Error(), "fabric registry records are required") { t.Fatalf("expected fabric validation error, got %v", err) } } func TestLoadConfigRejectsNegativeProductionObservationSinkCapacity(t *testing.T) { _, err := Load(nil, map[string]string{ "RAP_NODE_NAME": "node-a", "RAP_FABRIC_REGISTRY_RECORDS_JSON": `[{"schema":"rap.fabric.registry.gossip_record.v1"}]`, "RAP_MESH_PRODUCTION_OBSERVATION_SINK_CAPACITY": "-1", }) if err == nil { t.Fatal("Load returned nil error for negative sink capacity") } } func TestLoadConfigRejectsTooLargeProductionObservationSinkCapacity(t *testing.T) { _, err := Load(nil, map[string]string{ "RAP_NODE_NAME": "node-a", "RAP_FABRIC_REGISTRY_RECORDS_JSON": `[{"schema":"rap.fabric.registry.gossip_record.v1"}]`, "RAP_MESH_PRODUCTION_OBSERVATION_SINK_CAPACITY": "10001", }) if err == nil { t.Fatal("Load returned nil error for too-large sink capacity") } } func TestLoadConfigRejectsDisallowedMeshAdvertiseTransport(t *testing.T) { _, err := Load(nil, map[string]string{ "RAP_NODE_NAME": "node-a", "RAP_FABRIC_REGISTRY_RECORDS_JSON": `[{"schema":"rap.fabric.registry.gossip_record.v1"}]`, "RAP_MESH_ADVERTISE_ENDPOINT": "quic://node-a.example.test:19443", "RAP_MESH_ADVERTISE_TRANSPORT": "wss", }) if err == nil || !strings.Contains(err.Error(), "QUIC transport label") { t.Fatalf("expected QUIC transport rejection, got %v", err) } } func TestLoadConfigRejectsDisallowedMeshAdvertiseEndpointScheme(t *testing.T) { _, err := Load(nil, map[string]string{ "RAP_NODE_NAME": "node-a", "RAP_FABRIC_REGISTRY_RECORDS_JSON": `[{"schema":"rap.fabric.registry.gossip_record.v1"}]`, "RAP_MESH_ADVERTISE_ENDPOINT": "https://node-a.example.test:443", "RAP_MESH_ADVERTISE_TRANSPORT": "direct_quic", }) if err == nil || !strings.Contains(err.Error(), "QUIC endpoint") { t.Fatalf("expected QUIC endpoint rejection, got %v", err) } }