268 lines
8.9 KiB
Go
268 lines
8.9 KiB
Go
package mesh
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestLoadScopedSyntheticConfig(t *testing.T) {
|
|
expiresAt := time.Now().UTC().Add(time.Hour)
|
|
path := writeScopedConfig(t, ScopedSyntheticConfig{
|
|
SchemaVersion: "c17f.synthetic.v1",
|
|
ClusterID: "cluster-1",
|
|
LocalNodeID: "node-a",
|
|
ConfigVersion: "config-v1",
|
|
PeerDirectoryVersion: "peers-v1",
|
|
PolicyVersion: "policy-v1",
|
|
PeerEndpoints: map[string]string{"node-b": "http://127.0.0.1:19002"},
|
|
PeerEndpointCandidates: map[string][]PeerEndpointCandidate{
|
|
"node-b": {
|
|
{
|
|
EndpointID: "node-b-public",
|
|
NodeID: "node-b",
|
|
Transport: "direct_tcp_tls",
|
|
Address: "203.0.113.20:443",
|
|
Reachability: "public",
|
|
NATType: "restricted",
|
|
ConnectivityMode: "direct",
|
|
Priority: 10,
|
|
},
|
|
},
|
|
},
|
|
PeerEndpointObservations: map[string]EndpointCandidateHealthObservation{
|
|
"node-b-public": {
|
|
EndpointID: "node-b-public",
|
|
LastLatencyMs: 42,
|
|
SuccessCount: 3,
|
|
ReliabilityScore: 95,
|
|
ObservedAt: expiresAt.Add(-time.Minute),
|
|
},
|
|
},
|
|
PeerDirectory: []PeerDirectoryEntry{
|
|
{
|
|
NodeID: "node-b",
|
|
RouteIDs: []string{"route-a-b"},
|
|
EndpointCount: 1,
|
|
CandidateCount: 1,
|
|
ConnectivityModes: []string{"direct"},
|
|
RecoverySeed: true,
|
|
},
|
|
},
|
|
RecoverySeeds: []PeerRecoverySeed{
|
|
{
|
|
NodeID: "node-b",
|
|
Endpoint: "https://node-b.example.test:443",
|
|
Transport: "direct_tcp_tls",
|
|
ConnectivityMode: "direct",
|
|
Priority: 10,
|
|
},
|
|
},
|
|
RendezvousLeases: []PeerRendezvousLease{
|
|
{
|
|
LeaseID: "lease-node-b-via-node-r",
|
|
PeerNodeID: "node-b",
|
|
RelayNodeID: "node-r",
|
|
RelayEndpoint: "http://node-r:19000",
|
|
Transport: "relay_control",
|
|
ConnectivityMode: "relay_required",
|
|
RouteIDs: []string{"route-a-b"},
|
|
AllowedChannels: []string{"fabric_control", "route_control"},
|
|
Priority: 10,
|
|
ControlPlaneOnly: true,
|
|
IssuedAt: expiresAt.Add(-time.Minute),
|
|
ExpiresAt: expiresAt,
|
|
},
|
|
},
|
|
Routes: []SyntheticRoute{liveSyntheticRoute("route-a-b", []string{"node-a", "node-r", "node-b"})},
|
|
})
|
|
|
|
cfg, err := LoadScopedSyntheticConfig(path, PeerIdentity{ClusterID: "cluster-1", NodeID: "node-a"})
|
|
if err != nil {
|
|
t.Fatalf("load scoped config: %v", err)
|
|
}
|
|
if cfg.ConfigVersion != "config-v1" || cfg.PeerEndpoints["node-b"] == "" || len(cfg.Routes) != 1 {
|
|
t.Fatalf("unexpected config: %+v", cfg)
|
|
}
|
|
if got := cfg.PeerEndpointCandidates["node-b"]; len(got) != 1 || got[0].EndpointID != "node-b-public" {
|
|
t.Fatalf("unexpected endpoint candidates: %+v", cfg.PeerEndpointCandidates)
|
|
}
|
|
if got := cfg.PeerEndpointObservations["node-b-public"]; got.EndpointID != "node-b-public" || got.ReliabilityScore != 95 {
|
|
t.Fatalf("unexpected endpoint observations: %+v", cfg.PeerEndpointObservations)
|
|
}
|
|
if len(cfg.PeerDirectory) != 1 || cfg.PeerDirectory[0].NodeID != "node-b" || !cfg.PeerDirectory[0].RecoverySeed {
|
|
t.Fatalf("unexpected peer directory: %+v", cfg.PeerDirectory)
|
|
}
|
|
if len(cfg.RecoverySeeds) != 1 || cfg.RecoverySeeds[0].NodeID != "node-b" {
|
|
t.Fatalf("unexpected recovery seeds: %+v", cfg.RecoverySeeds)
|
|
}
|
|
if len(cfg.RendezvousLeases) != 1 || cfg.RendezvousLeases[0].RelayNodeID != "node-r" {
|
|
t.Fatalf("unexpected rendezvous leases: %+v", cfg.RendezvousLeases)
|
|
}
|
|
}
|
|
|
|
func TestLoadScopedSyntheticConfigRejectsWrongCluster(t *testing.T) {
|
|
path := writeScopedConfig(t, ScopedSyntheticConfig{
|
|
SchemaVersion: "c17f.synthetic.v1",
|
|
ClusterID: "cluster-2",
|
|
LocalNodeID: "node-a",
|
|
Routes: []SyntheticRoute{liveSyntheticRoute("route-a-b", []string{"node-a", "node-b"})},
|
|
})
|
|
|
|
_, err := LoadScopedSyntheticConfig(path, PeerIdentity{ClusterID: "cluster-1", NodeID: "node-a"})
|
|
if !errors.Is(err, ErrClusterMismatch) {
|
|
t.Fatalf("err = %v, want ErrClusterMismatch", err)
|
|
}
|
|
}
|
|
|
|
func TestLoadScopedSyntheticConfigRejectsWrongNode(t *testing.T) {
|
|
path := writeScopedConfig(t, ScopedSyntheticConfig{
|
|
SchemaVersion: "c17f.synthetic.v1",
|
|
ClusterID: "cluster-1",
|
|
LocalNodeID: "node-x",
|
|
Routes: []SyntheticRoute{liveSyntheticRoute("route-a-b", []string{"node-a", "node-b"})},
|
|
})
|
|
|
|
_, err := LoadScopedSyntheticConfig(path, PeerIdentity{ClusterID: "cluster-1", NodeID: "node-a"})
|
|
if !errors.Is(err, ErrNodeMismatch) {
|
|
t.Fatalf("err = %v, want ErrNodeMismatch", err)
|
|
}
|
|
}
|
|
|
|
func TestLoadScopedSyntheticConfigRejectsExpiredRoute(t *testing.T) {
|
|
route := liveSyntheticRoute("route-a-b", []string{"node-a", "node-b"})
|
|
route.ExpiresAt = time.Now().UTC().Add(-time.Minute)
|
|
path := writeScopedConfig(t, ScopedSyntheticConfig{
|
|
SchemaVersion: "c17f.synthetic.v1",
|
|
ClusterID: "cluster-1",
|
|
LocalNodeID: "node-a",
|
|
Routes: []SyntheticRoute{route},
|
|
})
|
|
|
|
_, err := LoadScopedSyntheticConfig(path, PeerIdentity{ClusterID: "cluster-1", NodeID: "node-a"})
|
|
if !errors.Is(err, ErrRouteExpired) {
|
|
t.Fatalf("err = %v, want ErrRouteExpired", err)
|
|
}
|
|
}
|
|
|
|
func TestLoadScopedSyntheticConfigRejectsInvalidPeerEndpointCandidate(t *testing.T) {
|
|
path := writeScopedConfig(t, ScopedSyntheticConfig{
|
|
SchemaVersion: "c17f.synthetic.v1",
|
|
ClusterID: "cluster-1",
|
|
LocalNodeID: "node-a",
|
|
PeerEndpointCandidates: map[string][]PeerEndpointCandidate{
|
|
"node-b": {
|
|
{
|
|
EndpointID: "node-b-public",
|
|
NodeID: "node-c",
|
|
Transport: "direct_tcp_tls",
|
|
Address: "203.0.113.20:443",
|
|
Reachability: "public",
|
|
ConnectivityMode: "direct",
|
|
},
|
|
},
|
|
},
|
|
Routes: []SyntheticRoute{liveSyntheticRoute("route-a-b", []string{"node-a", "node-b"})},
|
|
})
|
|
|
|
_, err := LoadScopedSyntheticConfig(path, PeerIdentity{ClusterID: "cluster-1", NodeID: "node-a"})
|
|
if err == nil {
|
|
t.Fatal("expected invalid peer endpoint candidate error")
|
|
}
|
|
}
|
|
|
|
func TestLoadScopedSyntheticConfigRejectsInvalidPeerEndpointObservation(t *testing.T) {
|
|
path := writeScopedConfig(t, ScopedSyntheticConfig{
|
|
SchemaVersion: "c17f.synthetic.v1",
|
|
ClusterID: "cluster-1",
|
|
LocalNodeID: "node-a",
|
|
PeerEndpoints: map[string]string{},
|
|
PeerEndpointObservations: map[string]EndpointCandidateHealthObservation{
|
|
"endpoint-a": {
|
|
EndpointID: "endpoint-b",
|
|
ReliabilityScore: 101,
|
|
},
|
|
},
|
|
Routes: []SyntheticRoute{liveSyntheticRoute("route-a-b", []string{"node-a", "node-b"})},
|
|
})
|
|
_, err := LoadScopedSyntheticConfig(path, PeerIdentity{ClusterID: "cluster-1", NodeID: "node-a"})
|
|
if err == nil {
|
|
t.Fatal("expected invalid peer endpoint observation error")
|
|
}
|
|
}
|
|
|
|
func TestLoadScopedSyntheticConfigRejectsInvalidPeerDirectory(t *testing.T) {
|
|
path := writeScopedConfig(t, ScopedSyntheticConfig{
|
|
SchemaVersion: "c17f.synthetic.v1",
|
|
ClusterID: "cluster-1",
|
|
LocalNodeID: "node-a",
|
|
PeerDirectory: []PeerDirectoryEntry{
|
|
{NodeID: "node-a"},
|
|
},
|
|
Routes: []SyntheticRoute{liveSyntheticRoute("route-a-b", []string{"node-a", "node-b"})},
|
|
})
|
|
|
|
_, err := LoadScopedSyntheticConfig(path, PeerIdentity{ClusterID: "cluster-1", NodeID: "node-a"})
|
|
if err == nil {
|
|
t.Fatal("expected invalid peer directory error")
|
|
}
|
|
}
|
|
|
|
func TestLoadScopedSyntheticConfigRejectsInvalidRecoverySeed(t *testing.T) {
|
|
path := writeScopedConfig(t, ScopedSyntheticConfig{
|
|
SchemaVersion: "c17f.synthetic.v1",
|
|
ClusterID: "cluster-1",
|
|
LocalNodeID: "node-a",
|
|
RecoverySeeds: []PeerRecoverySeed{
|
|
{NodeID: "node-b", Endpoint: "", Transport: "direct_tcp_tls"},
|
|
},
|
|
Routes: []SyntheticRoute{liveSyntheticRoute("route-a-b", []string{"node-a", "node-b"})},
|
|
})
|
|
|
|
_, err := LoadScopedSyntheticConfig(path, PeerIdentity{ClusterID: "cluster-1", NodeID: "node-a"})
|
|
if err == nil {
|
|
t.Fatal("expected invalid recovery seed error")
|
|
}
|
|
}
|
|
|
|
func TestLoadScopedSyntheticConfigRejectsInvalidRendezvousLease(t *testing.T) {
|
|
path := writeScopedConfig(t, ScopedSyntheticConfig{
|
|
SchemaVersion: "c17z12.synthetic.v1",
|
|
ClusterID: "cluster-1",
|
|
LocalNodeID: "node-a",
|
|
RendezvousLeases: []PeerRendezvousLease{
|
|
{
|
|
LeaseID: "lease-node-b-via-node-r",
|
|
PeerNodeID: "node-b",
|
|
RelayNodeID: "node-r",
|
|
RelayEndpoint: "http://node-r:19000",
|
|
Transport: "relay_control",
|
|
RouteIDs: []string{"route-a-b"},
|
|
ExpiresAt: time.Now().UTC().Add(time.Hour),
|
|
},
|
|
},
|
|
Routes: []SyntheticRoute{liveSyntheticRoute("route-a-b", []string{"node-a", "node-r", "node-b"})},
|
|
})
|
|
|
|
_, err := LoadScopedSyntheticConfig(path, PeerIdentity{ClusterID: "cluster-1", NodeID: "node-a"})
|
|
if err == nil {
|
|
t.Fatal("expected invalid rendezvous lease error")
|
|
}
|
|
}
|
|
|
|
func writeScopedConfig(t *testing.T, cfg ScopedSyntheticConfig) string {
|
|
t.Helper()
|
|
payload, err := json.Marshal(cfg)
|
|
if err != nil {
|
|
t.Fatalf("marshal config: %v", err)
|
|
}
|
|
path := filepath.Join(t.TempDir(), "mesh-config.json")
|
|
if err := os.WriteFile(path, payload, 0o600); err != nil {
|
|
t.Fatalf("write config: %v", err)
|
|
}
|
|
return path
|
|
}
|