package app import ( transporttoken "selective-vpn-api/app/transporttoken" "testing" ) func TestNormalizeTransportOwnerLockClearRequest(t *testing.T) { filter, err := normalizeTransportOwnerLockClearRequest(TransportOwnerLocksClearRequest{ ClientID: " SG-REALNETNS ", DestinationIP: "10.1.0.11", DestinationIPs: []string{ "10.1.0.12", "10.1.0.11", }, }) if err != nil { t.Fatalf("unexpected error: %v", err) } if filter.ClientID != "sg-realnetns" { t.Fatalf("unexpected client_id: %q", filter.ClientID) } if len(filter.DestinationIPs) != 2 { t.Fatalf("unexpected destination count: %d (%#v)", len(filter.DestinationIPs), filter.DestinationIPs) } } func TestNormalizeTransportOwnerLockClearRequestRequiresSelector(t *testing.T) { _, err := normalizeTransportOwnerLockClearRequest(TransportOwnerLocksClearRequest{}) if err == nil { t.Fatalf("expected error") } } func TestSplitTransportOwnerLocksByFilter(t *testing.T) { items := []TransportOwnerLockRecord{ {DestinationIP: "10.1.0.11", ClientID: "c1"}, {DestinationIP: "10.1.0.12", ClientID: "c1"}, {DestinationIP: "10.2.0.11", ClientID: "c2"}, } filter := transportOwnerLockClearFilter{ ClientID: "c1", DestinationIPs: []string{"10.1.0.12"}, } matched, remaining := splitTransportOwnerLocksByFilter(items, filter) if len(matched) != 1 { t.Fatalf("expected 1 matched, got %d (%#v)", len(matched), matched) } if matched[0].DestinationIP != "10.1.0.12" { t.Fatalf("unexpected matched destination: %q", matched[0].DestinationIP) } if len(remaining) != 2 { t.Fatalf("expected 2 remaining, got %d", len(remaining)) } } func TestDigestTransportOwnerLocksClearDeterministic(t *testing.T) { filter := transportOwnerLockClearFilter{ ClientID: "c1", DestinationIPs: []string{"10.1.0.11", "10.1.0.12"}, } matchedA := []TransportOwnerLockRecord{ {DestinationIP: "10.1.0.12", ClientID: "c1"}, {DestinationIP: "10.1.0.11", ClientID: "c1"}, } matchedB := []TransportOwnerLockRecord{ {DestinationIP: "10.1.0.11", ClientID: "c1"}, {DestinationIP: "10.1.0.12", ClientID: "c1"}, } a := digestTransportOwnerLocksClear(7, filter, matchedA) b := digestTransportOwnerLocksClear(7, filter, matchedB) if a != b { t.Fatalf("digest must be deterministic: %q != %q", a, b) } } func TestTransportOwnerLocksClearTokenLifecycle(t *testing.T) { transportConfirmStore = transporttoken.NewStore(transportConfirmTTL) digest := "owner-lock-clear-digest" token := issueTransportOwnerLocksClearToken(11, digest) if token == "" { t.Fatalf("empty token") } if !consumeTransportOwnerLocksClearToken(token, 11, digest) { t.Fatalf("expected token to be consumed") } if consumeTransportOwnerLocksClearToken(token, 11, digest) { t.Fatalf("token must be single-use") } }