153 lines
4.8 KiB
Go
153 lines
4.8 KiB
Go
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)
|
|
}
|