package auth_test import ( "bytes" "context" "encoding/json" "net/http/httptest" "testing" "time" "github.com/gofiber/fiber/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/techxcar/backend/internal/auth" "github.com/techxcar/backend/internal/config" ) // stubRepo is a minimal in-memory stub for testing auth handlers without a real DB. type stubRepo struct { superAdmins map[string]*auth.LoginSuperAdmin tenants map[string]*auth.LoginTenant users map[string]*auth.LoginUser } func (s *stubRepo) GetSuperAdminByEmail(_ context.Context, email string) (*auth.LoginSuperAdmin, error) { a, _ := s.superAdmins[email] return a, nil } func (s *stubRepo) GetTenantBySlug(_ context.Context, slug string) (*auth.LoginTenant, error) { t, _ := s.tenants[slug] return t, nil } func (s *stubRepo) GetTenantUserByEmail(_ context.Context, tenantID, email string) (*auth.LoginUser, error) { key := tenantID + ":" + email u, _ := s.users[key] return u, nil } func newTestApp(repo auth.LoginRepository, cfg *config.Config) *fiber.App { app := fiber.New(fiber.Config{ErrorHandler: func(c *fiber.Ctx, err error) error { code := fiber.StatusInternalServerError if e, ok := err.(*fiber.Error); ok { code = e.Code } return c.Status(code).JSON(fiber.Map{"data": nil, "error": err.Error()}) }}) app.Post("/api/v1/auth/login", auth.LoginHandler(repo, nil, cfg)) app.Post("/api/v1/auth/refresh", auth.RefreshHandler(nil, cfg)) app.Post("/api/v1/auth/logout", auth.LogoutHandler(nil)) return app } func TestLogin_superAdmin_success(t *testing.T) { hash, _ := auth.HashPassword("secret123") repo := &stubRepo{ superAdmins: map[string]*auth.LoginSuperAdmin{ "admin@example.com": {ID: "sa-1", Email: "admin@example.com", PasswordHash: hash}, }, } cfg := &config.Config{JWTSecret: testSecret} app := newTestApp(repo, cfg) body, _ := json.Marshal(map[string]string{"email": "admin@example.com", "password": "secret123"}) req := httptest.NewRequest("POST", "/api/v1/auth/login", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") resp, err := app.Test(req) require.NoError(t, err) assert.Equal(t, 200, resp.StatusCode) var result map[string]any require.NoError(t, json.NewDecoder(resp.Body).Decode(&result)) data := result["data"].(map[string]any) assert.NotEmpty(t, data["access_token"]) assert.NotNil(t, data["user"]) } func TestLogin_wrongPassword(t *testing.T) { hash, _ := auth.HashPassword("secret123") repo := &stubRepo{ superAdmins: map[string]*auth.LoginSuperAdmin{ "admin@example.com": {ID: "sa-1", Email: "admin@example.com", PasswordHash: hash}, }, } cfg := &config.Config{JWTSecret: testSecret} app := newTestApp(repo, cfg) body, _ := json.Marshal(map[string]string{"email": "admin@example.com", "password": "wrongpass"}) req := httptest.NewRequest("POST", "/api/v1/auth/login", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") resp, err := app.Test(req) require.NoError(t, err) assert.Equal(t, 401, resp.StatusCode) } func TestLogin_tenantUser_success(t *testing.T) { hash, _ := auth.HashPassword("tenantpass") repo := &stubRepo{ tenants: map[string]*auth.LoginTenant{ "my-workshop": {ID: "11111111-1111-1111-1111-111111111111", Status: "active"}, }, users: map[string]*auth.LoginUser{ "11111111-1111-1111-1111-111111111111:user@workshop.com": { ID: "u-1", Email: "user@workshop.com", PasswordHash: hash, Role: "tenant_admin", Name: "User", Active: true, }, }, } cfg := &config.Config{JWTSecret: testSecret} app := newTestApp(repo, cfg) body, _ := json.Marshal(map[string]string{ "email": "user@workshop.com", "password": "tenantpass", "tenant_slug": "my-workshop", }) req := httptest.NewRequest("POST", "/api/v1/auth/login", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") resp, err := app.Test(req) require.NoError(t, err) assert.Equal(t, 200, resp.StatusCode) var result map[string]any require.NoError(t, json.NewDecoder(resp.Body).Decode(&result)) data := result["data"].(map[string]any) token := data["access_token"].(string) claims, err := auth.ValidateToken(token, testSecret) require.NoError(t, err) assert.Equal(t, "11111111-1111-1111-1111-111111111111", claims.TenantID) assert.Equal(t, "tenant_admin", claims.Role) _ = time.Now() } func TestLogin_unknownTenant(t *testing.T) { repo := &stubRepo{tenants: map[string]*auth.LoginTenant{}} cfg := &config.Config{JWTSecret: testSecret} app := newTestApp(repo, cfg) body, _ := json.Marshal(map[string]string{ "email": "user@workshop.com", "password": "pass", "tenant_slug": "nonexistent", }) req := httptest.NewRequest("POST", "/api/v1/auth/login", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") resp, err := app.Test(req) require.NoError(t, err) assert.Equal(t, 401, resp.StatusCode) }