package tenant import ( "context" "errors" "net/http" "net/http/httptest" "testing" "github.com/jackc/pgx/v5" ) func TestOrgContextRoundTrip(t *testing.T) { ctx := WithOrg(context.Background(), "org-123") got, ok := OrgFromContext(ctx) if !ok || got != "org-123" { t.Fatalf("round-trip failed: got %q ok=%v", got, ok) } } func TestEmptyOrgIsTreatedAsAbsent(t *testing.T) { if _, ok := OrgFromContext(context.Background()); ok { t.Fatal("no org should be reported absent") } // An empty string must NOT count as a tenant, that would write an empty GUC and error at query time. if _, ok := OrgFromContext(WithOrg(context.Background(), "")); ok { t.Fatal("empty org must be treated as absent (fail-closed)") } } func TestRunInTenantTxFailsClosedWithoutOrg(t *testing.T) { // Pool is nil on purpose: the org check must short-circuit BEFORE the pool is ever touched. db := &DB{Pool: nil} ran := false err := db.RunInTenantTx(context.Background(), func(context.Context, pgx.Tx) error { ran = true return nil }) if ran { t.Fatal("fn must not run without a validated org") } if !errors.Is(err, ErrNoTenant) { t.Fatalf("want ErrNoTenant, got %v", err) } } func TestMiddlewareRejectsUnresolvedOrg(t *testing.T) { called := false h := Middleware(func(*http.Request) (string, bool) { return "", false })( http.HandlerFunc(func(http.ResponseWriter, *http.Request) { called = true })) rec := httptest.NewRecorder() h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/", nil)) if called { t.Fatal("handler must not run when the org is unresolved") } if rec.Code != http.StatusForbidden { t.Fatalf("want 403, got %d", rec.Code) } } func TestMiddlewarePassesResolvedOrgToContext(t *testing.T) { var seen string h := Middleware(func(*http.Request) (string, bool) { return "org-9", true })( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { seen, _ = OrgFromContext(r.Context()) })) h.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest(http.MethodGet, "/", nil)) if seen != "org-9" { t.Fatalf("handler saw org %q, want org-9", seen) } }