From 7bbebcc6922fe40a59eaa333519eaf0fc3f1f1fe Mon Sep 17 00:00:00 2001 From: AdithaBuwaneka Date: Fri, 21 Nov 2025 14:19:30 +0530 Subject: [PATCH 01/20] Add comprehensive repository tests for Role, User, UserPreferences, and VerificationToken - Implemented RoleRepositoryTest with tests for find, save, update, and delete operations. - Created UserPreferencesRepositoryTest covering save, find, update, and delete functionalities. - Developed UserRepositoryTest to validate user retrieval, existence checks, and updates. - Added VerificationTokenRepositoryTest to ensure proper handling of verification tokens, including expiration and usage checks. - Each test class includes edge cases and verifies database constraints. --- .../repository/LoginLockRepositoryTest.java | 286 +++++++++++++ .../repository/LoginLogRepositoryTest.java | 240 +++++++++++ .../repository/PermissionRepositoryTest.java | 316 ++++++++++++++ .../RefreshTokenRepositoryTest.java | 357 ++++++++++++++++ .../repository/RoleRepositoryTest.java | 268 ++++++++++++ .../UserPreferencesRepositoryTest.java | 395 ++++++++++++++++++ .../repository/UserRepositoryTest.java | 382 +++++++++++++++++ .../VerificationTokenRepositoryTest.java | 388 +++++++++++++++++ 8 files changed, 2632 insertions(+) create mode 100644 auth-service/src/test/java/com/techtorque/auth_service/repository/LoginLockRepositoryTest.java create mode 100644 auth-service/src/test/java/com/techtorque/auth_service/repository/LoginLogRepositoryTest.java create mode 100644 auth-service/src/test/java/com/techtorque/auth_service/repository/PermissionRepositoryTest.java create mode 100644 auth-service/src/test/java/com/techtorque/auth_service/repository/RefreshTokenRepositoryTest.java create mode 100644 auth-service/src/test/java/com/techtorque/auth_service/repository/RoleRepositoryTest.java create mode 100644 auth-service/src/test/java/com/techtorque/auth_service/repository/UserPreferencesRepositoryTest.java create mode 100644 auth-service/src/test/java/com/techtorque/auth_service/repository/UserRepositoryTest.java create mode 100644 auth-service/src/test/java/com/techtorque/auth_service/repository/VerificationTokenRepositoryTest.java diff --git a/auth-service/src/test/java/com/techtorque/auth_service/repository/LoginLockRepositoryTest.java b/auth-service/src/test/java/com/techtorque/auth_service/repository/LoginLockRepositoryTest.java new file mode 100644 index 0000000..f9a919d --- /dev/null +++ b/auth-service/src/test/java/com/techtorque/auth_service/repository/LoginLockRepositoryTest.java @@ -0,0 +1,286 @@ +package com.techtorque.auth_service.repository; + +import com.techtorque.auth_service.entity.LoginLock; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Comprehensive test class for LoginLockRepository + * Tests all repository methods, edge cases, and database constraints + */ +@DataJpaTest +@ActiveProfiles("test") +class LoginLockRepositoryTest { + + @Autowired + private TestEntityManager entityManager; + + @Autowired + private LoginLockRepository loginLockRepository; + + private LoginLock testLoginLock; + + @BeforeEach + void setUp() { + testLoginLock = LoginLock.builder() + .username("testuser") + .failedAttempts(3) + .lockUntil(LocalDateTime.now().plusMinutes(15)) + .build(); + } + + @Test + void save_WhenValidLoginLock_ShouldPersistSuccessfully() { + // When + LoginLock savedLock = loginLockRepository.save(testLoginLock); + + // Then + assertThat(savedLock.getId()).isNotNull(); + assertThat(savedLock.getUsername()).isEqualTo("testuser"); + assertThat(savedLock.getFailedAttempts()).isEqualTo(3); + assertThat(savedLock.getLockUntil()).isNotNull(); + } + + @Test + void save_WithDefaultFailedAttempts_ShouldUseZero() { + // Given + LoginLock lockWithDefaults = LoginLock.builder() + .username("newuser") + .build(); + + // When + LoginLock savedLock = loginLockRepository.save(lockWithDefaults); + + // Then + assertThat(savedLock.getId()).isNotNull(); + assertThat(savedLock.getUsername()).isEqualTo("newuser"); + assertThat(savedLock.getFailedAttempts()).isEqualTo(0); + assertThat(savedLock.getLockUntil()).isNull(); + } + + @Test + void findByUsername_WhenLockExists_ShouldReturnLock() { + // Given + entityManager.persistAndFlush(testLoginLock); + + // When + Optional result = loginLockRepository.findByUsername("testuser"); + + // Then + assertThat(result).isPresent(); + assertThat(result.get().getUsername()).isEqualTo("testuser"); + assertThat(result.get().getFailedAttempts()).isEqualTo(3); + } + + @Test + void findByUsername_WhenLockDoesNotExist_ShouldReturnEmpty() { + // When + Optional result = loginLockRepository.findByUsername("nonexistent"); + + // Then + assertThat(result).isEmpty(); + } + + @Test + void findByUsername_CaseSensitive_ShouldReturnEmpty() { + // Given + entityManager.persistAndFlush(testLoginLock); + + // When + Optional result = loginLockRepository.findByUsername("TESTUSER"); + + // Then + assertThat(result).isEmpty(); + } + + @Test + @Transactional + void deleteByUsername_WhenLockExists_ShouldDeleteLock() { + // Given + entityManager.persistAndFlush(testLoginLock); + + LoginLock anotherLock = LoginLock.builder() + .username("anotheruser") + .failedAttempts(1) + .build(); + entityManager.persistAndFlush(anotherLock); + + // When + loginLockRepository.deleteByUsername("testuser"); + entityManager.flush(); + + // Then + Optional deletedLock = loginLockRepository.findByUsername("testuser"); + Optional remainingLock = loginLockRepository.findByUsername("anotheruser"); + + assertThat(deletedLock).isEmpty(); + assertThat(remainingLock).isPresent(); + } + + @Test + void update_WhenLockExists_ShouldUpdateSuccessfully() { + // Given + LoginLock savedLock = entityManager.persistAndFlush(testLoginLock); + entityManager.detach(savedLock); + + // When + savedLock.setFailedAttempts(5); + savedLock.setLockUntil(LocalDateTime.now().plusMinutes(30)); + LoginLock updatedLock = loginLockRepository.save(savedLock); + + // Then + assertThat(updatedLock.getFailedAttempts()).isEqualTo(5); + assertThat(updatedLock.getLockUntil()).isNotNull(); + assertThat(updatedLock.getUsername()).isEqualTo("testuser"); // Should remain unchanged + } + + @Test + void findById_WhenLockExists_ShouldReturnLock() { + // Given + LoginLock savedLock = entityManager.persistAndFlush(testLoginLock); + + // When + Optional result = loginLockRepository.findById(savedLock.getId()); + + // Then + assertThat(result).isPresent(); + assertThat(result.get().getId()).isEqualTo(savedLock.getId()); + assertThat(result.get().getUsername()).isEqualTo("testuser"); + } + + @Test + void findById_WhenLockDoesNotExist_ShouldReturnEmpty() { + // When + Optional result = loginLockRepository.findById(999L); + + // Then + assertThat(result).isEmpty(); + } + + @Test + void findAll_ShouldReturnAllLocks() { + // Given + LoginLock lock1 = LoginLock.builder() + .username("user1") + .failedAttempts(2) + .lockUntil(LocalDateTime.now().plusMinutes(10)) + .build(); + + LoginLock lock2 = LoginLock.builder() + .username("user2") + .failedAttempts(1) + .build(); + + entityManager.persistAndFlush(lock1); + entityManager.persistAndFlush(lock2); + + // When + List allLocks = loginLockRepository.findAll(); + + // Then + assertThat(allLocks).hasSize(2); + assertThat(allLocks).extracting("username") + .containsExactlyInAnyOrder("user1", "user2"); + } + + @Test + void count_ShouldReturnCorrectCount() { + // Given + entityManager.persistAndFlush(testLoginLock); + + LoginLock secondLock = LoginLock.builder() + .username("user2") + .failedAttempts(1) + .build(); + entityManager.persistAndFlush(secondLock); + + // When + long count = loginLockRepository.count(); + + // Then + assertThat(count).isEqualTo(2); + } + + @Test + void save_WithoutLockUntil_ShouldPersistSuccessfully() { + // Given + LoginLock lockWithoutLockUntil = LoginLock.builder() + .username("testuser2") + .failedAttempts(1) + .lockUntil(null) + .build(); + + // When + LoginLock savedLock = loginLockRepository.save(lockWithoutLockUntil); + + // Then + assertThat(savedLock.getId()).isNotNull(); + assertThat(savedLock.getUsername()).isEqualTo("testuser2"); + assertThat(savedLock.getFailedAttempts()).isEqualTo(1); + assertThat(savedLock.getLockUntil()).isNull(); + } + + @Test + void save_WithZeroFailedAttempts_ShouldPersistSuccessfully() { + // Given + LoginLock lockWithZeroAttempts = LoginLock.builder() + .username("testuser3") + .failedAttempts(0) + .build(); + + // When + LoginLock savedLock = loginLockRepository.save(lockWithZeroAttempts); + + // Then + assertThat(savedLock.getId()).isNotNull(); + assertThat(savedLock.getUsername()).isEqualTo("testuser3"); + assertThat(savedLock.getFailedAttempts()).isEqualTo(0); + } + + @Test + void existsById_WhenLockExists_ShouldReturnTrue() { + // Given + LoginLock savedLock = entityManager.persistAndFlush(testLoginLock); + + // When + boolean exists = loginLockRepository.existsById(savedLock.getId()); + + // Then + assertThat(exists).isTrue(); + } + + @Test + void existsById_WhenLockDoesNotExist_ShouldReturnFalse() { + // When + boolean exists = loginLockRepository.existsById(999L); + + // Then + assertThat(exists).isFalse(); + } + + @Test + void deleteById_WhenLockExists_ShouldRemoveLock() { + // Given + LoginLock savedLock = entityManager.persistAndFlush(testLoginLock); + Long lockId = savedLock.getId(); + + // When + loginLockRepository.deleteById(lockId); + entityManager.flush(); + + // Then + Optional result = loginLockRepository.findById(lockId); + assertThat(result).isEmpty(); + } +} \ No newline at end of file diff --git a/auth-service/src/test/java/com/techtorque/auth_service/repository/LoginLogRepositoryTest.java b/auth-service/src/test/java/com/techtorque/auth_service/repository/LoginLogRepositoryTest.java new file mode 100644 index 0000000..0dbe12f --- /dev/null +++ b/auth-service/src/test/java/com/techtorque/auth_service/repository/LoginLogRepositoryTest.java @@ -0,0 +1,240 @@ +package com.techtorque.auth_service.repository; + +import com.techtorque.auth_service.entity.LoginLog; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Comprehensive test class for LoginLogRepository + * Tests all repository methods, edge cases, and database constraints + */ +@DataJpaTest +@ActiveProfiles("test") +class LoginLogRepositoryTest { + + @Autowired + private TestEntityManager entityManager; + + @Autowired + private LoginLogRepository loginLogRepository; + + private LoginLog testLoginLog; + + @BeforeEach + void setUp() { + testLoginLog = LoginLog.builder() + .username("testuser") + .success(true) + .ipAddress("192.168.1.1") + .userAgent("Mozilla/5.0 Test Browser") + .createdAt(LocalDateTime.now()) + .build(); + } + + @Test + void save_WhenValidLoginLog_ShouldPersistSuccessfully() { + // When + LoginLog savedLog = loginLogRepository.save(testLoginLog); + + // Then + assertThat(savedLog.getId()).isNotNull(); + assertThat(savedLog.getUsername()).isEqualTo("testuser"); + assertThat(savedLog.getSuccess()).isTrue(); + assertThat(savedLog.getIpAddress()).isEqualTo("192.168.1.1"); + assertThat(savedLog.getUserAgent()).isEqualTo("Mozilla/5.0 Test Browser"); + assertThat(savedLog.getCreatedAt()).isNotNull(); + } + + @Test + void save_WithFailedLogin_ShouldPersistSuccessfully() { + // Given + LoginLog failedLog = LoginLog.builder() + .username("testuser") + .success(false) + .ipAddress("192.168.1.2") + .userAgent("Chrome Test") + .createdAt(LocalDateTime.now()) + .build(); + + // When + LoginLog savedLog = loginLogRepository.save(failedLog); + + // Then + assertThat(savedLog.getId()).isNotNull(); + assertThat(savedLog.getUsername()).isEqualTo("testuser"); + assertThat(savedLog.getSuccess()).isFalse(); + assertThat(savedLog.getIpAddress()).isEqualTo("192.168.1.2"); + assertThat(savedLog.getUserAgent()).isEqualTo("Chrome Test"); + } + + @Test + @Transactional + void deleteByUsername_WhenUserHasLogs_ShouldDeleteAllUserLogs() { + // Given + LoginLog log1 = LoginLog.builder() + .username("testuser") + .success(true) + .ipAddress("192.168.1.1") + .userAgent("Browser 1") + .createdAt(LocalDateTime.now()) + .build(); + + LoginLog log2 = LoginLog.builder() + .username("testuser") + .success(false) + .ipAddress("192.168.1.2") + .userAgent("Browser 2") + .createdAt(LocalDateTime.now()) + .build(); + + LoginLog anotherUserLog = LoginLog.builder() + .username("anotheruser") + .success(true) + .ipAddress("192.168.1.3") + .userAgent("Browser 3") + .createdAt(LocalDateTime.now()) + .build(); + + entityManager.persistAndFlush(log1); + entityManager.persistAndFlush(log2); + entityManager.persistAndFlush(anotherUserLog); + + // When + loginLogRepository.deleteByUsername("testuser"); + entityManager.flush(); + + // Then + List remainingLogs = loginLogRepository.findAll(); + assertThat(remainingLogs).hasSize(1); + assertThat(remainingLogs.get(0).getUsername()).isEqualTo("anotheruser"); + } + + @Test + void findById_WhenLogExists_ShouldReturnLog() { + // Given + LoginLog savedLog = entityManager.persistAndFlush(testLoginLog); + + // When + Optional result = loginLogRepository.findById(savedLog.getId()); + + // Then + assertThat(result).isPresent(); + assertThat(result.get().getId()).isEqualTo(savedLog.getId()); + assertThat(result.get().getUsername()).isEqualTo("testuser"); + } + + @Test + void findById_WhenLogDoesNotExist_ShouldReturnEmpty() { + // When + Optional result = loginLogRepository.findById(999L); + + // Then + assertThat(result).isEmpty(); + } + + @Test + void findAll_ShouldReturnAllLogs() { + // Given + LoginLog log1 = LoginLog.builder() + .username("user1") + .success(true) + .ipAddress("192.168.1.1") + .userAgent("Browser 1") + .createdAt(LocalDateTime.now()) + .build(); + + LoginLog log2 = LoginLog.builder() + .username("user2") + .success(false) + .ipAddress("192.168.1.2") + .userAgent("Browser 2") + .createdAt(LocalDateTime.now()) + .build(); + + entityManager.persistAndFlush(log1); + entityManager.persistAndFlush(log2); + + // When + List allLogs = loginLogRepository.findAll(); + + // Then + assertThat(allLogs).hasSize(2); + assertThat(allLogs).extracting("username") + .containsExactlyInAnyOrder("user1", "user2"); + } + + @Test + void count_ShouldReturnCorrectCount() { + // Given + entityManager.persistAndFlush(testLoginLog); + + LoginLog secondLog = LoginLog.builder() + .username("user2") + .success(false) + .ipAddress("192.168.1.2") + .userAgent("Browser 2") + .createdAt(LocalDateTime.now()) + .build(); + entityManager.persistAndFlush(secondLog); + + // When + long count = loginLogRepository.count(); + + // Then + assertThat(count).isEqualTo(2); + } + + @Test + void save_WithNullOptionalFields_ShouldPersistSuccessfully() { + // Given + LoginLog logWithNulls = LoginLog.builder() + .username("testuser") + .success(true) + .ipAddress(null) + .userAgent(null) + .createdAt(LocalDateTime.now()) + .build(); + + // When + LoginLog savedLog = loginLogRepository.save(logWithNulls); + + // Then + assertThat(savedLog.getId()).isNotNull(); + assertThat(savedLog.getUsername()).isEqualTo("testuser"); + assertThat(savedLog.getSuccess()).isTrue(); + assertThat(savedLog.getIpAddress()).isNull(); + assertThat(savedLog.getUserAgent()).isNull(); + } + + @Test + void existsById_WhenLogExists_ShouldReturnTrue() { + // Given + LoginLog savedLog = entityManager.persistAndFlush(testLoginLog); + + // When + boolean exists = loginLogRepository.existsById(savedLog.getId()); + + // Then + assertThat(exists).isTrue(); + } + + @Test + void existsById_WhenLogDoesNotExist_ShouldReturnFalse() { + // When + boolean exists = loginLogRepository.existsById(999L); + + // Then + assertThat(exists).isFalse(); + } +} \ No newline at end of file diff --git a/auth-service/src/test/java/com/techtorque/auth_service/repository/PermissionRepositoryTest.java b/auth-service/src/test/java/com/techtorque/auth_service/repository/PermissionRepositoryTest.java new file mode 100644 index 0000000..c4905f3 --- /dev/null +++ b/auth-service/src/test/java/com/techtorque/auth_service/repository/PermissionRepositoryTest.java @@ -0,0 +1,316 @@ +package com.techtorque.auth_service.repository; + +import com.techtorque.auth_service.entity.Permission; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.test.context.ActiveProfiles; + +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Comprehensive test class for PermissionRepository + * Tests all repository methods, edge cases, and database constraints + */ +@DataJpaTest +@ActiveProfiles("test") +class PermissionRepositoryTest { + + @Autowired + private TestEntityManager entityManager; + + @Autowired + private PermissionRepository permissionRepository; + + private Permission testPermission; + + @BeforeEach + void setUp() { + testPermission = Permission.builder() + .name("CREATE_USER") + .description("Permission to create new users") + .build(); + } + + @Test + void save_WhenValidPermission_ShouldPersistSuccessfully() { + // When + Permission savedPermission = permissionRepository.save(testPermission); + + // Then + assertThat(savedPermission.getId()).isNotNull(); + assertThat(savedPermission.getName()).isEqualTo("CREATE_USER"); + assertThat(savedPermission.getDescription()).isEqualTo("Permission to create new users"); + } + + @Test + void findByName_WhenPermissionExists_ShouldReturnPermission() { + // Given + entityManager.persistAndFlush(testPermission); + + // When + Optional result = permissionRepository.findByName("CREATE_USER"); + + // Then + assertThat(result).isPresent(); + assertThat(result.get().getName()).isEqualTo("CREATE_USER"); + assertThat(result.get().getDescription()).isEqualTo("Permission to create new users"); + } + + @Test + void findByName_WhenPermissionDoesNotExist_ShouldReturnEmpty() { + // When + Optional result = permissionRepository.findByName("NON_EXISTENT"); + + // Then + assertThat(result).isEmpty(); + } + + @Test + void findByName_CaseSensitive_ShouldReturnEmpty() { + // Given + entityManager.persistAndFlush(testPermission); + + // When + Optional result = permissionRepository.findByName("create_user"); + + // Then + assertThat(result).isEmpty(); + } + + @Test + void findByNameIn_WhenPermissionsExist_ShouldReturnMatchingPermissions() { + // Given + Permission permission1 = Permission.builder() + .name("READ_USER") + .description("Permission to read user data") + .build(); + + Permission permission2 = Permission.builder() + .name("UPDATE_USER") + .description("Permission to update user data") + .build(); + + Permission permission3 = Permission.builder() + .name("DELETE_USER") + .description("Permission to delete users") + .build(); + + entityManager.persistAndFlush(testPermission); + entityManager.persistAndFlush(permission1); + entityManager.persistAndFlush(permission2); + entityManager.persistAndFlush(permission3); + + // When + Set names = Set.of("CREATE_USER", "READ_USER", "NON_EXISTENT"); + Set result = permissionRepository.findByNameIn(names); + + // Then + assertThat(result).hasSize(2); + assertThat(result).extracting("name") + .containsExactlyInAnyOrder("CREATE_USER", "READ_USER"); + } + + @Test + void findByNameIn_WhenEmptySet_ShouldReturnEmptySet() { + // Given + entityManager.persistAndFlush(testPermission); + + // When + Set result = permissionRepository.findByNameIn(Set.of()); + + // Then + assertThat(result).isEmpty(); + } + + @Test + void findByNameIn_WhenNoMatches_ShouldReturnEmptySet() { + // Given + entityManager.persistAndFlush(testPermission); + + // When + Set names = Set.of("NON_EXISTENT1", "NON_EXISTENT2"); + Set result = permissionRepository.findByNameIn(names); + + // Then + assertThat(result).isEmpty(); + } + + @Test + void existsByName_WhenPermissionExists_ShouldReturnTrue() { + // Given + entityManager.persistAndFlush(testPermission); + + // When + boolean exists = permissionRepository.existsByName("CREATE_USER"); + + // Then + assertThat(exists).isTrue(); + } + + @Test + void existsByName_WhenPermissionDoesNotExist_ShouldReturnFalse() { + // When + boolean exists = permissionRepository.existsByName("NON_EXISTENT"); + + // Then + assertThat(exists).isFalse(); + } + + @Test + void findById_WhenPermissionExists_ShouldReturnPermission() { + // Given + Permission savedPermission = entityManager.persistAndFlush(testPermission); + + // When + Optional result = permissionRepository.findById(savedPermission.getId()); + + // Then + assertThat(result).isPresent(); + assertThat(result.get().getId()).isEqualTo(savedPermission.getId()); + assertThat(result.get().getName()).isEqualTo("CREATE_USER"); + } + + @Test + void findById_WhenPermissionDoesNotExist_ShouldReturnEmpty() { + // When + Optional result = permissionRepository.findById(999L); + + // Then + assertThat(result).isEmpty(); + } + + @Test + void findAll_ShouldReturnAllPermissions() { + // Given + Permission permission1 = Permission.builder() + .name("READ_REPORTS") + .description("Permission to read reports") + .build(); + + Permission permission2 = Permission.builder() + .name("WRITE_REPORTS") + .description("Permission to write reports") + .build(); + + entityManager.persistAndFlush(permission1); + entityManager.persistAndFlush(permission2); + + // When + List allPermissions = permissionRepository.findAll(); + + // Then + assertThat(allPermissions).hasSize(2); + assertThat(allPermissions).extracting("name") + .containsExactlyInAnyOrder("READ_REPORTS", "WRITE_REPORTS"); + } + + @Test + void count_ShouldReturnCorrectCount() { + // Given + entityManager.persistAndFlush(testPermission); + + Permission secondPermission = Permission.builder() + .name("DELETE_USER") + .description("Permission to delete users") + .build(); + entityManager.persistAndFlush(secondPermission); + + // When + long count = permissionRepository.count(); + + // Then + assertThat(count).isEqualTo(2); + } + + @Test + void update_WhenPermissionExists_ShouldUpdateSuccessfully() { + // Given + Permission savedPermission = entityManager.persistAndFlush(testPermission); + entityManager.detach(savedPermission); + + // When + savedPermission.setDescription("Updated description for creating users"); + Permission updatedPermission = permissionRepository.save(savedPermission); + + // Then + assertThat(updatedPermission.getDescription()).isEqualTo("Updated description for creating users"); + assertThat(updatedPermission.getName()).isEqualTo("CREATE_USER"); // Should remain unchanged + } + + @Test + void deleteById_WhenPermissionExists_ShouldRemovePermission() { + // Given + Permission savedPermission = entityManager.persistAndFlush(testPermission); + Long permissionId = savedPermission.getId(); + + // When + permissionRepository.deleteById(permissionId); + entityManager.flush(); + + // Then + Optional result = permissionRepository.findById(permissionId); + assertThat(result).isEmpty(); + } + + @Test + void save_WithNullDescription_ShouldPersistSuccessfully() { + // Given + Permission permissionWithoutDescription = Permission.builder() + .name("SIMPLE_PERMISSION") + .description(null) + .build(); + + // When + Permission savedPermission = permissionRepository.save(permissionWithoutDescription); + + // Then + assertThat(savedPermission.getId()).isNotNull(); + assertThat(savedPermission.getName()).isEqualTo("SIMPLE_PERMISSION"); + assertThat(savedPermission.getDescription()).isNull(); + } + + @Test + void save_WithEmptyDescription_ShouldPersistSuccessfully() { + // Given + Permission permissionWithEmptyDescription = Permission.builder() + .name("ANOTHER_PERMISSION") + .description("") + .build(); + + // When + Permission savedPermission = permissionRepository.save(permissionWithEmptyDescription); + + // Then + assertThat(savedPermission.getId()).isNotNull(); + assertThat(savedPermission.getName()).isEqualTo("ANOTHER_PERMISSION"); + assertThat(savedPermission.getDescription()).isEmpty(); + } + + @Test + void existsById_WhenPermissionExists_ShouldReturnTrue() { + // Given + Permission savedPermission = entityManager.persistAndFlush(testPermission); + + // When + boolean exists = permissionRepository.existsById(savedPermission.getId()); + + // Then + assertThat(exists).isTrue(); + } + + @Test + void existsById_WhenPermissionDoesNotExist_ShouldReturnFalse() { + // When + boolean exists = permissionRepository.existsById(999L); + + // Then + assertThat(exists).isFalse(); + } +} \ No newline at end of file diff --git a/auth-service/src/test/java/com/techtorque/auth_service/repository/RefreshTokenRepositoryTest.java b/auth-service/src/test/java/com/techtorque/auth_service/repository/RefreshTokenRepositoryTest.java new file mode 100644 index 0000000..8990ed3 --- /dev/null +++ b/auth-service/src/test/java/com/techtorque/auth_service/repository/RefreshTokenRepositoryTest.java @@ -0,0 +1,357 @@ +package com.techtorque.auth_service.repository; + +import com.techtorque.auth_service.entity.RefreshToken; +import com.techtorque.auth_service.entity.Role; +import com.techtorque.auth_service.entity.RoleName; +import com.techtorque.auth_service.entity.User; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Comprehensive test class for RefreshTokenRepository + * Tests all repository methods, edge cases, and database constraints + */ +@DataJpaTest +@ActiveProfiles("test") +class RefreshTokenRepositoryTest { + + @Autowired + private TestEntityManager entityManager; + + @Autowired + private RefreshTokenRepository refreshTokenRepository; + + private User testUser; + private RefreshToken testToken; + + @BeforeEach + void setUp() { + // Create test role + Role testRole = Role.builder() + .name(RoleName.CUSTOMER) + .description("Test customer role") + .build(); + testRole = entityManager.persistAndFlush(testRole); + + // Create test user + testUser = User.builder() + .username("testuser") + .password("encodedPassword") + .email("test@example.com") + .fullName("Test User") + .enabled(true) + .emailVerified(false) + .createdAt(LocalDateTime.now()) + .build(); + testUser.addRole(testRole); + testUser = entityManager.persistAndFlush(testUser); + + // Create test refresh token + testToken = RefreshToken.builder() + .token("test-refresh-token") + .user(testUser) + .expiryDate(LocalDateTime.now().plusDays(7)) + .createdAt(LocalDateTime.now()) + .ipAddress("192.168.1.1") + .userAgent("Test User Agent") + .build(); + } + + @Test + void save_WhenValidToken_ShouldPersistSuccessfully() { + // When + RefreshToken savedToken = refreshTokenRepository.save(testToken); + + // Then + assertThat(savedToken.getId()).isNotNull(); + assertThat(savedToken.getToken()).isEqualTo("test-refresh-token"); + assertThat(savedToken.getUser().getId()).isEqualTo(testUser.getId()); + assertThat(savedToken.getExpiryDate()).isNotNull(); + assertThat(savedToken.getCreatedAt()).isNotNull(); + assertThat(savedToken.getIpAddress()).isEqualTo("192.168.1.1"); + assertThat(savedToken.getUserAgent()).isEqualTo("Test User Agent"); + assertThat(savedToken.getRevokedAt()).isNull(); + } + + @Test + void findByToken_WhenTokenExists_ShouldReturnToken() { + // Given + entityManager.persistAndFlush(testToken); + + // When + Optional result = refreshTokenRepository.findByToken("test-refresh-token"); + + // Then + assertThat(result).isPresent(); + assertThat(result.get().getToken()).isEqualTo("test-refresh-token"); + assertThat(result.get().getUser().getId()).isEqualTo(testUser.getId()); + assertThat(result.get().getIpAddress()).isEqualTo("192.168.1.1"); + } + + @Test + void findByToken_WhenTokenDoesNotExist_ShouldReturnEmpty() { + // When + Optional result = refreshTokenRepository.findByToken("non-existent-token"); + + // Then + assertThat(result).isEmpty(); + } + + @Test + @Transactional + void deleteByUser_WhenUserHasTokens_ShouldDeleteAllUserTokens() { + // Given + RefreshToken token1 = RefreshToken.builder() + .token("token-1") + .user(testUser) + .expiryDate(LocalDateTime.now().plusDays(7)) + .createdAt(LocalDateTime.now()) + .build(); + + RefreshToken token2 = RefreshToken.builder() + .token("token-2") + .user(testUser) + .expiryDate(LocalDateTime.now().plusDays(7)) + .createdAt(LocalDateTime.now()) + .build(); + + entityManager.persistAndFlush(token1); + entityManager.persistAndFlush(token2); + + // Create another user with a token to ensure we only delete current user's + // tokens + User anotherUser = User.builder() + .username("anotheruser") + .password("password") + .email("another@example.com") + .enabled(true) + .emailVerified(false) + .createdAt(LocalDateTime.now()) + .build(); + anotherUser = entityManager.persistAndFlush(anotherUser); + + RefreshToken anotherUserToken = RefreshToken.builder() + .token("another-token") + .user(anotherUser) + .expiryDate(LocalDateTime.now().plusDays(7)) + .createdAt(LocalDateTime.now()) + .build(); + entityManager.persistAndFlush(anotherUserToken); + + // When + refreshTokenRepository.deleteByUser(testUser); + entityManager.flush(); + + // Then + assertThat(refreshTokenRepository.findByToken("token-1")).isEmpty(); + assertThat(refreshTokenRepository.findByToken("token-2")).isEmpty(); + assertThat(refreshTokenRepository.findByToken("another-token")).isPresent(); + } + + @Test + @Transactional + void deleteExpiredTokens_WhenExpiredTokensExist_ShouldDeleteOnlyExpiredTokens() { + // Given + RefreshToken expiredToken1 = RefreshToken.builder() + .token("expired-token-1") + .user(testUser) + .expiryDate(LocalDateTime.now().minusDays(1)) // Expired + .createdAt(LocalDateTime.now().minusDays(2)) + .build(); + + RefreshToken expiredToken2 = RefreshToken.builder() + .token("expired-token-2") + .user(testUser) + .expiryDate(LocalDateTime.now().minusHours(1)) // Expired + .createdAt(LocalDateTime.now().minusDays(1)) + .build(); + + RefreshToken validToken = RefreshToken.builder() + .token("valid-token") + .user(testUser) + .expiryDate(LocalDateTime.now().plusDays(7)) // Not expired + .createdAt(LocalDateTime.now()) + .build(); + + entityManager.persistAndFlush(expiredToken1); + entityManager.persistAndFlush(expiredToken2); + entityManager.persistAndFlush(validToken); + + // When + refreshTokenRepository.deleteExpiredTokens(LocalDateTime.now()); + entityManager.flush(); + + // Then + assertThat(refreshTokenRepository.findByToken("expired-token-1")).isEmpty(); + assertThat(refreshTokenRepository.findByToken("expired-token-2")).isEmpty(); + assertThat(refreshTokenRepository.findByToken("valid-token")).isPresent(); + } + + @Test + void isExpired_WhenTokenIsExpired_ShouldReturnTrue() { + // Given + RefreshToken expiredToken = RefreshToken.builder() + .token("expired-token") + .user(testUser) + .expiryDate(LocalDateTime.now().minusDays(1)) + .createdAt(LocalDateTime.now().minusDays(2)) + .build(); + + // When + boolean isExpired = expiredToken.isExpired(); + + // Then + assertThat(isExpired).isTrue(); + } + + @Test + void isExpired_WhenTokenIsNotExpired_ShouldReturnFalse() { + // Given + RefreshToken validToken = RefreshToken.builder() + .token("valid-token") + .user(testUser) + .expiryDate(LocalDateTime.now().plusDays(7)) + .createdAt(LocalDateTime.now()) + .build(); + + // When + boolean isExpired = validToken.isExpired(); + + // Then + assertThat(isExpired).isFalse(); + } + + @Test + void isRevoked_WhenTokenIsRevoked_ShouldReturnTrue() { + // Given + RefreshToken revokedToken = RefreshToken.builder() + .token("revoked-token") + .user(testUser) + .expiryDate(LocalDateTime.now().plusDays(7)) + .createdAt(LocalDateTime.now()) + .revokedAt(LocalDateTime.now()) + .build(); + + // When + boolean isRevoked = revokedToken.isRevoked(); + + // Then + assertThat(isRevoked).isTrue(); + } + + @Test + void isRevoked_WhenTokenIsNotRevoked_ShouldReturnFalse() { + // Given + RefreshToken activeToken = RefreshToken.builder() + .token("active-token") + .user(testUser) + .expiryDate(LocalDateTime.now().plusDays(7)) + .createdAt(LocalDateTime.now()) + .revokedAt(null) + .build(); + + // When + boolean isRevoked = activeToken.isRevoked(); + + // Then + assertThat(isRevoked).isFalse(); + } + + @Test + void findById_WhenTokenExists_ShouldReturnToken() { + // Given + RefreshToken savedToken = entityManager.persistAndFlush(testToken); + + // When + Optional result = refreshTokenRepository.findById(savedToken.getId()); + + // Then + assertThat(result).isPresent(); + assertThat(result.get().getId()).isEqualTo(savedToken.getId()); + assertThat(result.get().getToken()).isEqualTo("test-refresh-token"); + } + + @Test + void findById_WhenTokenDoesNotExist_ShouldReturnEmpty() { + // When + Optional result = refreshTokenRepository.findById("non-existent-id"); + + // Then + assertThat(result).isEmpty(); + } + + @Test + void update_WhenTokenIsRevoked_ShouldUpdateRevokedAt() { + // Given + RefreshToken savedToken = entityManager.persistAndFlush(testToken); + entityManager.detach(savedToken); + + // When + LocalDateTime revokedTime = LocalDateTime.now(); + savedToken.setRevokedAt(revokedTime); + RefreshToken updatedToken = refreshTokenRepository.save(savedToken); + + // Then + assertThat(updatedToken.getRevokedAt()).isEqualTo(revokedTime); + assertThat(updatedToken.isRevoked()).isTrue(); + } + + @Test + void findAll_ShouldReturnAllTokens() { + // Given + RefreshToken token1 = RefreshToken.builder() + .token("token-1") + .user(testUser) + .expiryDate(LocalDateTime.now().plusDays(7)) + .createdAt(LocalDateTime.now()) + .build(); + + RefreshToken token2 = RefreshToken.builder() + .token("token-2") + .user(testUser) + .expiryDate(LocalDateTime.now().plusDays(7)) + .createdAt(LocalDateTime.now()) + .build(); + + entityManager.persistAndFlush(token1); + entityManager.persistAndFlush(token2); + + // When + var allTokens = refreshTokenRepository.findAll(); + + // Then + assertThat(allTokens).hasSize(2); + assertThat(allTokens).extracting("token") + .containsExactlyInAnyOrder("token-1", "token-2"); + } + + @Test + void count_ShouldReturnCorrectCount() { + // Given + entityManager.persistAndFlush(testToken); + + RefreshToken secondToken = RefreshToken.builder() + .token("second-token") + .user(testUser) + .expiryDate(LocalDateTime.now().plusDays(7)) + .createdAt(LocalDateTime.now()) + .build(); + entityManager.persistAndFlush(secondToken); + + // When + long count = refreshTokenRepository.count(); + + // Then + assertThat(count).isEqualTo(2); + } +} \ No newline at end of file diff --git a/auth-service/src/test/java/com/techtorque/auth_service/repository/RoleRepositoryTest.java b/auth-service/src/test/java/com/techtorque/auth_service/repository/RoleRepositoryTest.java new file mode 100644 index 0000000..4d35dbd --- /dev/null +++ b/auth-service/src/test/java/com/techtorque/auth_service/repository/RoleRepositoryTest.java @@ -0,0 +1,268 @@ +package com.techtorque.auth_service.repository; + +import com.techtorque.auth_service.entity.Role; +import com.techtorque.auth_service.entity.RoleName; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.test.context.ActiveProfiles; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Comprehensive test class for RoleRepository + * Tests all repository methods, edge cases, and database constraints + */ +@DataJpaTest +@ActiveProfiles("test") +class RoleRepositoryTest { + + @Autowired + private TestEntityManager entityManager; + + @Autowired + private RoleRepository roleRepository; + + private Role testRole; + + @BeforeEach + void setUp() { + testRole = Role.builder() + .name(RoleName.ADMIN) + .description("Administrator role with full access") + .build(); + } + + @Test + void findByName_WhenRoleExists_ShouldReturnRole() { + // Given + entityManager.persistAndFlush(testRole); + + // When + Optional result = roleRepository.findByName(RoleName.ADMIN); + + // Then + assertThat(result).isPresent(); + assertThat(result.get().getName()).isEqualTo(RoleName.ADMIN); + assertThat(result.get().getDescription()).isEqualTo("Administrator role with full access"); + } + + @Test + void findByName_WhenRoleDoesNotExist_ShouldReturnEmpty() { + // When + Optional result = roleRepository.findByName(RoleName.SUPER_ADMIN); + + // Then + assertThat(result).isEmpty(); + } + + @Test + void existsByName_WhenRoleExists_ShouldReturnTrue() { + // Given + entityManager.persistAndFlush(testRole); + + // When + boolean exists = roleRepository.existsByName(RoleName.ADMIN); + + // Then + assertThat(exists).isTrue(); + } + + @Test + void existsByName_WhenRoleDoesNotExist_ShouldReturnFalse() { + // When + boolean exists = roleRepository.existsByName(RoleName.CUSTOMER); + + // Then + assertThat(exists).isFalse(); + } + + @Test + void save_WhenValidRole_ShouldPersistSuccessfully() { + // Given + Role newRole = Role.builder() + .name(RoleName.EMPLOYEE) + .description("Employee role with limited access") + .build(); + + // When + Role savedRole = roleRepository.save(newRole); + + // Then + assertThat(savedRole.getId()).isNotNull(); + assertThat(savedRole.getName()).isEqualTo(RoleName.EMPLOYEE); + assertThat(savedRole.getDescription()).isEqualTo("Employee role with limited access"); + } + + @Test + void save_AllRoleNames_ShouldPersistAllEnumValues() { + // Given & When & Then + for (RoleName roleName : RoleName.values()) { + Role role = Role.builder() + .name(roleName) + .description(roleName.name() + " role") + .build(); + + Role savedRole = roleRepository.save(role); + + assertThat(savedRole.getId()).isNotNull(); + assertThat(savedRole.getName()).isEqualTo(roleName); + assertThat(savedRole.getDescription()).isEqualTo(roleName.name() + " role"); + } + } + + @Test + void findById_WhenRoleExists_ShouldReturnRole() { + // Given + Role savedRole = entityManager.persistAndFlush(testRole); + + // When + Optional result = roleRepository.findById(savedRole.getId()); + + // Then + assertThat(result).isPresent(); + assertThat(result.get().getId()).isEqualTo(savedRole.getId()); + assertThat(result.get().getName()).isEqualTo(RoleName.ADMIN); + } + + @Test + void findById_WhenRoleDoesNotExist_ShouldReturnEmpty() { + // When + Optional result = roleRepository.findById(999L); + + // Then + assertThat(result).isEmpty(); + } + + @Test + void deleteById_WhenRoleExists_ShouldRemoveRole() { + // Given + Role savedRole = entityManager.persistAndFlush(testRole); + Long roleId = savedRole.getId(); + + // When + roleRepository.deleteById(roleId); + entityManager.flush(); + + // Then + Optional result = roleRepository.findById(roleId); + assertThat(result).isEmpty(); + } + + @Test + void findAll_ShouldReturnAllRoles() { + // Given + Role adminRole = Role.builder() + .name(RoleName.ADMIN) + .description("Admin role") + .build(); + + Role customerRole = Role.builder() + .name(RoleName.CUSTOMER) + .description("Customer role") + .build(); + + entityManager.persistAndFlush(adminRole); + entityManager.persistAndFlush(customerRole); + + // When + var allRoles = roleRepository.findAll(); + + // Then + assertThat(allRoles).hasSize(2); + assertThat(allRoles).extracting("name") + .containsExactlyInAnyOrder(RoleName.ADMIN, RoleName.CUSTOMER); + } + + @Test + void count_ShouldReturnCorrectCount() { + // Given + entityManager.persistAndFlush(testRole); + + Role secondRole = Role.builder() + .name(RoleName.EMPLOYEE) + .description("Employee role") + .build(); + entityManager.persistAndFlush(secondRole); + + // When + long count = roleRepository.count(); + + // Then + assertThat(count).isEqualTo(2); + } + + @Test + void update_WhenRoleExists_ShouldUpdateSuccessfully() { + // Given + Role savedRole = entityManager.persistAndFlush(testRole); + entityManager.detach(savedRole); + + // When + savedRole.setDescription("Updated admin role description"); + Role updatedRole = roleRepository.save(savedRole); + + // Then + assertThat(updatedRole.getDescription()).isEqualTo("Updated admin role description"); + assertThat(updatedRole.getName()).isEqualTo(RoleName.ADMIN); // Should remain unchanged + } + + @Test + void existsById_WhenRoleExists_ShouldReturnTrue() { + // Given + Role savedRole = entityManager.persistAndFlush(testRole); + + // When + boolean exists = roleRepository.existsById(savedRole.getId()); + + // Then + assertThat(exists).isTrue(); + } + + @Test + void existsById_WhenRoleDoesNotExist_ShouldReturnFalse() { + // When + boolean exists = roleRepository.existsById(999L); + + // Then + assertThat(exists).isFalse(); + } + + @Test + void save_WithNullDescription_ShouldPersistSuccessfully() { + // Given + Role roleWithoutDescription = Role.builder() + .name(RoleName.CUSTOMER) + .description(null) + .build(); + + // When + Role savedRole = roleRepository.save(roleWithoutDescription); + + // Then + assertThat(savedRole.getId()).isNotNull(); + assertThat(savedRole.getName()).isEqualTo(RoleName.CUSTOMER); + assertThat(savedRole.getDescription()).isNull(); + } + + @Test + void save_WithEmptyDescription_ShouldPersistSuccessfully() { + // Given + Role roleWithEmptyDescription = Role.builder() + .name(RoleName.CUSTOMER) + .description("") + .build(); + + // When + Role savedRole = roleRepository.save(roleWithEmptyDescription); + + // Then + assertThat(savedRole.getId()).isNotNull(); + assertThat(savedRole.getName()).isEqualTo(RoleName.CUSTOMER); + assertThat(savedRole.getDescription()).isEmpty(); + } +} \ No newline at end of file diff --git a/auth-service/src/test/java/com/techtorque/auth_service/repository/UserPreferencesRepositoryTest.java b/auth-service/src/test/java/com/techtorque/auth_service/repository/UserPreferencesRepositoryTest.java new file mode 100644 index 0000000..3feb79a --- /dev/null +++ b/auth-service/src/test/java/com/techtorque/auth_service/repository/UserPreferencesRepositoryTest.java @@ -0,0 +1,395 @@ +package com.techtorque.auth_service.repository; + +import com.techtorque.auth_service.entity.Role; +import com.techtorque.auth_service.entity.RoleName; +import com.techtorque.auth_service.entity.User; +import com.techtorque.auth_service.entity.UserPreferences; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Comprehensive test class for UserPreferencesRepository + * Tests all repository methods, edge cases, and database constraints + */ +@DataJpaTest +@ActiveProfiles("test") +class UserPreferencesRepositoryTest { + + @Autowired + private TestEntityManager entityManager; + + @Autowired + private UserPreferencesRepository userPreferencesRepository; + + private User testUser; + private UserPreferences testPreferences; + + @BeforeEach + void setUp() { + // Create test role + Role testRole = Role.builder() + .name(RoleName.CUSTOMER) + .description("Test customer role") + .build(); + testRole = entityManager.persistAndFlush(testRole); + + // Create test user + testUser = User.builder() + .username("testuser") + .password("encodedPassword") + .email("test@example.com") + .fullName("Test User") + .enabled(true) + .emailVerified(false) + .createdAt(LocalDateTime.now()) + .build(); + testUser.addRole(testRole); + testUser = entityManager.persistAndFlush(testUser); + + // Create test user preferences + testPreferences = UserPreferences.builder() + .user(testUser) + .emailNotifications(true) + .smsNotifications(false) + .pushNotifications(true) + .language("en") + .appointmentReminders(true) + .serviceUpdates(true) + .marketingEmails(false) + .build(); + } + + @Test + void save_WhenValidPreferences_ShouldPersistSuccessfully() { + // When + UserPreferences savedPreferences = userPreferencesRepository.save(testPreferences); + + // Then + assertThat(savedPreferences.getId()).isNotNull(); + assertThat(savedPreferences.getUser().getId()).isEqualTo(testUser.getId()); + assertThat(savedPreferences.getEmailNotifications()).isTrue(); + assertThat(savedPreferences.getSmsNotifications()).isFalse(); + assertThat(savedPreferences.getPushNotifications()).isTrue(); + assertThat(savedPreferences.getLanguage()).isEqualTo("en"); + assertThat(savedPreferences.getAppointmentReminders()).isTrue(); + assertThat(savedPreferences.getServiceUpdates()).isTrue(); + assertThat(savedPreferences.getMarketingEmails()).isFalse(); + } + + @Test + void save_WithDefaults_ShouldUseDefaultValues() { + // Given + UserPreferences preferencesWithDefaults = UserPreferences.builder() + .user(testUser) + .build(); + + // When + UserPreferences savedPreferences = userPreferencesRepository.save(preferencesWithDefaults); + + // Then + assertThat(savedPreferences.getId()).isNotNull(); + assertThat(savedPreferences.getEmailNotifications()).isTrue(); // Default + assertThat(savedPreferences.getSmsNotifications()).isFalse(); // Default + assertThat(savedPreferences.getPushNotifications()).isTrue(); // Default + assertThat(savedPreferences.getLanguage()).isEqualTo("en"); // Default + assertThat(savedPreferences.getAppointmentReminders()).isTrue(); // Default + assertThat(savedPreferences.getServiceUpdates()).isTrue(); // Default + assertThat(savedPreferences.getMarketingEmails()).isFalse(); // Default + } + + @Test + void findByUser_WhenPreferencesExist_ShouldReturnPreferences() { + // Given + entityManager.persistAndFlush(testPreferences); + + // When + Optional result = userPreferencesRepository.findByUser(testUser); + + // Then + assertThat(result).isPresent(); + assertThat(result.get().getUser().getId()).isEqualTo(testUser.getId()); + assertThat(result.get().getEmailNotifications()).isTrue(); + assertThat(result.get().getLanguage()).isEqualTo("en"); + } + + @Test + void findByUser_WhenPreferencesDoNotExist_ShouldReturnEmpty() { + // Given + User anotherUser = User.builder() + .username("anotheruser") + .password("password") + .email("another@example.com") + .enabled(true) + .emailVerified(false) + .createdAt(LocalDateTime.now()) + .build(); + anotherUser = entityManager.persistAndFlush(anotherUser); + + // When + Optional result = userPreferencesRepository.findByUser(anotherUser); + + // Then + assertThat(result).isEmpty(); + } + + @Test + @Transactional + void deleteByUser_WhenPreferencesExist_ShouldDeleteUserPreferences() { + // Given + entityManager.persistAndFlush(testPreferences); + + // Create another user with preferences to ensure we only delete current user's + // preferences + User anotherUser = User.builder() + .username("anotheruser") + .password("password") + .email("another@example.com") + .enabled(true) + .emailVerified(false) + .createdAt(LocalDateTime.now()) + .build(); + anotherUser = entityManager.persistAndFlush(anotherUser); + + UserPreferences anotherPreferences = UserPreferences.builder() + .user(anotherUser) + .emailNotifications(false) + .language("fr") + .build(); + entityManager.persistAndFlush(anotherPreferences); + + // When + userPreferencesRepository.deleteByUser(testUser); + entityManager.flush(); + + // Then + Optional deletedPreferences = userPreferencesRepository.findByUser(testUser); + Optional remainingPreferences = userPreferencesRepository.findByUser(anotherUser); + + assertThat(deletedPreferences).isEmpty(); + assertThat(remainingPreferences).isPresent(); + } + + @Test + void update_WhenPreferencesExist_ShouldUpdateSuccessfully() { + // Given + UserPreferences savedPreferences = entityManager.persistAndFlush(testPreferences); + entityManager.detach(savedPreferences); + + // When + savedPreferences.setEmailNotifications(false); + savedPreferences.setSmsNotifications(true); + savedPreferences.setLanguage("es"); + savedPreferences.setMarketingEmails(true); + UserPreferences updatedPreferences = userPreferencesRepository.save(savedPreferences); + + // Then + assertThat(updatedPreferences.getEmailNotifications()).isFalse(); + assertThat(updatedPreferences.getSmsNotifications()).isTrue(); + assertThat(updatedPreferences.getLanguage()).isEqualTo("es"); + assertThat(updatedPreferences.getMarketingEmails()).isTrue(); + assertThat(updatedPreferences.getUser().getId()).isEqualTo(testUser.getId()); // Should remain unchanged + } + + @Test + void findById_WhenPreferencesExist_ShouldReturnPreferences() { + // Given + UserPreferences savedPreferences = entityManager.persistAndFlush(testPreferences); + + // When + Optional result = userPreferencesRepository.findById(savedPreferences.getId()); + + // Then + assertThat(result).isPresent(); + assertThat(result.get().getId()).isEqualTo(savedPreferences.getId()); + assertThat(result.get().getUser().getId()).isEqualTo(testUser.getId()); + } + + @Test + void findById_WhenPreferencesDoNotExist_ShouldReturnEmpty() { + // When + Optional result = userPreferencesRepository.findById("non-existent-id"); + + // Then + assertThat(result).isEmpty(); + } + + @Test + void findAll_ShouldReturnAllPreferences() { + // Given + User user1 = User.builder() + .username("user1") + .password("password") + .email("user1@example.com") + .enabled(true) + .emailVerified(false) + .createdAt(LocalDateTime.now()) + .build(); + user1 = entityManager.persistAndFlush(user1); + + User user2 = User.builder() + .username("user2") + .password("password") + .email("user2@example.com") + .enabled(true) + .emailVerified(false) + .createdAt(LocalDateTime.now()) + .build(); + user2 = entityManager.persistAndFlush(user2); + + UserPreferences prefs1 = UserPreferences.builder() + .user(user1) + .language("en") + .emailNotifications(true) + .build(); + + UserPreferences prefs2 = UserPreferences.builder() + .user(user2) + .language("fr") + .emailNotifications(false) + .build(); + + entityManager.persistAndFlush(prefs1); + entityManager.persistAndFlush(prefs2); + + // When + List allPreferences = userPreferencesRepository.findAll(); + + // Then + assertThat(allPreferences).hasSize(2); + assertThat(allPreferences).extracting("language") + .containsExactlyInAnyOrder("en", "fr"); + } + + @Test + void count_ShouldReturnCorrectCount() { + // Given + entityManager.persistAndFlush(testPreferences); + + User anotherUser = User.builder() + .username("user2") + .password("password") + .email("user2@example.com") + .enabled(true) + .emailVerified(false) + .createdAt(LocalDateTime.now()) + .build(); + anotherUser = entityManager.persistAndFlush(anotherUser); + + UserPreferences secondPreferences = UserPreferences.builder() + .user(anotherUser) + .language("fr") + .build(); + entityManager.persistAndFlush(secondPreferences); + + // When + long count = userPreferencesRepository.count(); + + // Then + assertThat(count).isEqualTo(2); + } + + @Test + void save_WithDifferentLanguages_ShouldPersistSuccessfully() { + // Given + String[] languages = { "en", "es", "fr", "de", "it", "pt", "ja", "zh", "ko", "ar" }; + + for (int i = 0; i < languages.length; i++) { + User user = User.builder() + .username("user" + i) + .password("password") + .email("user" + i + "@example.com") + .enabled(true) + .emailVerified(false) + .createdAt(LocalDateTime.now()) + .build(); + user = entityManager.persistAndFlush(user); + + UserPreferences preferences = UserPreferences.builder() + .user(user) + .language(languages[i]) + .build(); + + // When + UserPreferences savedPreferences = userPreferencesRepository.save(preferences); + + // Then + assertThat(savedPreferences.getId()).isNotNull(); + assertThat(savedPreferences.getLanguage()).isEqualTo(languages[i]); + assertThat(savedPreferences.getUser().getId()).isEqualTo(user.getId()); + } + } + + @Test + void save_WithAllNotificationsDisabled_ShouldPersistSuccessfully() { + // Given + UserPreferences allDisabledPreferences = UserPreferences.builder() + .user(testUser) + .emailNotifications(false) + .smsNotifications(false) + .pushNotifications(false) + .appointmentReminders(false) + .serviceUpdates(false) + .marketingEmails(false) + .language("en") + .build(); + + // When + UserPreferences savedPreferences = userPreferencesRepository.save(allDisabledPreferences); + + // Then + assertThat(savedPreferences.getId()).isNotNull(); + assertThat(savedPreferences.getEmailNotifications()).isFalse(); + assertThat(savedPreferences.getSmsNotifications()).isFalse(); + assertThat(savedPreferences.getPushNotifications()).isFalse(); + assertThat(savedPreferences.getAppointmentReminders()).isFalse(); + assertThat(savedPreferences.getServiceUpdates()).isFalse(); + assertThat(savedPreferences.getMarketingEmails()).isFalse(); + } + + @Test + void existsById_WhenPreferencesExist_ShouldReturnTrue() { + // Given + UserPreferences savedPreferences = entityManager.persistAndFlush(testPreferences); + + // When + boolean exists = userPreferencesRepository.existsById(savedPreferences.getId()); + + // Then + assertThat(exists).isTrue(); + } + + @Test + void existsById_WhenPreferencesDoNotExist_ShouldReturnFalse() { + // When + boolean exists = userPreferencesRepository.existsById("non-existent-id"); + + // Then + assertThat(exists).isFalse(); + } + + @Test + void deleteById_WhenPreferencesExist_ShouldRemovePreferences() { + // Given + UserPreferences savedPreferences = entityManager.persistAndFlush(testPreferences); + String preferencesId = savedPreferences.getId(); + + // When + userPreferencesRepository.deleteById(preferencesId); + entityManager.flush(); + + // Then + Optional result = userPreferencesRepository.findById(preferencesId); + assertThat(result).isEmpty(); + } +} \ No newline at end of file diff --git a/auth-service/src/test/java/com/techtorque/auth_service/repository/UserRepositoryTest.java b/auth-service/src/test/java/com/techtorque/auth_service/repository/UserRepositoryTest.java new file mode 100644 index 0000000..208abbf --- /dev/null +++ b/auth-service/src/test/java/com/techtorque/auth_service/repository/UserRepositoryTest.java @@ -0,0 +1,382 @@ +package com.techtorque.auth_service.repository; + +import com.techtorque.auth_service.entity.Role; +import com.techtorque.auth_service.entity.RoleName; +import com.techtorque.auth_service.entity.User; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.test.context.ActiveProfiles; + +import java.time.LocalDateTime; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Comprehensive test class for UserRepository + * Tests all repository methods, edge cases, and database constraints + */ +@DataJpaTest +@ActiveProfiles("test") +class UserRepositoryTest { + + @Autowired + private TestEntityManager entityManager; + + @Autowired + private UserRepository userRepository; + + @Autowired + private RoleRepository roleRepository; + + private User testUser; + private Role testRole; + + @BeforeEach + void setUp() { + // Create test role + testRole = Role.builder() + .name(RoleName.CUSTOMER) + .description("Test customer role") + .build(); + testRole = entityManager.persistAndFlush(testRole); + + // Create test user + testUser = User.builder() + .username("testuser") + .password("encodedPassword") + .email("test@example.com") + .fullName("Test User") + .phone("1234567890") + .address("123 Test Street") + .enabled(true) + .emailVerified(false) + .createdAt(LocalDateTime.now()) + .build(); + testUser.addRole(testRole); + } + + @Test + void findByUsername_WhenUserExists_ShouldReturnUser() { + // Given + entityManager.persistAndFlush(testUser); + + // When + Optional result = userRepository.findByUsername("testuser"); + + // Then + assertThat(result).isPresent(); + assertThat(result.get().getUsername()).isEqualTo("testuser"); + assertThat(result.get().getEmail()).isEqualTo("test@example.com"); + assertThat(result.get().getFullName()).isEqualTo("Test User"); + } + + @Test + void findByUsername_WhenUserDoesNotExist_ShouldReturnEmpty() { + // When + Optional result = userRepository.findByUsername("nonexistent"); + + // Then + assertThat(result).isEmpty(); + } + + @Test + void findByUsername_CaseSensitive_ShouldReturnEmpty() { + // Given + entityManager.persistAndFlush(testUser); + + // When + Optional result = userRepository.findByUsername("TESTUSER"); + + // Then + assertThat(result).isEmpty(); + } + + @Test + void findByEmail_WhenEmailExists_ShouldReturnUser() { + // Given + entityManager.persistAndFlush(testUser); + + // When + Optional result = userRepository.findByEmail("test@example.com"); + + // Then + assertThat(result).isPresent(); + assertThat(result.get().getEmail()).isEqualTo("test@example.com"); + assertThat(result.get().getUsername()).isEqualTo("testuser"); + } + + @Test + void findByEmail_WhenEmailDoesNotExist_ShouldReturnEmpty() { + // When + Optional result = userRepository.findByEmail("nonexistent@example.com"); + + // Then + assertThat(result).isEmpty(); + } + + @Test + void findByEmail_CaseSensitive_ShouldReturnEmpty() { + // Given + entityManager.persistAndFlush(testUser); + + // When + Optional result = userRepository.findByEmail("TEST@EXAMPLE.COM"); + + // Then + assertThat(result).isEmpty(); + } + + @Test + void existsByUsername_WhenUsernameExists_ShouldReturnTrue() { + // Given + entityManager.persistAndFlush(testUser); + + // When + boolean exists = userRepository.existsByUsername("testuser"); + + // Then + assertThat(exists).isTrue(); + } + + @Test + void existsByUsername_WhenUsernameDoesNotExist_ShouldReturnFalse() { + // When + boolean exists = userRepository.existsByUsername("nonexistent"); + + // Then + assertThat(exists).isFalse(); + } + + @Test + void existsByEmail_WhenEmailExists_ShouldReturnTrue() { + // Given + entityManager.persistAndFlush(testUser); + + // When + boolean exists = userRepository.existsByEmail("test@example.com"); + + // Then + assertThat(exists).isTrue(); + } + + @Test + void existsByEmail_WhenEmailDoesNotExist_ShouldReturnFalse() { + // When + boolean exists = userRepository.existsByEmail("nonexistent@example.com"); + + // Then + assertThat(exists).isFalse(); + } + + @Test + void findByUsernameWithRoles_WhenUserExists_ShouldReturnUserWithRoles() { + // Given + entityManager.persistAndFlush(testUser); + + // When + Optional result = userRepository.findByUsernameWithRoles("testuser"); + + // Then + assertThat(result).isPresent(); + assertThat(result.get().getUsername()).isEqualTo("testuser"); + assertThat(result.get().getRoles()).isNotEmpty(); + assertThat(result.get().getRoles()).hasSize(1); + assertThat(result.get().getRoles().iterator().next().getName()).isEqualTo(RoleName.CUSTOMER); + } + + @Test + void findByUsernameWithRoles_WhenUserDoesNotExist_ShouldReturnEmpty() { + // When + Optional result = userRepository.findByUsernameWithRoles("nonexistent"); + + // Then + assertThat(result).isEmpty(); + } + + @Test + void save_WhenValidUser_ShouldPersistSuccessfully() { + // Given + User newUser = User.builder() + .username("newuser") + .password("password") + .email("newuser@example.com") + .fullName("New User") + .enabled(true) + .emailVerified(false) + .createdAt(LocalDateTime.now()) + .build(); + + // When + User savedUser = userRepository.save(newUser); + + // Then + assertThat(savedUser.getId()).isNotNull(); + assertThat(savedUser.getUsername()).isEqualTo("newuser"); + assertThat(savedUser.getEmail()).isEqualTo("newuser@example.com"); + assertThat(savedUser.getEnabled()).isTrue(); + assertThat(savedUser.getEmailVerified()).isFalse(); + } + + @Test + void save_WithProfilePhoto_ShouldPersistPhotoData() { + // Given + byte[] photoData = "fake-image-data".getBytes(); + User userWithPhoto = User.builder() + .username("photouser") + .password("password") + .email("photo@example.com") + .profilePhoto(photoData) + .profilePhotoMimeType("image/jpeg") + .profilePhotoUpdatedAt(LocalDateTime.now()) + .enabled(true) + .emailVerified(false) + .createdAt(LocalDateTime.now()) + .build(); + + // When + User savedUser = userRepository.save(userWithPhoto); + + // Then + assertThat(savedUser.getId()).isNotNull(); + assertThat(savedUser.getProfilePhoto()).isEqualTo(photoData); + assertThat(savedUser.getProfilePhotoMimeType()).isEqualTo("image/jpeg"); + assertThat(savedUser.getProfilePhotoUpdatedAt()).isNotNull(); + } + + @Test + void findById_WhenUserExists_ShouldReturnUser() { + // Given + User savedUser = entityManager.persistAndFlush(testUser); + + // When + Optional result = userRepository.findById(savedUser.getId()); + + // Then + assertThat(result).isPresent(); + assertThat(result.get().getId()).isEqualTo(savedUser.getId()); + assertThat(result.get().getUsername()).isEqualTo("testuser"); + } + + @Test + void findById_WhenUserDoesNotExist_ShouldReturnEmpty() { + // When + Optional result = userRepository.findById(999L); + + // Then + assertThat(result).isEmpty(); + } + + @Test + void deleteById_WhenUserExists_ShouldRemoveUser() { + // Given + User savedUser = entityManager.persistAndFlush(testUser); + Long userId = savedUser.getId(); + + // When + userRepository.deleteById(userId); + entityManager.flush(); + + // Then + Optional result = userRepository.findById(userId); + assertThat(result).isEmpty(); + } + + @Test + void findAll_ShouldReturnAllUsers() { + // Given + User user1 = User.builder() + .username("user1") + .password("password1") + .email("user1@example.com") + .enabled(true) + .emailVerified(false) + .createdAt(LocalDateTime.now()) + .build(); + + User user2 = User.builder() + .username("user2") + .password("password2") + .email("user2@example.com") + .enabled(true) + .emailVerified(false) + .createdAt(LocalDateTime.now()) + .build(); + + entityManager.persistAndFlush(user1); + entityManager.persistAndFlush(user2); + + // When + var allUsers = userRepository.findAll(); + + // Then + assertThat(allUsers).hasSize(2); + assertThat(allUsers).extracting("username") + .containsExactlyInAnyOrder("user1", "user2"); + } + + @Test + void count_ShouldReturnCorrectCount() { + // Given + entityManager.persistAndFlush(testUser); + + User secondUser = User.builder() + .username("user2") + .password("password2") + .email("user2@example.com") + .enabled(true) + .emailVerified(false) + .createdAt(LocalDateTime.now()) + .build(); + entityManager.persistAndFlush(secondUser); + + // When + long count = userRepository.count(); + + // Then + assertThat(count).isEqualTo(2); + } + + @Test + void update_WhenUserExists_ShouldUpdateSuccessfully() { + // Given + User savedUser = entityManager.persistAndFlush(testUser); + entityManager.detach(savedUser); + + // When + savedUser.setFullName("Updated Name"); + savedUser.setPhone("9876543210"); + savedUser.setEmailVerified(true); + User updatedUser = userRepository.save(savedUser); + + // Then + assertThat(updatedUser.getFullName()).isEqualTo("Updated Name"); + assertThat(updatedUser.getPhone()).isEqualTo("9876543210"); + assertThat(updatedUser.getEmailVerified()).isTrue(); + assertThat(updatedUser.getUsername()).isEqualTo("testuser"); // Should remain unchanged + } + + @Test + void existsById_WhenUserExists_ShouldReturnTrue() { + // Given + User savedUser = entityManager.persistAndFlush(testUser); + + // When + boolean exists = userRepository.existsById(savedUser.getId()); + + // Then + assertThat(exists).isTrue(); + } + + @Test + void existsById_WhenUserDoesNotExist_ShouldReturnFalse() { + // When + boolean exists = userRepository.existsById(999L); + + // Then + assertThat(exists).isFalse(); + } +} \ No newline at end of file diff --git a/auth-service/src/test/java/com/techtorque/auth_service/repository/VerificationTokenRepositoryTest.java b/auth-service/src/test/java/com/techtorque/auth_service/repository/VerificationTokenRepositoryTest.java new file mode 100644 index 0000000..d4c6043 --- /dev/null +++ b/auth-service/src/test/java/com/techtorque/auth_service/repository/VerificationTokenRepositoryTest.java @@ -0,0 +1,388 @@ +package com.techtorque.auth_service.repository; + +import com.techtorque.auth_service.entity.Role; +import com.techtorque.auth_service.entity.RoleName; +import com.techtorque.auth_service.entity.User; +import com.techtorque.auth_service.entity.VerificationToken; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Comprehensive test class for VerificationTokenRepository + * Tests all repository methods, edge cases, and database constraints + */ +@DataJpaTest +@ActiveProfiles("test") +class VerificationTokenRepositoryTest { + + @Autowired + private TestEntityManager entityManager; + + @Autowired + private VerificationTokenRepository verificationTokenRepository; + + private User testUser; + private VerificationToken testToken; + + @BeforeEach + void setUp() { + // Create test role + Role testRole = Role.builder() + .name(RoleName.CUSTOMER) + .description("Test customer role") + .build(); + testRole = entityManager.persistAndFlush(testRole); + + // Create test user + testUser = User.builder() + .username("testuser") + .password("encodedPassword") + .email("test@example.com") + .fullName("Test User") + .enabled(true) + .emailVerified(false) + .createdAt(LocalDateTime.now()) + .build(); + testUser.addRole(testRole); + testUser = entityManager.persistAndFlush(testUser); + + // Create test verification token + testToken = VerificationToken.builder() + .token("test-verification-token") + .user(testUser) + .expiryDate(LocalDateTime.now().plusDays(1)) + .createdAt(LocalDateTime.now()) + .tokenType(VerificationToken.TokenType.EMAIL_VERIFICATION) + .build(); + } + + @Test + void save_WhenValidToken_ShouldPersistSuccessfully() { + // When + VerificationToken savedToken = verificationTokenRepository.save(testToken); + + // Then + assertThat(savedToken.getId()).isNotNull(); + assertThat(savedToken.getToken()).isEqualTo("test-verification-token"); + assertThat(savedToken.getUser().getId()).isEqualTo(testUser.getId()); + assertThat(savedToken.getExpiryDate()).isNotNull(); + assertThat(savedToken.getCreatedAt()).isNotNull(); + assertThat(savedToken.getTokenType()).isEqualTo(VerificationToken.TokenType.EMAIL_VERIFICATION); + assertThat(savedToken.getUsedAt()).isNull(); + } + + @Test + void findByToken_WhenTokenExists_ShouldReturnToken() { + // Given + entityManager.persistAndFlush(testToken); + + // When + Optional result = verificationTokenRepository.findByToken("test-verification-token"); + + // Then + assertThat(result).isPresent(); + assertThat(result.get().getToken()).isEqualTo("test-verification-token"); + assertThat(result.get().getUser().getId()).isEqualTo(testUser.getId()); + assertThat(result.get().getTokenType()).isEqualTo(VerificationToken.TokenType.EMAIL_VERIFICATION); + } + + @Test + void findByToken_WhenTokenDoesNotExist_ShouldReturnEmpty() { + // When + Optional result = verificationTokenRepository.findByToken("non-existent-token"); + + // Then + assertThat(result).isEmpty(); + } + + @Test + void findByUserAndTokenType_WhenTokenExists_ShouldReturnToken() { + // Given + entityManager.persistAndFlush(testToken); + + // When + Optional result = verificationTokenRepository + .findByUserAndTokenType(testUser, VerificationToken.TokenType.EMAIL_VERIFICATION); + + // Then + assertThat(result).isPresent(); + assertThat(result.get().getUser().getId()).isEqualTo(testUser.getId()); + assertThat(result.get().getTokenType()).isEqualTo(VerificationToken.TokenType.EMAIL_VERIFICATION); + } + + @Test + void findByUserAndTokenType_WhenTokenDoesNotExist_ShouldReturnEmpty() { + // When + Optional result = verificationTokenRepository + .findByUserAndTokenType(testUser, VerificationToken.TokenType.PASSWORD_RESET); + + // Then + assertThat(result).isEmpty(); + } + + @Test + void findByUserAndTokenType_WhenDifferentTokenType_ShouldReturnEmpty() { + // Given + entityManager.persistAndFlush(testToken); + + // When + Optional result = verificationTokenRepository + .findByUserAndTokenType(testUser, VerificationToken.TokenType.PASSWORD_RESET); + + // Then + assertThat(result).isEmpty(); + } + + @Test + @Transactional + void deleteByUser_WhenUserHasTokens_ShouldDeleteAllUserTokens() { + // Given + VerificationToken emailToken = VerificationToken.builder() + .token("email-token") + .user(testUser) + .expiryDate(LocalDateTime.now().plusDays(1)) + .createdAt(LocalDateTime.now()) + .tokenType(VerificationToken.TokenType.EMAIL_VERIFICATION) + .build(); + + VerificationToken passwordToken = VerificationToken.builder() + .token("password-token") + .user(testUser) + .expiryDate(LocalDateTime.now().plusHours(1)) + .createdAt(LocalDateTime.now()) + .tokenType(VerificationToken.TokenType.PASSWORD_RESET) + .build(); + + entityManager.persistAndFlush(emailToken); + entityManager.persistAndFlush(passwordToken); + + // Create another user with a token to ensure we only delete current user's + // tokens + User anotherUser = User.builder() + .username("anotheruser") + .password("password") + .email("another@example.com") + .enabled(true) + .emailVerified(false) + .createdAt(LocalDateTime.now()) + .build(); + anotherUser = entityManager.persistAndFlush(anotherUser); + + VerificationToken anotherUserToken = VerificationToken.builder() + .token("another-token") + .user(anotherUser) + .expiryDate(LocalDateTime.now().plusDays(1)) + .createdAt(LocalDateTime.now()) + .tokenType(VerificationToken.TokenType.EMAIL_VERIFICATION) + .build(); + entityManager.persistAndFlush(anotherUserToken); + + // When + verificationTokenRepository.deleteByUser(testUser); + entityManager.flush(); + + // Then + assertThat(verificationTokenRepository.findByToken("email-token")).isEmpty(); + assertThat(verificationTokenRepository.findByToken("password-token")).isEmpty(); + assertThat(verificationTokenRepository.findByToken("another-token")).isPresent(); + } + + @Test + void isExpired_WhenTokenIsExpired_ShouldReturnTrue() { + // Given + VerificationToken expiredToken = VerificationToken.builder() + .token("expired-token") + .user(testUser) + .expiryDate(LocalDateTime.now().minusDays(1)) + .createdAt(LocalDateTime.now().minusDays(2)) + .tokenType(VerificationToken.TokenType.EMAIL_VERIFICATION) + .build(); + + // When + boolean isExpired = expiredToken.isExpired(); + + // Then + assertThat(isExpired).isTrue(); + } + + @Test + void isExpired_WhenTokenIsNotExpired_ShouldReturnFalse() { + // Given + VerificationToken validToken = VerificationToken.builder() + .token("valid-token") + .user(testUser) + .expiryDate(LocalDateTime.now().plusDays(1)) + .createdAt(LocalDateTime.now()) + .tokenType(VerificationToken.TokenType.EMAIL_VERIFICATION) + .build(); + + // When + boolean isExpired = validToken.isExpired(); + + // Then + assertThat(isExpired).isFalse(); + } + + @Test + void isUsed_WhenTokenIsUsed_ShouldReturnTrue() { + // Given + VerificationToken usedToken = VerificationToken.builder() + .token("used-token") + .user(testUser) + .expiryDate(LocalDateTime.now().plusDays(1)) + .createdAt(LocalDateTime.now()) + .usedAt(LocalDateTime.now()) + .tokenType(VerificationToken.TokenType.EMAIL_VERIFICATION) + .build(); + + // When + boolean isUsed = usedToken.isUsed(); + + // Then + assertThat(isUsed).isTrue(); + } + + @Test + void isUsed_WhenTokenIsNotUsed_ShouldReturnFalse() { + // Given + VerificationToken unusedToken = VerificationToken.builder() + .token("unused-token") + .user(testUser) + .expiryDate(LocalDateTime.now().plusDays(1)) + .createdAt(LocalDateTime.now()) + .usedAt(null) + .tokenType(VerificationToken.TokenType.EMAIL_VERIFICATION) + .build(); + + // When + boolean isUsed = unusedToken.isUsed(); + + // Then + assertThat(isUsed).isFalse(); + } + + @Test + void save_WithPasswordResetType_ShouldPersistSuccessfully() { + // Given + VerificationToken passwordResetToken = VerificationToken.builder() + .token("password-reset-token") + .user(testUser) + .expiryDate(LocalDateTime.now().plusHours(1)) + .createdAt(LocalDateTime.now()) + .tokenType(VerificationToken.TokenType.PASSWORD_RESET) + .build(); + + // When + VerificationToken savedToken = verificationTokenRepository.save(passwordResetToken); + + // Then + assertThat(savedToken.getId()).isNotNull(); + assertThat(savedToken.getToken()).isEqualTo("password-reset-token"); + assertThat(savedToken.getTokenType()).isEqualTo(VerificationToken.TokenType.PASSWORD_RESET); + } + + @Test + void findById_WhenTokenExists_ShouldReturnToken() { + // Given + VerificationToken savedToken = entityManager.persistAndFlush(testToken); + + // When + Optional result = verificationTokenRepository.findById(savedToken.getId()); + + // Then + assertThat(result).isPresent(); + assertThat(result.get().getId()).isEqualTo(savedToken.getId()); + assertThat(result.get().getToken()).isEqualTo("test-verification-token"); + } + + @Test + void findById_WhenTokenDoesNotExist_ShouldReturnEmpty() { + // When + Optional result = verificationTokenRepository.findById("non-existent-id"); + + // Then + assertThat(result).isEmpty(); + } + + @Test + void update_WhenTokenIsUsed_ShouldUpdateUsedAt() { + // Given + VerificationToken savedToken = entityManager.persistAndFlush(testToken); + entityManager.detach(savedToken); + + // When + LocalDateTime usedTime = LocalDateTime.now(); + savedToken.setUsedAt(usedTime); + VerificationToken updatedToken = verificationTokenRepository.save(savedToken); + + // Then + assertThat(updatedToken.getUsedAt()).isEqualTo(usedTime); + assertThat(updatedToken.isUsed()).isTrue(); + } + + @Test + void findAll_ShouldReturnAllTokens() { + // Given + VerificationToken emailToken = VerificationToken.builder() + .token("email-token") + .user(testUser) + .expiryDate(LocalDateTime.now().plusDays(1)) + .createdAt(LocalDateTime.now()) + .tokenType(VerificationToken.TokenType.EMAIL_VERIFICATION) + .build(); + + VerificationToken passwordToken = VerificationToken.builder() + .token("password-token") + .user(testUser) + .expiryDate(LocalDateTime.now().plusHours(1)) + .createdAt(LocalDateTime.now()) + .tokenType(VerificationToken.TokenType.PASSWORD_RESET) + .build(); + + entityManager.persistAndFlush(emailToken); + entityManager.persistAndFlush(passwordToken); + + // When + var allTokens = verificationTokenRepository.findAll(); + + // Then + assertThat(allTokens).hasSize(2); + assertThat(allTokens).extracting("token") + .containsExactlyInAnyOrder("email-token", "password-token"); + assertThat(allTokens).extracting("tokenType") + .containsExactlyInAnyOrder( + VerificationToken.TokenType.EMAIL_VERIFICATION, + VerificationToken.TokenType.PASSWORD_RESET); + } + + @Test + void count_ShouldReturnCorrectCount() { + // Given + entityManager.persistAndFlush(testToken); + + VerificationToken secondToken = VerificationToken.builder() + .token("second-token") + .user(testUser) + .expiryDate(LocalDateTime.now().plusDays(1)) + .createdAt(LocalDateTime.now()) + .tokenType(VerificationToken.TokenType.PASSWORD_RESET) + .build(); + entityManager.persistAndFlush(secondToken); + + // When + long count = verificationTokenRepository.count(); + + // Then + assertThat(count).isEqualTo(2); + } +} \ No newline at end of file From 9748b1b0c2f855ec4924ea3f8845ef1aa992727a Mon Sep 17 00:00:00 2001 From: AdithaBuwaneka Date: Fri, 21 Nov 2025 14:21:19 +0530 Subject: [PATCH 02/20] feat: Add comprehensive unit tests for AuthService including authentication, registration, and token management --- .../auth_service/service/AuthServiceTest.java | 578 ++++++++++++++++++ 1 file changed, 578 insertions(+) create mode 100644 auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java new file mode 100644 index 0000000..12f1a1c --- /dev/null +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java @@ -0,0 +1,578 @@ +package com.techtorque.auth_service.service; + +import com.techtorque.auth_service.dto.request.LoginRequest; +import com.techtorque.auth_service.dto.request.RegisterRequest; +import com.techtorque.auth_service.dto.response.LoginResponse; +import com.techtorque.auth_service.entity.*; +import com.techtorque.auth_service.repository.*; +import com.techtorque.auth_service.util.JwtUtil; +import jakarta.servlet.http.HttpServletRequest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.DisabledException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.test.util.ReflectionTestUtils; + +import java.time.LocalDateTime; +import java.util.*; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +/** + * Comprehensive test class for AuthService + * Tests authentication, registration, token management, and security features + */ +@ExtendWith(MockitoExtension.class) +class AuthServiceTest { + + @Mock + private AuthenticationManager authenticationManager; + + @Mock + private UserRepository userRepository; + + @Mock + private RoleRepository roleRepository; + + @Mock + private PasswordEncoder passwordEncoder; + + @Mock + private JwtUtil jwtUtil; + + @Mock + private LoginLockRepository loginLockRepository; + + @Mock + private LoginLogRepository loginLogRepository; + + @Mock + private LoginAuditService loginAuditService; + + @Mock + private TokenService tokenService; + + @Mock + private EmailService emailService; + + @Mock + private HttpServletRequest request; + + @Mock + private Authentication authentication; + + @Mock + private UserDetails userDetails; + + @InjectMocks + private AuthService authService; + + private User testUser; + private Role customerRole; + private Role adminRole; + private LoginRequest loginRequest; + private RegisterRequest registerRequest; + private LoginLock loginLock; + private VerificationToken verificationToken; + private RefreshToken refreshToken; + + @BeforeEach + void setUp() { + // Set up test configuration + ReflectionTestUtils.setField(authService, "maxFailedAttempts", 3); + ReflectionTestUtils.setField(authService, "lockDurationMinutes", 15L); + + // Create test roles + customerRole = Role.builder() + .id("role-1") + .name(RoleName.CUSTOMER) + .description("Customer role") + .build(); + + adminRole = Role.builder() + .id("role-2") + .name(RoleName.ADMIN) + .description("Admin role") + .build(); + + // Create test user + testUser = User.builder() + .id("user-1") + .username("testuser") + .email("test@example.com") + .password("encoded-password") + .fullName("Test User") + .phone("1234567890") + .address("Test Address") + .enabled(true) + .emailVerified(true) + .createdAt(LocalDateTime.now()) + .roles(Set.of(customerRole)) + .build(); + + // Create test requests + loginRequest = new LoginRequest(); + loginRequest.setUsername("testuser"); + loginRequest.setPassword("password"); + + registerRequest = new RegisterRequest(); + registerRequest.setEmail("new@example.com"); + registerRequest.setPassword("newpassword"); + registerRequest.setFullName("New User"); + registerRequest.setPhone("9876543210"); + registerRequest.setAddress("New Address"); + + // Create test login lock + loginLock = LoginLock.builder() + .id("lock-1") + .username("testuser") + .failedAttempts(0) + .lockUntil(null) + .build(); + + // Create test verification token + verificationToken = VerificationToken.builder() + .id("token-1") + .token("verification-token") + .user(testUser) + .tokenType(VerificationToken.TokenType.EMAIL_VERIFICATION) + .expiryDate(LocalDateTime.now().plusHours(24)) + .createdAt(LocalDateTime.now()) + .build(); + + // Create test refresh token + refreshToken = RefreshToken.builder() + .id("refresh-1") + .token("refresh-token") + .user(testUser) + .expiryDate(LocalDateTime.now().plusDays(7)) + .createdAt(LocalDateTime.now()) + .build(); + } + + @Test + void authenticateUser_WhenValidCredentials_ShouldReturnLoginResponse() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(loginLockRepository.findByUsername("testuser")).thenReturn(Optional.of(loginLock)); + when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class))) + .thenReturn(authentication); + when(authentication.getPrincipal()).thenReturn(userDetails); + when(userDetails.getUsername()).thenReturn("testuser"); + when(userDetails.getAuthorities()).thenReturn(List.of(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); + when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())).thenReturn("refresh-token"); + when(request.getHeader("X-Forwarded-For")).thenReturn(null); + when(request.getRemoteAddr()).thenReturn("127.0.0.1"); + when(request.getHeader("User-Agent")).thenReturn("Test-Agent"); + + // When + LoginResponse response = authService.authenticateUser(loginRequest, request); + + // Then + assertThat(response).isNotNull(); + assertThat(response.getToken()).isEqualTo("jwt-token"); + assertThat(response.getRefreshToken()).isEqualTo("refresh-token"); + assertThat(response.getUsername()).isEqualTo("testuser"); + assertThat(response.getEmail()).isEqualTo("test@example.com"); + assertThat(response.getRoles()).contains("CUSTOMER"); + + verify(loginLockRepository).save(any(LoginLock.class)); + verify(loginLogRepository).save(any(LoginLog.class)); + } + + @Test + void authenticateUser_WhenUserNotFound_ShouldCheckByEmail() { + // Given + when(userRepository.findByUsername("test@example.com")).thenReturn(Optional.empty()); + when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.of(testUser)); + when(loginLockRepository.findByUsername("test@example.com")).thenReturn(Optional.of(loginLock)); + when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class))) + .thenReturn(authentication); + when(authentication.getPrincipal()).thenReturn(userDetails); + when(userDetails.getUsername()).thenReturn("test@example.com"); + when(userDetails.getAuthorities()).thenReturn(List.of(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); + + loginRequest.setUsername("test@example.com"); + + // When/Then + when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); + when(userRepository.findByUsername("test@example.com")).thenReturn(Optional.of(testUser)); + when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())).thenReturn("refresh-token"); + + LoginResponse response = authService.authenticateUser(loginRequest, request); + assertThat(response).isNotNull(); + } + + @Test + void authenticateUser_WhenUserDisabledAndNotVerified_ShouldThrowDisabledException() { + // Given + testUser.setEnabled(false); + testUser.setEmailVerified(false); + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + + // When/Then + assertThatThrownBy(() -> authService.authenticateUser(loginRequest, request)) + .isInstanceOf(DisabledException.class) + .hasMessageContaining("Please verify your email address"); + } + + @Test + void authenticateUser_WhenUserDisabledAndVerified_ShouldThrowDisabledException() { + // Given + testUser.setEnabled(false); + testUser.setEmailVerified(true); + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + + // When/Then + assertThatThrownBy(() -> authService.authenticateUser(loginRequest, request)) + .isInstanceOf(DisabledException.class) + .hasMessageContaining("Your account has been deactivated"); + } + + @Test + void authenticateUser_WhenAccountLocked_ShouldThrowBadCredentialsException() { + // Given + loginLock.setLockUntil(LocalDateTime.now().plusMinutes(10)); + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(loginLockRepository.findByUsername("testuser")).thenReturn(Optional.of(loginLock)); + + // When/Then + assertThatThrownBy(() -> authService.authenticateUser(loginRequest, request)) + .isInstanceOf(BadCredentialsException.class) + .hasMessageContaining("Account is temporarily locked"); + + verify(loginAuditService).recordLogin(eq("testuser"), eq(false), anyString(), anyString()); + } + + @Test + void authenticateUser_WhenNoLockRecord_ShouldCreateNewLock() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(loginLockRepository.findByUsername("testuser")).thenReturn(Optional.empty()); + when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class))) + .thenReturn(authentication); + when(authentication.getPrincipal()).thenReturn(userDetails); + when(userDetails.getUsername()).thenReturn("testuser"); + when(userDetails.getAuthorities()).thenReturn(List.of(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); + when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())).thenReturn("refresh-token"); + + // When + LoginResponse response = authService.authenticateUser(loginRequest, request); + + // Then + assertThat(response).isNotNull(); + verify(loginLockRepository) + .save(argThat(lock -> lock.getUsername().equals("testuser") && lock.getFailedAttempts() == 0)); + } + + @Test + void authenticateUser_WhenBadCredentials_ShouldIncrementFailedAttempts() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(loginLockRepository.findByUsername("testuser")).thenReturn(Optional.of(loginLock)); + when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class))) + .thenThrow(new BadCredentialsException("Invalid credentials")); + + // When/Then + assertThatThrownBy(() -> authService.authenticateUser(loginRequest, request)) + .isInstanceOf(BadCredentialsException.class) + .hasMessage("Invalid username or password"); + + verify(loginAuditService).incrementFailedAttempt("testuser", 15L, 3); + verify(loginAuditService).recordLogin(eq("testuser"), eq(false), anyString(), anyString()); + } + + @Test + void registerUser_WhenValidRequest_ShouldCreateUserAndSendVerificationEmail() { + // Given + when(userRepository.existsByEmail("new@example.com")).thenReturn(false); + when(roleRepository.findByName(RoleName.CUSTOMER)).thenReturn(Optional.of(customerRole)); + when(passwordEncoder.encode("newpassword")).thenReturn("encoded-password"); + when(userRepository.save(any(User.class))).thenReturn(testUser); + when(tokenService.createVerificationToken(any(User.class))).thenReturn("verification-token"); + + // When + String result = authService.registerUser(registerRequest); + + // Then + assertThat(result).contains("User registered successfully"); + verify(userRepository).save(argThat(user -> user.getEmail().equals("new@example.com") && + user.getFullName().equals("New User") && + !user.getEnabled() && + !user.getEmailVerified())); + verify(emailService).sendVerificationEmail("new@example.com", "new@example.com", "verification-token"); + } + + @Test + void registerUser_WhenEmailExists_ShouldThrowRuntimeException() { + // Given + when(userRepository.existsByEmail("new@example.com")).thenReturn(true); + + // When/Then + assertThatThrownBy(() -> authService.registerUser(registerRequest)) + .isInstanceOf(RuntimeException.class) + .hasMessage("Error: Email is already in use!"); + } + + @Test + void registerUser_WhenAdminRole_ShouldAssignAdminRole() { + // Given + registerRequest.setRoles(Set.of("admin")); + when(userRepository.existsByEmail("new@example.com")).thenReturn(false); + when(roleRepository.findByName(RoleName.ADMIN)).thenReturn(Optional.of(adminRole)); + when(passwordEncoder.encode("newpassword")).thenReturn("encoded-password"); + when(userRepository.save(any(User.class))).thenReturn(testUser); + when(tokenService.createVerificationToken(any(User.class))).thenReturn("verification-token"); + + // When + authService.registerUser(registerRequest); + + // Then + verify(roleRepository).findByName(RoleName.ADMIN); + verify(userRepository).save(argThat(user -> user.getRoles().contains(adminRole))); + } + + @Test + void registerUser_WhenEmployeeRole_ShouldAssignEmployeeRole() { + // Given + Role employeeRole = Role.builder().id("role-3").name(RoleName.EMPLOYEE).build(); + registerRequest.setRoles(Set.of("employee")); + when(userRepository.existsByEmail("new@example.com")).thenReturn(false); + when(roleRepository.findByName(RoleName.EMPLOYEE)).thenReturn(Optional.of(employeeRole)); + when(passwordEncoder.encode("newpassword")).thenReturn("encoded-password"); + when(userRepository.save(any(User.class))).thenReturn(testUser); + when(tokenService.createVerificationToken(any(User.class))).thenReturn("verification-token"); + + // When + authService.registerUser(registerRequest); + + // Then + verify(roleRepository).findByName(RoleName.EMPLOYEE); + verify(userRepository).save(argThat(user -> user.getRoles().contains(employeeRole))); + } + + @Test + void registerUser_WhenInvalidRole_ShouldAssignCustomerRole() { + // Given + registerRequest.setRoles(Set.of("invalid")); + when(userRepository.existsByEmail("new@example.com")).thenReturn(false); + when(roleRepository.findByName(RoleName.CUSTOMER)).thenReturn(Optional.of(customerRole)); + when(passwordEncoder.encode("newpassword")).thenReturn("encoded-password"); + when(userRepository.save(any(User.class))).thenReturn(testUser); + when(tokenService.createVerificationToken(any(User.class))).thenReturn("verification-token"); + + // When + authService.registerUser(registerRequest); + + // Then + verify(roleRepository).findByName(RoleName.CUSTOMER); + verify(userRepository).save(argThat(user -> user.getRoles().contains(customerRole))); + } + + @Test + void registerUser_WhenRoleNotFound_ShouldThrowRuntimeException() { + // Given + when(userRepository.existsByEmail("new@example.com")).thenReturn(false); + when(roleRepository.findByName(RoleName.CUSTOMER)).thenReturn(Optional.empty()); + when(passwordEncoder.encode("newpassword")).thenReturn("encoded-password"); + + // When/Then + assertThatThrownBy(() -> authService.registerUser(registerRequest)) + .isInstanceOf(RuntimeException.class) + .hasMessage("Error: Customer Role not found."); + } + + @Test + void verifyEmail_WhenValidToken_ShouldEnableUserAndReturnLoginResponse() { + // Given + testUser.setEnabled(false); + testUser.setEmailVerified(false); + when(tokenService.validateToken("verification-token", VerificationToken.TokenType.EMAIL_VERIFICATION)) + .thenReturn(verificationToken); + when(userRepository.save(any(User.class))).thenReturn(testUser); + when(jwtUtil.generateJwtToken(any(UserDetails.class), anyList())).thenReturn("jwt-token"); + when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())).thenReturn("refresh-token"); + + // When + LoginResponse response = authService.verifyEmail("verification-token", request); + + // Then + assertThat(response).isNotNull(); + assertThat(response.getToken()).isEqualTo("jwt-token"); + assertThat(response.getRefreshToken()).isEqualTo("refresh-token"); + verify(userRepository).save(argThat(user -> user.getEnabled() && user.getEmailVerified())); + verify(tokenService).markTokenAsUsed(verificationToken); + verify(emailService).sendWelcomeEmail("test@example.com", "testuser"); + } + + @Test + void resendVerificationEmail_WhenUserExists_ShouldSendEmail() { + // Given + testUser.setEmailVerified(false); + when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.of(testUser)); + when(tokenService.createVerificationToken(testUser)).thenReturn("new-verification-token"); + + // When + String result = authService.resendVerificationEmail("test@example.com"); + + // Then + assertThat(result).contains("Verification email sent successfully"); + verify(emailService).sendVerificationEmail("test@example.com", "testuser", "new-verification-token"); + } + + @Test + void resendVerificationEmail_WhenUserNotFound_ShouldThrowRuntimeException() { + // Given + when(userRepository.findByEmail("nonexistent@example.com")).thenReturn(Optional.empty()); + + // When/Then + assertThatThrownBy(() -> authService.resendVerificationEmail("nonexistent@example.com")) + .isInstanceOf(RuntimeException.class) + .hasMessage("User not found with email: nonexistent@example.com"); + } + + @Test + void resendVerificationEmail_WhenEmailAlreadyVerified_ShouldThrowRuntimeException() { + // Given + testUser.setEmailVerified(true); + when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.of(testUser)); + + // When/Then + assertThatThrownBy(() -> authService.resendVerificationEmail("test@example.com")) + .isInstanceOf(RuntimeException.class) + .hasMessage("Email is already verified"); + } + + @Test + void refreshToken_WhenValidToken_ShouldReturnNewLoginResponse() { + // Given + when(tokenService.validateRefreshToken("refresh-token")).thenReturn(refreshToken); + when(jwtUtil.generateJwtToken(any(UserDetails.class), anyList())).thenReturn("new-jwt-token"); + + // When + LoginResponse response = authService.refreshToken("refresh-token"); + + // Then + assertThat(response).isNotNull(); + assertThat(response.getToken()).isEqualTo("new-jwt-token"); + assertThat(response.getRefreshToken()).isEqualTo("refresh-token"); + assertThat(response.getUsername()).isEqualTo("testuser"); + assertThat(response.getEmail()).isEqualTo("test@example.com"); + } + + @Test + void logout_ShouldRevokeRefreshToken() { + // When + authService.logout("refresh-token"); + + // Then + verify(tokenService).revokeRefreshToken("refresh-token"); + } + + @Test + void forgotPassword_WhenUserExists_ShouldSendResetEmail() { + // Given + when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.of(testUser)); + when(tokenService.createPasswordResetToken(testUser)).thenReturn("reset-token"); + + // When + String result = authService.forgotPassword("test@example.com"); + + // Then + assertThat(result).contains("Password reset email sent successfully"); + verify(emailService).sendPasswordResetEmail("test@example.com", "testuser", "reset-token"); + } + + @Test + void forgotPassword_WhenUserNotFound_ShouldThrowRuntimeException() { + // Given + when(userRepository.findByEmail("nonexistent@example.com")).thenReturn(Optional.empty()); + + // When/Then + assertThatThrownBy(() -> authService.forgotPassword("nonexistent@example.com")) + .isInstanceOf(RuntimeException.class) + .hasMessage("User not found with email: nonexistent@example.com"); + } + + @Test + void resetPassword_WhenValidToken_ShouldUpdatePasswordAndRevokeTokens() { + // Given + VerificationToken resetToken = VerificationToken.builder() + .token("reset-token") + .user(testUser) + .tokenType(VerificationToken.TokenType.PASSWORD_RESET) + .build(); + + when(tokenService.validateToken("reset-token", VerificationToken.TokenType.PASSWORD_RESET)) + .thenReturn(resetToken); + when(passwordEncoder.encode("newpassword")).thenReturn("new-encoded-password"); + when(userRepository.save(any(User.class))).thenReturn(testUser); + + // When + String result = authService.resetPassword("reset-token", "newpassword"); + + // Then + assertThat(result).contains("Password reset successfully"); + verify(userRepository).save(argThat(user -> user.getPassword().equals("new-encoded-password"))); + verify(tokenService).markTokenAsUsed(resetToken); + verify(tokenService).revokeAllUserTokens(testUser); + } + + @Test + void authenticateUser_WhenNullRequest_ShouldHandleGracefully() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(loginLockRepository.findByUsername("testuser")).thenReturn(Optional.of(loginLock)); + when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class))) + .thenReturn(authentication); + when(authentication.getPrincipal()).thenReturn(userDetails); + when(userDetails.getUsername()).thenReturn("testuser"); + when(userDetails.getAuthorities()).thenReturn(List.of(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); + when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(tokenService.createRefreshToken(eq(testUser), isNull(), isNull())).thenReturn("refresh-token"); + + // When + LoginResponse response = authService.authenticateUser(loginRequest, null); + + // Then + assertThat(response).isNotNull(); + verify(tokenService).createRefreshToken(eq(testUser), isNull(), isNull()); + } + + @Test + void verifyEmail_WhenNullRequest_ShouldHandleGracefully() { + // Given + testUser.setEnabled(false); + testUser.setEmailVerified(false); + when(tokenService.validateToken("verification-token", VerificationToken.TokenType.EMAIL_VERIFICATION)) + .thenReturn(verificationToken); + when(userRepository.save(any(User.class))).thenReturn(testUser); + when(jwtUtil.generateJwtToken(any(UserDetails.class), anyList())).thenReturn("jwt-token"); + when(tokenService.createRefreshToken(eq(testUser), isNull(), isNull())).thenReturn("refresh-token"); + + // When + LoginResponse response = authService.verifyEmail("verification-token", null); + + // Then + assertThat(response).isNotNull(); + verify(tokenService).createRefreshToken(eq(testUser), isNull(), isNull()); + } +} \ No newline at end of file From 9df11de36fa1c74632ad6ee7ed41f6c8cceb71d0 Mon Sep 17 00:00:00 2001 From: AdithaBuwaneka Date: Fri, 21 Nov 2025 14:21:31 +0530 Subject: [PATCH 03/20] feat: Add comprehensive unit tests for UserService covering user management, role assignments, and permissions --- .../auth_service/service/UserServiceTest.java | 702 ++++++++++++++++++ 1 file changed, 702 insertions(+) create mode 100644 auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java new file mode 100644 index 0000000..40d83e9 --- /dev/null +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java @@ -0,0 +1,702 @@ +package com.techtorque.auth_service.service; + +import com.techtorque.auth_service.entity.Role; +import com.techtorque.auth_service.entity.RoleName; +import com.techtorque.auth_service.entity.User; +import com.techtorque.auth_service.repository.*; +import jakarta.persistence.EntityNotFoundException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.crypto.password.PasswordEncoder; + +import java.util.*; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +/** + * Comprehensive test class for UserService + * Tests user management, security, and role/permission operations + */ +@ExtendWith(MockitoExtension.class) +class UserServiceTest { + + @Mock + private UserRepository userRepository; + + @Mock + private RoleRepository roleRepository; + + @Mock + private PasswordEncoder passwordEncoder; + + @Mock + private LoginLockRepository loginLockRepository; + + @Mock + private RefreshTokenRepository refreshTokenRepository; + + @Mock + private VerificationTokenRepository verificationTokenRepository; + + @Mock + private LoginLogRepository loginLogRepository; + + @Mock + private SecurityContext securityContext; + + @Mock + private Authentication authentication; + + @InjectMocks + private UserService userService; + + private User testUser; + private Role customerRole; + private Role employeeRole; + private Role adminRole; + private Role superAdminRole; + + @BeforeEach + void setUp() { + // Create test roles + customerRole = Role.builder() + .id("role-1") + .name(RoleName.CUSTOMER) + .description("Customer role") + .permissions(new HashSet<>()) + .build(); + + employeeRole = Role.builder() + .id("role-2") + .name(RoleName.EMPLOYEE) + .description("Employee role") + .permissions(new HashSet<>()) + .build(); + + adminRole = Role.builder() + .id("role-3") + .name(RoleName.ADMIN) + .description("Admin role") + .permissions(new HashSet<>()) + .build(); + + superAdminRole = Role.builder() + .id("role-4") + .name(RoleName.SUPER_ADMIN) + .description("Super Admin role") + .permissions(new HashSet<>()) + .build(); + + // Create test user + testUser = User.builder() + .id("user-1") + .username("testuser") + .email("test@example.com") + .password("encoded-password") + .fullName("Test User") + .phone("1234567890") + .address("Test Address") + .enabled(true) + .emailVerified(true) + .roles(new HashSet<>(Set.of(customerRole))) + .build(); + } + + @Test + void loadUserByUsername_WhenUserFoundByUsername_ShouldReturnUserDetails() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + + // When + UserDetails userDetails = userService.loadUserByUsername("testuser"); + + // Then + assertThat(userDetails).isNotNull(); + assertThat(userDetails.getUsername()).isEqualTo("testuser"); + assertThat(userDetails.getPassword()).isEqualTo("encoded-password"); + assertThat(userDetails.isEnabled()).isTrue(); + assertThat(userDetails.isAccountNonLocked()).isTrue(); + assertThat(userDetails.getAuthorities()).hasSize(1); + assertThat(userDetails.getAuthorities()).extracting(GrantedAuthority::getAuthority) + .contains("ROLE_CUSTOMER"); + } + + @Test + void loadUserByUsername_WhenUserFoundByEmail_ShouldReturnUserDetails() { + // Given + when(userRepository.findByUsername("test@example.com")).thenReturn(Optional.empty()); + when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.of(testUser)); + + // When + UserDetails userDetails = userService.loadUserByUsername("test@example.com"); + + // Then + assertThat(userDetails).isNotNull(); + assertThat(userDetails.getUsername()).isEqualTo("testuser"); + verify(userRepository).findByUsername("test@example.com"); + verify(userRepository).findByEmail("test@example.com"); + } + + @Test + void loadUserByUsername_WhenUserNotFound_ShouldThrowUsernameNotFoundException() { + // Given + when(userRepository.findByUsername("nonexistent")).thenReturn(Optional.empty()); + when(userRepository.findByEmail("nonexistent")).thenReturn(Optional.empty()); + + // When/Then + assertThatThrownBy(() -> userService.loadUserByUsername("nonexistent")) + .isInstanceOf(UsernameNotFoundException.class) + .hasMessage("User not found: nonexistent"); + } + + @Test + void loadUserByUsername_WhenUserDisabled_ShouldReturnDisabledUserDetails() { + // Given + testUser.setEnabled(false); + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + + // When + UserDetails userDetails = userService.loadUserByUsername("testuser"); + + // Then + assertThat(userDetails.isEnabled()).isFalse(); + assertThat(userDetails.isAccountNonLocked()).isFalse(); + } + + @Test + void registerCustomer_WhenValidInput_ShouldCreateCustomerUser() { + // Given + when(userRepository.findByUsername("newuser")).thenReturn(Optional.empty()); + when(userRepository.findByEmail("new@example.com")).thenReturn(Optional.empty()); + when(roleRepository.findByName(RoleName.CUSTOMER)).thenReturn(Optional.of(customerRole)); + when(passwordEncoder.encode("password")).thenReturn("encoded-password"); + when(userRepository.save(any(User.class))).thenReturn(testUser); + + // When + User result = userService.registerCustomer("newuser", "new@example.com", "password"); + + // Then + assertThat(result).isNotNull(); + verify(userRepository).save(argThat(user -> user.getUsername().equals("newuser") && + user.getEmail().equals("new@example.com") && + user.getPassword().equals("encoded-password") && + user.getEnabled() && + user.getRoles().contains(customerRole))); + } + + @Test + void registerCustomer_WhenUsernameExists_ShouldThrowIllegalArgumentException() { + // Given + when(userRepository.findByUsername("existinguser")).thenReturn(Optional.of(testUser)); + + // When/Then + assertThatThrownBy(() -> userService.registerCustomer("existinguser", "new@example.com", "password")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Username already exists: existinguser"); + } + + @Test + void registerCustomer_WhenEmailExists_ShouldThrowIllegalArgumentException() { + // Given + when(userRepository.findByUsername("newuser")).thenReturn(Optional.empty()); + when(userRepository.findByEmail("existing@example.com")).thenReturn(Optional.of(testUser)); + + // When/Then + assertThatThrownBy(() -> userService.registerCustomer("newuser", "existing@example.com", "password")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Email already exists: existing@example.com"); + } + + @Test + void registerCustomer_WhenCustomerRoleNotFound_ShouldThrowEntityNotFoundException() { + // Given + when(userRepository.findByUsername("newuser")).thenReturn(Optional.empty()); + when(userRepository.findByEmail("new@example.com")).thenReturn(Optional.empty()); + when(roleRepository.findByName(RoleName.CUSTOMER)).thenReturn(Optional.empty()); + + // When/Then + assertThatThrownBy(() -> userService.registerCustomer("newuser", "new@example.com", "password")) + .isInstanceOf(EntityNotFoundException.class) + .hasMessage("Customer role not found"); + } + + @Test + void createEmployee_WhenValidInput_ShouldCreateEmployeeUser() { + // Given + when(userRepository.findByUsername("employee")).thenReturn(Optional.empty()); + when(userRepository.findByEmail("employee@example.com")).thenReturn(Optional.empty()); + when(roleRepository.findByName(RoleName.EMPLOYEE)).thenReturn(Optional.of(employeeRole)); + when(passwordEncoder.encode("password")).thenReturn("encoded-password"); + when(userRepository.save(any(User.class))).thenReturn(testUser); + + // When + User result = userService.createEmployee("employee", "employee@example.com", "password"); + + // Then + assertThat(result).isNotNull(); + verify(userRepository).save(argThat(user -> user.getUsername().equals("employee") && + user.getEmail().equals("employee@example.com") && + user.getRoles().contains(employeeRole))); + } + + @Test + void createAdmin_WhenValidInput_ShouldCreateAdminUser() { + // Given + when(userRepository.findByUsername("admin")).thenReturn(Optional.empty()); + when(userRepository.findByEmail("admin@example.com")).thenReturn(Optional.empty()); + when(roleRepository.findByName(RoleName.ADMIN)).thenReturn(Optional.of(adminRole)); + when(passwordEncoder.encode("password")).thenReturn("encoded-password"); + when(userRepository.save(any(User.class))).thenReturn(testUser); + + // When + User result = userService.createAdmin("admin", "admin@example.com", "password"); + + // Then + assertThat(result).isNotNull(); + verify(userRepository).save(argThat(user -> user.getUsername().equals("admin") && + user.getEmail().equals("admin@example.com") && + user.getRoles().contains(adminRole))); + } + + @Test + void findByUsername_WhenUserExists_ShouldReturnUser() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + + // When + Optional result = userService.findByUsername("testuser"); + + // Then + assertThat(result).isPresent(); + assertThat(result.get()).isEqualTo(testUser); + } + + @Test + void findByEmail_WhenUserExists_ShouldReturnUser() { + // Given + when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.of(testUser)); + + // When + Optional result = userService.findByEmail("test@example.com"); + + // Then + assertThat(result).isPresent(); + assertThat(result.get()).isEqualTo(testUser); + } + + @Test + void findAllUsers_ShouldReturnAllUsers() { + // Given + List users = List.of(testUser); + when(userRepository.findAll()).thenReturn(users); + + // When + List result = userService.findAllUsers(); + + // Then + assertThat(result).isEqualTo(users); + } + + @Test + void getUserPermissions_WhenUserExists_ShouldReturnPermissions() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + + // When + Set permissions = userService.getUserPermissions("testuser"); + + // Then + assertThat(permissions).isNotNull(); + // Note: permissions are empty in our test setup, so this just verifies the + // method works + } + + @Test + void getUserPermissions_WhenUserNotFound_ShouldThrowEntityNotFoundException() { + // Given + when(userRepository.findByUsername("nonexistent")).thenReturn(Optional.empty()); + + // When/Then + assertThatThrownBy(() -> userService.getUserPermissions("nonexistent")) + .isInstanceOf(EntityNotFoundException.class) + .hasMessage("User not found: nonexistent"); + } + + @Test + void getUserRoles_WhenUserExists_ShouldReturnRoles() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + + // When + Set roles = userService.getUserRoles("testuser"); + + // Then + assertThat(roles).contains("CUSTOMER"); + } + + @Test + void enableUser_WhenUserExists_ShouldEnableUser() { + // Given + testUser.setEnabled(false); + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(userRepository.save(testUser)).thenReturn(testUser); + + // When + userService.enableUser("testuser"); + + // Then + assertThat(testUser.getEnabled()).isTrue(); + verify(userRepository).save(testUser); + } + + @Test + void disableUser_WhenUserExists_ShouldDisableUser() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(userRepository.save(testUser)).thenReturn(testUser); + + // When + userService.disableUser("testuser"); + + // Then + assertThat(testUser.getEnabled()).isFalse(); + verify(userRepository).save(testUser); + } + + @Test + void deleteUser_WhenUserExists_ShouldDeleteUserAndRelatedData() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + + // When + userService.deleteUser("testuser"); + + // Then + verify(userRepository).save(testUser); // Clear roles + verify(refreshTokenRepository).deleteByUser(testUser); + verify(verificationTokenRepository).deleteByUser(testUser); + verify(loginLockRepository).deleteByUsername("testuser"); + verify(loginLogRepository).deleteByUsername("testuser"); + verify(userRepository).delete(testUser); + } + + @Test + void deleteUser_WhenUserNotFound_ShouldThrowEntityNotFoundException() { + // Given + when(userRepository.findByUsername("nonexistent")).thenReturn(Optional.empty()); + + // When/Then + assertThatThrownBy(() -> userService.deleteUser("nonexistent")) + .isInstanceOf(EntityNotFoundException.class) + .hasMessage("User not found: nonexistent"); + } + + @Test + void clearLoginLock_WhenLockExists_ShouldClearLock() { + // Given + com.techtorque.auth_service.entity.LoginLock loginLock = com.techtorque.auth_service.entity.LoginLock.builder() + .username("testuser") + .failedAttempts(3) + .lockUntil(java.time.LocalDateTime.now().plusMinutes(15)) + .build(); + when(loginLockRepository.findByUsername("testuser")).thenReturn(Optional.of(loginLock)); + + // When + userService.clearLoginLock("testuser"); + + // Then + assertThat(loginLock.getFailedAttempts()).isEqualTo(0); + assertThat(loginLock.getLockUntil()).isNull(); + verify(loginLockRepository).save(loginLock); + } + + @Test + void clearLoginLock_WhenLockNotExists_ShouldNotThrowException() { + // Given + when(loginLockRepository.findByUsername("testuser")).thenReturn(Optional.empty()); + + // When/Then + assertThatCode(() -> userService.clearLoginLock("testuser")) + .doesNotThrowAnyException(); + } + + @Test + void hasRole_WhenUserHasRole_ShouldReturnTrue() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + + // When + boolean result = userService.hasRole("testuser", RoleName.CUSTOMER); + + // Then + assertThat(result).isTrue(); + } + + @Test + void hasRole_WhenUserDoesNotHaveRole_ShouldReturnFalse() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + + // When + boolean result = userService.hasRole("testuser", RoleName.ADMIN); + + // Then + assertThat(result).isFalse(); + } + + @Test + void hasPermission_WhenUserHasPermission_ShouldReturnTrue() { + // Given + com.techtorque.auth_service.entity.Permission permission = com.techtorque.auth_service.entity.Permission + .builder() + .name("READ_USERS") + .build(); + customerRole.getPermissions().add(permission); + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + + // When + boolean result = userService.hasPermission("testuser", "READ_USERS"); + + // Then + assertThat(result).isTrue(); + } + + @Test + void hasPermission_WhenUserDoesNotHavePermission_ShouldReturnFalse() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + + // When + boolean result = userService.hasPermission("testuser", "DELETE_USERS"); + + // Then + assertThat(result).isFalse(); + } + + @Test + void updateUserDetails_WhenValidInput_ShouldUpdateUser() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(userRepository.existsByUsername("newusername")).thenReturn(false); + when(userRepository.existsByEmail("new@example.com")).thenReturn(false); + when(userRepository.save(testUser)).thenReturn(testUser); + + // When + User result = userService.updateUserDetails("testuser", "newusername", "new@example.com", false); + + // Then + assertThat(result.getUsername()).isEqualTo("newusername"); + assertThat(result.getEmail()).isEqualTo("new@example.com"); + assertThat(result.getEnabled()).isFalse(); + } + + @Test + void updateUserDetails_WhenUsernameExists_ShouldThrowIllegalArgumentException() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(userRepository.existsByUsername("existingusername")).thenReturn(true); + + // When/Then + assertThatThrownBy(() -> userService.updateUserDetails("testuser", "existingusername", null, null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Username already exists: existingusername"); + } + + @Test + void resetUserPassword_WhenUserExists_ShouldUpdatePassword() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(passwordEncoder.encode("newpassword")).thenReturn("new-encoded-password"); + when(userRepository.save(testUser)).thenReturn(testUser); + + // When + userService.resetUserPassword("testuser", "newpassword"); + + // Then + assertThat(testUser.getPassword()).isEqualTo("new-encoded-password"); + verify(userRepository).save(testUser); + } + + @Test + void changeUserPassword_WhenCurrentPasswordCorrect_ShouldUpdatePassword() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(passwordEncoder.matches("currentpassword", "encoded-password")).thenReturn(true); + when(passwordEncoder.encode("newpassword")).thenReturn("new-encoded-password"); + when(userRepository.save(testUser)).thenReturn(testUser); + + // When + userService.changeUserPassword("testuser", "currentpassword", "newpassword"); + + // Then + assertThat(testUser.getPassword()).isEqualTo("new-encoded-password"); + verify(userRepository).save(testUser); + } + + @Test + void changeUserPassword_WhenCurrentPasswordIncorrect_ShouldThrowIllegalStateException() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(passwordEncoder.matches("wrongpassword", "encoded-password")).thenReturn(false); + + // When/Then + assertThatThrownBy(() -> userService.changeUserPassword("testuser", "wrongpassword", "newpassword")) + .isInstanceOf(IllegalStateException.class) + .hasMessage("Current password is incorrect"); + } + + @Test + void assignRoleToUser_WhenValidRole_ShouldAssignRole() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(roleRepository.findByName(RoleName.EMPLOYEE)).thenReturn(Optional.of(employeeRole)); + when(userRepository.save(testUser)).thenReturn(testUser); + + // When + userService.assignRoleToUser("testuser", "EMPLOYEE"); + + // Then + assertThat(testUser.getRoles()).contains(employeeRole); + verify(userRepository).save(testUser); + } + + @Test + void assignRoleToUser_WhenAssigningAdminRoleWithoutSuperAdminAuth_ShouldThrowAccessDeniedException() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(roleRepository.findByName(RoleName.ADMIN)).thenReturn(Optional.of(adminRole)); + + SecurityContextHolder.setContext(securityContext); + when(securityContext.getAuthentication()).thenReturn(authentication); + when(authentication.getAuthorities()).thenReturn(List.of(new SimpleGrantedAuthority("ROLE_ADMIN"))); + + // When/Then + assertThatThrownBy(() -> userService.assignRoleToUser("testuser", "ADMIN")) + .isInstanceOf(AccessDeniedException.class) + .hasMessage("Permission denied: Only a SUPER_ADMIN can assign the ADMIN role."); + + SecurityContextHolder.clearContext(); + } + + @Test + void assignRoleToUser_WhenAssigningAdminRoleWithSuperAdminAuth_ShouldSucceed() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(roleRepository.findByName(RoleName.ADMIN)).thenReturn(Optional.of(adminRole)); + when(userRepository.save(testUser)).thenReturn(testUser); + + SecurityContextHolder.setContext(securityContext); + when(securityContext.getAuthentication()).thenReturn(authentication); + when(authentication.getAuthorities()).thenReturn(List.of(new SimpleGrantedAuthority("ROLE_SUPER_ADMIN"))); + + // When + userService.assignRoleToUser("testuser", "ADMIN"); + + // Then + assertThat(testUser.getRoles()).contains(adminRole); + verify(userRepository).save(testUser); + SecurityContextHolder.clearContext(); + } + + @Test + void assignRoleToUser_WhenRoleAlreadyAssigned_ShouldThrowIllegalStateException() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(roleRepository.findByName(RoleName.CUSTOMER)).thenReturn(Optional.of(customerRole)); + + // When/Then + assertThatThrownBy(() -> userService.assignRoleToUser("testuser", "CUSTOMER")) + .isInstanceOf(IllegalStateException.class) + .hasMessage("User already has role: CUSTOMER"); + } + + @Test + void revokeRoleFromUser_WhenValidRole_ShouldRevokeRole() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(roleRepository.findByName(RoleName.CUSTOMER)).thenReturn(Optional.of(customerRole)); + when(userRepository.save(testUser)).thenReturn(testUser); + + // When + userService.revokeRoleFromUser("testuser", "CUSTOMER"); + + // Then + assertThat(testUser.getRoles()).doesNotContain(customerRole); + verify(userRepository).save(testUser); + } + + @Test + void revokeRoleFromUser_WhenRevokingOwnSuperAdminRole_ShouldThrowAccessDeniedException() { + // Given + testUser.getRoles().add(superAdminRole); + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(roleRepository.findByName(RoleName.SUPER_ADMIN)).thenReturn(Optional.of(superAdminRole)); + + SecurityContextHolder.setContext(securityContext); + when(securityContext.getAuthentication()).thenReturn(authentication); + when(authentication.getName()).thenReturn("testuser"); + + // When/Then + assertThatThrownBy(() -> userService.revokeRoleFromUser("testuser", "SUPER_ADMIN")) + .isInstanceOf(AccessDeniedException.class) + .hasMessage("Action denied: A SUPER_ADMIN cannot revoke their own SUPER_ADMIN role."); + + SecurityContextHolder.clearContext(); + } + + @Test + void revokeRoleFromUser_WhenRoleNotAssigned_ShouldThrowIllegalStateException() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(roleRepository.findByName(RoleName.ADMIN)).thenReturn(Optional.of(adminRole)); + + // When/Then + assertThatThrownBy(() -> userService.revokeRoleFromUser("testuser", "ADMIN")) + .isInstanceOf(IllegalStateException.class) + .hasMessage("User does not have role: ADMIN"); + } + + @Test + void updateProfile_WhenValidInput_ShouldUpdateProfile() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(userRepository.save(testUser)).thenReturn(testUser); + + // When + User result = userService.updateProfile("testuser", "New Full Name", "9876543210", "New Address"); + + // Then + assertThat(result.getFullName()).isEqualTo("New Full Name"); + assertThat(result.getPhone()).isEqualTo("9876543210"); + assertThat(result.getAddress()).isEqualTo("New Address"); + verify(userRepository).save(testUser); + } + + @Test + void updateProfilePhoto_WhenValidInput_ShouldUpdatePhotoUrl() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(userRepository.save(testUser)).thenReturn(testUser); + + // When + User result = userService.updateProfilePhoto("testuser", "http://example.com/photo.jpg"); + + // Then + assertThat(result.getProfilePhotoUrl()).isEqualTo("http://example.com/photo.jpg"); + verify(userRepository).save(testUser); + } +} \ No newline at end of file From 9b6242569089ec232ebff4eebadaa10945174c41 Mon Sep 17 00:00:00 2001 From: AdithaBuwaneka Date: Fri, 21 Nov 2025 14:26:48 +0530 Subject: [PATCH 04/20] feat: Update role IDs to use Long type and add comprehensive tests for TokenService covering token creation, validation, and management --- .../auth_service/service/AuthServiceTest.java | 20 +- .../service/TokenServiceTest.java | 470 ++++++++++++++++++ .../auth_service/service/UserServiceTest.java | 16 +- 3 files changed, 488 insertions(+), 18 deletions(-) create mode 100644 auth-service/src/test/java/com/techtorque/auth_service/service/TokenServiceTest.java diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java index 12f1a1c..014a0f6 100644 --- a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java @@ -97,20 +97,20 @@ void setUp() { // Create test roles customerRole = Role.builder() - .id("role-1") + .id(1L) .name(RoleName.CUSTOMER) .description("Customer role") .build(); adminRole = Role.builder() - .id("role-2") + .id(2L) .name(RoleName.ADMIN) .description("Admin role") .build(); // Create test user testUser = User.builder() - .id("user-1") + .id(1L) .username("testuser") .email("test@example.com") .password("encoded-password") @@ -137,7 +137,7 @@ void setUp() { // Create test login lock loginLock = LoginLock.builder() - .id("lock-1") + .id(1L) .username("testuser") .failedAttempts(0) .lockUntil(null) @@ -172,7 +172,7 @@ void authenticateUser_WhenValidCredentials_ShouldReturnLoginResponse() { .thenReturn(authentication); when(authentication.getPrincipal()).thenReturn(userDetails); when(userDetails.getUsername()).thenReturn("testuser"); - when(userDetails.getAuthorities()).thenReturn(List.of(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); + when(userDetails.getAuthorities()).thenReturn(java.util.Arrays.asList(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())).thenReturn("refresh-token"); @@ -205,7 +205,7 @@ void authenticateUser_WhenUserNotFound_ShouldCheckByEmail() { .thenReturn(authentication); when(authentication.getPrincipal()).thenReturn(userDetails); when(userDetails.getUsername()).thenReturn("test@example.com"); - when(userDetails.getAuthorities()).thenReturn(List.of(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); + when(userDetails.getAuthorities()).thenReturn(java.util.Arrays.asList(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); loginRequest.setUsername("test@example.com"); @@ -268,7 +268,7 @@ void authenticateUser_WhenNoLockRecord_ShouldCreateNewLock() { .thenReturn(authentication); when(authentication.getPrincipal()).thenReturn(userDetails); when(userDetails.getUsername()).thenReturn("testuser"); - when(userDetails.getAuthorities()).thenReturn(List.of(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); + when(userDetails.getAuthorities()).thenReturn(java.util.Arrays.asList(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())).thenReturn("refresh-token"); @@ -352,7 +352,7 @@ void registerUser_WhenAdminRole_ShouldAssignAdminRole() { @Test void registerUser_WhenEmployeeRole_ShouldAssignEmployeeRole() { // Given - Role employeeRole = Role.builder().id("role-3").name(RoleName.EMPLOYEE).build(); + Role employeeRole = Role.builder().id(3L).name(RoleName.EMPLOYEE).build(); registerRequest.setRoles(Set.of("employee")); when(userRepository.existsByEmail("new@example.com")).thenReturn(false); when(roleRepository.findByName(RoleName.EMPLOYEE)).thenReturn(Optional.of(employeeRole)); @@ -544,7 +544,7 @@ void authenticateUser_WhenNullRequest_ShouldHandleGracefully() { .thenReturn(authentication); when(authentication.getPrincipal()).thenReturn(userDetails); when(userDetails.getUsername()).thenReturn("testuser"); - when(userDetails.getAuthorities()).thenReturn(List.of(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); + when(userDetails.getAuthorities()).thenReturn(java.util.Arrays.asList(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); when(tokenService.createRefreshToken(eq(testUser), isNull(), isNull())).thenReturn("refresh-token"); @@ -575,4 +575,4 @@ void verifyEmail_WhenNullRequest_ShouldHandleGracefully() { assertThat(response).isNotNull(); verify(tokenService).createRefreshToken(eq(testUser), isNull(), isNull()); } -} \ No newline at end of file +} diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/TokenServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/TokenServiceTest.java new file mode 100644 index 0000000..49065c8 --- /dev/null +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/TokenServiceTest.java @@ -0,0 +1,470 @@ +package com.techtorque.auth_service.service; + +import com.techtorque.auth_service.entity.RefreshToken; +import com.techtorque.auth_service.entity.User; +import com.techtorque.auth_service.entity.VerificationToken; +import com.techtorque.auth_service.repository.RefreshTokenRepository; +import com.techtorque.auth_service.repository.VerificationTokenRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.util.ReflectionTestUtils; + +import java.time.LocalDateTime; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +/** + * Comprehensive test class for TokenService + * Tests token creation, validation, expiry, and cleanup operations + */ +@ExtendWith(MockitoExtension.class) +class TokenServiceTest { + + @Mock + private VerificationTokenRepository verificationTokenRepository; + + @Mock + private RefreshTokenRepository refreshTokenRepository; + + @InjectMocks + private TokenService tokenService; + + private User testUser; + private VerificationToken verificationToken; + private RefreshToken refreshToken; + + @BeforeEach + void setUp() { + // Set up test configuration + ReflectionTestUtils.setField(tokenService, "verificationExpiryHours", 24); + ReflectionTestUtils.setField(tokenService, "passwordResetExpiryHours", 1); + ReflectionTestUtils.setField(tokenService, "refreshTokenExpiryDays", 7); + + // Create test user + testUser = User.builder() + .id(1L) + .username("testuser") + .email("test@example.com") + .password("encoded-password") + .enabled(true) + .build(); + + // Create test verification token + verificationToken = VerificationToken.builder() + .id("token-1") + .token("verification-token") + .user(testUser) + .tokenType(VerificationToken.TokenType.EMAIL_VERIFICATION) + .createdAt(LocalDateTime.now()) + .expiryDate(LocalDateTime.now().plusHours(24)) + .build(); + + // Create test refresh token + refreshToken = RefreshToken.builder() + .id("refresh-1") + .token("refresh-token") + .user(testUser) + .createdAt(LocalDateTime.now()) + .expiryDate(LocalDateTime.now().plusDays(7)) + .ipAddress("127.0.0.1") + .userAgent("Test-Agent") + .build(); + } + + @Test + void createVerificationToken_WhenValidUser_ShouldCreateAndReturnToken() { + // Given + when(verificationTokenRepository.findByUserAndTokenType(testUser, + VerificationToken.TokenType.EMAIL_VERIFICATION)) + .thenReturn(Optional.empty()); + when(verificationTokenRepository.save(any(VerificationToken.class))) + .thenAnswer(invocation -> invocation.getArgument(0)); + + // When + String result = tokenService.createVerificationToken(testUser); + + // Then + assertThat(result).isNotNull(); + assertThat(result).hasSize(36); // UUID length + verify(verificationTokenRepository).save(argThat(token -> token.getUser().equals(testUser) && + token.getTokenType().equals(VerificationToken.TokenType.EMAIL_VERIFICATION) && + token.getExpiryDate().isAfter(LocalDateTime.now().plusHours(23)))); + } + + @Test + void createVerificationToken_WhenExistingTokenExists_ShouldDeleteExistingToken() { + // Given + VerificationToken existingToken = VerificationToken.builder() + .token("existing-token") + .user(testUser) + .tokenType(VerificationToken.TokenType.EMAIL_VERIFICATION) + .build(); + + when(verificationTokenRepository.findByUserAndTokenType(testUser, + VerificationToken.TokenType.EMAIL_VERIFICATION)) + .thenReturn(Optional.of(existingToken)); + when(verificationTokenRepository.save(any(VerificationToken.class))) + .thenAnswer(invocation -> invocation.getArgument(0)); + + // When + String result = tokenService.createVerificationToken(testUser); + + // Then + assertThat(result).isNotNull(); + verify(verificationTokenRepository).delete(existingToken); + verify(verificationTokenRepository).save(any(VerificationToken.class)); + } + + @Test + void createPasswordResetToken_WhenValidUser_ShouldCreateAndReturnToken() { + // Given + when(verificationTokenRepository.findByUserAndTokenType(testUser, VerificationToken.TokenType.PASSWORD_RESET)) + .thenReturn(Optional.empty()); + when(verificationTokenRepository.save(any(VerificationToken.class))) + .thenAnswer(invocation -> invocation.getArgument(0)); + + // When + String result = tokenService.createPasswordResetToken(testUser); + + // Then + assertThat(result).isNotNull(); + assertThat(result).hasSize(36); // UUID length + verify(verificationTokenRepository).save(argThat(token -> token.getUser().equals(testUser) && + token.getTokenType().equals(VerificationToken.TokenType.PASSWORD_RESET) && + token.getExpiryDate().isAfter(LocalDateTime.now().plusMinutes(30)))); + } + + @Test + void createPasswordResetToken_WhenExistingTokenExists_ShouldDeleteExistingToken() { + // Given + VerificationToken existingToken = VerificationToken.builder() + .token("existing-reset-token") + .user(testUser) + .tokenType(VerificationToken.TokenType.PASSWORD_RESET) + .build(); + + when(verificationTokenRepository.findByUserAndTokenType(testUser, VerificationToken.TokenType.PASSWORD_RESET)) + .thenReturn(Optional.of(existingToken)); + when(verificationTokenRepository.save(any(VerificationToken.class))) + .thenAnswer(invocation -> invocation.getArgument(0)); + + // When + String result = tokenService.createPasswordResetToken(testUser); + + // Then + assertThat(result).isNotNull(); + verify(verificationTokenRepository).delete(existingToken); + verify(verificationTokenRepository).save(any(VerificationToken.class)); + } + + @Test + void validateToken_WhenValidToken_ShouldReturnToken() { + // Given + when(verificationTokenRepository.findByToken("verification-token")).thenReturn(Optional.of(verificationToken)); + + // When + VerificationToken result = tokenService.validateToken("verification-token", + VerificationToken.TokenType.EMAIL_VERIFICATION); + + // Then + assertThat(result).isEqualTo(verificationToken); + } + + @Test + void validateToken_WhenTokenNotFound_ShouldThrowRuntimeException() { + // Given + when(verificationTokenRepository.findByToken("invalid-token")).thenReturn(Optional.empty()); + + // When/Then + assertThatThrownBy( + () -> tokenService.validateToken("invalid-token", VerificationToken.TokenType.EMAIL_VERIFICATION)) + .isInstanceOf(RuntimeException.class) + .hasMessage("Invalid token"); + } + + @Test + void validateToken_WhenWrongTokenType_ShouldThrowRuntimeException() { + // Given + when(verificationTokenRepository.findByToken("verification-token")).thenReturn(Optional.of(verificationToken)); + + // When/Then + assertThatThrownBy( + () -> tokenService.validateToken("verification-token", VerificationToken.TokenType.PASSWORD_RESET)) + .isInstanceOf(RuntimeException.class) + .hasMessage("Invalid token type"); + } + + @Test + void validateToken_WhenTokenAlreadyUsed_ShouldThrowRuntimeException() { + // Given + verificationToken.setUsedAt(LocalDateTime.now()); + when(verificationTokenRepository.findByToken("verification-token")).thenReturn(Optional.of(verificationToken)); + + // When/Then + assertThatThrownBy( + () -> tokenService.validateToken("verification-token", VerificationToken.TokenType.EMAIL_VERIFICATION)) + .isInstanceOf(RuntimeException.class) + .hasMessage("Token has already been used"); + } + + @Test + void validateToken_WhenTokenExpired_ShouldThrowRuntimeException() { + // Given + verificationToken.setExpiryDate(LocalDateTime.now().minusHours(1)); + when(verificationTokenRepository.findByToken("verification-token")).thenReturn(Optional.of(verificationToken)); + + // When/Then + assertThatThrownBy( + () -> tokenService.validateToken("verification-token", VerificationToken.TokenType.EMAIL_VERIFICATION)) + .isInstanceOf(RuntimeException.class) + .hasMessage("Token has expired"); + } + + @Test + void markTokenAsUsed_ShouldSetUsedAtTimestamp() { + // Given + when(verificationTokenRepository.save(verificationToken)).thenReturn(verificationToken); + + // When + tokenService.markTokenAsUsed(verificationToken); + + // Then + assertThat(verificationToken.getUsedAt()).isNotNull(); + assertThat(verificationToken.getUsedAt()).isBefore(LocalDateTime.now().plusSeconds(1)); + verify(verificationTokenRepository).save(verificationToken); + } + + @Test + void createRefreshToken_WhenValidUser_ShouldCreateAndReturnToken() { + // Given + when(refreshTokenRepository.save(any(RefreshToken.class))).thenAnswer(invocation -> invocation.getArgument(0)); + + // When + String result = tokenService.createRefreshToken(testUser, "192.168.1.1", "Mozilla/5.0"); + + // Then + assertThat(result).isNotNull(); + assertThat(result).hasSize(36); // UUID length + verify(refreshTokenRepository).save(argThat(token -> token.getUser().equals(testUser) && + token.getIpAddress().equals("192.168.1.1") && + token.getUserAgent().equals("Mozilla/5.0") && + token.getExpiryDate().isAfter(LocalDateTime.now().plusDays(6)))); + } + + @Test + void createRefreshToken_WhenNullIpAndUserAgent_ShouldCreateTokenWithNulls() { + // Given + when(refreshTokenRepository.save(any(RefreshToken.class))).thenAnswer(invocation -> invocation.getArgument(0)); + + // When + String result = tokenService.createRefreshToken(testUser, null, null); + + // Then + assertThat(result).isNotNull(); + verify(refreshTokenRepository).save(argThat(token -> token.getUser().equals(testUser) && + token.getIpAddress() == null && + token.getUserAgent() == null)); + } + + @Test + void validateRefreshToken_WhenValidToken_ShouldReturnToken() { + // Given + when(refreshTokenRepository.findByToken("refresh-token")).thenReturn(Optional.of(refreshToken)); + + // When + RefreshToken result = tokenService.validateRefreshToken("refresh-token"); + + // Then + assertThat(result).isEqualTo(refreshToken); + } + + @Test + void validateRefreshToken_WhenTokenNotFound_ShouldThrowRuntimeException() { + // Given + when(refreshTokenRepository.findByToken("invalid-token")).thenReturn(Optional.empty()); + + // When/Then + assertThatThrownBy(() -> tokenService.validateRefreshToken("invalid-token")) + .isInstanceOf(RuntimeException.class) + .hasMessage("Invalid refresh token"); + } + + @Test + void validateRefreshToken_WhenTokenRevoked_ShouldThrowRuntimeException() { + // Given + refreshToken.setRevokedAt(LocalDateTime.now()); + when(refreshTokenRepository.findByToken("refresh-token")).thenReturn(Optional.of(refreshToken)); + + // When/Then + assertThatThrownBy(() -> tokenService.validateRefreshToken("refresh-token")) + .isInstanceOf(RuntimeException.class) + .hasMessage("Refresh token has been revoked"); + } + + @Test + void validateRefreshToken_WhenTokenExpired_ShouldThrowRuntimeException() { + // Given + refreshToken.setExpiryDate(LocalDateTime.now().minusDays(1)); + when(refreshTokenRepository.findByToken("refresh-token")).thenReturn(Optional.of(refreshToken)); + + // When/Then + assertThatThrownBy(() -> tokenService.validateRefreshToken("refresh-token")) + .isInstanceOf(RuntimeException.class) + .hasMessage("Refresh token has expired"); + } + + @Test + void revokeRefreshToken_WhenValidToken_ShouldSetRevokedAt() { + // Given + when(refreshTokenRepository.findByToken("refresh-token")).thenReturn(Optional.of(refreshToken)); + when(refreshTokenRepository.save(refreshToken)).thenReturn(refreshToken); + + // When + tokenService.revokeRefreshToken("refresh-token"); + + // Then + assertThat(refreshToken.getRevokedAt()).isNotNull(); + assertThat(refreshToken.getRevokedAt()).isBefore(LocalDateTime.now().plusSeconds(1)); + verify(refreshTokenRepository).save(refreshToken); + } + + @Test + void revokeRefreshToken_WhenTokenNotFound_ShouldThrowRuntimeException() { + // Given + when(refreshTokenRepository.findByToken("invalid-token")).thenReturn(Optional.empty()); + + // When/Then + assertThatThrownBy(() -> tokenService.revokeRefreshToken("invalid-token")) + .isInstanceOf(RuntimeException.class) + .hasMessage("Invalid refresh token"); + } + + @Test + void revokeAllUserTokens_ShouldDeleteAllUserTokens() { + // When + tokenService.revokeAllUserTokens(testUser); + + // Then + verify(refreshTokenRepository).deleteByUser(testUser); + } + + @Test + void cleanupExpiredTokens_ShouldDeleteExpiredTokens() { + // When + tokenService.cleanupExpiredTokens(); + + // Then + verify(refreshTokenRepository).deleteExpiredTokens(any(LocalDateTime.class)); + } + + @Test + void createVerificationToken_WithCustomExpiryHours_ShouldUseConfiguredExpiry() { + // Given + ReflectionTestUtils.setField(tokenService, "verificationExpiryHours", 48); + when(verificationTokenRepository.findByUserAndTokenType(testUser, + VerificationToken.TokenType.EMAIL_VERIFICATION)) + .thenReturn(Optional.empty()); + when(verificationTokenRepository.save(any(VerificationToken.class))) + .thenAnswer(invocation -> invocation.getArgument(0)); + + // When + String result = tokenService.createVerificationToken(testUser); + + // Then + assertThat(result).isNotNull(); + verify(verificationTokenRepository) + .save(argThat(token -> token.getExpiryDate().isAfter(LocalDateTime.now().plusHours(47)))); + } + + @Test + void createPasswordResetToken_WithCustomExpiryHours_ShouldUseConfiguredExpiry() { + // Given + ReflectionTestUtils.setField(tokenService, "passwordResetExpiryHours", 2); + when(verificationTokenRepository.findByUserAndTokenType(testUser, VerificationToken.TokenType.PASSWORD_RESET)) + .thenReturn(Optional.empty()); + when(verificationTokenRepository.save(any(VerificationToken.class))) + .thenAnswer(invocation -> invocation.getArgument(0)); + + // When + String result = tokenService.createPasswordResetToken(testUser); + + // Then + assertThat(result).isNotNull(); + verify(verificationTokenRepository).save( + argThat(token -> token.getExpiryDate().isAfter(LocalDateTime.now().plusHours(1).plusMinutes(30)))); + } + + @Test + void createRefreshToken_WithCustomExpiryDays_ShouldUseConfiguredExpiry() { + // Given + ReflectionTestUtils.setField(tokenService, "refreshTokenExpiryDays", 14); + when(refreshTokenRepository.save(any(RefreshToken.class))).thenAnswer(invocation -> invocation.getArgument(0)); + + // When + String result = tokenService.createRefreshToken(testUser, "127.0.0.1", "Test-Agent"); + + // Then + assertThat(result).isNotNull(); + verify(refreshTokenRepository) + .save(argThat(token -> token.getExpiryDate().isAfter(LocalDateTime.now().plusDays(13)))); + } + + @Test + void validateToken_WhenTokenJustExpired_ShouldThrowRuntimeException() { + // Given + verificationToken.setExpiryDate(LocalDateTime.now().minusSeconds(1)); + when(verificationTokenRepository.findByToken("verification-token")).thenReturn(Optional.of(verificationToken)); + + // When/Then + assertThatThrownBy( + () -> tokenService.validateToken("verification-token", VerificationToken.TokenType.EMAIL_VERIFICATION)) + .isInstanceOf(RuntimeException.class) + .hasMessage("Token has expired"); + } + + @Test + void validateRefreshToken_WhenTokenJustExpired_ShouldThrowRuntimeException() { + // Given + refreshToken.setExpiryDate(LocalDateTime.now().minusSeconds(1)); + when(refreshTokenRepository.findByToken("refresh-token")).thenReturn(Optional.of(refreshToken)); + + // When/Then + assertThatThrownBy(() -> tokenService.validateRefreshToken("refresh-token")) + .isInstanceOf(RuntimeException.class) + .hasMessage("Refresh token has expired"); + } + + @Test + void validateToken_WhenTokenJustBeforeExpiry_ShouldReturnToken() { + // Given + verificationToken.setExpiryDate(LocalDateTime.now().plusSeconds(1)); + when(verificationTokenRepository.findByToken("verification-token")).thenReturn(Optional.of(verificationToken)); + + // When + VerificationToken result = tokenService.validateToken("verification-token", + VerificationToken.TokenType.EMAIL_VERIFICATION); + + // Then + assertThat(result).isEqualTo(verificationToken); + } + + @Test + void validateRefreshToken_WhenTokenJustBeforeExpiry_ShouldReturnToken() { + // Given + refreshToken.setExpiryDate(LocalDateTime.now().plusSeconds(1)); + when(refreshTokenRepository.findByToken("refresh-token")).thenReturn(Optional.of(refreshToken)); + + // When + RefreshToken result = tokenService.validateRefreshToken("refresh-token"); + + // Then + assertThat(result).isEqualTo(refreshToken); + } +} diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java index 40d83e9..fdce122 100644 --- a/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java @@ -74,28 +74,28 @@ class UserServiceTest { void setUp() { // Create test roles customerRole = Role.builder() - .id("role-1") + .id(1L) .name(RoleName.CUSTOMER) .description("Customer role") .permissions(new HashSet<>()) .build(); employeeRole = Role.builder() - .id("role-2") + .id(2L) .name(RoleName.EMPLOYEE) .description("Employee role") .permissions(new HashSet<>()) .build(); adminRole = Role.builder() - .id("role-3") + .id(3L) .name(RoleName.ADMIN) .description("Admin role") .permissions(new HashSet<>()) .build(); superAdminRole = Role.builder() - .id("role-4") + .id(4L) .name(RoleName.SUPER_ADMIN) .description("Super Admin role") .permissions(new HashSet<>()) @@ -103,7 +103,7 @@ void setUp() { // Create test user testUser = User.builder() - .id("user-1") + .id(1L) .username("testuser") .email("test@example.com") .password("encoded-password") @@ -582,7 +582,7 @@ void assignRoleToUser_WhenAssigningAdminRoleWithoutSuperAdminAuth_ShouldThrowAcc SecurityContextHolder.setContext(securityContext); when(securityContext.getAuthentication()).thenReturn(authentication); - when(authentication.getAuthorities()).thenReturn(List.of(new SimpleGrantedAuthority("ROLE_ADMIN"))); + when(authentication.getAuthorities()).thenReturn(java.util.Arrays.asList(new SimpleGrantedAuthority("ROLE_ADMIN"))); // When/Then assertThatThrownBy(() -> userService.assignRoleToUser("testuser", "ADMIN")) @@ -601,7 +601,7 @@ void assignRoleToUser_WhenAssigningAdminRoleWithSuperAdminAuth_ShouldSucceed() { SecurityContextHolder.setContext(securityContext); when(securityContext.getAuthentication()).thenReturn(authentication); - when(authentication.getAuthorities()).thenReturn(List.of(new SimpleGrantedAuthority("ROLE_SUPER_ADMIN"))); + when(authentication.getAuthorities()).thenReturn(java.util.Arrays.asList(new SimpleGrantedAuthority("ROLE_SUPER_ADMIN"))); // When userService.assignRoleToUser("testuser", "ADMIN"); @@ -699,4 +699,4 @@ void updateProfilePhoto_WhenValidInput_ShouldUpdatePhotoUrl() { assertThat(result.getProfilePhotoUrl()).isEqualTo("http://example.com/photo.jpg"); verify(userRepository).save(testUser); } -} \ No newline at end of file +} From e32f8bfa3c0b071d966eb44d66d853cda810cc68 Mon Sep 17 00:00:00 2001 From: AdithaBuwaneka Date: Fri, 21 Nov 2025 14:27:47 +0530 Subject: [PATCH 05/20] refactor: Improve readability of authority retrieval in AuthServiceTest --- .../auth_service/service/AuthServiceTest.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java index 014a0f6..914714d 100644 --- a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java @@ -172,7 +172,9 @@ void authenticateUser_WhenValidCredentials_ShouldReturnLoginResponse() { .thenReturn(authentication); when(authentication.getPrincipal()).thenReturn(userDetails); when(userDetails.getUsername()).thenReturn("testuser"); - when(userDetails.getAuthorities()).thenReturn(java.util.Arrays.asList(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); + when(userDetails.getAuthorities()) + .thenReturn(java.util.Arrays.asList( + new SimpleGrantedAuthority("ROLE_CUSTOMER"))); when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())).thenReturn("refresh-token"); @@ -205,7 +207,8 @@ void authenticateUser_WhenUserNotFound_ShouldCheckByEmail() { .thenReturn(authentication); when(authentication.getPrincipal()).thenReturn(userDetails); when(userDetails.getUsername()).thenReturn("test@example.com"); - when(userDetails.getAuthorities()).thenReturn(java.util.Arrays.asList(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); + when(userDetails.getAuthorities()).thenReturn((Collection) java.util.Arrays + .asList(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); loginRequest.setUsername("test@example.com"); @@ -268,7 +271,9 @@ void authenticateUser_WhenNoLockRecord_ShouldCreateNewLock() { .thenReturn(authentication); when(authentication.getPrincipal()).thenReturn(userDetails); when(userDetails.getUsername()).thenReturn("testuser"); - when(userDetails.getAuthorities()).thenReturn(java.util.Arrays.asList(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); + when(userDetails.getAuthorities()) + .thenReturn(java.util.Arrays.asList( + new SimpleGrantedAuthority("ROLE_CUSTOMER"))); when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())).thenReturn("refresh-token"); @@ -544,7 +549,9 @@ void authenticateUser_WhenNullRequest_ShouldHandleGracefully() { .thenReturn(authentication); when(authentication.getPrincipal()).thenReturn(userDetails); when(userDetails.getUsername()).thenReturn("testuser"); - when(userDetails.getAuthorities()).thenReturn(java.util.Arrays.asList(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); + when(userDetails.getAuthorities()) + .thenReturn(java.util.Arrays.asList( + new SimpleGrantedAuthority("ROLE_CUSTOMER"))); when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); when(tokenService.createRefreshToken(eq(testUser), isNull(), isNull())).thenReturn("refresh-token"); From 355f72c717fae16a5eaa6f99cb97994604238530 Mon Sep 17 00:00:00 2001 From: AdithaBuwaneka Date: Fri, 21 Nov 2025 14:28:34 +0530 Subject: [PATCH 06/20] refactor: Simplify authority retrieval in AuthServiceTest --- .../com/techtorque/auth_service/service/AuthServiceTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java index 914714d..92f7d48 100644 --- a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java @@ -272,8 +272,8 @@ void authenticateUser_WhenNoLockRecord_ShouldCreateNewLock() { when(authentication.getPrincipal()).thenReturn(userDetails); when(userDetails.getUsername()).thenReturn("testuser"); when(userDetails.getAuthorities()) - .thenReturn(java.util.Arrays.asList( - new SimpleGrantedAuthority("ROLE_CUSTOMER"))); + .thenReturn(java.util.Collections + .singletonList(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())).thenReturn("refresh-token"); From 52002b0fd5331bbd4b3eb8b8ff5e2837f9629e79 Mon Sep 17 00:00:00 2001 From: AdithaBuwaneka Date: Fri, 21 Nov 2025 14:28:54 +0530 Subject: [PATCH 07/20] refactor: Optimize authority retrieval in AuthServiceTest --- .../com/techtorque/auth_service/service/AuthServiceTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java index 92f7d48..bcd379f 100644 --- a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java @@ -272,8 +272,7 @@ void authenticateUser_WhenNoLockRecord_ShouldCreateNewLock() { when(authentication.getPrincipal()).thenReturn(userDetails); when(userDetails.getUsername()).thenReturn("testuser"); when(userDetails.getAuthorities()) - .thenReturn(java.util.Collections - .singletonList(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); + .thenReturn((Collection) java.util.Collections.singleton(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())).thenReturn("refresh-token"); From 98f3c038185e5cf2418e6b797edc45e050abce62 Mon Sep 17 00:00:00 2001 From: AdithaBuwaneka Date: Fri, 21 Nov 2025 14:30:37 +0530 Subject: [PATCH 08/20] refactor: Replace array list with singleton for user authorities in AuthServiceTest --- .../com/techtorque/auth_service/service/AuthServiceTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java index bcd379f..96521a6 100644 --- a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java @@ -207,8 +207,8 @@ void authenticateUser_WhenUserNotFound_ShouldCheckByEmail() { .thenReturn(authentication); when(authentication.getPrincipal()).thenReturn(userDetails); when(userDetails.getUsername()).thenReturn("test@example.com"); - when(userDetails.getAuthorities()).thenReturn((Collection) java.util.Arrays - .asList(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); + when(userDetails.getAuthorities()).thenReturn((Collection) java.util.Collections + .singletonList(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); loginRequest.setUsername("test@example.com"); From f3857e6e4677cf77a47e4486c7382babb698e17f Mon Sep 17 00:00:00 2001 From: AdithaBuwaneka Date: Fri, 21 Nov 2025 14:30:43 +0530 Subject: [PATCH 09/20] refactor: Consolidate mock declarations and setup in AuthServiceTest for improved readability --- .../auth_service/service/AuthServiceTest.java | 1092 +++++++++-------- 1 file changed, 549 insertions(+), 543 deletions(-) diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java index 96521a6..12df01f 100644 --- a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java @@ -38,547 +38,553 @@ @ExtendWith(MockitoExtension.class) class AuthServiceTest { - @Mock - private AuthenticationManager authenticationManager; - - @Mock - private UserRepository userRepository; - - @Mock - private RoleRepository roleRepository; - - @Mock - private PasswordEncoder passwordEncoder; - - @Mock - private JwtUtil jwtUtil; - - @Mock - private LoginLockRepository loginLockRepository; - - @Mock - private LoginLogRepository loginLogRepository; - - @Mock - private LoginAuditService loginAuditService; - - @Mock - private TokenService tokenService; - - @Mock - private EmailService emailService; - - @Mock - private HttpServletRequest request; - - @Mock - private Authentication authentication; - - @Mock - private UserDetails userDetails; - - @InjectMocks - private AuthService authService; - - private User testUser; - private Role customerRole; - private Role adminRole; - private LoginRequest loginRequest; - private RegisterRequest registerRequest; - private LoginLock loginLock; - private VerificationToken verificationToken; - private RefreshToken refreshToken; - - @BeforeEach - void setUp() { - // Set up test configuration - ReflectionTestUtils.setField(authService, "maxFailedAttempts", 3); - ReflectionTestUtils.setField(authService, "lockDurationMinutes", 15L); - - // Create test roles - customerRole = Role.builder() - .id(1L) - .name(RoleName.CUSTOMER) - .description("Customer role") - .build(); - - adminRole = Role.builder() - .id(2L) - .name(RoleName.ADMIN) - .description("Admin role") - .build(); - - // Create test user - testUser = User.builder() - .id(1L) - .username("testuser") - .email("test@example.com") - .password("encoded-password") - .fullName("Test User") - .phone("1234567890") - .address("Test Address") - .enabled(true) - .emailVerified(true) - .createdAt(LocalDateTime.now()) - .roles(Set.of(customerRole)) - .build(); - - // Create test requests - loginRequest = new LoginRequest(); - loginRequest.setUsername("testuser"); - loginRequest.setPassword("password"); - - registerRequest = new RegisterRequest(); - registerRequest.setEmail("new@example.com"); - registerRequest.setPassword("newpassword"); - registerRequest.setFullName("New User"); - registerRequest.setPhone("9876543210"); - registerRequest.setAddress("New Address"); - - // Create test login lock - loginLock = LoginLock.builder() - .id(1L) - .username("testuser") - .failedAttempts(0) - .lockUntil(null) - .build(); - - // Create test verification token - verificationToken = VerificationToken.builder() - .id("token-1") - .token("verification-token") - .user(testUser) - .tokenType(VerificationToken.TokenType.EMAIL_VERIFICATION) - .expiryDate(LocalDateTime.now().plusHours(24)) - .createdAt(LocalDateTime.now()) - .build(); - - // Create test refresh token - refreshToken = RefreshToken.builder() - .id("refresh-1") - .token("refresh-token") - .user(testUser) - .expiryDate(LocalDateTime.now().plusDays(7)) - .createdAt(LocalDateTime.now()) - .build(); - } - - @Test - void authenticateUser_WhenValidCredentials_ShouldReturnLoginResponse() { - // Given - when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); - when(loginLockRepository.findByUsername("testuser")).thenReturn(Optional.of(loginLock)); - when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class))) - .thenReturn(authentication); - when(authentication.getPrincipal()).thenReturn(userDetails); - when(userDetails.getUsername()).thenReturn("testuser"); - when(userDetails.getAuthorities()) - .thenReturn(java.util.Arrays.asList( - new SimpleGrantedAuthority("ROLE_CUSTOMER"))); - when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); - when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); - when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())).thenReturn("refresh-token"); - when(request.getHeader("X-Forwarded-For")).thenReturn(null); - when(request.getRemoteAddr()).thenReturn("127.0.0.1"); - when(request.getHeader("User-Agent")).thenReturn("Test-Agent"); - - // When - LoginResponse response = authService.authenticateUser(loginRequest, request); - - // Then - assertThat(response).isNotNull(); - assertThat(response.getToken()).isEqualTo("jwt-token"); - assertThat(response.getRefreshToken()).isEqualTo("refresh-token"); - assertThat(response.getUsername()).isEqualTo("testuser"); - assertThat(response.getEmail()).isEqualTo("test@example.com"); - assertThat(response.getRoles()).contains("CUSTOMER"); - - verify(loginLockRepository).save(any(LoginLock.class)); - verify(loginLogRepository).save(any(LoginLog.class)); - } - - @Test - void authenticateUser_WhenUserNotFound_ShouldCheckByEmail() { - // Given - when(userRepository.findByUsername("test@example.com")).thenReturn(Optional.empty()); - when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.of(testUser)); - when(loginLockRepository.findByUsername("test@example.com")).thenReturn(Optional.of(loginLock)); - when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class))) - .thenReturn(authentication); - when(authentication.getPrincipal()).thenReturn(userDetails); - when(userDetails.getUsername()).thenReturn("test@example.com"); - when(userDetails.getAuthorities()).thenReturn((Collection) java.util.Collections - .singletonList(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); - - loginRequest.setUsername("test@example.com"); - - // When/Then - when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); - when(userRepository.findByUsername("test@example.com")).thenReturn(Optional.of(testUser)); - when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())).thenReturn("refresh-token"); - - LoginResponse response = authService.authenticateUser(loginRequest, request); - assertThat(response).isNotNull(); - } - - @Test - void authenticateUser_WhenUserDisabledAndNotVerified_ShouldThrowDisabledException() { - // Given - testUser.setEnabled(false); - testUser.setEmailVerified(false); - when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); - - // When/Then - assertThatThrownBy(() -> authService.authenticateUser(loginRequest, request)) - .isInstanceOf(DisabledException.class) - .hasMessageContaining("Please verify your email address"); - } - - @Test - void authenticateUser_WhenUserDisabledAndVerified_ShouldThrowDisabledException() { - // Given - testUser.setEnabled(false); - testUser.setEmailVerified(true); - when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); - - // When/Then - assertThatThrownBy(() -> authService.authenticateUser(loginRequest, request)) - .isInstanceOf(DisabledException.class) - .hasMessageContaining("Your account has been deactivated"); - } - - @Test - void authenticateUser_WhenAccountLocked_ShouldThrowBadCredentialsException() { - // Given - loginLock.setLockUntil(LocalDateTime.now().plusMinutes(10)); - when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); - when(loginLockRepository.findByUsername("testuser")).thenReturn(Optional.of(loginLock)); - - // When/Then - assertThatThrownBy(() -> authService.authenticateUser(loginRequest, request)) - .isInstanceOf(BadCredentialsException.class) - .hasMessageContaining("Account is temporarily locked"); - - verify(loginAuditService).recordLogin(eq("testuser"), eq(false), anyString(), anyString()); - } - - @Test - void authenticateUser_WhenNoLockRecord_ShouldCreateNewLock() { - // Given - when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); - when(loginLockRepository.findByUsername("testuser")).thenReturn(Optional.empty()); - when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class))) - .thenReturn(authentication); - when(authentication.getPrincipal()).thenReturn(userDetails); - when(userDetails.getUsername()).thenReturn("testuser"); - when(userDetails.getAuthorities()) - .thenReturn((Collection) java.util.Collections.singleton(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); - when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); - when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); - when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())).thenReturn("refresh-token"); - - // When - LoginResponse response = authService.authenticateUser(loginRequest, request); - - // Then - assertThat(response).isNotNull(); - verify(loginLockRepository) - .save(argThat(lock -> lock.getUsername().equals("testuser") && lock.getFailedAttempts() == 0)); - } - - @Test - void authenticateUser_WhenBadCredentials_ShouldIncrementFailedAttempts() { - // Given - when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); - when(loginLockRepository.findByUsername("testuser")).thenReturn(Optional.of(loginLock)); - when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class))) - .thenThrow(new BadCredentialsException("Invalid credentials")); - - // When/Then - assertThatThrownBy(() -> authService.authenticateUser(loginRequest, request)) - .isInstanceOf(BadCredentialsException.class) - .hasMessage("Invalid username or password"); - - verify(loginAuditService).incrementFailedAttempt("testuser", 15L, 3); - verify(loginAuditService).recordLogin(eq("testuser"), eq(false), anyString(), anyString()); - } - - @Test - void registerUser_WhenValidRequest_ShouldCreateUserAndSendVerificationEmail() { - // Given - when(userRepository.existsByEmail("new@example.com")).thenReturn(false); - when(roleRepository.findByName(RoleName.CUSTOMER)).thenReturn(Optional.of(customerRole)); - when(passwordEncoder.encode("newpassword")).thenReturn("encoded-password"); - when(userRepository.save(any(User.class))).thenReturn(testUser); - when(tokenService.createVerificationToken(any(User.class))).thenReturn("verification-token"); - - // When - String result = authService.registerUser(registerRequest); - - // Then - assertThat(result).contains("User registered successfully"); - verify(userRepository).save(argThat(user -> user.getEmail().equals("new@example.com") && - user.getFullName().equals("New User") && - !user.getEnabled() && - !user.getEmailVerified())); - verify(emailService).sendVerificationEmail("new@example.com", "new@example.com", "verification-token"); - } - - @Test - void registerUser_WhenEmailExists_ShouldThrowRuntimeException() { - // Given - when(userRepository.existsByEmail("new@example.com")).thenReturn(true); - - // When/Then - assertThatThrownBy(() -> authService.registerUser(registerRequest)) - .isInstanceOf(RuntimeException.class) - .hasMessage("Error: Email is already in use!"); - } - - @Test - void registerUser_WhenAdminRole_ShouldAssignAdminRole() { - // Given - registerRequest.setRoles(Set.of("admin")); - when(userRepository.existsByEmail("new@example.com")).thenReturn(false); - when(roleRepository.findByName(RoleName.ADMIN)).thenReturn(Optional.of(adminRole)); - when(passwordEncoder.encode("newpassword")).thenReturn("encoded-password"); - when(userRepository.save(any(User.class))).thenReturn(testUser); - when(tokenService.createVerificationToken(any(User.class))).thenReturn("verification-token"); - - // When - authService.registerUser(registerRequest); - - // Then - verify(roleRepository).findByName(RoleName.ADMIN); - verify(userRepository).save(argThat(user -> user.getRoles().contains(adminRole))); - } - - @Test - void registerUser_WhenEmployeeRole_ShouldAssignEmployeeRole() { - // Given - Role employeeRole = Role.builder().id(3L).name(RoleName.EMPLOYEE).build(); - registerRequest.setRoles(Set.of("employee")); - when(userRepository.existsByEmail("new@example.com")).thenReturn(false); - when(roleRepository.findByName(RoleName.EMPLOYEE)).thenReturn(Optional.of(employeeRole)); - when(passwordEncoder.encode("newpassword")).thenReturn("encoded-password"); - when(userRepository.save(any(User.class))).thenReturn(testUser); - when(tokenService.createVerificationToken(any(User.class))).thenReturn("verification-token"); - - // When - authService.registerUser(registerRequest); - - // Then - verify(roleRepository).findByName(RoleName.EMPLOYEE); - verify(userRepository).save(argThat(user -> user.getRoles().contains(employeeRole))); - } - - @Test - void registerUser_WhenInvalidRole_ShouldAssignCustomerRole() { - // Given - registerRequest.setRoles(Set.of("invalid")); - when(userRepository.existsByEmail("new@example.com")).thenReturn(false); - when(roleRepository.findByName(RoleName.CUSTOMER)).thenReturn(Optional.of(customerRole)); - when(passwordEncoder.encode("newpassword")).thenReturn("encoded-password"); - when(userRepository.save(any(User.class))).thenReturn(testUser); - when(tokenService.createVerificationToken(any(User.class))).thenReturn("verification-token"); - - // When - authService.registerUser(registerRequest); - - // Then - verify(roleRepository).findByName(RoleName.CUSTOMER); - verify(userRepository).save(argThat(user -> user.getRoles().contains(customerRole))); - } - - @Test - void registerUser_WhenRoleNotFound_ShouldThrowRuntimeException() { - // Given - when(userRepository.existsByEmail("new@example.com")).thenReturn(false); - when(roleRepository.findByName(RoleName.CUSTOMER)).thenReturn(Optional.empty()); - when(passwordEncoder.encode("newpassword")).thenReturn("encoded-password"); - - // When/Then - assertThatThrownBy(() -> authService.registerUser(registerRequest)) - .isInstanceOf(RuntimeException.class) - .hasMessage("Error: Customer Role not found."); - } - - @Test - void verifyEmail_WhenValidToken_ShouldEnableUserAndReturnLoginResponse() { - // Given - testUser.setEnabled(false); - testUser.setEmailVerified(false); - when(tokenService.validateToken("verification-token", VerificationToken.TokenType.EMAIL_VERIFICATION)) - .thenReturn(verificationToken); - when(userRepository.save(any(User.class))).thenReturn(testUser); - when(jwtUtil.generateJwtToken(any(UserDetails.class), anyList())).thenReturn("jwt-token"); - when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())).thenReturn("refresh-token"); - - // When - LoginResponse response = authService.verifyEmail("verification-token", request); - - // Then - assertThat(response).isNotNull(); - assertThat(response.getToken()).isEqualTo("jwt-token"); - assertThat(response.getRefreshToken()).isEqualTo("refresh-token"); - verify(userRepository).save(argThat(user -> user.getEnabled() && user.getEmailVerified())); - verify(tokenService).markTokenAsUsed(verificationToken); - verify(emailService).sendWelcomeEmail("test@example.com", "testuser"); - } - - @Test - void resendVerificationEmail_WhenUserExists_ShouldSendEmail() { - // Given - testUser.setEmailVerified(false); - when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.of(testUser)); - when(tokenService.createVerificationToken(testUser)).thenReturn("new-verification-token"); - - // When - String result = authService.resendVerificationEmail("test@example.com"); - - // Then - assertThat(result).contains("Verification email sent successfully"); - verify(emailService).sendVerificationEmail("test@example.com", "testuser", "new-verification-token"); - } - - @Test - void resendVerificationEmail_WhenUserNotFound_ShouldThrowRuntimeException() { - // Given - when(userRepository.findByEmail("nonexistent@example.com")).thenReturn(Optional.empty()); - - // When/Then - assertThatThrownBy(() -> authService.resendVerificationEmail("nonexistent@example.com")) - .isInstanceOf(RuntimeException.class) - .hasMessage("User not found with email: nonexistent@example.com"); - } - - @Test - void resendVerificationEmail_WhenEmailAlreadyVerified_ShouldThrowRuntimeException() { - // Given - testUser.setEmailVerified(true); - when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.of(testUser)); - - // When/Then - assertThatThrownBy(() -> authService.resendVerificationEmail("test@example.com")) - .isInstanceOf(RuntimeException.class) - .hasMessage("Email is already verified"); - } - - @Test - void refreshToken_WhenValidToken_ShouldReturnNewLoginResponse() { - // Given - when(tokenService.validateRefreshToken("refresh-token")).thenReturn(refreshToken); - when(jwtUtil.generateJwtToken(any(UserDetails.class), anyList())).thenReturn("new-jwt-token"); - - // When - LoginResponse response = authService.refreshToken("refresh-token"); - - // Then - assertThat(response).isNotNull(); - assertThat(response.getToken()).isEqualTo("new-jwt-token"); - assertThat(response.getRefreshToken()).isEqualTo("refresh-token"); - assertThat(response.getUsername()).isEqualTo("testuser"); - assertThat(response.getEmail()).isEqualTo("test@example.com"); - } - - @Test - void logout_ShouldRevokeRefreshToken() { - // When - authService.logout("refresh-token"); - - // Then - verify(tokenService).revokeRefreshToken("refresh-token"); - } - - @Test - void forgotPassword_WhenUserExists_ShouldSendResetEmail() { - // Given - when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.of(testUser)); - when(tokenService.createPasswordResetToken(testUser)).thenReturn("reset-token"); - - // When - String result = authService.forgotPassword("test@example.com"); - - // Then - assertThat(result).contains("Password reset email sent successfully"); - verify(emailService).sendPasswordResetEmail("test@example.com", "testuser", "reset-token"); - } - - @Test - void forgotPassword_WhenUserNotFound_ShouldThrowRuntimeException() { - // Given - when(userRepository.findByEmail("nonexistent@example.com")).thenReturn(Optional.empty()); - - // When/Then - assertThatThrownBy(() -> authService.forgotPassword("nonexistent@example.com")) - .isInstanceOf(RuntimeException.class) - .hasMessage("User not found with email: nonexistent@example.com"); - } - - @Test - void resetPassword_WhenValidToken_ShouldUpdatePasswordAndRevokeTokens() { - // Given - VerificationToken resetToken = VerificationToken.builder() - .token("reset-token") - .user(testUser) - .tokenType(VerificationToken.TokenType.PASSWORD_RESET) - .build(); - - when(tokenService.validateToken("reset-token", VerificationToken.TokenType.PASSWORD_RESET)) - .thenReturn(resetToken); - when(passwordEncoder.encode("newpassword")).thenReturn("new-encoded-password"); - when(userRepository.save(any(User.class))).thenReturn(testUser); - - // When - String result = authService.resetPassword("reset-token", "newpassword"); - - // Then - assertThat(result).contains("Password reset successfully"); - verify(userRepository).save(argThat(user -> user.getPassword().equals("new-encoded-password"))); - verify(tokenService).markTokenAsUsed(resetToken); - verify(tokenService).revokeAllUserTokens(testUser); - } - - @Test - void authenticateUser_WhenNullRequest_ShouldHandleGracefully() { - // Given - when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); - when(loginLockRepository.findByUsername("testuser")).thenReturn(Optional.of(loginLock)); - when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class))) - .thenReturn(authentication); - when(authentication.getPrincipal()).thenReturn(userDetails); - when(userDetails.getUsername()).thenReturn("testuser"); - when(userDetails.getAuthorities()) - .thenReturn(java.util.Arrays.asList( - new SimpleGrantedAuthority("ROLE_CUSTOMER"))); - when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); - when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); - when(tokenService.createRefreshToken(eq(testUser), isNull(), isNull())).thenReturn("refresh-token"); - - // When - LoginResponse response = authService.authenticateUser(loginRequest, null); - - // Then - assertThat(response).isNotNull(); - verify(tokenService).createRefreshToken(eq(testUser), isNull(), isNull()); - } - - @Test - void verifyEmail_WhenNullRequest_ShouldHandleGracefully() { - // Given - testUser.setEnabled(false); - testUser.setEmailVerified(false); - when(tokenService.validateToken("verification-token", VerificationToken.TokenType.EMAIL_VERIFICATION)) - .thenReturn(verificationToken); - when(userRepository.save(any(User.class))).thenReturn(testUser); - when(jwtUtil.generateJwtToken(any(UserDetails.class), anyList())).thenReturn("jwt-token"); - when(tokenService.createRefreshToken(eq(testUser), isNull(), isNull())).thenReturn("refresh-token"); - - // When - LoginResponse response = authService.verifyEmail("verification-token", null); - - // Then - assertThat(response).isNotNull(); - verify(tokenService).createRefreshToken(eq(testUser), isNull(), isNull()); - } + @Mock + private AuthenticationManager authenticationManager; + + @Mock + private UserRepository userRepository; + + @Mock + private RoleRepository roleRepository; + + @Mock + private PasswordEncoder passwordEncoder; + + @Mock + private JwtUtil jwtUtil; + + @Mock + private LoginLockRepository loginLockRepository; + + @Mock + private LoginLogRepository loginLogRepository; + + @Mock + private LoginAuditService loginAuditService; + + @Mock + private TokenService tokenService; + + @Mock + private EmailService emailService; + + @Mock + private HttpServletRequest request; + + @Mock + private Authentication authentication; + + @Mock + private UserDetails userDetails; + + @InjectMocks + private AuthService authService; + + private User testUser; + private Role customerRole; + private Role adminRole; + private LoginRequest loginRequest; + private RegisterRequest registerRequest; + private LoginLock loginLock; + private VerificationToken verificationToken; + private RefreshToken refreshToken; + + @BeforeEach + void setUp() { + // Set up test configuration + ReflectionTestUtils.setField(authService, "maxFailedAttempts", 3); + ReflectionTestUtils.setField(authService, "lockDurationMinutes", 15L); + + // Create test roles + customerRole = Role.builder() + .id(1L) + .name(RoleName.CUSTOMER) + .description("Customer role") + .build(); + + adminRole = Role.builder() + .id(2L) + .name(RoleName.ADMIN) + .description("Admin role") + .build(); + + // Create test user + testUser = User.builder() + .id(1L) + .username("testuser") + .email("test@example.com") + .password("encoded-password") + .fullName("Test User") + .phone("1234567890") + .address("Test Address") + .enabled(true) + .emailVerified(true) + .createdAt(LocalDateTime.now()) + .roles(Set.of(customerRole)) + .build(); + + // Create test requests + loginRequest = new LoginRequest(); + loginRequest.setUsername("testuser"); + loginRequest.setPassword("password"); + + registerRequest = new RegisterRequest(); + registerRequest.setEmail("new@example.com"); + registerRequest.setPassword("newpassword"); + registerRequest.setFullName("New User"); + registerRequest.setPhone("9876543210"); + registerRequest.setAddress("New Address"); + + // Create test login lock + loginLock = LoginLock.builder() + .id(1L) + .username("testuser") + .failedAttempts(0) + .lockUntil(null) + .build(); + + // Create test verification token + verificationToken = VerificationToken.builder() + .id("token-1") + .token("verification-token") + .user(testUser) + .tokenType(VerificationToken.TokenType.EMAIL_VERIFICATION) + .expiryDate(LocalDateTime.now().plusHours(24)) + .createdAt(LocalDateTime.now()) + .build(); + + // Create test refresh token + refreshToken = RefreshToken.builder() + .id("refresh-1") + .token("refresh-token") + .user(testUser) + .expiryDate(LocalDateTime.now().plusDays(7)) + .createdAt(LocalDateTime.now()) + .build(); + } + + @Test + void authenticateUser_WhenValidCredentials_ShouldReturnLoginResponse() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(loginLockRepository.findByUsername("testuser")).thenReturn(Optional.of(loginLock)); + when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class))) + .thenReturn(authentication); + when(authentication.getPrincipal()).thenReturn(userDetails); + when(userDetails.getUsername()).thenReturn("testuser"); + when(userDetails.getAuthorities()) + .thenReturn(java.util.Arrays.asList( + new SimpleGrantedAuthority("ROLE_CUSTOMER"))); + when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())) + .thenReturn("refresh-token"); + when(request.getHeader("X-Forwarded-For")).thenReturn(null); + when(request.getRemoteAddr()).thenReturn("127.0.0.1"); + when(request.getHeader("User-Agent")).thenReturn("Test-Agent"); + + // When + LoginResponse response = authService.authenticateUser(loginRequest, request); + + // Then + assertThat(response).isNotNull(); + assertThat(response.getToken()).isEqualTo("jwt-token"); + assertThat(response.getRefreshToken()).isEqualTo("refresh-token"); + assertThat(response.getUsername()).isEqualTo("testuser"); + assertThat(response.getEmail()).isEqualTo("test@example.com"); + assertThat(response.getRoles()).contains("CUSTOMER"); + + verify(loginLockRepository).save(any(LoginLock.class)); + verify(loginLogRepository).save(any(LoginLog.class)); + } + + @Test + void authenticateUser_WhenUserNotFound_ShouldCheckByEmail() { + // Given + when(userRepository.findByUsername("test@example.com")).thenReturn(Optional.empty()); + when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.of(testUser)); + when(loginLockRepository.findByUsername("test@example.com")).thenReturn(Optional.of(loginLock)); + when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class))) + .thenReturn(authentication); + when(authentication.getPrincipal()).thenReturn(userDetails); + when(userDetails.getUsername()).thenReturn("test@example.com"); + when(userDetails.getAuthorities()).thenReturn((Collection) java.util.Collections + .singletonList(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); + + loginRequest.setUsername("test@example.com"); + + // When/Then + when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); + when(userRepository.findByUsername("test@example.com")).thenReturn(Optional.of(testUser)); + when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())) + .thenReturn("refresh-token"); + + LoginResponse response = authService.authenticateUser(loginRequest, request); + assertThat(response).isNotNull(); + } + + @Test + void authenticateUser_WhenUserDisabledAndNotVerified_ShouldThrowDisabledException() { + // Given + testUser.setEnabled(false); + testUser.setEmailVerified(false); + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + + // When/Then + assertThatThrownBy(() -> authService.authenticateUser(loginRequest, request)) + .isInstanceOf(DisabledException.class) + .hasMessageContaining("Please verify your email address"); + } + + @Test + void authenticateUser_WhenUserDisabledAndVerified_ShouldThrowDisabledException() { + // Given + testUser.setEnabled(false); + testUser.setEmailVerified(true); + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + + // When/Then + assertThatThrownBy(() -> authService.authenticateUser(loginRequest, request)) + .isInstanceOf(DisabledException.class) + .hasMessageContaining("Your account has been deactivated"); + } + + @Test + void authenticateUser_WhenAccountLocked_ShouldThrowBadCredentialsException() { + // Given + loginLock.setLockUntil(LocalDateTime.now().plusMinutes(10)); + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(loginLockRepository.findByUsername("testuser")).thenReturn(Optional.of(loginLock)); + + // When/Then + assertThatThrownBy(() -> authService.authenticateUser(loginRequest, request)) + .isInstanceOf(BadCredentialsException.class) + .hasMessageContaining("Account is temporarily locked"); + + verify(loginAuditService).recordLogin(eq("testuser"), eq(false), anyString(), anyString()); + } + + @Test + void authenticateUser_WhenNoLockRecord_ShouldCreateNewLock() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(loginLockRepository.findByUsername("testuser")).thenReturn(Optional.empty()); + when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class))) + .thenReturn(authentication); + when(authentication.getPrincipal()).thenReturn(userDetails); + when(userDetails.getUsername()).thenReturn("testuser"); + when(userDetails.getAuthorities()) + .thenReturn((Collection) java.util.Collections + .singleton(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); + when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())) + .thenReturn("refresh-token"); + + // When + LoginResponse response = authService.authenticateUser(loginRequest, request); + + // Then + assertThat(response).isNotNull(); + verify(loginLockRepository) + .save(argThat(lock -> lock.getUsername().equals("testuser") + && lock.getFailedAttempts() == 0)); + } + + @Test + void authenticateUser_WhenBadCredentials_ShouldIncrementFailedAttempts() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(loginLockRepository.findByUsername("testuser")).thenReturn(Optional.of(loginLock)); + when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class))) + .thenThrow(new BadCredentialsException("Invalid credentials")); + + // When/Then + assertThatThrownBy(() -> authService.authenticateUser(loginRequest, request)) + .isInstanceOf(BadCredentialsException.class) + .hasMessage("Invalid username or password"); + + verify(loginAuditService).incrementFailedAttempt("testuser", 15L, 3); + verify(loginAuditService).recordLogin(eq("testuser"), eq(false), anyString(), anyString()); + } + + @Test + void registerUser_WhenValidRequest_ShouldCreateUserAndSendVerificationEmail() { + // Given + when(userRepository.existsByEmail("new@example.com")).thenReturn(false); + when(roleRepository.findByName(RoleName.CUSTOMER)).thenReturn(Optional.of(customerRole)); + when(passwordEncoder.encode("newpassword")).thenReturn("encoded-password"); + when(userRepository.save(any(User.class))).thenReturn(testUser); + when(tokenService.createVerificationToken(any(User.class))).thenReturn("verification-token"); + + // When + String result = authService.registerUser(registerRequest); + + // Then + assertThat(result).contains("User registered successfully"); + verify(userRepository).save(argThat(user -> user.getEmail().equals("new@example.com") && + user.getFullName().equals("New User") && + !user.getEnabled() && + !user.getEmailVerified())); + verify(emailService).sendVerificationEmail("new@example.com", "new@example.com", "verification-token"); + } + + @Test + void registerUser_WhenEmailExists_ShouldThrowRuntimeException() { + // Given + when(userRepository.existsByEmail("new@example.com")).thenReturn(true); + + // When/Then + assertThatThrownBy(() -> authService.registerUser(registerRequest)) + .isInstanceOf(RuntimeException.class) + .hasMessage("Error: Email is already in use!"); + } + + @Test + void registerUser_WhenAdminRole_ShouldAssignAdminRole() { + // Given + registerRequest.setRoles(Set.of("admin")); + when(userRepository.existsByEmail("new@example.com")).thenReturn(false); + when(roleRepository.findByName(RoleName.ADMIN)).thenReturn(Optional.of(adminRole)); + when(passwordEncoder.encode("newpassword")).thenReturn("encoded-password"); + when(userRepository.save(any(User.class))).thenReturn(testUser); + when(tokenService.createVerificationToken(any(User.class))).thenReturn("verification-token"); + + // When + authService.registerUser(registerRequest); + + // Then + verify(roleRepository).findByName(RoleName.ADMIN); + verify(userRepository).save(argThat(user -> user.getRoles().contains(adminRole))); + } + + @Test + void registerUser_WhenEmployeeRole_ShouldAssignEmployeeRole() { + // Given + Role employeeRole = Role.builder().id(3L).name(RoleName.EMPLOYEE).build(); + registerRequest.setRoles(Set.of("employee")); + when(userRepository.existsByEmail("new@example.com")).thenReturn(false); + when(roleRepository.findByName(RoleName.EMPLOYEE)).thenReturn(Optional.of(employeeRole)); + when(passwordEncoder.encode("newpassword")).thenReturn("encoded-password"); + when(userRepository.save(any(User.class))).thenReturn(testUser); + when(tokenService.createVerificationToken(any(User.class))).thenReturn("verification-token"); + + // When + authService.registerUser(registerRequest); + + // Then + verify(roleRepository).findByName(RoleName.EMPLOYEE); + verify(userRepository).save(argThat(user -> user.getRoles().contains(employeeRole))); + } + + @Test + void registerUser_WhenInvalidRole_ShouldAssignCustomerRole() { + // Given + registerRequest.setRoles(Set.of("invalid")); + when(userRepository.existsByEmail("new@example.com")).thenReturn(false); + when(roleRepository.findByName(RoleName.CUSTOMER)).thenReturn(Optional.of(customerRole)); + when(passwordEncoder.encode("newpassword")).thenReturn("encoded-password"); + when(userRepository.save(any(User.class))).thenReturn(testUser); + when(tokenService.createVerificationToken(any(User.class))).thenReturn("verification-token"); + + // When + authService.registerUser(registerRequest); + + // Then + verify(roleRepository).findByName(RoleName.CUSTOMER); + verify(userRepository).save(argThat(user -> user.getRoles().contains(customerRole))); + } + + @Test + void registerUser_WhenRoleNotFound_ShouldThrowRuntimeException() { + // Given + when(userRepository.existsByEmail("new@example.com")).thenReturn(false); + when(roleRepository.findByName(RoleName.CUSTOMER)).thenReturn(Optional.empty()); + when(passwordEncoder.encode("newpassword")).thenReturn("encoded-password"); + + // When/Then + assertThatThrownBy(() -> authService.registerUser(registerRequest)) + .isInstanceOf(RuntimeException.class) + .hasMessage("Error: Customer Role not found."); + } + + @Test + void verifyEmail_WhenValidToken_ShouldEnableUserAndReturnLoginResponse() { + // Given + testUser.setEnabled(false); + testUser.setEmailVerified(false); + when(tokenService.validateToken("verification-token", VerificationToken.TokenType.EMAIL_VERIFICATION)) + .thenReturn(verificationToken); + when(userRepository.save(any(User.class))).thenReturn(testUser); + when(jwtUtil.generateJwtToken(any(UserDetails.class), anyList())).thenReturn("jwt-token"); + when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())) + .thenReturn("refresh-token"); + + // When + LoginResponse response = authService.verifyEmail("verification-token", request); + + // Then + assertThat(response).isNotNull(); + assertThat(response.getToken()).isEqualTo("jwt-token"); + assertThat(response.getRefreshToken()).isEqualTo("refresh-token"); + verify(userRepository).save(argThat(user -> user.getEnabled() && user.getEmailVerified())); + verify(tokenService).markTokenAsUsed(verificationToken); + verify(emailService).sendWelcomeEmail("test@example.com", "testuser"); + } + + @Test + void resendVerificationEmail_WhenUserExists_ShouldSendEmail() { + // Given + testUser.setEmailVerified(false); + when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.of(testUser)); + when(tokenService.createVerificationToken(testUser)).thenReturn("new-verification-token"); + + // When + String result = authService.resendVerificationEmail("test@example.com"); + + // Then + assertThat(result).contains("Verification email sent successfully"); + verify(emailService).sendVerificationEmail("test@example.com", "testuser", "new-verification-token"); + } + + @Test + void resendVerificationEmail_WhenUserNotFound_ShouldThrowRuntimeException() { + // Given + when(userRepository.findByEmail("nonexistent@example.com")).thenReturn(Optional.empty()); + + // When/Then + assertThatThrownBy(() -> authService.resendVerificationEmail("nonexistent@example.com")) + .isInstanceOf(RuntimeException.class) + .hasMessage("User not found with email: nonexistent@example.com"); + } + + @Test + void resendVerificationEmail_WhenEmailAlreadyVerified_ShouldThrowRuntimeException() { + // Given + testUser.setEmailVerified(true); + when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.of(testUser)); + + // When/Then + assertThatThrownBy(() -> authService.resendVerificationEmail("test@example.com")) + .isInstanceOf(RuntimeException.class) + .hasMessage("Email is already verified"); + } + + @Test + void refreshToken_WhenValidToken_ShouldReturnNewLoginResponse() { + // Given + when(tokenService.validateRefreshToken("refresh-token")).thenReturn(refreshToken); + when(jwtUtil.generateJwtToken(any(UserDetails.class), anyList())).thenReturn("new-jwt-token"); + + // When + LoginResponse response = authService.refreshToken("refresh-token"); + + // Then + assertThat(response).isNotNull(); + assertThat(response.getToken()).isEqualTo("new-jwt-token"); + assertThat(response.getRefreshToken()).isEqualTo("refresh-token"); + assertThat(response.getUsername()).isEqualTo("testuser"); + assertThat(response.getEmail()).isEqualTo("test@example.com"); + } + + @Test + void logout_ShouldRevokeRefreshToken() { + // When + authService.logout("refresh-token"); + + // Then + verify(tokenService).revokeRefreshToken("refresh-token"); + } + + @Test + void forgotPassword_WhenUserExists_ShouldSendResetEmail() { + // Given + when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.of(testUser)); + when(tokenService.createPasswordResetToken(testUser)).thenReturn("reset-token"); + + // When + String result = authService.forgotPassword("test@example.com"); + + // Then + assertThat(result).contains("Password reset email sent successfully"); + verify(emailService).sendPasswordResetEmail("test@example.com", "testuser", "reset-token"); + } + + @Test + void forgotPassword_WhenUserNotFound_ShouldThrowRuntimeException() { + // Given + when(userRepository.findByEmail("nonexistent@example.com")).thenReturn(Optional.empty()); + + // When/Then + assertThatThrownBy(() -> authService.forgotPassword("nonexistent@example.com")) + .isInstanceOf(RuntimeException.class) + .hasMessage("User not found with email: nonexistent@example.com"); + } + + @Test + void resetPassword_WhenValidToken_ShouldUpdatePasswordAndRevokeTokens() { + // Given + VerificationToken resetToken = VerificationToken.builder() + .token("reset-token") + .user(testUser) + .tokenType(VerificationToken.TokenType.PASSWORD_RESET) + .build(); + + when(tokenService.validateToken("reset-token", VerificationToken.TokenType.PASSWORD_RESET)) + .thenReturn(resetToken); + when(passwordEncoder.encode("newpassword")).thenReturn("new-encoded-password"); + when(userRepository.save(any(User.class))).thenReturn(testUser); + + // When + String result = authService.resetPassword("reset-token", "newpassword"); + + // Then + assertThat(result).contains("Password reset successfully"); + verify(userRepository).save(argThat(user -> user.getPassword().equals("new-encoded-password"))); + verify(tokenService).markTokenAsUsed(resetToken); + verify(tokenService).revokeAllUserTokens(testUser); + } + + @Test + void authenticateUser_WhenNullRequest_ShouldHandleGracefully() { + // Given + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(loginLockRepository.findByUsername("testuser")).thenReturn(Optional.of(loginLock)); + when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class))) + .thenReturn(authentication); + when(authentication.getPrincipal()).thenReturn(userDetails); + when(userDetails.getUsername()).thenReturn("testuser"); + when(userDetails.getAuthorities()) + .thenReturn(java.util.Arrays.asList( + new SimpleGrantedAuthority("ROLE_CUSTOMER"))); + when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); + when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(tokenService.createRefreshToken(eq(testUser), isNull(), isNull())).thenReturn("refresh-token"); + + // When + LoginResponse response = authService.authenticateUser(loginRequest, null); + + // Then + assertThat(response).isNotNull(); + verify(tokenService).createRefreshToken(eq(testUser), isNull(), isNull()); + } + + @Test + void verifyEmail_WhenNullRequest_ShouldHandleGracefully() { + // Given + testUser.setEnabled(false); + testUser.setEmailVerified(false); + when(tokenService.validateToken("verification-token", VerificationToken.TokenType.EMAIL_VERIFICATION)) + .thenReturn(verificationToken); + when(userRepository.save(any(User.class))).thenReturn(testUser); + when(jwtUtil.generateJwtToken(any(UserDetails.class), anyList())).thenReturn("jwt-token"); + when(tokenService.createRefreshToken(eq(testUser), isNull(), isNull())).thenReturn("refresh-token"); + + // When + LoginResponse response = authService.verifyEmail("verification-token", null); + + // Then + assertThat(response).isNotNull(); + verify(tokenService).createRefreshToken(eq(testUser), isNull(), isNull()); + } } From 88a9292449d7aee4cf82c3c7b5cd21def7b64ebd Mon Sep 17 00:00:00 2001 From: AdithaBuwaneka Date: Fri, 21 Nov 2025 14:31:09 +0530 Subject: [PATCH 10/20] refactor: Replace array list with singleton for authorities in AuthServiceTest --- .../com/techtorque/auth_service/service/AuthServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java index 12df01f..beb7a00 100644 --- a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java @@ -555,7 +555,7 @@ void authenticateUser_WhenNullRequest_ShouldHandleGracefully() { when(authentication.getPrincipal()).thenReturn(userDetails); when(userDetails.getUsername()).thenReturn("testuser"); when(userDetails.getAuthorities()) - .thenReturn(java.util.Arrays.asList( + .thenReturn((Collection) java.util.Collections.singletonList( new SimpleGrantedAuthority("ROLE_CUSTOMER"))); when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); From f60fe28a3121021db949666c23470debb97f43e3 Mon Sep 17 00:00:00 2001 From: AdithaBuwaneka Date: Fri, 21 Nov 2025 14:32:16 +0530 Subject: [PATCH 11/20] refactor: Replace array list with singleton for authorities in AuthServiceTest --- .../com/techtorque/auth_service/service/AuthServiceTest.java | 2 +- .../com/techtorque/auth_service/service/UserServiceTest.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java index beb7a00..85e1bc3 100644 --- a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java @@ -173,7 +173,7 @@ void authenticateUser_WhenValidCredentials_ShouldReturnLoginResponse() { when(authentication.getPrincipal()).thenReturn(userDetails); when(userDetails.getUsername()).thenReturn("testuser"); when(userDetails.getAuthorities()) - .thenReturn(java.util.Arrays.asList( + .thenReturn((Collection) java.util.Collections.singletonList( new SimpleGrantedAuthority("ROLE_CUSTOMER"))); when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java index fdce122..94ea1e5 100644 --- a/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java @@ -582,7 +582,7 @@ void assignRoleToUser_WhenAssigningAdminRoleWithoutSuperAdminAuth_ShouldThrowAcc SecurityContextHolder.setContext(securityContext); when(securityContext.getAuthentication()).thenReturn(authentication); - when(authentication.getAuthorities()).thenReturn(java.util.Arrays.asList(new SimpleGrantedAuthority("ROLE_ADMIN"))); + when(authentication.getAuthorities()).thenReturn((Collection) java.util.Collections.singletonList(new SimpleGrantedAuthority("ROLE_ADMIN"))); // When/Then assertThatThrownBy(() -> userService.assignRoleToUser("testuser", "ADMIN")) @@ -601,7 +601,7 @@ void assignRoleToUser_WhenAssigningAdminRoleWithSuperAdminAuth_ShouldSucceed() { SecurityContextHolder.setContext(securityContext); when(securityContext.getAuthentication()).thenReturn(authentication); - when(authentication.getAuthorities()).thenReturn(java.util.Arrays.asList(new SimpleGrantedAuthority("ROLE_SUPER_ADMIN"))); + when(authentication.getAuthorities()).thenReturn((Collection) java.util.Collections.singletonList(new SimpleGrantedAuthority("ROLE_SUPER_ADMIN"))); // When userService.assignRoleToUser("testuser", "ADMIN"); From 0dab850601f1912306db1adaff6674dfa1d09449 Mon Sep 17 00:00:00 2001 From: AdithaBuwaneka Date: Fri, 21 Nov 2025 14:32:30 +0530 Subject: [PATCH 12/20] refactor: Improve readability of authority retrieval in UserServiceTest --- .../techtorque/auth_service/service/UserServiceTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java index 94ea1e5..7062bcb 100644 --- a/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java @@ -582,7 +582,8 @@ void assignRoleToUser_WhenAssigningAdminRoleWithoutSuperAdminAuth_ShouldThrowAcc SecurityContextHolder.setContext(securityContext); when(securityContext.getAuthentication()).thenReturn(authentication); - when(authentication.getAuthorities()).thenReturn((Collection) java.util.Collections.singletonList(new SimpleGrantedAuthority("ROLE_ADMIN"))); + when(authentication.getAuthorities()) + .thenReturn((Collection) java.util.Collections.singletonList(new SimpleGrantedAuthority("ROLE_ADMIN"))); // When/Then assertThatThrownBy(() -> userService.assignRoleToUser("testuser", "ADMIN")) @@ -601,7 +602,8 @@ void assignRoleToUser_WhenAssigningAdminRoleWithSuperAdminAuth_ShouldSucceed() { SecurityContextHolder.setContext(securityContext); when(securityContext.getAuthentication()).thenReturn(authentication); - when(authentication.getAuthorities()).thenReturn((Collection) java.util.Collections.singletonList(new SimpleGrantedAuthority("ROLE_SUPER_ADMIN"))); + when(authentication.getAuthorities()).thenReturn( + (Collection) java.util.Collections.singletonList(new SimpleGrantedAuthority("ROLE_SUPER_ADMIN"))); // When userService.assignRoleToUser("testuser", "ADMIN"); From 3c4b79c8b18290dd228c03b1ab6a13aee05ca73c Mon Sep 17 00:00:00 2001 From: AdithaBuwaneka Date: Fri, 21 Nov 2025 14:35:04 +0530 Subject: [PATCH 13/20] refactor: Update mock request IP address and email verification in AuthServiceTest --- .../techtorque/auth_service/service/AuthServiceTest.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java index 85e1bc3..db68a72 100644 --- a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java @@ -95,17 +95,23 @@ void setUp() { ReflectionTestUtils.setField(authService, "maxFailedAttempts", 3); ReflectionTestUtils.setField(authService, "lockDurationMinutes", 15L); + // Mock request IP address + when(request.getRemoteAddr()).thenReturn("192.168.1.1"); + when(request.getHeader("X-Forwarded-For")).thenReturn(null); + // Create test roles customerRole = Role.builder() .id(1L) .name(RoleName.CUSTOMER) .description("Customer role") + .permissions(Collections.emptySet()) .build(); adminRole = Role.builder() .id(2L) .name(RoleName.ADMIN) .description("Admin role") + .permissions(Collections.emptySet()) .build(); // Create test user @@ -326,7 +332,7 @@ void registerUser_WhenValidRequest_ShouldCreateUserAndSendVerificationEmail() { user.getFullName().equals("New User") && !user.getEnabled() && !user.getEmailVerified())); - verify(emailService).sendVerificationEmail("new@example.com", "new@example.com", "verification-token"); + verify(emailService).sendVerificationEmail("test@example.com", "testuser", "verification-token"); } @Test From 729741f0d1306ef21d54db0a9e7a834b9019ad82 Mon Sep 17 00:00:00 2001 From: AdithaBuwaneka Date: Fri, 21 Nov 2025 14:37:23 +0530 Subject: [PATCH 14/20] refactor: Simplify tokenService.createRefreshToken calls in AuthServiceTest --- .../auth_service/service/AuthServiceTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java index db68a72..6e1db62 100644 --- a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java @@ -183,7 +183,7 @@ void authenticateUser_WhenValidCredentials_ShouldReturnLoginResponse() { new SimpleGrantedAuthority("ROLE_CUSTOMER"))); when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); - when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())) + when(tokenService.createRefreshToken(any(User.class), anyString(), anyString())) .thenReturn("refresh-token"); when(request.getHeader("X-Forwarded-For")).thenReturn(null); when(request.getRemoteAddr()).thenReturn("127.0.0.1"); @@ -222,7 +222,7 @@ void authenticateUser_WhenUserNotFound_ShouldCheckByEmail() { // When/Then when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); when(userRepository.findByUsername("test@example.com")).thenReturn(Optional.of(testUser)); - when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())) + when(tokenService.createRefreshToken(any(User.class), anyString(), anyString())) .thenReturn("refresh-token"); LoginResponse response = authService.authenticateUser(loginRequest, request); @@ -284,7 +284,7 @@ void authenticateUser_WhenNoLockRecord_ShouldCreateNewLock() { .singleton(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); - when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())) + when(tokenService.createRefreshToken(any(User.class), anyString(), anyString())) .thenReturn("refresh-token"); // When @@ -423,7 +423,7 @@ void verifyEmail_WhenValidToken_ShouldEnableUserAndReturnLoginResponse() { .thenReturn(verificationToken); when(userRepository.save(any(User.class))).thenReturn(testUser); when(jwtUtil.generateJwtToken(any(UserDetails.class), anyList())).thenReturn("jwt-token"); - when(tokenService.createRefreshToken(eq(testUser), anyString(), anyString())) + when(tokenService.createRefreshToken(any(User.class), anyString(), anyString())) .thenReturn("refresh-token"); // When @@ -565,7 +565,7 @@ void authenticateUser_WhenNullRequest_ShouldHandleGracefully() { new SimpleGrantedAuthority("ROLE_CUSTOMER"))); when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); - when(tokenService.createRefreshToken(eq(testUser), isNull(), isNull())).thenReturn("refresh-token"); + when(tokenService.createRefreshToken(any(User.class), isNull(), isNull())).thenReturn("refresh-token"); // When LoginResponse response = authService.authenticateUser(loginRequest, null); @@ -584,7 +584,7 @@ void verifyEmail_WhenNullRequest_ShouldHandleGracefully() { .thenReturn(verificationToken); when(userRepository.save(any(User.class))).thenReturn(testUser); when(jwtUtil.generateJwtToken(any(UserDetails.class), anyList())).thenReturn("jwt-token"); - when(tokenService.createRefreshToken(eq(testUser), isNull(), isNull())).thenReturn("refresh-token"); + when(tokenService.createRefreshToken(any(User.class), isNull(), isNull())).thenReturn("refresh-token"); // When LoginResponse response = authService.verifyEmail("verification-token", null); From fa2d0b8cdb45b3f9021860f741922eec251269ee Mon Sep 17 00:00:00 2001 From: AdithaBuwaneka Date: Fri, 21 Nov 2025 14:39:03 +0530 Subject: [PATCH 15/20] refactor: Use lenient stubbing for request IP address in AuthServiceTest --- .../auth_service/service/AuthServiceTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java index 6e1db62..ecdab8a 100644 --- a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java @@ -95,9 +95,9 @@ void setUp() { ReflectionTestUtils.setField(authService, "maxFailedAttempts", 3); ReflectionTestUtils.setField(authService, "lockDurationMinutes", 15L); - // Mock request IP address - when(request.getRemoteAddr()).thenReturn("192.168.1.1"); - when(request.getHeader("X-Forwarded-For")).thenReturn(null); + // Mock request IP address (lenient to avoid unnecessary stubbing warnings) + lenient().when(request.getRemoteAddr()).thenReturn("192.168.1.1"); + lenient().when(request.getHeader("X-Forwarded-For")).thenReturn(null); // Create test roles customerRole = Role.builder() @@ -267,7 +267,7 @@ void authenticateUser_WhenAccountLocked_ShouldThrowBadCredentialsException() { .isInstanceOf(BadCredentialsException.class) .hasMessageContaining("Account is temporarily locked"); - verify(loginAuditService).recordLogin(eq("testuser"), eq(false), anyString(), anyString()); + verify(loginAuditService).recordLogin(eq("testuser"), eq(false), eq("192.168.1.1"), isNull()); } @Test @@ -311,7 +311,7 @@ void authenticateUser_WhenBadCredentials_ShouldIncrementFailedAttempts() { .hasMessage("Invalid username or password"); verify(loginAuditService).incrementFailedAttempt("testuser", 15L, 3); - verify(loginAuditService).recordLogin(eq("testuser"), eq(false), anyString(), anyString()); + verify(loginAuditService).recordLogin(eq("testuser"), eq(false), eq("192.168.1.1"), isNull()); } @Test From 4424cf00d181d2fb9f5dc24170af696494cc9535 Mon Sep 17 00:00:00 2001 From: AdithaBuwaneka Date: Fri, 21 Nov 2025 14:40:16 +0530 Subject: [PATCH 16/20] refactor: Update tokenService.createRefreshToken calls to use fixed IP address and null for user agent in AuthServiceTest --- .../com/techtorque/auth_service/service/AuthServiceTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java index ecdab8a..6ac0226 100644 --- a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java @@ -222,7 +222,7 @@ void authenticateUser_WhenUserNotFound_ShouldCheckByEmail() { // When/Then when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); when(userRepository.findByUsername("test@example.com")).thenReturn(Optional.of(testUser)); - when(tokenService.createRefreshToken(any(User.class), anyString(), anyString())) + when(tokenService.createRefreshToken(any(User.class), eq("192.168.1.1"), isNull())) .thenReturn("refresh-token"); LoginResponse response = authService.authenticateUser(loginRequest, request); @@ -423,7 +423,7 @@ void verifyEmail_WhenValidToken_ShouldEnableUserAndReturnLoginResponse() { .thenReturn(verificationToken); when(userRepository.save(any(User.class))).thenReturn(testUser); when(jwtUtil.generateJwtToken(any(UserDetails.class), anyList())).thenReturn("jwt-token"); - when(tokenService.createRefreshToken(any(User.class), anyString(), anyString())) + when(tokenService.createRefreshToken(any(User.class), eq("192.168.1.1"), isNull())) .thenReturn("refresh-token"); // When From 17aae48e098fe6a26bd495b4b702932c9ee966b9 Mon Sep 17 00:00:00 2001 From: AdithaBuwaneka Date: Fri, 21 Nov 2025 14:43:49 +0530 Subject: [PATCH 17/20] refactor: Use lenient stubbing for userRepository in AuthServiceTest and UserServiceTest --- .../com/techtorque/auth_service/service/AuthServiceTest.java | 4 ++-- .../com/techtorque/auth_service/service/UserServiceTest.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java index 6ac0226..e3d2e02 100644 --- a/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/AuthServiceTest.java @@ -208,7 +208,7 @@ void authenticateUser_WhenValidCredentials_ShouldReturnLoginResponse() { void authenticateUser_WhenUserNotFound_ShouldCheckByEmail() { // Given when(userRepository.findByUsername("test@example.com")).thenReturn(Optional.empty()); - when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.of(testUser)); + lenient().when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.of(testUser)); when(loginLockRepository.findByUsername("test@example.com")).thenReturn(Optional.of(loginLock)); when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class))) .thenReturn(authentication); @@ -284,7 +284,7 @@ void authenticateUser_WhenNoLockRecord_ShouldCreateNewLock() { .singleton(new SimpleGrantedAuthority("ROLE_CUSTOMER"))); when(jwtUtil.generateJwtToken(eq(userDetails), anyList())).thenReturn("jwt-token"); when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); - when(tokenService.createRefreshToken(any(User.class), anyString(), anyString())) + when(tokenService.createRefreshToken(any(User.class), eq("192.168.1.1"), isNull())) .thenReturn("refresh-token"); // When diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java index 7062bcb..fab2d62 100644 --- a/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java @@ -577,8 +577,8 @@ void assignRoleToUser_WhenValidRole_ShouldAssignRole() { @Test void assignRoleToUser_WhenAssigningAdminRoleWithoutSuperAdminAuth_ShouldThrowAccessDeniedException() { // Given - when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); - when(roleRepository.findByName(RoleName.ADMIN)).thenReturn(Optional.of(adminRole)); + lenient().when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + when(roleRepository.findByName(RoleName.SUPER_ADMIN)).thenReturn(Optional.of(superAdminRole)); SecurityContextHolder.setContext(securityContext); when(securityContext.getAuthentication()).thenReturn(authentication); From 3ec461180944630103eba13cdb6dec24199b0841 Mon Sep 17 00:00:00 2001 From: AdithaBuwaneka Date: Fri, 21 Nov 2025 14:45:16 +0530 Subject: [PATCH 18/20] refactor: Use lenient stubbing for userRepository in UserServiceTest --- .../com/techtorque/auth_service/service/UserServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java index fab2d62..d7689ff 100644 --- a/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java @@ -645,7 +645,7 @@ void revokeRoleFromUser_WhenValidRole_ShouldRevokeRole() { void revokeRoleFromUser_WhenRevokingOwnSuperAdminRole_ShouldThrowAccessDeniedException() { // Given testUser.getRoles().add(superAdminRole); - when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); + lenient().when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); when(roleRepository.findByName(RoleName.SUPER_ADMIN)).thenReturn(Optional.of(superAdminRole)); SecurityContextHolder.setContext(securityContext); From 55d9b9eae7a357cd0f95f20de97d621424c9bf83 Mon Sep 17 00:00:00 2001 From: AdithaBuwaneka Date: Fri, 21 Nov 2025 14:46:59 +0530 Subject: [PATCH 19/20] refactor: Use lenient stubbing for roleRepository in UserServiceTest --- .../com/techtorque/auth_service/service/UserServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java index d7689ff..51b1afd 100644 --- a/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java @@ -578,7 +578,7 @@ void assignRoleToUser_WhenValidRole_ShouldAssignRole() { void assignRoleToUser_WhenAssigningAdminRoleWithoutSuperAdminAuth_ShouldThrowAccessDeniedException() { // Given lenient().when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); - when(roleRepository.findByName(RoleName.SUPER_ADMIN)).thenReturn(Optional.of(superAdminRole)); + lenient().when(roleRepository.findByName(RoleName.ADMIN)).thenReturn(Optional.of(adminRole)); SecurityContextHolder.setContext(securityContext); when(securityContext.getAuthentication()).thenReturn(authentication); From 90d51f06a7c819d2d91d1f4bf4cc34a99c4c43b2 Mon Sep 17 00:00:00 2001 From: AdithaBuwaneka Date: Fri, 21 Nov 2025 14:47:06 +0530 Subject: [PATCH 20/20] refactor: Use lenient stubbing for roleRepository in UserServiceTest --- .../com/techtorque/auth_service/service/UserServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java b/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java index 51b1afd..1ff1e4b 100644 --- a/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java +++ b/auth-service/src/test/java/com/techtorque/auth_service/service/UserServiceTest.java @@ -646,7 +646,7 @@ void revokeRoleFromUser_WhenRevokingOwnSuperAdminRole_ShouldThrowAccessDeniedExc // Given testUser.getRoles().add(superAdminRole); lenient().when(userRepository.findByUsername("testuser")).thenReturn(Optional.of(testUser)); - when(roleRepository.findByName(RoleName.SUPER_ADMIN)).thenReturn(Optional.of(superAdminRole)); + lenient().when(roleRepository.findByName(RoleName.SUPER_ADMIN)).thenReturn(Optional.of(superAdminRole)); SecurityContextHolder.setContext(securityContext); when(securityContext.getAuthentication()).thenReturn(authentication);