package app import "testing" func TestTransportOwnershipNeedsRebuildByPlanDigest(t *testing.T) { owners := TransportOwnershipState{ PolicyRevision: 11, PlanDigest: "digest-old", } if !transportOwnershipNeedsRebuild(11, owners, "digest-new") { t.Fatalf("expected rebuild on plan digest mismatch") } } func TestTransportOwnershipNeedsRebuildByPolicyRevision(t *testing.T) { owners := TransportOwnershipState{ PolicyRevision: 10, PlanDigest: "digest-same", } if !transportOwnershipNeedsRebuild(11, owners, "digest-same") { t.Fatalf("expected rebuild on policy revision mismatch") } } func TestTransportOwnershipNeedsRebuildNoDigestNoRebuild(t *testing.T) { owners := TransportOwnershipState{ PolicyRevision: 11, PlanDigest: "digest-existing", } if transportOwnershipNeedsRebuild(11, owners, "") { t.Fatalf("did not expect rebuild when expected digest is empty") } } func TestBuildTransportOwnershipStateFromPlanIncludesOwnerScopeAndDigest(t *testing.T) { plan := TransportPolicyCompilePlan{ PolicyRevision: 23, Interfaces: []TransportPolicyCompileInterface{ { IfaceID: "edge-a", RoutingTable: "agvpn_if_edge_a", RuntimeIface: "tun99", RuleCount: 1, Rules: []TransportPolicyCompileRule{ { SelectorType: "domain", SelectorValue: "example.com", ClientID: "sg-a", ClientKind: "singbox", OwnerScope: "edge_a_sg_a", NftSet: "agvpn_pi_edge_a_sg_a_domain", MarkHex: "0x121", PriorityBase: 13300, Mode: "strict", Priority: 100, }, }, }, }, } st := buildTransportOwnershipStateFromPlan(plan, 23) if st.PolicyRevision != 23 { t.Fatalf("unexpected policy revision: %d", st.PolicyRevision) } if st.PlanDigest == "" { t.Fatalf("expected non-empty plan digest") } if st.PlanDigest != digestTransportPolicyCompilePlan(plan) { t.Fatalf("unexpected plan digest: got=%q want=%q", st.PlanDigest, digestTransportPolicyCompilePlan(plan)) } if len(st.Items) != 1 { t.Fatalf("unexpected ownership item count: %d", len(st.Items)) } if st.Items[0].OwnerScope != "edge_a_sg_a" { t.Fatalf("unexpected owner_scope: %#v", st.Items[0]) } }