saveinmed/backend/internal/http/middleware/middleware_test.go
Tiago Yamamoto b8973739ab feat(backend): add comprehensive test suite for 80% coverage
- Add config_test.go (5 tests for env parsing)
- Add middleware_test.go (16 tests for CORS, Auth, Gzip, Logger)
- Add usecase_test.go (30+ tests for business logic)
- Add payments_test.go (6 tests for MercadoPago gateway)

Coverage: config 100%, middleware 95.9%, payments 100%, usecase 64.7%

feat(marketplace): add test framework and new pages

- Setup Vitest with jsdom environment
- Add cartStore.test.ts (15 tests for Zustand store)
- Add usePersistentFilters.test.ts (5 tests for hook)
- Add apiClient.test.ts (7 tests for axios client)
- Add Orders page with status transitions
- Add Inventory page with stock adjustments
- Add Company page with edit functionality
- Add SellerDashboard page with KPIs

Total marketplace tests: 27 passing
2025-12-20 07:43:56 -03:00

342 lines
9.5 KiB
Go

package middleware
import (
"compress/gzip"
"context"
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/gofrs/uuid/v5"
"github.com/golang-jwt/jwt/v5"
)
// --- CORS Tests ---
func TestCORSWithConfigAllowAll(t *testing.T) {
cfg := CORSConfig{AllowedOrigins: []string{"*"}}
handler := CORSWithConfig(cfg)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}))
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Set("Origin", "https://example.com")
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Header().Get("Access-Control-Allow-Origin") != "*" {
t.Errorf("expected Access-Control-Allow-Origin '*', got '%s'", rec.Header().Get("Access-Control-Allow-Origin"))
}
}
func TestCORSWithConfigSpecificOrigins(t *testing.T) {
cfg := CORSConfig{AllowedOrigins: []string{"https://allowed.com", "https://another.com"}}
handler := CORSWithConfig(cfg)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}))
// Test allowed origin
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Set("Origin", "https://allowed.com")
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Header().Get("Access-Control-Allow-Origin") != "https://allowed.com" {
t.Errorf("expected origin 'https://allowed.com', got '%s'", rec.Header().Get("Access-Control-Allow-Origin"))
}
// Test blocked origin
req2 := httptest.NewRequest(http.MethodGet, "/", nil)
req2.Header.Set("Origin", "https://blocked.com")
rec2 := httptest.NewRecorder()
handler.ServeHTTP(rec2, req2)
if rec2.Header().Get("Access-Control-Allow-Origin") != "" {
t.Errorf("expected empty Access-Control-Allow-Origin, got '%s'", rec2.Header().Get("Access-Control-Allow-Origin"))
}
}
func TestCORSPreflight(t *testing.T) {
cfg := CORSConfig{AllowedOrigins: []string{"*"}}
handler := CORSWithConfig(cfg)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusTeapot) // Should not reach here
}))
req := httptest.NewRequest(http.MethodOptions, "/", nil)
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Errorf("expected status 200 for preflight, got %d", rec.Code)
}
}
func TestCORSHeaders(t *testing.T) {
cfg := CORSConfig{AllowedOrigins: []string{"*"}}
handler := CORSWithConfig(cfg)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}))
req := httptest.NewRequest(http.MethodGet, "/", nil)
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if !strings.Contains(rec.Header().Get("Access-Control-Allow-Methods"), "GET") {
t.Error("expected Access-Control-Allow-Methods to include GET")
}
if !strings.Contains(rec.Header().Get("Access-Control-Allow-Headers"), "Authorization") {
t.Error("expected Access-Control-Allow-Headers to include Authorization")
}
}
// --- Auth Tests ---
func createTestToken(secret string, userID uuid.UUID, role string, companyID *uuid.UUID) string {
claims := jwt.MapClaims{
"sub": userID.String(),
"role": role,
"exp": time.Now().Add(time.Hour).Unix(),
}
if companyID != nil {
claims["company_id"] = companyID.String()
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenStr, _ := token.SignedString([]byte(secret))
return tokenStr
}
func TestRequireAuthValidToken(t *testing.T) {
secret := "test-secret"
userID, _ := uuid.NewV4()
companyID, _ := uuid.NewV4()
tokenStr := createTestToken(secret, userID, "Admin", &companyID)
var receivedClaims Claims
handler := RequireAuth([]byte(secret))(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
receivedClaims, _ = GetClaims(r.Context())
w.WriteHeader(http.StatusOK)
}))
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Set("Authorization", "Bearer "+tokenStr)
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Errorf("expected status 200, got %d", rec.Code)
}
if receivedClaims.UserID != userID {
t.Errorf("expected userID %s, got %s", userID, receivedClaims.UserID)
}
if receivedClaims.Role != "Admin" {
t.Errorf("expected role 'Admin', got '%s'", receivedClaims.Role)
}
}
func TestRequireAuthMissingToken(t *testing.T) {
handler := RequireAuth([]byte("secret"))(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}))
req := httptest.NewRequest(http.MethodGet, "/", nil)
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Code != http.StatusUnauthorized {
t.Errorf("expected status 401, got %d", rec.Code)
}
}
func TestRequireAuthInvalidToken(t *testing.T) {
handler := RequireAuth([]byte("secret"))(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}))
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Set("Authorization", "Bearer invalid-token")
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Code != http.StatusUnauthorized {
t.Errorf("expected status 401, got %d", rec.Code)
}
}
func TestRequireAuthWrongSecret(t *testing.T) {
userID, _ := uuid.NewV4()
tokenStr := createTestToken("correct-secret", userID, "User", nil)
handler := RequireAuth([]byte("wrong-secret"))(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}))
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Set("Authorization", "Bearer "+tokenStr)
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Code != http.StatusUnauthorized {
t.Errorf("expected status 401, got %d", rec.Code)
}
}
func TestRequireAuthRoleRestriction(t *testing.T) {
secret := "secret"
userID, _ := uuid.NewV4()
tokenStr := createTestToken(secret, userID, "User", nil)
handler := RequireAuth([]byte(secret), "Admin")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}))
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Set("Authorization", "Bearer "+tokenStr)
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Code != http.StatusForbidden {
t.Errorf("expected status 403, got %d", rec.Code)
}
}
func TestRequireAuthRoleAllowed(t *testing.T) {
secret := "secret"
userID, _ := uuid.NewV4()
tokenStr := createTestToken(secret, userID, "Admin", nil)
handler := RequireAuth([]byte(secret), "Admin")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}))
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Set("Authorization", "Bearer "+tokenStr)
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Errorf("expected status 200, got %d", rec.Code)
}
}
func TestGetClaimsFromContext(t *testing.T) {
claims := Claims{
UserID: uuid.Must(uuid.NewV4()),
Role: "Admin",
}
ctx := context.WithValue(context.Background(), claimsKey, claims)
retrieved, ok := GetClaims(ctx)
if !ok {
t.Error("expected to retrieve claims from context")
}
if retrieved.UserID != claims.UserID {
t.Errorf("expected userID %s, got %s", claims.UserID, retrieved.UserID)
}
}
func TestGetClaimsNotInContext(t *testing.T) {
_, ok := GetClaims(context.Background())
if ok {
t.Error("expected claims to not be in context")
}
}
// --- Gzip Tests ---
func TestGzipCompression(t *testing.T) {
handler := Gzip(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, World!"))
}))
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Set("Accept-Encoding", "gzip")
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Header().Get("Content-Encoding") != "gzip" {
t.Error("expected Content-Encoding 'gzip'")
}
// Decompress and verify
reader, err := gzip.NewReader(rec.Body)
if err != nil {
t.Fatalf("failed to create gzip reader: %v", err)
}
defer reader.Close()
body, err := io.ReadAll(reader)
if err != nil {
t.Fatalf("failed to read gzip body: %v", err)
}
if string(body) != "Hello, World!" {
t.Errorf("expected 'Hello, World!', got '%s'", string(body))
}
}
func TestGzipNoCompression(t *testing.T) {
handler := Gzip(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, World!"))
}))
req := httptest.NewRequest(http.MethodGet, "/", nil)
// No Accept-Encoding header
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Header().Get("Content-Encoding") == "gzip" {
t.Error("should not use gzip when not requested")
}
if rec.Body.String() != "Hello, World!" {
t.Errorf("expected 'Hello, World!', got '%s'", rec.Body.String())
}
}
// --- Logger Tests ---
func TestLoggerMiddleware(t *testing.T) {
handler := Logger(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}))
req := httptest.NewRequest(http.MethodGet, "/test-path", nil)
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Errorf("expected status 200, got %d", rec.Code)
}
}
// --- CORS Legacy Wrapper Test ---
func TestCORSLegacyWrapper(t *testing.T) {
handler := CORS(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}))
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Set("Origin", "https://example.com")
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Header().Get("Access-Control-Allow-Origin") != "*" {
t.Errorf("expected '*', got '%s'", rec.Header().Get("Access-Control-Allow-Origin"))
}
}