package handlers import ( "context" "encoding/json" "net/http" "testing" archivalDomain "git.nakama.town/fmartingr/hako/internal/archival/domain" authDomain "git.nakama.town/fmartingr/hako/internal/auth/domain" "git.nakama.town/fmartingr/hako/internal/server/middleware" "git.nakama.town/fmartingr/hako/internal/testutil" "github.com/stretchr/testify/require" ) func TestHandleLogin_Success(t *testing.T) { ctx := context.Background() deps := testutil.GetTestConfigurationAndDependencies(t, ctx) // Initialize domains deps.Dependencies.Domains().SetLinks(archivalDomain.NewLinkDomain(deps.Dependencies)) deps.Dependencies.Domains().SetArchives(archivalDomain.NewArchiveDomain(deps.Dependencies)) deps.Dependencies.Domains().SetCategories(archivalDomain.NewCategoryDomain(deps.Dependencies)) deps.Dependencies.Domains().SetAuth(authDomain.NewAuthDomain(deps.Dependencies)) // Create a test user first _, _, err := testutil.NewTestUser(t, deps.Dependencies, "test@example.com", "testpassword123") require.NoError(t, err) // Create auth handler authHandler := NewAuthHandler(deps.Dependencies) // Create login request loginReq := map[string]string{ "email": "test@example.com", "password": "testpassword123", } body, _ := json.Marshal(loginReq) // Perform request w := testutil.PerformRequest(authHandler.HandleLogin, http.MethodPost, "/api/v1/auth/login", testutil.WithBody(string(body)), testutil.WithHeader("Content-Type", "application/json"), ) // Assert response resp := testutil.NewTestResponse(w) resp.AssertStatus(t, http.StatusOK) // Check response structure tokenValue := resp.AssertJSONContainsKey(t, "token") require.NotEmpty(t, tokenValue) userValue := resp.AssertJSONContainsKey(t, "user") userMap, ok := userValue.(map[string]any) require.True(t, ok) require.Equal(t, "test@example.com", userMap["email"]) // Verify role is returned (should default to "user") require.Equal(t, "user", userMap["role"]) } func TestHandleLogin_InvalidCredentials(t *testing.T) { ctx := context.Background() deps := testutil.GetTestConfigurationAndDependencies(t, ctx) // Initialize domains deps.Dependencies.Domains().SetLinks(archivalDomain.NewLinkDomain(deps.Dependencies)) deps.Dependencies.Domains().SetArchives(archivalDomain.NewArchiveDomain(deps.Dependencies)) deps.Dependencies.Domains().SetCategories(archivalDomain.NewCategoryDomain(deps.Dependencies)) deps.Dependencies.Domains().SetAuth(authDomain.NewAuthDomain(deps.Dependencies)) // Create a test user first _, _, err := testutil.NewTestUser(t, deps.Dependencies, "test@example.com", "testpassword123") require.NoError(t, err) // Create auth handler authHandler := NewAuthHandler(deps.Dependencies) // Create login request with wrong password loginReq := map[string]string{ "email": "test@example.com", "password": "wrongpassword", } body, _ := json.Marshal(loginReq) // Perform request w := testutil.PerformRequest(authHandler.HandleLogin, http.MethodPost, "/api/v1/auth/login", testutil.WithBody(string(body)), testutil.WithHeader("Content-Type", "application/json"), ) // Assert response resp := testutil.NewTestResponse(w) resp.AssertStatus(t, http.StatusUnauthorized) resp.AssertBodyContains(t, "Invalid credentials") } func TestHandleLogin_MissingFields(t *testing.T) { ctx := context.Background() deps := testutil.GetTestConfigurationAndDependencies(t, ctx) // Create auth handler authHandler := NewAuthHandler(deps.Dependencies) // Test with empty email loginReq := map[string]string{ "email": "", "password": "testpassword123", } body, _ := json.Marshal(loginReq) w := testutil.PerformRequest(authHandler.HandleLogin, http.MethodPost, "/api/v1/auth/login", testutil.WithBody(string(body)), testutil.WithHeader("Content-Type", "application/json"), ) resp := testutil.NewTestResponse(w) resp.AssertStatus(t, http.StatusBadRequest) resp.AssertBodyContains(t, "Email and password are required") // Test with empty password loginReq = map[string]string{ "email": "test@example.com", "password": "", } body, _ = json.Marshal(loginReq) w = testutil.PerformRequest(authHandler.HandleLogin, http.MethodPost, "/api/v1/auth/login", testutil.WithBody(string(body)), testutil.WithHeader("Content-Type", "application/json"), ) resp = testutil.NewTestResponse(w) resp.AssertStatus(t, http.StatusBadRequest) resp.AssertBodyContains(t, "Email and password are required") } func TestHandleLogin_InvalidMethod(t *testing.T) { ctx := context.Background() deps := testutil.GetTestConfigurationAndDependencies(t, ctx) // Create auth handler authHandler := NewAuthHandler(deps.Dependencies) // Try GET instead of POST w := testutil.PerformRequest(authHandler.HandleLogin, http.MethodGet, "/api/v1/auth/login") resp := testutil.NewTestResponse(w) resp.AssertStatus(t, http.StatusMethodNotAllowed) resp.AssertBodyContains(t, "Method not allowed") } func TestHandleGetCurrentUser_Success(t *testing.T) { ctx := context.Background() deps := testutil.GetTestConfigurationAndDependencies(t, ctx) // Initialize domains deps.Dependencies.Domains().SetLinks(archivalDomain.NewLinkDomain(deps.Dependencies)) deps.Dependencies.Domains().SetArchives(archivalDomain.NewArchiveDomain(deps.Dependencies)) deps.Dependencies.Domains().SetCategories(archivalDomain.NewCategoryDomain(deps.Dependencies)) deps.Dependencies.Domains().SetAuth(authDomain.NewAuthDomain(deps.Dependencies)) // Create a test user and get token user, token, err := testutil.NewTestUser(t, deps.Dependencies, "test@example.com", "testpassword123") require.NoError(t, err) // Create auth handler authHandler := NewAuthHandler(deps.Dependencies) // Create handlers with new middleware pattern // Global auth middleware sets context if token is present globalAuthMiddleware := middleware.AuthMiddleware(deps.Dependencies.GetJWTService(), deps.Dependencies.UserStore) // Require auth middleware blocks if not authenticated requireAuthMiddleware := middleware.RequireAuthMiddleware() handler := globalAuthMiddleware(requireAuthMiddleware(http.HandlerFunc(authHandler.HandleGetCurrentUser))) // Perform authenticated request w := testutil.PerformRequestWithHandler(handler, http.MethodGet, "/api/v1/auth/me", testutil.WithAuthToken(token), ) // Assert response resp := testutil.NewTestResponse(w) resp.AssertStatus(t, http.StatusOK) // Check response structure emailValue := resp.AssertJSONContainsKey(t, "email") require.Equal(t, user.Email, emailValue) // Verify role is returned roleValue := resp.AssertJSONContainsKey(t, "role") require.Equal(t, "user", roleValue) } func TestHandleGetCurrentUser_Unauthorized(t *testing.T) { ctx := context.Background() deps := testutil.GetTestConfigurationAndDependencies(t, ctx) // Create auth handler authHandler := NewAuthHandler(deps.Dependencies) // Create handlers with new middleware pattern globalAuthMiddleware := middleware.AuthMiddleware(deps.Dependencies.GetJWTService(), deps.Dependencies.UserStore) requireAuthMiddleware := middleware.RequireAuthMiddleware() handler := globalAuthMiddleware(requireAuthMiddleware(http.HandlerFunc(authHandler.HandleGetCurrentUser))) // Perform request without token w := testutil.PerformRequestWithHandler(handler, http.MethodGet, "/api/v1/auth/me") // Assert response resp := testutil.NewTestResponse(w) resp.AssertStatus(t, http.StatusUnauthorized) resp.AssertBodyContains(t, "Authorization required") } func TestHandleGetCurrentUser_InvalidToken(t *testing.T) { ctx := context.Background() deps := testutil.GetTestConfigurationAndDependencies(t, ctx) // Create auth handler authHandler := NewAuthHandler(deps.Dependencies) // Create handlers with new middleware pattern globalAuthMiddleware := middleware.AuthMiddleware(deps.Dependencies.GetJWTService(), deps.Dependencies.UserStore) requireAuthMiddleware := middleware.RequireAuthMiddleware() handler := globalAuthMiddleware(requireAuthMiddleware(http.HandlerFunc(authHandler.HandleGetCurrentUser))) // Perform request with invalid token w := testutil.PerformRequestWithHandler(handler, http.MethodGet, "/api/v1/auth/me", testutil.WithAuthToken("invalid-token"), ) // Assert response resp := testutil.NewTestResponse(w) resp.AssertStatus(t, http.StatusUnauthorized) resp.AssertBodyContains(t, "Authorization required") } func TestHandleGetCurrentUser_InvalidMethod(t *testing.T) { ctx := context.Background() deps := testutil.GetTestConfigurationAndDependencies(t, ctx) // Create auth handler authHandler := NewAuthHandler(deps.Dependencies) // Try POST instead of GET w := testutil.PerformRequest(authHandler.HandleGetCurrentUser, http.MethodPost, "/api/v1/auth/me") resp := testutil.NewTestResponse(w) resp.AssertStatus(t, http.StatusMethodNotAllowed) resp.AssertBodyContains(t, "Method not allowed") } func TestHandleLogin_ReturnsRole(t *testing.T) { ctx := context.Background() deps := testutil.GetTestConfigurationAndDependencies(t, ctx) // Initialize domains deps.Dependencies.Domains().SetLinks(archivalDomain.NewLinkDomain(deps.Dependencies)) deps.Dependencies.Domains().SetArchives(archivalDomain.NewArchiveDomain(deps.Dependencies)) deps.Dependencies.Domains().SetCategories(archivalDomain.NewCategoryDomain(deps.Dependencies)) deps.Dependencies.Domains().SetAuth(authDomain.NewAuthDomain(deps.Dependencies)) // Create a test admin user _, _, err := testutil.NewTestAdminUser(t, deps.Dependencies, "admin@example.com", "adminpassword123") require.NoError(t, err) // Create auth handler authHandler := NewAuthHandler(deps.Dependencies) // Create login request loginReq := map[string]string{ "email": "admin@example.com", "password": "adminpassword123", } body, _ := json.Marshal(loginReq) // Perform request w := testutil.PerformRequest(authHandler.HandleLogin, http.MethodPost, "/api/v1/auth/login", testutil.WithBody(string(body)), testutil.WithHeader("Content-Type", "application/json"), ) // Assert response resp := testutil.NewTestResponse(w) resp.AssertStatus(t, http.StatusOK) // Check response structure userValue := resp.AssertJSONContainsKey(t, "user") userMap, ok := userValue.(map[string]any) require.True(t, ok) require.Equal(t, "admin@example.com", userMap["email"]) require.Equal(t, "admin", userMap["role"]) } func TestHandleGetCurrentUser_ReturnsRole(t *testing.T) { ctx := context.Background() deps := testutil.GetTestConfigurationAndDependencies(t, ctx) // Initialize domains deps.Dependencies.Domains().SetLinks(archivalDomain.NewLinkDomain(deps.Dependencies)) deps.Dependencies.Domains().SetArchives(archivalDomain.NewArchiveDomain(deps.Dependencies)) deps.Dependencies.Domains().SetCategories(archivalDomain.NewCategoryDomain(deps.Dependencies)) deps.Dependencies.Domains().SetAuth(authDomain.NewAuthDomain(deps.Dependencies)) // Create a test admin user and get token user, token, err := testutil.NewTestAdminUser(t, deps.Dependencies, "admin@example.com", "adminpassword123") require.NoError(t, err) // Create auth handler authHandler := NewAuthHandler(deps.Dependencies) // Create handlers with new middleware pattern globalAuthMiddleware := middleware.AuthMiddleware(deps.Dependencies.GetJWTService(), deps.Dependencies.UserStore) requireAuthMiddleware := middleware.RequireAuthMiddleware() handler := globalAuthMiddleware(requireAuthMiddleware(http.HandlerFunc(authHandler.HandleGetCurrentUser))) // Perform authenticated request w := testutil.PerformRequestWithHandler(handler, http.MethodGet, "/api/v1/auth/me", testutil.WithAuthToken(token), ) // Assert response resp := testutil.NewTestResponse(w) resp.AssertStatus(t, http.StatusOK) // Check response structure emailValue := resp.AssertJSONContainsKey(t, "email") require.Equal(t, user.Email, emailValue) // Verify admin role is returned roleValue := resp.AssertJSONContainsKey(t, "role") require.Equal(t, "admin", roleValue) }