package handler import ( "context" "strings" "testing" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgconn" db "github.com/multica-ai/multica/server/pkg/db/generated" ) func newTestHandler(cfg Config) *Handler { return &Handler{ cfg: cfg, } } func TestSignupGating(t *testing.T) { tests := []struct { name string cfg Config email string isNew bool wantErr bool }{ {"allow_signup_true_new", Config{AllowSignup: true}, "a@x.com", true, false}, {"allow_signup_false_new", Config{AllowSignup: false}, "a@x.com", true, true}, {"allow_signup_false_existing", Config{AllowSignup: false}, "a@x.com", false, false}, {"domain_allowlist_match", Config{AllowSignup: false, AllowedEmailDomains: []string{"company.com"}}, "user@company.com", true, false}, {"domain_allowlist_mismatch", Config{AllowSignup: false, AllowedEmailDomains: []string{"company.com"}}, "user@other.com", true, true}, {"email_allowlist_match", Config{AllowSignup: false, AllowedEmails: []string{"boss@x.com"}}, "boss@x.com", true, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { h := newTestHandler(tt.cfg) err := h.checkSignupAllowed(tt.email, tt.isNew) if (err != nil) != tt.wantErr { t.Fatalf("got err=%v wantErr=%v", err, tt.wantErr) } }) } } type mockDB struct { db.DBTX getUserErr error } func (m *mockDB) QueryRow(ctx context.Context, sql string, args ...interface{}) pgx.Row { return &mockRow{err: m.getUserErr} } func (m *mockDB) Exec(ctx context.Context, sql string, args ...interface{}) (pgconn.CommandTag, error) { return pgconn.NewCommandTag("INSERT 1"), nil } type mockRow struct { pgx.Row err error } func (m *mockRow) Scan(dest ...interface{}) error { return m.err } func TestFindOrCreateUserGating(t *testing.T) { t.Run("new_user_blocked", func(t *testing.T) { cfg := Config{AllowSignup: false} h := newTestHandler(cfg) h.Queries = db.New(&mockDB{getUserErr: pgx.ErrNoRows}) _, isNew, err := h.findOrCreateUser(context.Background(), "new@blocked.com") if err == nil { t.Fatal("expected error for new user when signup disabled") } if isNew { t.Fatal("isNew should be false when signup is blocked") } if !strings.Contains(err.Error(), "registration is disabled") { t.Fatalf("expected registration disabled error, got %v", err) } }) t.Run("existing_user_allowed", func(t *testing.T) { cfg := Config{AllowSignup: false} h := newTestHandler(cfg) // mockDB returns nil error for Scan, simulating user found h.Queries = db.New(&mockDB{getUserErr: nil}) _, isNew, err := h.findOrCreateUser(context.Background(), "existing@test.com") if err != nil { t.Fatalf("expected no error for existing user, got %v", err) } if isNew { t.Fatal("existing user should not be flagged as new") } }) t.Run("whitelisted_user_allowed", func(t *testing.T) { cfg := Config{AllowSignup: false, AllowedEmails: []string{"whitelisted@test.com"}} h := newTestHandler(cfg) h.Queries = db.New(&mockDB{getUserErr: pgx.ErrNoRows}) // This will pass checkSignupAllowed and move to CreateUser. // Our mockDB Exec returns success, but Queries.CreateUser might expect QueryRow for RETURNING id. // Let's see if it works. _, _, err := h.findOrCreateUser(context.Background(), "whitelisted@test.com") if err != nil && strings.Contains(err.Error(), "registration is disabled") { t.Fatalf("expected whitelisted user to pass signup check, but got %v", err) } }) }