package app import ( "testing" "time" ) func TestRunTransportPolicyHealthCheckSkipsInactiveDraftClient(t *testing.T) { now := time.Date(2026, time.March, 15, 12, 0, 0, 0, time.UTC) clients := []TransportClient{ { ID: "draft-a", Kind: TransportClientSingBox, Enabled: false, Status: TransportClientDown, }, } plan := TransportPolicyCompilePlan{ Interfaces: []TransportPolicyCompileInterface{ {IfaceID: "edge-a", ClientIDs: []string{"draft-a"}}, }, } res, updated, changed := runTransportPolicyHealthCheck(clients, plan, now) if !res.OK { t.Fatalf("expected skipped draft client to keep health-check green: %#v", res) } if res.CheckedCount != 0 || res.FailedCount != 0 { t.Fatalf("unexpected counts: %#v", res) } if len(res.Items) != 1 || res.Items[0].Required { t.Fatalf("expected one skipped item: %#v", res.Items) } if res.InterfaceCount != 1 || len(res.Interfaces) != 1 { t.Fatalf("expected one interface summary: %#v", res) } if !res.Interfaces[0].OK || res.Interfaces[0].CheckedCount != 0 || res.Interfaces[0].SkippedCount != 1 { t.Fatalf("unexpected interface summary: %#v", res.Interfaces[0]) } if changed { t.Fatalf("inactive draft client should not mutate health snapshot") } if updated[0].Health.LastCheck != "" { t.Fatalf("unexpected health update for skipped client: %#v", updated[0]) } } func TestRunTransportPolicyHealthCheckFailsEnabledDownClient(t *testing.T) { now := time.Date(2026, time.March, 15, 12, 0, 0, 0, time.UTC) clients := []TransportClient{ { ID: "edge-a-main", Kind: TransportClientSingBox, Enabled: true, Status: TransportClientDown, Config: map[string]any{ "runner": "mock", }, }, } plan := TransportPolicyCompilePlan{ Interfaces: []TransportPolicyCompileInterface{ {IfaceID: "edge-a", ClientIDs: []string{"edge-a-main"}}, }, } res, updated, changed := runTransportPolicyHealthCheck(clients, plan, now) if res.OK { t.Fatalf("expected enabled down client to fail health-check: %#v", res) } if res.CheckedCount != 1 || res.FailedCount != 1 { t.Fatalf("unexpected counts: %#v", res) } if len(res.Items) != 1 || res.Items[0].Code != "TRANSPORT_POLICY_HEALTH_DOWN" { t.Fatalf("unexpected health-check item: %#v", res.Items) } if res.InterfaceCount != 1 || len(res.Interfaces) != 1 { t.Fatalf("expected one interface summary: %#v", res) } if res.Interfaces[0].OK || res.Interfaces[0].CheckedCount != 1 || res.Interfaces[0].FailedCount != 1 { t.Fatalf("unexpected interface summary: %#v", res.Interfaces[0]) } if !changed { t.Fatalf("expected health snapshot to be updated") } if updated[0].Health.LastCheck != now.Format(time.RFC3339) { t.Fatalf("missing health timestamp update: %#v", updated[0]) } } func TestRunTransportPolicyHealthCheckFailsUnsupportedRuntime(t *testing.T) { now := time.Date(2026, time.March, 15, 12, 0, 0, 0, time.UTC) clients := []TransportClient{ { ID: "edge-b-embedded", Kind: TransportClientPhoenix, Enabled: true, Status: TransportClientUp, Config: map[string]any{ "runtime_mode": "embedded", }, }, } plan := TransportPolicyCompilePlan{ Interfaces: []TransportPolicyCompileInterface{ {IfaceID: "edge-b", ClientIDs: []string{"edge-b-embedded"}}, }, } res, updated, changed := runTransportPolicyHealthCheck(clients, plan, now) if res.OK { t.Fatalf("expected unsupported runtime to fail health-check: %#v", res) } if len(res.Items) != 1 || res.Items[0].Code != "TRANSPORT_BACKEND_RUNTIME_MODE_UNSUPPORTED" { t.Fatalf("unexpected health-check item: %#v", res.Items) } if res.InterfaceCount != 1 || len(res.Interfaces) != 1 { t.Fatalf("expected one interface summary: %#v", res) } if res.Interfaces[0].OK || res.Interfaces[0].CheckedCount != 1 || res.Interfaces[0].FailedCount != 1 { t.Fatalf("unexpected interface summary: %#v", res.Interfaces[0]) } if !changed { t.Fatalf("expected unsupported runtime probe to update snapshot") } if updated[0].Status != TransportClientDegraded { t.Fatalf("unexpected degraded status after failed probe: %#v", updated[0]) } if updated[0].Health.LastError == "" { t.Fatalf("expected last_error to be persisted after failed probe") } } func TestRunTransportPolicyHealthCheckBuildsPerInterfaceSummary(t *testing.T) { now := time.Date(2026, time.March, 15, 12, 0, 0, 0, time.UTC) clients := []TransportClient{ { ID: "edge-a-main", Kind: TransportClientSingBox, Enabled: true, Status: TransportClientUp, Config: map[string]any{ "runner": "mock", }, }, { ID: "edge-a-draft", Kind: TransportClientSingBox, Enabled: false, Status: TransportClientDown, }, { ID: "edge-b-main", Kind: TransportClientPhoenix, Enabled: true, Status: TransportClientUp, Config: map[string]any{ "runtime_mode": "embedded", }, }, } plan := TransportPolicyCompilePlan{ Interfaces: []TransportPolicyCompileInterface{ { IfaceID: "edge-a", Mode: "dedicated", RuntimeIface: "tun-a", NetnsName: "svpn-edge-a", RoutingTable: "agvpn_if_edge_a", ClientIDs: []string{"edge-a-main", "edge-a-draft"}, }, { IfaceID: "edge-b", Mode: "dedicated", RuntimeIface: "tun-b", RoutingTable: "agvpn_if_edge_b", ClientIDs: []string{"edge-b-main"}, }, }, } res, _, _ := runTransportPolicyHealthCheck(clients, plan, now) if res.InterfaceCount != 2 || len(res.Interfaces) != 2 { t.Fatalf("expected two interface summaries: %#v", res) } ifaceA := res.Interfaces[0] if ifaceA.IfaceID != "edge-a" || !ifaceA.OK || ifaceA.ClientCount != 2 || ifaceA.CheckedCount != 1 || ifaceA.SkippedCount != 1 { t.Fatalf("unexpected edge-a summary: %#v", ifaceA) } if ifaceA.RuntimeIface != "tun-a" || ifaceA.NetnsName != "svpn-edge-a" || ifaceA.RoutingTable != "agvpn_if_edge_a" { t.Fatalf("edge-a runtime metadata missing: %#v", ifaceA) } if ifaceA.ActiveClientID != "edge-a-main" || ifaceA.Status != string(TransportClientUp) { t.Fatalf("edge-a runtime status fields mismatch: %#v", ifaceA) } ifaceB := res.Interfaces[1] if ifaceB.IfaceID != "edge-b" || ifaceB.OK || ifaceB.ClientCount != 1 || ifaceB.CheckedCount != 1 || ifaceB.FailedCount != 1 { t.Fatalf("unexpected edge-b summary: %#v", ifaceB) } if ifaceB.RuntimeIface != "tun-b" || ifaceB.RoutingTable != "agvpn_if_edge_b" { t.Fatalf("edge-b runtime metadata missing: %#v", ifaceB) } if ifaceB.ActiveClientID != "edge-b-main" || ifaceB.Status != string(TransportClientDegraded) { t.Fatalf("edge-b runtime status fields mismatch: %#v", ifaceB) } if ifaceB.LastError == "" { t.Fatalf("edge-b expected last_error from degraded probe: %#v", ifaceB) } }