package repository_test import ( "context" "strings" "testing" "github.com/travelswitch/travelhub/backend/internal/repository" "github.com/travelswitch/travelhub/backend/internal/testsupport" ) func TestTenantBySlug(t *testing.T) { f := testsupport.Setup(t) got, err := f.Repo.TenantBySlug(context.Background(), f.Tenant.Slug) if err != nil { t.Fatalf("lookup: %v", err) } if got.ID != f.Tenant.ID { t.Errorf("got tenant %s, want %s", got.ID, f.Tenant.ID) } } func TestTenantBySlugUnknownIsNotFound(t *testing.T) { f := testsupport.Setup(t) if _, err := f.Repo.TenantBySlug(context.Background(), "no-such-agency"); err != repository.ErrNotFound { t.Fatalf("want ErrNotFound, got %v", err) } } // A suspended tenant must be indistinguishable from a missing one, so its // users cannot sign in. func TestTenantBySlugSuspendedIsNotFound(t *testing.T) { f := testsupport.Setup(t) f.Suspend(t) if _, err := f.Repo.TenantBySlug(context.Background(), f.Tenant.Slug); err != repository.ErrNotFound { t.Fatalf("want ErrNotFound for a suspended tenant, got %v", err) } } func TestUserByEmailIsCaseInsensitive(t *testing.T) { f := testsupport.Setup(t) got, err := f.Repo.UserByEmail(context.Background(), f.Tenant.ID, strings.ToUpper(f.Agent.Email)) if err != nil { t.Fatalf("lookup: %v", err) } if got.ID != f.Agent.ID { t.Errorf("got user %s, want %s", got.ID, f.Agent.ID) } } // The tenant filter on the user lookup is what stops one agency's credentials // from authenticating at another. func TestUserByEmailIsScopedToTenant(t *testing.T) { mine := testsupport.Setup(t) theirs := testsupport.Setup(t) _, err := mine.Repo.UserByEmail(context.Background(), mine.Tenant.ID, theirs.Agent.Email) if err != repository.ErrNotFound { t.Fatalf("want ErrNotFound looking up another tenant's user, got %v", err) } } // The same address may hold an account at more than one agency; each must // resolve to its own row. func TestSameEmailCanExistInTwoTenants(t *testing.T) { a := testsupport.Setup(t) b := testsupport.Setup(t) const shared = "traveller@example.com" inA := a.NewUser(t, shared, "agent") inB := b.NewUser(t, shared, "admin") gotA, err := a.Repo.UserByEmail(context.Background(), a.Tenant.ID, shared) if err != nil { t.Fatalf("lookup in A: %v", err) } gotB, err := b.Repo.UserByEmail(context.Background(), b.Tenant.ID, shared) if err != nil { t.Fatalf("lookup in B: %v", err) } if gotA.ID != inA.ID || gotB.ID != inB.ID { t.Error("shared email resolved to the wrong tenant's user") } if gotA.ID == gotB.ID { t.Error("the two tenants collapsed onto one user row") } if gotA.Role != "agent" || gotB.Role != "admin" { t.Errorf("roles crossed over: A=%s B=%s", gotA.Role, gotB.Role) } } func TestListTenantsExcludesSuspended(t *testing.T) { live := testsupport.Setup(t) dead := testsupport.Setup(t) dead.Suspend(t) tenants, err := live.Repo.ListTenants(context.Background()) if err != nil { t.Fatalf("list: %v", err) } seen := map[string]bool{} for _, tn := range tenants { seen[tn.Slug] = true } if !seen[live.Tenant.Slug] { t.Error("active tenant missing from the sign-in picker") } if seen[dead.Tenant.Slug] { t.Error("suspended tenant offered in the sign-in picker") } }