Files
fm_be/internal/app/api/routes_auth_test.go
2026-07-16 22:16:45 +07:00

155 lines
5.2 KiB
Go

package api
import (
"net/http"
"testing"
"time"
"github.com/gofiber/fiber/v2"
"wucher/internal/config"
"wucher/internal/service"
"wucher/internal/transport/http/handlers"
)
func TestForgotPasswordIPLimiter(t *testing.T) {
cfg := config.AuthConfig{
ForgotPasswordIPRateMax: 1,
ForgotPasswordIPRateWindow: time.Minute,
}
svc := service.NewAuthService(nil, nil, nil, nil, service.AuthServiceDependencies{SSO: nil, Protector: nil, Config: cfg})
app := fiber.New()
app.Post("/forgot", forgotPasswordIPLimiter(svc), func(c *fiber.Ctx) error {
return c.SendStatus(http.StatusOK)
})
req1, _ := http.NewRequest(http.MethodPost, "/forgot", nil)
resp1, err := app.Test(req1)
if err != nil {
t.Fatalf("first request failed: %v", err)
}
if resp1.StatusCode != http.StatusOK {
t.Fatalf("expected first request 200, got %d", resp1.StatusCode)
}
req2, _ := http.NewRequest(http.MethodPost, "/forgot", nil)
resp2, err := app.Test(req2)
if err != nil {
t.Fatalf("second request failed: %v", err)
}
if resp2.StatusCode != http.StatusTooManyRequests {
t.Fatalf("expected second request 429, got %d", resp2.StatusCode)
}
}
func TestLoginIPLimiter(t *testing.T) {
cfg := config.AuthConfig{
LoginIPRateMax: 1,
LoginIPRateWindow: time.Minute,
}
svc := service.NewAuthService(nil, nil, nil, nil, service.AuthServiceDependencies{SSO: nil, Protector: nil, Config: cfg})
app := fiber.New()
app.Post("/login", loginIPLimiter(svc), func(c *fiber.Ctx) error {
return c.SendStatus(http.StatusOK)
})
req1, _ := http.NewRequest(http.MethodPost, "/login", nil)
resp1, err := app.Test(req1)
if err != nil {
t.Fatalf("first request failed: %v", err)
}
if resp1.StatusCode != http.StatusOK {
t.Fatalf("expected first request 200, got %d", resp1.StatusCode)
}
req2, _ := http.NewRequest(http.MethodPost, "/login", nil)
resp2, err := app.Test(req2)
if err != nil {
t.Fatalf("second request failed: %v", err)
}
if resp2.StatusCode != http.StatusTooManyRequests {
t.Fatalf("expected second request 429, got %d", resp2.StatusCode)
}
}
func TestRegisterAuthRoutes(t *testing.T) {
app := fiber.New()
v1 := app.Group("/api/v1")
svc := service.NewAuthService(nil, nil, nil, nil, service.AuthServiceDependencies{SSO: nil, Protector: nil, Config: config.AuthConfig{}})
authHandler := handlers.NewAuthHandler(svc)
registerAuthRoutes(v1, authHandler, svc, nil)
routes := app.GetRoutes(true)
required := []struct {
method string
path string
}{
{method: http.MethodPost, path: "/api/v1/auth/register"},
{method: http.MethodPost, path: "/api/v1/auth/invite"},
{method: http.MethodPost, path: "/api/v1/auth/invite/resend-set-password"},
{method: http.MethodPost, path: "/api/v1/auth/forgot-password"},
{method: http.MethodPost, path: "/api/v1/auth/reset-password"},
{method: http.MethodPost, path: "/api/v1/auth/pin/setup"},
{method: http.MethodPost, path: "/api/v1/auth/pin/verify"},
{method: http.MethodPost, path: "/api/v1/auth/pin/change"},
{method: http.MethodPost, path: "/api/v1/auth/pin/request-reset"},
{method: http.MethodPost, path: "/api/v1/auth/pin/forgot"},
{method: http.MethodPost, path: "/api/v1/auth/pin/reset"},
{method: http.MethodPost, path: "/api/v1/auth/login"},
{method: http.MethodPost, path: "/api/v1/auth/exchange"},
{method: http.MethodPost, path: "/api/v1/auth/webauthn/register/begin"},
{method: http.MethodPost, path: "/api/v1/auth/webauthn/register/finish"},
{method: http.MethodPost, path: "/api/v1/auth/webauthn/login/begin"},
{method: http.MethodPost, path: "/api/v1/auth/webauthn/login/finish"},
{method: http.MethodPost, path: "/api/v1/auth/webauthn/reset-setup"},
{method: http.MethodPost, path: "/api/v1/auth/refresh"},
{method: http.MethodGet, path: "/api/v1/auth/sessions"},
{method: http.MethodDelete, path: "/api/v1/auth/sessions/:session_id"},
{method: http.MethodGet, path: "/api/v1/auth/me"},
{method: http.MethodGet, path: "/api/v1/auth/microsoft/login"},
{method: http.MethodGet, path: "/api/v1/auth/microsoft/login-check"},
{method: http.MethodGet, path: "/api/v1/auth/microsoft/link"},
{method: http.MethodPost, path: "/api/v1/auth/sso/link"},
{method: http.MethodDelete, path: "/api/v1/auth/sso/unlink"},
{method: http.MethodPost, path: "/api/v1/auth/totp/verify"},
{method: http.MethodPost, path: "/api/v1/auth/totp/reset-setup"},
}
for _, tc := range required {
if !hasRoute(routes, tc.method, tc.path) {
t.Fatalf("route %s %s not registered", tc.method, tc.path)
}
}
var forgotRoute *fiber.Route
for i := range routes {
if routes[i].Method == http.MethodPost && routes[i].Path == "/api/v1/auth/forgot-password" {
forgotRoute = &routes[i]
break
}
}
if forgotRoute == nil {
t.Fatalf("forgot password route not found")
}
if len(forgotRoute.Handlers) < 2 {
t.Fatalf("expected forgot password route to have limiter and handler, got %d handlers", len(forgotRoute.Handlers))
}
var loginRoute *fiber.Route
for i := range routes {
if routes[i].Method == http.MethodPost && routes[i].Path == "/api/v1/auth/login" {
loginRoute = &routes[i]
break
}
}
if loginRoute == nil {
t.Fatalf("login route not found")
}
if len(loginRoute.Handlers) < 2 {
t.Fatalf("expected login route to have limiter and handler, got %d handlers", len(loginRoute.Handlers))
}
}