package lighthouse import ( "context" "fmt" "reflect" "sync" "testing" ) // TestRegistry covers the namespace registry: empty, colon, nil and // duplicate registrations are refused, lookups are byte-exact, Namespaces // is sorted, and concurrent lookups are safe (run under -race). func TestRegistry(t *testing.T) { r := NewRegistry() allow := AuthorizerFunc(func(context.Context, uint, string) Result { return Allowed(nil) }) if err := r.Register("b", allow); err != nil { t.Fatal(err) } if err := r.Register("a", allow); err != nil { t.Fatal(err) } for _, bad := range []struct { ns string a Authorizer }{{"", allow}, {"x:y", allow}, {"c", nil}, {"a", allow}} { if err := r.Register(bad.ns, bad.a); err == nil { t.Errorf("Register(%q) accepted", bad.ns) } } if got := r.Namespaces(); !reflect.DeepEqual(got, []string{"a", "b"}) { t.Fatalf("Namespaces = %v", got) } if _, ok := r.Get("A"); ok { t.Fatal("lookup is not case-sensitive") } if a, ok := r.Get("a"); !ok || !a.Authorize(context.Background(), 1, "a:1").Allowed { t.Fatal("Get(a) failed") } d := Denied("why") if d.Allowed || d.Reason() != "why" { t.Fatalf("Denied = %+v", d) } var nilReg *Registry if _, ok := nilReg.Get("a"); ok || nilReg.Namespaces() != nil { t.Fatal("nil registry is not empty") } if Allowed(map[string]any{"k": 1}).Reason() != "" { t.Fatal("an allow carries a reason") } var wg sync.WaitGroup for i := range 16 { wg.Add(1) go func() { defer wg.Done() if i%4 == 0 { _ = r.Register(fmt.Sprintf("ns%d", i), allow) } for range 100 { if _, ok := r.Get("a"); !ok { t.Error("concurrent Get lost a namespace") return } _ = r.Namespaces() } }() } wg.Wait() if n := len(r.Namespaces()); n != 6 { t.Fatalf("namespaces after concurrent registration = %d, want 6", n) } }