=== RUN TestValidateJWT --- PASS: TestValidateJWT (0.00s) === RUN TestConfigureSwagger --- PASS: TestConfigureSwagger (0.00s) PASS ok github.com/rede5/gohorsejobs/backend/cmd/api (cached) === RUN TestVerifyUserPassword --- PASS: TestVerifyUserPassword (0.61s) PASS ok github.com/rede5/gohorsejobs/backend/cmd/debug_user (cached) ? github.com/rede5/gohorsejobs/backend/cmd/fixhash [no test files] === RUN TestGenerateHash --- PASS: TestGenerateHash (0.23s) PASS ok github.com/rede5/gohorsejobs/backend/cmd/genhash (cached) ? github.com/rede5/gohorsejobs/backend/cmd/inspect_schema [no test files] ? github.com/rede5/gohorsejobs/backend/cmd/manual_migrate [no test files] ? github.com/rede5/gohorsejobs/backend/docs [no test files] === RUN TestNewAdminHandlers --- PASS: TestNewAdminHandlers (0.00s) === RUN TestAdminHandlers_ListCompanies --- PASS: TestAdminHandlers_ListCompanies (0.00s) === RUN TestAdminHandlers_DuplicateJob --- PASS: TestAdminHandlers_DuplicateJob (0.00s) === RUN TestAdminHandlers_ListAccessRoles --- PASS: TestAdminHandlers_ListAccessRoles (0.00s) === RUN TestAdminHandlers_ListTags --- PASS: TestAdminHandlers_ListTags (0.00s) === RUN TestRegisterCandidateHandler_Success core_handlers_test.go:74: Integration test requires full DI setup --- SKIP: TestRegisterCandidateHandler_Success (0.00s) === RUN TestRegisterCandidateHandler_InvalidPayload --- PASS: TestRegisterCandidateHandler_InvalidPayload (0.00s) === RUN TestRegisterCandidateHandler_MissingFields === RUN TestRegisterCandidateHandler_MissingFields/Missing_Email === RUN TestRegisterCandidateHandler_MissingFields/Missing_Password === RUN TestRegisterCandidateHandler_MissingFields/Missing_Name === RUN TestRegisterCandidateHandler_MissingFields/All_Empty --- PASS: TestRegisterCandidateHandler_MissingFields (0.00s) --- PASS: TestRegisterCandidateHandler_MissingFields/Missing_Email (0.00s) --- PASS: TestRegisterCandidateHandler_MissingFields/Missing_Password (0.00s) --- PASS: TestRegisterCandidateHandler_MissingFields/Missing_Name (0.00s) --- PASS: TestRegisterCandidateHandler_MissingFields/All_Empty (0.00s) === RUN TestLoginHandler_InvalidPayload --- PASS: TestLoginHandler_InvalidPayload (0.00s) === RUN TestLoginHandler_Success [LOGIN DEBUG] Searching for user: john@example.com [LOGIN DEBUG] User found: ID=u1, Status=active, HashPrefix=hashed_123 [LOGIN DEBUG] Password verification PASSED [LOGIN DEBUG] Status check PASSED --- PASS: TestLoginHandler_Success (0.00s) === RUN TestCoreHandlers_ListNotifications --- PASS: TestCoreHandlers_ListNotifications (0.00s) === RUN TestCoreHandlers_Tickets === RUN TestCoreHandlers_Tickets/CreateTicket === RUN TestCoreHandlers_Tickets/ListTickets --- PASS: TestCoreHandlers_Tickets (0.00s) --- PASS: TestCoreHandlers_Tickets/CreateTicket (0.00s) --- PASS: TestCoreHandlers_Tickets/ListTickets (0.00s) === RUN TestNewLocationHandlers --- PASS: TestNewLocationHandlers (0.00s) === RUN TestListStatesByCountry_MissingID --- PASS: TestListStatesByCountry_MissingID (0.00s) === RUN TestListCitiesByState_MissingID --- PASS: TestListCitiesByState_MissingID (0.00s) === RUN TestSearchLocations_ShortQuery --- PASS: TestSearchLocations_ShortQuery (0.00s) === RUN TestSearchLocations_MissingCountryID --- PASS: TestSearchLocations_MissingCountryID (0.00s) === RUN TestSearchLocations_InvalidCountryID --- PASS: TestSearchLocations_InvalidCountryID (0.00s) PASS ok github.com/rede5/gohorsejobs/backend/internal/api/handlers 0.036s === RUN TestHeaderAuthGuard_ValidTokenFromHeader [TEST] === TestHeaderAuthGuard_ValidTokenFromHeader === [AUTH DEBUG] === HeaderAuthGuard START === [AUTH DEBUG] Method: GET, Path: /protected [AUTH DEBUG] Authorization Header: 'Bearer valid-jwt-token' [AUTH DEBUG] Token from Header (first 20 chars): 'valid-jwt-token...' [AUTH DEBUG] Validating token... [TEST LOG] ValidateToken called with token: 'valid-jwt-token...' [AUTH DEBUG] Token VALID! Claims: sub=user-123, tenant=tenant-456, roles=[admin user] [AUTH DEBUG] === HeaderAuthGuard SUCCESS === [TEST LOG] Handler reached - checking context values [TEST LOG] Context: userID=user-123, tenantID=tenant-456, roles=[admin user] [TEST LOG] Response status: 200 (expected: 200) --- PASS: TestHeaderAuthGuard_ValidTokenFromHeader (0.00s) === RUN TestHeaderAuthGuard_ValidTokenFromCookie [TEST] === TestHeaderAuthGuard_ValidTokenFromCookie === [AUTH DEBUG] === HeaderAuthGuard START === [AUTH DEBUG] Method: GET, Path: /protected [AUTH DEBUG] Authorization Header: '' [AUTH DEBUG] Token from Cookie (first 20 chars): 'cookie-jwt-token...' [AUTH DEBUG] Validating token... [TEST LOG] ValidateToken called with token: 'cookie-jwt-token...' [AUTH DEBUG] Token VALID! Claims: sub=user-cookie-123, tenant=tenant-cookie-456, roles=[candidate] [AUTH DEBUG] === HeaderAuthGuard SUCCESS === [TEST LOG] Handler reached via cookie auth [TEST LOG] Context userID: user-cookie-123 [TEST LOG] Response status: 200 (expected: 200) --- PASS: TestHeaderAuthGuard_ValidTokenFromCookie (0.00s) === RUN TestHeaderAuthGuard_MissingToken [TEST] === TestHeaderAuthGuard_MissingToken === [AUTH DEBUG] === HeaderAuthGuard START === [AUTH DEBUG] Method: GET, Path: /protected [AUTH DEBUG] Authorization Header: '' [AUTH DEBUG] No jwt cookie found: http: named cookie not present [AUTH DEBUG] No token found - returning 401 [TEST LOG] Response status: 401 (expected: 401) --- PASS: TestHeaderAuthGuard_MissingToken (0.00s) === RUN TestHeaderAuthGuard_InvalidTokenFormat [TEST] === TestHeaderAuthGuard_InvalidTokenFormat === [AUTH DEBUG] === HeaderAuthGuard START === [AUTH DEBUG] Method: GET, Path: /protected [AUTH DEBUG] Authorization Header: 'Basic some-token' [AUTH DEBUG] Invalid header format: 2 parts, first part: 'Basic' [AUTH DEBUG] No jwt cookie found: http: named cookie not present [AUTH DEBUG] No token found - returning 401 [TEST LOG] Response status: 401 (expected: 401) --- PASS: TestHeaderAuthGuard_InvalidTokenFormat (0.00s) === RUN TestHeaderAuthGuard_InvalidToken [TEST] === TestHeaderAuthGuard_InvalidToken === [AUTH DEBUG] === HeaderAuthGuard START === [AUTH DEBUG] Method: GET, Path: /protected [AUTH DEBUG] Authorization Header: 'Bearer invalid-token' [AUTH DEBUG] Token from Header (first 20 chars): 'invalid-token...' [AUTH DEBUG] Validating token... [TEST LOG] ValidateToken called with token: 'invalid-token...' [AUTH DEBUG] Token validation FAILED: token expired [TEST LOG] Response status: 401 (expected: 401) --- PASS: TestHeaderAuthGuard_InvalidToken (0.00s) === RUN TestOptionalHeaderAuthGuard_NoToken [TEST] === TestOptionalHeaderAuthGuard_NoToken === [TEST LOG] Handler reached without token - context should be empty [TEST LOG] Context userID (should be nil): [TEST LOG] Handler was called: true (expected: true) --- PASS: TestOptionalHeaderAuthGuard_NoToken (0.00s) === RUN TestOptionalHeaderAuthGuard_ValidToken [TEST] === TestOptionalHeaderAuthGuard_ValidToken === [TEST LOG] ValidateToken called with token: 'optional-token...' [TEST LOG] Handler reached with optional token [TEST LOG] Context userID: optional-user --- PASS: TestOptionalHeaderAuthGuard_ValidToken (0.00s) === RUN TestOptionalHeaderAuthGuard_InvalidToken [TEST] === TestOptionalHeaderAuthGuard_InvalidToken === [TEST LOG] ValidateToken called with token: 'bad-optional-token...' [TEST LOG] Response status: 401 (expected: 401) --- PASS: TestOptionalHeaderAuthGuard_InvalidToken (0.00s) === RUN TestOptionalHeaderAuthGuard_TokenFromCookie [TEST] === TestOptionalHeaderAuthGuard_TokenFromCookie === [TEST LOG] ValidateToken called with token: 'cookie-optional-toke...' --- PASS: TestOptionalHeaderAuthGuard_TokenFromCookie (0.00s) === RUN TestRequireRoles_UserHasRequiredRole [TEST] === TestRequireRoles_UserHasRequiredRole === [RBAC DEBUG] === RequireRoles START for GET /admin === [RBAC DEBUG] Required roles: [admin] [RBAC DEBUG] Raw roles from context: [admin user] (type: []string) [RBAC DEBUG] Extracted roles: [admin user] [RBAC DEBUG] SUCCESS: User has required role [TEST LOG] Handler reached - user has required role [TEST LOG] Response status: 200 (expected: 200) --- PASS: TestRequireRoles_UserHasRequiredRole (0.00s) === RUN TestRequireRoles_UserLacksRequiredRole [TEST] === TestRequireRoles_UserLacksRequiredRole === [RBAC DEBUG] === RequireRoles START for GET /admin === [RBAC DEBUG] Required roles: [admin superadmin] [RBAC DEBUG] Raw roles from context: [user viewer] (type: []string) [RBAC DEBUG] Extracted roles: [user viewer] [RBAC DEBUG] FAILED: User roles [user viewer] do not match required [admin superadmin] [TEST LOG] Response status: 403 (expected: 403) --- PASS: TestRequireRoles_UserLacksRequiredRole (0.00s) === RUN TestRequireRoles_CaseInsensitive [TEST] === TestRequireRoles_CaseInsensitive === [RBAC DEBUG] === RequireRoles START for GET /admin === [RBAC DEBUG] Required roles: [admin] [RBAC DEBUG] Raw roles from context: [ADMIN USER] (type: []string) [RBAC DEBUG] Extracted roles: [ADMIN USER] [RBAC DEBUG] SUCCESS: User has required role [TEST LOG] Handler reached - case insensitive match worked [TEST LOG] Response status: 200 (expected: 200) --- PASS: TestRequireRoles_CaseInsensitive (0.00s) === RUN TestRequireRoles_NoRolesInContext [TEST] === TestRequireRoles_NoRolesInContext === [RBAC DEBUG] === RequireRoles START for GET /admin === [RBAC DEBUG] Required roles: [admin] [RBAC DEBUG] Raw roles from context: (type: ) [RBAC DEBUG] Extracted roles: [] [RBAC DEBUG] FAILED: No roles found in context [TEST LOG] Response status: 403 (expected: 403) --- PASS: TestRequireRoles_NoRolesInContext (0.00s) === RUN TestRequireRoles_MultipleAllowedRoles [TEST] === TestRequireRoles_MultipleAllowedRoles === [RBAC DEBUG] === RequireRoles START for GET /manage === [RBAC DEBUG] Required roles: [admin moderator superadmin] [RBAC DEBUG] Raw roles from context: [moderator] (type: []string) [RBAC DEBUG] Extracted roles: [moderator] [RBAC DEBUG] SUCCESS: User has required role [TEST LOG] Handler reached - matched one of multiple allowed roles [TEST LOG] Response status: 200 (expected: 200) --- PASS: TestRequireRoles_MultipleAllowedRoles (0.00s) === RUN TestTenantGuard_ValidTenant [TEST] === TestTenantGuard_ValidTenant === [TEST LOG] Handler reached - tenant is valid [TEST LOG] Response status: 200 (expected: 200) --- PASS: TestTenantGuard_ValidTenant (0.00s) === RUN TestTenantGuard_MissingTenant [TEST] === TestTenantGuard_MissingTenant === [TEST LOG] Response status: 403 (expected: 403) --- PASS: TestTenantGuard_MissingTenant (0.00s) === RUN TestTenantGuard_EmptyTenant [TEST] === TestTenantGuard_EmptyTenant === [TEST LOG] Response status: 403 (expected: 403) --- PASS: TestTenantGuard_EmptyTenant (0.00s) === RUN TestExtractRoles_FromStringSlice [TEST] === TestExtractRoles_FromStringSlice === [TEST LOG] Input: [admin user viewer], Result: [admin user viewer] --- PASS: TestExtractRoles_FromStringSlice (0.00s) === RUN TestExtractRoles_FromInterfaceSlice [TEST] === TestExtractRoles_FromInterfaceSlice === [TEST LOG] Input: [admin moderator], Result: [admin moderator] --- PASS: TestExtractRoles_FromInterfaceSlice (0.00s) === RUN TestExtractRoles_FromNil [TEST] === TestExtractRoles_FromNil === [TEST LOG] Input: nil, Result: [] --- PASS: TestExtractRoles_FromNil (0.00s) === RUN TestExtractRoles_FromUnknownType [TEST] === TestExtractRoles_FromUnknownType === [TEST LOG] Input: not-a-slice (type: string), Result: [] --- PASS: TestExtractRoles_FromUnknownType (0.00s) === RUN TestExtractRoles_FromMixedInterfaceSlice [TEST] === TestExtractRoles_FromMixedInterfaceSlice === [TEST LOG] Input: [admin 123 user ], Result: [admin user] --- PASS: TestExtractRoles_FromMixedInterfaceSlice (0.00s) === RUN TestHasRole_SingleMatch [TEST] === TestHasRole_SingleMatch === [TEST LOG] User roles: [admin user], Allowed: [admin], Result: true --- PASS: TestHasRole_SingleMatch (0.00s) === RUN TestHasRole_NoMatch [TEST] === TestHasRole_NoMatch === [TEST LOG] User roles: [user viewer], Allowed: [admin superadmin], Result: false --- PASS: TestHasRole_NoMatch (0.00s) === RUN TestHasRole_CaseInsensitive [TEST] === TestHasRole_CaseInsensitive === [TEST LOG] User roles: [ADMIN USER], Allowed: [admin], Result: true --- PASS: TestHasRole_CaseInsensitive (0.00s) === RUN TestHasRole_EmptyUserRoles [TEST] === TestHasRole_EmptyUserRoles === [TEST LOG] User roles: [], Allowed: [admin], Result: false --- PASS: TestHasRole_EmptyUserRoles (0.00s) === RUN TestHasRole_EmptyAllowedRoles [TEST] === TestHasRole_EmptyAllowedRoles === [TEST LOG] User roles: [admin], Allowed: [], Result: false --- PASS: TestHasRole_EmptyAllowedRoles (0.00s) === RUN TestCORSMiddleware_AllowedOrigin [TEST] === TestCORSMiddleware_AllowedOrigin === [TEST LOG] Handler reached - CORS headers should be set [TEST LOG] Access-Control-Allow-Origin: 'http://localhost:3000' [TEST LOG] Access-Control-Allow-Credentials: 'true' --- PASS: TestCORSMiddleware_AllowedOrigin (0.00s) === RUN TestCORSMiddleware_DeniedOrigin [TEST] === TestCORSMiddleware_DeniedOrigin === [TEST LOG] Handler reached - CORS origin should be empty [TEST LOG] Access-Control-Allow-Origin: '' (expected empty) --- PASS: TestCORSMiddleware_DeniedOrigin (0.00s) === RUN TestCORSMiddleware_WildcardOrigin [TEST] === TestCORSMiddleware_WildcardOrigin === [TEST LOG] Handler reached - wildcard CORS [TEST LOG] Access-Control-Allow-Origin: '*' (expected *) --- PASS: TestCORSMiddleware_WildcardOrigin (0.00s) === RUN TestCORSMiddleware_PreflightOptions [TEST] === TestCORSMiddleware_PreflightOptions === [TEST LOG] Response status: 200 (expected: 200 for preflight) [TEST LOG] Handler was called: false (expected: false) [TEST LOG] Access-Control-Allow-Methods: 'POST, GET, OPTIONS, PUT, PATCH, DELETE' --- PASS: TestCORSMiddleware_PreflightOptions (0.00s) === RUN TestCORSMiddleware_DefaultOrigin [TEST] === TestCORSMiddleware_DefaultOrigin === [TEST LOG] Handler reached - default origin [TEST LOG] Access-Control-Allow-Origin: 'http://localhost:3000' --- PASS: TestCORSMiddleware_DefaultOrigin (0.00s) === RUN TestCORSMiddleware_MultipleOrigins [TEST] === TestCORSMiddleware_MultipleOrigins === [TEST LOG] Access-Control-Allow-Origin: 'http://admin.example.com' --- PASS: TestCORSMiddleware_MultipleOrigins (0.00s) === RUN TestCORSMiddleware_NoOriginHeader [TEST] === TestCORSMiddleware_NoOriginHeader === [TEST LOG] Handler reached - no origin header in request [TEST LOG] Access-Control-Allow-Origin: '' (expected empty) --- PASS: TestCORSMiddleware_NoOriginHeader (0.00s) PASS ok github.com/rede5/gohorsejobs/backend/internal/api/middleware 0.041s === RUN TestNewUser --- PASS: TestNewUser (0.00s) === RUN TestUser_AssignRole_And_HasPermission --- PASS: TestUser_AssignRole_And_HasPermission (0.00s) === RUN TestNewCompany --- PASS: TestNewCompany (0.00s) === RUN TestCompany_ActivateDeactivate --- PASS: TestCompany_ActivateDeactivate (0.00s) PASS ok github.com/rede5/gohorsejobs/backend/internal/core/domain/entity 0.007s ? github.com/rede5/gohorsejobs/backend/internal/core/dto [no test files] ? github.com/rede5/gohorsejobs/backend/internal/core/ports [no test files] === RUN TestLoginUseCase_Execute_StatusCheck === RUN TestLoginUseCase_Execute_StatusCheck/Active_user_(lowercase)_-_Should_Success [LOGIN DEBUG] Searching for user: test@example.com [LOGIN DEBUG] User found: ID=user-123, Status=active, HashPrefix=hashed_pas [LOGIN DEBUG] Password verification PASSED [LOGIN DEBUG] Status check PASSED === RUN TestLoginUseCase_Execute_StatusCheck/Active_user_(uppercase)_-_Should_Success [LOGIN DEBUG] Searching for user: test@example.com [LOGIN DEBUG] User found: ID=user-123, Status=ACTIVE, HashPrefix=hashed_pas [LOGIN DEBUG] Password verification PASSED [LOGIN DEBUG] Status check PASSED === RUN TestLoginUseCase_Execute_StatusCheck/Active_user_(mixed_case)_-_Should_Success [LOGIN DEBUG] Searching for user: test@example.com [LOGIN DEBUG] User found: ID=user-123, Status=Active, HashPrefix=hashed_pas [LOGIN DEBUG] Password verification PASSED [LOGIN DEBUG] Status check PASSED === RUN TestLoginUseCase_Execute_StatusCheck/Inactive_user_-_Should_Fail [LOGIN DEBUG] Searching for user: test@example.com [LOGIN DEBUG] User found: ID=user-123, Status=inactive, HashPrefix=hashed_pas [LOGIN DEBUG] Password verification PASSED [LOGIN DEBUG] Status check FAILED: Expected active, got 'inactive' === RUN TestLoginUseCase_Execute_StatusCheck/Banned_user_-_Should_Fail [LOGIN DEBUG] Searching for user: test@example.com [LOGIN DEBUG] User found: ID=user-123, Status=banned, HashPrefix=hashed_pas [LOGIN DEBUG] Password verification PASSED [LOGIN DEBUG] Status check FAILED: Expected active, got 'banned' --- PASS: TestLoginUseCase_Execute_StatusCheck (0.00s) --- PASS: TestLoginUseCase_Execute_StatusCheck/Active_user_(lowercase)_-_Should_Success (0.00s) --- PASS: TestLoginUseCase_Execute_StatusCheck/Active_user_(uppercase)_-_Should_Success (0.00s) --- PASS: TestLoginUseCase_Execute_StatusCheck/Active_user_(mixed_case)_-_Should_Success (0.00s) --- PASS: TestLoginUseCase_Execute_StatusCheck/Inactive_user_-_Should_Fail (0.00s) --- PASS: TestLoginUseCase_Execute_StatusCheck/Banned_user_-_Should_Fail (0.00s) === RUN TestRegisterCandidateUseCase_Execute === RUN TestRegisterCandidateUseCase_Execute/Success === RUN TestRegisterCandidateUseCase_Execute/EmailAlreadyExists === RUN TestRegisterCandidateUseCase_Execute/MetadataSaved === RUN TestRegisterCandidateUseCase_Execute/CompanyCreatedForCandidate --- PASS: TestRegisterCandidateUseCase_Execute (0.00s) --- PASS: TestRegisterCandidateUseCase_Execute/Success (0.00s) --- PASS: TestRegisterCandidateUseCase_Execute/EmailAlreadyExists (0.00s) --- PASS: TestRegisterCandidateUseCase_Execute/MetadataSaved (0.00s) --- PASS: TestRegisterCandidateUseCase_Execute/CompanyCreatedForCandidate (0.00s) PASS ok github.com/rede5/gohorsejobs/backend/internal/core/usecases/auth 0.004s ? github.com/rede5/gohorsejobs/backend/internal/core/usecases/tenant [no test files] ? github.com/rede5/gohorsejobs/backend/internal/core/usecases/user [no test files] === RUN TestBuildConnectionString 2026/01/01 14:38:55 Using DATABASE_URL for connection 2026/01/01 14:38:55 Using individual DB_* params for connection --- PASS: TestBuildConnectionString (0.00s) === RUN TestRunMigrations 2026/01/01 14:38:55 📦 Running migration: 001_test.sql 2026/01/01 14:38:55 ✅ Migration 001_test.sql executed successfully 2026/01/01 14:38:55 All migrations processed --- PASS: TestRunMigrations (0.00s) PASS ok github.com/rede5/gohorsejobs/backend/internal/database 0.007s ? github.com/rede5/gohorsejobs/backend/internal/dto [no test files] === RUN TestCreateApplication_Success --- PASS: TestCreateApplication_Success (0.00s) === RUN TestCreateApplication_InvalidJSON --- PASS: TestCreateApplication_InvalidJSON (0.00s) === RUN TestCreateApplication_ServiceError --- PASS: TestCreateApplication_ServiceError (0.00s) === RUN TestGetApplications_Success --- PASS: TestGetApplications_Success (0.00s) === RUN TestGetApplications_Empty --- PASS: TestGetApplications_Empty (0.00s) === RUN TestGetApplications_Error --- PASS: TestGetApplications_Error (0.00s) === RUN TestGetApplicationByID_Success --- PASS: TestGetApplicationByID_Success (0.00s) === RUN TestGetApplicationByID_NotFound --- PASS: TestGetApplicationByID_NotFound (0.00s) === RUN TestUpdateApplicationStatus_Success --- PASS: TestUpdateApplicationStatus_Success (0.00s) === RUN TestUpdateApplicationStatus_InvalidJSON --- PASS: TestUpdateApplicationStatus_InvalidJSON (0.00s) === RUN TestUpdateApplicationStatus_Error --- PASS: TestUpdateApplicationStatus_Error (0.00s) === RUN TestGetJobs_Success --- PASS: TestGetJobs_Success (0.00s) === RUN TestGetJobs_Empty --- PASS: TestGetJobs_Empty (0.00s) === RUN TestGetJobs_Error --- PASS: TestGetJobs_Error (0.00s) === RUN TestCreateJob_Success --- PASS: TestCreateJob_Success (0.00s) === RUN TestCreateJob_InvalidJSON --- PASS: TestCreateJob_InvalidJSON (0.00s) === RUN TestCreateJob_ServiceError --- PASS: TestCreateJob_ServiceError (0.00s) === RUN TestGetJobByID_Success --- PASS: TestGetJobByID_Success (0.00s) === RUN TestGetJobByID_NotFound --- PASS: TestGetJobByID_NotFound (0.00s) === RUN TestDeleteJob_Success --- PASS: TestDeleteJob_Success (0.00s) === RUN TestDeleteJob_Error --- PASS: TestDeleteJob_Error (0.00s) PASS ok github.com/rede5/gohorsejobs/backend/internal/handlers 0.034s === RUN TestJWTService_HashAndVerifyPassword [TEST] === TestJWTService_HashAndVerifyPassword === === RUN TestJWTService_HashAndVerifyPassword/Should_hash_and_verify_password_correctly [TEST LOG] Testing password hash and verify [TEST LOG] Hash generated: $2a$10$ByAhy3YIbrYbR... [TEST LOG] Password verification result: true === RUN TestJWTService_HashAndVerifyPassword/Should_fail_verification_with_wrong_password [TEST LOG] Testing wrong password rejection [TEST LOG] Wrong password verification result: false (expected false) === RUN TestJWTService_HashAndVerifyPassword/Should_fail_verification_with_wrong_pepper [TEST LOG] Testing wrong pepper rejection [TEST LOG] Wrong pepper verification result: false (expected false) --- PASS: TestJWTService_HashAndVerifyPassword (0.98s) --- PASS: TestJWTService_HashAndVerifyPassword/Should_hash_and_verify_password_correctly (0.30s) --- PASS: TestJWTService_HashAndVerifyPassword/Should_fail_verification_with_wrong_password (0.30s) --- PASS: TestJWTService_HashAndVerifyPassword/Should_fail_verification_with_wrong_pepper (0.37s) === RUN TestJWTService_HashPassword_NoPepper [TEST] === TestJWTService_HashPassword_NoPepper === [TEST LOG] Hash without pepper: $2a$10$HqwM6UutC6X19... [TEST LOG] Verification without pepper: true --- PASS: TestJWTService_HashPassword_NoPepper (0.27s) === RUN TestJWTService_TokenOperations [TEST] === TestJWTService_TokenOperations === === RUN TestJWTService_TokenOperations/Should_generate_and_validate_token [TEST LOG] Testing token generation and validation [TEST LOG] Token generated: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3N... [TEST LOG] Claims: sub=user-123, tenant=tenant-456 === RUN TestJWTService_TokenOperations/Should_fail_invalid_token [TEST LOG] Testing invalid token rejection [TEST LOG] Invalid token error: token is malformed: token contains an invalid number of segments --- PASS: TestJWTService_TokenOperations (0.00s) --- PASS: TestJWTService_TokenOperations/Should_generate_and_validate_token (0.00s) --- PASS: TestJWTService_TokenOperations/Should_fail_invalid_token (0.00s) === RUN TestJWTService_GenerateToken_ExpirationParsing [TEST] === TestJWTService_GenerateToken_ExpirationParsing === === RUN TestJWTService_GenerateToken_ExpirationParsing/Default_expiration_(no_env) [TEST LOG] Testing default expiration (24h) [TEST LOG] Token with default expiration: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3N... [TEST LOG] Token claims: exp=1.767375539e+09 === RUN TestJWTService_GenerateToken_ExpirationParsing/Days_format_(7d) [TEST LOG] Testing days format expiration (7d) [TEST LOG] Token with 7d expiration: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3N... === RUN TestJWTService_GenerateToken_ExpirationParsing/Duration_format_(2h) [TEST LOG] Testing duration format expiration (2h) [TEST LOG] Token with 2h expiration: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3N... === RUN TestJWTService_GenerateToken_ExpirationParsing/Invalid_days_format_fallback [TEST LOG] Testing invalid days format (abcd) [TEST LOG] Token with invalid format (fallback): eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3N... === RUN TestJWTService_GenerateToken_ExpirationParsing/Invalid_day_number_fallback [TEST LOG] Testing invalid day number (xxd) [TEST LOG] Token with xxd format (fallback): eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3N... --- PASS: TestJWTService_GenerateToken_ExpirationParsing (0.00s) --- PASS: TestJWTService_GenerateToken_ExpirationParsing/Default_expiration_(no_env) (0.00s) --- PASS: TestJWTService_GenerateToken_ExpirationParsing/Days_format_(7d) (0.00s) --- PASS: TestJWTService_GenerateToken_ExpirationParsing/Duration_format_(2h) (0.00s) --- PASS: TestJWTService_GenerateToken_ExpirationParsing/Invalid_days_format_fallback (0.00s) --- PASS: TestJWTService_GenerateToken_ExpirationParsing/Invalid_day_number_fallback (0.00s) === RUN TestJWTService_ValidateToken_WrongSigningMethod [TEST] === TestJWTService_ValidateToken_WrongSigningMethod === === RUN TestJWTService_ValidateToken_WrongSigningMethod/Malformed_token [TEST LOG] Testing malformed token [TEST LOG] Malformed token error: token is unverifiable: error while executing keyfunc: unexpected signing method === RUN TestJWTService_ValidateToken_WrongSigningMethod/Token_with_different_secret [TEST LOG] Testing token from different secret [TEST LOG] Wrong secret error: token signature is invalid: signature is invalid --- PASS: TestJWTService_ValidateToken_WrongSigningMethod (0.00s) --- PASS: TestJWTService_ValidateToken_WrongSigningMethod/Malformed_token (0.00s) --- PASS: TestJWTService_ValidateToken_WrongSigningMethod/Token_with_different_secret (0.00s) === RUN TestJWTService_NewJWTService [TEST] === TestJWTService_NewJWTService === [TEST LOG] Service created: &{[109 121 45 115 101 99 114 101 116] my-issuer} --- PASS: TestJWTService_NewJWTService (0.00s) === RUN TestJWTService_HashPassword_EmptyPassword [TEST] === TestJWTService_HashPassword_EmptyPassword === === RUN TestJWTService_HashPassword_EmptyPassword/Empty_password_should_still_hash [TEST LOG] Empty password hash: $2a$10$Th7uegfjmUOkL... --- PASS: TestJWTService_HashPassword_EmptyPassword (0.19s) --- PASS: TestJWTService_HashPassword_EmptyPassword/Empty_password_should_still_hash (0.19s) === RUN TestJWTService_PepperConsistency [TEST] === TestJWTService_PepperConsistency === === RUN TestJWTService_PepperConsistency/Same_pepper_produces_verifiable_hash === RUN TestJWTService_PepperConsistency/Different_peppers_produce_different_hashes --- PASS: TestJWTService_PepperConsistency (0.49s) --- PASS: TestJWTService_PepperConsistency/Same_pepper_produces_verifiable_hash (0.21s) --- PASS: TestJWTService_PepperConsistency/Different_peppers_produce_different_hashes (0.28s) === RUN TestJWTService_TokenClaims_Content [TEST] === TestJWTService_TokenClaims_Content === === RUN TestJWTService_TokenClaims_Content/Token_should_contain_all_expected_claims --- PASS: TestJWTService_TokenClaims_Content (0.00s) --- PASS: TestJWTService_TokenClaims_Content/Token_should_contain_all_expected_claims (0.00s) === RUN TestJWTService_LongPassword [TEST] === TestJWTService_LongPassword === === RUN TestJWTService_LongPassword/Very_long_password_should_work --- PASS: TestJWTService_LongPassword (0.26s) --- PASS: TestJWTService_LongPassword/Very_long_password_should_work (0.26s) === RUN TestJWTService_SpecialCharactersPassword [TEST] === TestJWTService_SpecialCharactersPassword === === RUN TestJWTService_SpecialCharactersPassword/Password:_Admin@2025 === RUN TestJWTService_SpecialCharactersPassword/Password:_Pässwörd === RUN TestJWTService_SpecialCharactersPassword/Password:_密码123 === RUN TestJWTService_SpecialCharactersPassword/Password:_パスワ� === RUN TestJWTService_SpecialCharactersPassword/Password:_🔐Secure === RUN TestJWTService_SpecialCharactersPassword/Password:_test_with_ === RUN TestJWTService_SpecialCharactersPassword/Password:_tab_here --- PASS: TestJWTService_SpecialCharactersPassword (1.47s) --- PASS: TestJWTService_SpecialCharactersPassword/Password:_Admin@2025 (0.25s) --- PASS: TestJWTService_SpecialCharactersPassword/Password:_Pässwörd (0.21s) --- PASS: TestJWTService_SpecialCharactersPassword/Password:_密码123 (0.21s) --- PASS: TestJWTService_SpecialCharactersPassword/Password:_パスワ� (0.20s) --- PASS: TestJWTService_SpecialCharactersPassword/Password:_🔐Secure (0.21s) --- PASS: TestJWTService_SpecialCharactersPassword/Password:_test_with_ (0.19s) --- PASS: TestJWTService_SpecialCharactersPassword/Password:_tab_here (0.19s) PASS ok github.com/rede5/gohorsejobs/backend/internal/infrastructure/auth 3.670s ? github.com/rede5/gohorsejobs/backend/internal/infrastructure/email [no test files] ? github.com/rede5/gohorsejobs/backend/internal/infrastructure/persistence/postgres [no test files] ? github.com/rede5/gohorsejobs/backend/internal/infrastructure/storage [no test files] === RUN TestLoggingMiddleware 2026/01/01 14:38:59 GET /test 200 1.558µs --- PASS: TestLoggingMiddleware (0.00s) === RUN TestAuthMiddleware_Success --- PASS: TestAuthMiddleware_Success (0.00s) === RUN TestRateLimiter_isAllowed --- PASS: TestRateLimiter_isAllowed (0.00s) === RUN TestRateLimitMiddleware --- PASS: TestRateLimitMiddleware (0.00s) === RUN TestSecurityHeadersMiddleware --- PASS: TestSecurityHeadersMiddleware (0.00s) === RUN TestAuthMiddleware_NoAuthHeader --- PASS: TestAuthMiddleware_NoAuthHeader (0.00s) === RUN TestAuthMiddleware_InvalidFormat --- PASS: TestAuthMiddleware_InvalidFormat (0.00s) === RUN TestAuthMiddleware_InvalidToken --- PASS: TestAuthMiddleware_InvalidToken (0.00s) === RUN TestRequireRole_NoClaims --- PASS: TestRequireRole_NoClaims (0.00s) === RUN TestCORSMiddleware --- PASS: TestCORSMiddleware (0.00s) === RUN TestSanitizeMiddleware --- PASS: TestSanitizeMiddleware (0.00s) === RUN TestRequireRole_Success --- PASS: TestRequireRole_Success (0.00s) === RUN TestRequireRole_Forbidden --- PASS: TestRequireRole_Forbidden (0.00s) === RUN TestSanitizeMiddleware_InvalidJSON --- PASS: TestSanitizeMiddleware_InvalidJSON (0.00s) PASS ok github.com/rede5/gohorsejobs/backend/internal/middleware 0.015s ? github.com/rede5/gohorsejobs/backend/internal/models [no test files] === RUN TestRootHandler --- PASS: TestRootHandler (0.00s) PASS ok github.com/rede5/gohorsejobs/backend/internal/router 0.046s === RUN TestAdminService_ListCompanies === RUN TestAdminService_ListCompanies/returns_empty_list_when_no_companies === RUN TestAdminService_ListCompanies/filters_by_verified_status --- PASS: TestAdminService_ListCompanies (0.00s) --- PASS: TestAdminService_ListCompanies/returns_empty_list_when_no_companies (0.00s) --- PASS: TestAdminService_ListCompanies/filters_by_verified_status (0.00s) === RUN TestAdminService_ListTags === RUN TestAdminService_ListTags/returns_empty_list_when_no_tags === RUN TestAdminService_ListTags/filters_by_category --- PASS: TestAdminService_ListTags (0.00s) --- PASS: TestAdminService_ListTags/returns_empty_list_when_no_tags (0.00s) --- PASS: TestAdminService_ListTags/filters_by_category (0.00s) === RUN TestAdminService_CreateTag === RUN TestAdminService_CreateTag/creates_a_new_tag === RUN TestAdminService_CreateTag/rejects_empty_tag_name --- PASS: TestAdminService_CreateTag (0.00s) --- PASS: TestAdminService_CreateTag/creates_a_new_tag (0.00s) --- PASS: TestAdminService_CreateTag/rejects_empty_tag_name (0.00s) === RUN TestAdminService_GetUser === RUN TestAdminService_GetUser/returns_user_by_id --- PASS: TestAdminService_GetUser (0.00s) --- PASS: TestAdminService_GetUser/returns_user_by_id (0.00s) === RUN TestAdminService_UpdateCompanyStatus === RUN TestAdminService_UpdateCompanyStatus/updates_active_status_successfully === RUN TestAdminService_UpdateCompanyStatus/updates_verified_status_successfully === RUN TestAdminService_UpdateCompanyStatus/returns_error_when_company_not_found --- PASS: TestAdminService_UpdateCompanyStatus (0.00s) --- PASS: TestAdminService_UpdateCompanyStatus/updates_active_status_successfully (0.00s) --- PASS: TestAdminService_UpdateCompanyStatus/updates_verified_status_successfully (0.00s) --- PASS: TestAdminService_UpdateCompanyStatus/returns_error_when_company_not_found (0.00s) === RUN TestAdminService_ListUsers === RUN TestAdminService_ListUsers/returns_users_list --- PASS: TestAdminService_ListUsers (0.00s) --- PASS: TestAdminService_ListUsers/returns_users_list (0.00s) === RUN TestAdminService_DuplicateJob --- PASS: TestAdminService_DuplicateJob (0.00s) === RUN TestAdminService_EmailTemplates === RUN TestAdminService_EmailTemplates/ListEmailTemplates === RUN TestAdminService_EmailTemplates/CreateEmailTemplate --- PASS: TestAdminService_EmailTemplates (0.00s) --- PASS: TestAdminService_EmailTemplates/ListEmailTemplates (0.00s) --- PASS: TestAdminService_EmailTemplates/CreateEmailTemplate (0.00s) === RUN TestNewApplicationService --- PASS: TestNewApplicationService (0.00s) === RUN TestApplicationService_DeleteApplication --- PASS: TestApplicationService_DeleteApplication (0.00s) === RUN TestApplicationService_CreateApplication --- PASS: TestApplicationService_CreateApplication (0.00s) === RUN TestApplicationService_GetApplications --- PASS: TestApplicationService_GetApplications (0.00s) === RUN TestApplicationService_GetApplicationByID --- PASS: TestApplicationService_GetApplicationByID (0.00s) === RUN TestAuditService_RecordLogin === RUN TestAuditService_RecordLogin/records_login_successfully === RUN TestAuditService_RecordLogin/records_login_without_optional_fields --- PASS: TestAuditService_RecordLogin (0.00s) --- PASS: TestAuditService_RecordLogin/records_login_successfully (0.00s) --- PASS: TestAuditService_RecordLogin/records_login_without_optional_fields (0.00s) === RUN TestAuditService_ListLogins === RUN TestAuditService_ListLogins/returns_empty_list_when_no_audits === RUN TestAuditService_ListLogins/respects_custom_limit --- PASS: TestAuditService_ListLogins (0.00s) --- PASS: TestAuditService_ListLogins/returns_empty_list_when_no_audits (0.00s) --- PASS: TestAuditService_ListLogins/respects_custom_limit (0.00s) === RUN TestNotificationService_ListNotifications === RUN TestNotificationService_ListNotifications/returns_empty_list_when_no_notifications --- PASS: TestNotificationService_ListNotifications (0.00s) --- PASS: TestNotificationService_ListNotifications/returns_empty_list_when_no_notifications (0.00s) === RUN TestNotificationService_CreateNotification === RUN TestNotificationService_CreateNotification/creates_a_new_notification --- PASS: TestNotificationService_CreateNotification (0.00s) --- PASS: TestNotificationService_CreateNotification/creates_a_new_notification (0.00s) === RUN TestNotificationService_MarkAsRead === RUN TestNotificationService_MarkAsRead/marks_notification_as_read --- PASS: TestNotificationService_MarkAsRead (0.00s) --- PASS: TestNotificationService_MarkAsRead/marks_notification_as_read (0.00s) === RUN TestNotificationService_MarkAllAsRead === RUN TestNotificationService_MarkAllAsRead/marks_all_notifications_as_read --- PASS: TestNotificationService_MarkAllAsRead (0.00s) --- PASS: TestNotificationService_MarkAllAsRead/marks_all_notifications_as_read (0.00s) === RUN TestNewNotificationService --- PASS: TestNewNotificationService (0.00s) === RUN TestSaveCredentials --- PASS: TestSaveCredentials (0.00s) === RUN TestGetDecryptedKey --- PASS: TestGetDecryptedKey (0.03s) === RUN TestListConfiguredServices --- PASS: TestListConfiguredServices (0.00s) === RUN TestDeleteCredentials --- PASS: TestDeleteCredentials (0.00s) === RUN TestCreateJob === RUN TestCreateJob/Success [JOB_SERVICE DEBUG] === CreateJob Started === [JOB_SERVICE DEBUG] CompanyID=1, CreatedBy=user-123, Title=Go Developer, Status=published [JOB_SERVICE DEBUG] Executing INSERT query... [JOB_SERVICE DEBUG] Job struct: &{ID: CompanyID:1 CreatedBy:user-123 Title:Go Developer Description: SalaryMin: SalaryMax: SalaryType: Currency: SalaryNegotiable:false EmploymentType: WorkMode: WorkingHours: Location: RegionID: CityID: Requirements:map[] Benefits:map[] VisaSupport:false LanguageLevel: Status:published IsFeatured:false CreatedAt:2026-01-01 14:39:05.548082416 -0300 -03 m=+0.050863726 UpdatedAt:2026-01-01 14:39:05.548082508 -0300 -03 m=+0.050863818} [JOB_SERVICE DEBUG] Job created successfully! ID=100 === RUN TestCreateJob/DB_Error [JOB_SERVICE DEBUG] === CreateJob Started === [JOB_SERVICE DEBUG] CompanyID=1, CreatedBy=user-123, Title=Go Developer, Status= [JOB_SERVICE DEBUG] Executing INSERT query... [JOB_SERVICE DEBUG] Job struct: &{ID: CompanyID:1 CreatedBy:user-123 Title:Go Developer Description: SalaryMin: SalaryMax: SalaryType: Currency: SalaryNegotiable:false EmploymentType: WorkMode: WorkingHours: Location: RegionID: CityID: Requirements:map[] Benefits:map[] VisaSupport:false LanguageLevel: Status: IsFeatured:false CreatedAt:2026-01-01 14:39:05.548610508 -0300 -03 m=+0.051391818 UpdatedAt:2026-01-01 14:39:05.548610508 -0300 -03 m=+0.051391818} [JOB_SERVICE ERROR] INSERT query failed: assert.AnError general error for testing --- PASS: TestCreateJob (0.00s) --- PASS: TestCreateJob/Success (0.00s) --- PASS: TestCreateJob/DB_Error (0.00s) === RUN TestGetJobs === RUN TestGetJobs/List_All --- PASS: TestGetJobs (0.00s) --- PASS: TestGetJobs/List_All (0.00s) === RUN TestGetJobByID --- PASS: TestGetJobByID (0.00s) === RUN TestUpdateJob --- PASS: TestUpdateJob (0.00s) === RUN TestDeleteJob --- PASS: TestDeleteJob (0.00s) === RUN TestCreateTicket === RUN TestCreateTicket/Success === RUN TestCreateTicket/Default_Priority --- PASS: TestCreateTicket (0.00s) --- PASS: TestCreateTicket/Success (0.00s) --- PASS: TestCreateTicket/Default_Priority (0.00s) === RUN TestListTickets === RUN TestListTickets/Success --- PASS: TestListTickets (0.00s) --- PASS: TestListTickets/Success (0.00s) === RUN TestGetTicket === RUN TestGetTicket/Success --- PASS: TestGetTicket (0.00s) --- PASS: TestGetTicket/Success (0.00s) PASS ok github.com/rede5/gohorsejobs/backend/internal/services 0.061s === RUN TestSanitizeString === RUN TestSanitizeString/simple_text === RUN TestSanitizeString/with_whitespace === RUN TestSanitizeString/with_html === RUN TestSanitizeString/empty_string === RUN TestSanitizeString/special_chars --- PASS: TestSanitizeString (0.00s) --- PASS: TestSanitizeString/simple_text (0.00s) --- PASS: TestSanitizeString/with_whitespace (0.00s) --- PASS: TestSanitizeString/with_html (0.00s) --- PASS: TestSanitizeString/empty_string (0.00s) --- PASS: TestSanitizeString/special_chars (0.00s) === RUN TestSanitizeSlug === RUN TestSanitizeSlug/simple_text === RUN TestSanitizeSlug/special_chars === RUN TestSanitizeSlug/multiple_spaces === RUN TestSanitizeSlug/already_slug === RUN TestSanitizeSlug/numbers --- PASS: TestSanitizeSlug (0.00s) --- PASS: TestSanitizeSlug/simple_text (0.00s) --- PASS: TestSanitizeSlug/special_chars (0.00s) --- PASS: TestSanitizeSlug/multiple_spaces (0.00s) --- PASS: TestSanitizeSlug/already_slug (0.00s) --- PASS: TestSanitizeSlug/numbers (0.00s) === RUN TestSanitizeName === RUN TestSanitizeName/short_name === RUN TestSanitizeName/max_length === RUN TestSanitizeName/over_limit --- PASS: TestSanitizeName (0.00s) --- PASS: TestSanitizeName/short_name (0.00s) --- PASS: TestSanitizeName/max_length (0.00s) --- PASS: TestSanitizeName/over_limit (0.00s) === RUN TestStripHTML === RUN TestStripHTML/simple_html === RUN TestStripHTML/script_tag === RUN TestStripHTML/nested_tags === RUN TestStripHTML/no_html --- PASS: TestStripHTML (0.00s) --- PASS: TestStripHTML/simple_html (0.00s) --- PASS: TestStripHTML/script_tag (0.00s) --- PASS: TestStripHTML/nested_tags (0.00s) --- PASS: TestStripHTML/no_html (0.00s) === RUN TestSanitizeEmail === RUN TestSanitizeEmail/simple_email === RUN TestSanitizeEmail/with_whitespace === RUN TestSanitizeEmail/empty_string === RUN TestSanitizeEmail/over_max_length --- PASS: TestSanitizeEmail (0.00s) --- PASS: TestSanitizeEmail/simple_email (0.00s) --- PASS: TestSanitizeEmail/with_whitespace (0.00s) --- PASS: TestSanitizeEmail/empty_string (0.00s) --- PASS: TestSanitizeEmail/over_max_length (0.00s) === RUN TestSanitizeDescription === RUN TestSanitizeDescription/short_description === RUN TestSanitizeDescription/with_html === RUN TestSanitizeDescription/empty_string === RUN TestSanitizeDescription/over_limit --- PASS: TestSanitizeDescription (0.00s) --- PASS: TestSanitizeDescription/short_description (0.00s) --- PASS: TestSanitizeDescription/with_html (0.00s) --- PASS: TestSanitizeDescription/empty_string (0.00s) --- PASS: TestSanitizeDescription/over_limit (0.00s) === RUN TestDefaultSanitizer --- PASS: TestDefaultSanitizer (0.00s) PASS ok github.com/rede5/gohorsejobs/backend/internal/utils 0.010s ? github.com/rede5/gohorsejobs/backend/internal/utils/uuid [no test files] === RUN TestVerifyLogin 🔍 Found hash in DB: $2a$10$x7AN/r8MpVylJnd2uq4HT.lZbbNCqHuBuadpsr4xV.KlsleITmR5. verify_login_test.go:73: ✅ SUCCESS! Password verifies correctly with pepper 'some-random-string-for-password-hashing' --- PASS: TestVerifyLogin (0.83s) === RUN TestVerifyLoginNoPepper verify_login_test.go:106: ✅ Hash was NOT created without pepper (expected) --- PASS: TestVerifyLoginNoPepper (0.37s) PASS ok github.com/rede5/gohorsejobs/backend/tests 1.207s ? github.com/rede5/gohorsejobs/backend/tests/integration [no test files]