From a3baaf14e9dd1e961e357e5b9005687ee67fdc14 Mon Sep 17 00:00:00 2001 From: Nour Eldien Ayman Date: Thu, 1 May 2025 12:58:13 +0300 Subject: [PATCH 1/5] Add unit tests for AdminService, AuthenticationService, CustomUserDetailsService, and TokenService --- .../auth/service/AuthenticationService.java | 15 +- .../service/CustomUserDetailsService.java | 5 + src/main/resources/application.properties | 2 +- .../auth/service/AdminServiceTest.java | 42 ++ .../service/AuthenticationServiceTest.java | 293 +++++++++++ .../service/CustomUserDetailsServiceTest.java | 149 ++++++ .../auth/service/TokenServiceTest.java | 487 ++++++++++++++++++ 7 files changed, 990 insertions(+), 3 deletions(-) create mode 100644 src/test/java/com/podzilla/auth/service/AdminServiceTest.java create mode 100644 src/test/java/com/podzilla/auth/service/AuthenticationServiceTest.java create mode 100644 src/test/java/com/podzilla/auth/service/CustomUserDetailsServiceTest.java create mode 100644 src/test/java/com/podzilla/auth/service/TokenServiceTest.java diff --git a/src/main/java/com/podzilla/auth/service/AuthenticationService.java b/src/main/java/com/podzilla/auth/service/AuthenticationService.java index aa9f95d..504982f 100644 --- a/src/main/java/com/podzilla/auth/service/AuthenticationService.java +++ b/src/main/java/com/podzilla/auth/service/AuthenticationService.java @@ -65,10 +65,21 @@ public String login(final LoginRequest loginRequest, } public void registerAccount(final SignupRequest signupRequest) { - if (signupRequest.getPassword().isEmpty()) { + if (signupRequest.getPassword() == null + || signupRequest.getPassword().isEmpty()) { throw new ValidationException("Password cannot be empty."); } + if (signupRequest.getName() == null + || signupRequest.getName().isEmpty()) { + throw new ValidationException("Name cannot be empty."); + } + + if (signupRequest.getEmail() == null + || signupRequest.getEmail().isEmpty()) { + throw new ValidationException("Email cannot be empty."); + } + if (userRepository.existsByEmail(signupRequest.getEmail())) { throw new ValidationException("Email already in use."); } @@ -82,7 +93,7 @@ public void registerAccount(final SignupRequest signupRequest) { signupRequest.getPassword())) .build(); Role role = roleRepository.findByErole(ERole.ROLE_USER).orElse(null); - account.setRoles(Collections.singleton(role)); + account.setRoles(role != null ? Collections.singleton(role) : null); userRepository.save(account); } diff --git a/src/main/java/com/podzilla/auth/service/CustomUserDetailsService.java b/src/main/java/com/podzilla/auth/service/CustomUserDetailsService.java index 5af441f..1d2e2d4 100644 --- a/src/main/java/com/podzilla/auth/service/CustomUserDetailsService.java +++ b/src/main/java/com/podzilla/auth/service/CustomUserDetailsService.java @@ -2,6 +2,7 @@ import com.podzilla.auth.dto.CustomUserDetails; import com.podzilla.auth.exception.NotFoundException; +import com.podzilla.auth.exception.ValidationException; import com.podzilla.auth.model.User; import com.podzilla.auth.repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; @@ -33,6 +34,10 @@ public UserDetails loadUserByUsername(final String email) { new NotFoundException( email + " not found.")); + if (user.getRoles() == null || user.getRoles().isEmpty()) { + throw new ValidationException("User has no roles assigned."); + } + Set authorities = user .getRoles() .stream() diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index e7e6d89..6dcc38a 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -19,7 +19,7 @@ spring.datasource.password=1234 spring.datasource.driver-class-name=org.postgresql.Driver spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect -spring.jpa.hibernate.ddl-auto=create-drop +spring.jpa.hibernate.ddl-auto=update spring.jpa.generate-ddl=true spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true diff --git a/src/test/java/com/podzilla/auth/service/AdminServiceTest.java b/src/test/java/com/podzilla/auth/service/AdminServiceTest.java new file mode 100644 index 0000000..f09023b --- /dev/null +++ b/src/test/java/com/podzilla/auth/service/AdminServiceTest.java @@ -0,0 +1,42 @@ +package com.podzilla.auth.service; + +import com.podzilla.auth.model.User; +import com.podzilla.auth.repository.UserRepository; +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 java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class AdminServiceTest { + + @Mock + private UserRepository userRepository; + + @InjectMocks + private AdminService adminService; + + @Test + void getUsers_shouldReturnListOfUsers() { + User user1 = User.builder().id(1L).email("user1@example.com").name("User One").build(); + User user2 = User.builder().id(2L).email("user2@example.com").name("User Two").build(); + List expectedUsers = Arrays.asList(user1, user2); + + when(userRepository.findAll()).thenReturn(expectedUsers); + + List actualUsers = adminService.getUsers(); + + assertEquals(expectedUsers.size(), actualUsers.size()); + assertEquals(expectedUsers, actualUsers); + + verify(userRepository).findAll(); + } +} \ No newline at end of file diff --git a/src/test/java/com/podzilla/auth/service/AuthenticationServiceTest.java b/src/test/java/com/podzilla/auth/service/AuthenticationServiceTest.java new file mode 100644 index 0000000..d5b6da3 --- /dev/null +++ b/src/test/java/com/podzilla/auth/service/AuthenticationServiceTest.java @@ -0,0 +1,293 @@ +package com.podzilla.auth.service; + +import com.podzilla.auth.dto.LoginRequest; +import com.podzilla.auth.dto.SignupRequest; +import com.podzilla.auth.exception.ValidationException; +import com.podzilla.auth.model.ERole; +import com.podzilla.auth.model.Role; +import com.podzilla.auth.model.User; +import com.podzilla.auth.repository.RoleRepository; +import com.podzilla.auth.repository.UserRepository; +import jakarta.servlet.http.HttpServletRequest; // Added import +import jakarta.servlet.http.HttpServletResponse; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +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.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.crypto.password.PasswordEncoder; + +import java.util.Collections; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class AuthenticationServiceTest { + + @Mock + private AuthenticationManager authenticationManager; + @Mock + private PasswordEncoder passwordEncoder; + @Mock + private UserRepository userRepository; + @Mock + private TokenService tokenService; + @Mock + private RoleRepository roleRepository; + @Mock + private HttpServletResponse httpServletResponse; + @Mock // Added mock for HttpServletRequest + private HttpServletRequest httpServletRequest; + + @InjectMocks + private AuthenticationService authenticationService; + + private SignupRequest signupRequest; + private LoginRequest loginRequest; + private User user; + private Role userRole; + + @BeforeEach + void setUp() { + signupRequest = new SignupRequest(); + signupRequest.setName("Test User"); + signupRequest.setEmail("test@example.com"); + signupRequest.setPassword("password123"); + + loginRequest = new LoginRequest(); + loginRequest.setEmail("test@example.com"); + loginRequest.setPassword("password123"); + + userRole = new Role(ERole.ROLE_USER); + user = User.builder() + .id(1L) + .name("Test User") + .email("test@example.com") + .password("encodedPassword") + .roles(Collections.singleton(userRole)) + .build(); + } + + // --- registerAccount Tests --- + + @Test + void registerAccount_shouldSaveUser_whenEmailNotExistsAndPasswordNotEmpty() { + // Arrange + when(userRepository.existsByEmail(signupRequest.getEmail())).thenReturn(false); + when(passwordEncoder.encode(signupRequest.getPassword())).thenReturn("encodedPassword"); + when(roleRepository.findByErole(ERole.ROLE_USER)).thenReturn(Optional.of(userRole)); + when(userRepository.save(any(User.class))).thenReturn(user); // Return the saved user + + // Act + authenticationService.registerAccount(signupRequest); + + // Assert + verify(userRepository).existsByEmail(signupRequest.getEmail()); + verify(passwordEncoder).encode(signupRequest.getPassword()); + verify(roleRepository).findByErole(ERole.ROLE_USER); + + // Capture the user argument passed to save + ArgumentCaptor userCaptor = ArgumentCaptor.forClass(User.class); + verify(userRepository).save(userCaptor.capture()); + User savedUser = userCaptor.getValue(); + + assertEquals(signupRequest.getName(), savedUser.getName()); + assertEquals(signupRequest.getEmail(), savedUser.getEmail()); + assertEquals("encodedPassword", savedUser.getPassword()); + assertTrue(savedUser.getRoles().contains(userRole)); + } + + @Test + void registerAccount_shouldThrowValidationException_whenEmailExists() { + // Arrange + when(userRepository.existsByEmail(signupRequest.getEmail())).thenReturn(true); + + // Act & Assert + ValidationException exception = assertThrows(ValidationException.class, () -> { + authenticationService.registerAccount(signupRequest); + }); + + assertEquals("Validation error: Email already in use.", + exception.getMessage()); + verify(userRepository).existsByEmail(signupRequest.getEmail()); + verify(passwordEncoder, never()).encode(anyString()); + verify(roleRepository, never()).findByErole(any()); + verify(userRepository, never()).save(any(User.class)); + } + + @Test + void registerAccount_shouldThrowValidationException_whenPasswordIsEmpty() { + // Arrange + signupRequest.setPassword(""); // Empty password + + // Act & Assert + ValidationException exception = assertThrows(ValidationException.class, () -> { + authenticationService.registerAccount(signupRequest); + }); + + assertEquals("Validation error: Password cannot be empty.", + exception.getMessage()); + verify(userRepository, never()).existsByEmail(anyString()); + verify(passwordEncoder, never()).encode(anyString()); + verify(roleRepository, never()).findByErole(any()); + verify(userRepository, never()).save(any(User.class)); + } + + @Test + void registerAccount_shouldHandleRoleNotFoundGracefully() { + // Arrange - Simulate role not found in DB + when(userRepository.existsByEmail(signupRequest.getEmail())).thenReturn(false); + when(passwordEncoder.encode(signupRequest.getPassword())).thenReturn("encodedPassword"); + when(roleRepository.findByErole(ERole.ROLE_USER)).thenReturn(Optional.empty()); // Role not found + when(userRepository.save(any(User.class))).thenReturn(user); + + // Act + authenticationService.registerAccount(signupRequest); + + // Assert + verify(userRepository).existsByEmail(signupRequest.getEmail()); + verify(passwordEncoder).encode(signupRequest.getPassword()); + verify(roleRepository).findByErole(ERole.ROLE_USER); + + ArgumentCaptor userCaptor = ArgumentCaptor.forClass(User.class); + verify(userRepository).save(userCaptor.capture()); + User savedUser = userCaptor.getValue(); + + // Check that roles are empty or null as expected when role isn't found + assertTrue(savedUser.getRoles() == null || savedUser.getRoles().isEmpty()); + assertEquals(signupRequest.getName(), savedUser.getName()); + assertEquals(signupRequest.getEmail(), savedUser.getEmail()); + assertEquals("encodedPassword", savedUser.getPassword()); + } + + + // --- login Tests --- + + @Test + void login_shouldReturnUsernameAndSetTokens_whenCredentialsAreValid() { + // Arrange + UserDetails userDetails = new org.springframework.security.core.userdetails.User( + loginRequest.getEmail(), + "encodedPassword", // Password doesn't matter much here as AuthenticationManager handles it + Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")) + ); + Authentication successfulAuth = new UsernamePasswordAuthenticationToken( + userDetails, // Principal + loginRequest.getPassword(), // Credentials + userDetails.getAuthorities() // Authorities + ); + + // Mock AuthenticationManager behavior + when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class))) + .thenReturn(successfulAuth); + + // Mocks for token generation (void methods, no 'when' needed unless checking args) + // doNothing().when(tokenService).generateAccessToken(anyString(), any(HttpServletResponse.class)); + // doNothing().when(tokenService).generateRefreshToken(anyString(), any(HttpServletResponse.class)); + + // Act + String loggedInUsername = authenticationService.login(loginRequest, httpServletResponse); + + // Assert + assertEquals(loginRequest.getEmail(), loggedInUsername); + + // Verify AuthenticationManager was called with unauthenticated token + ArgumentCaptor authCaptor = + ArgumentCaptor.forClass(UsernamePasswordAuthenticationToken.class); + verify(authenticationManager).authenticate(authCaptor.capture()); + UsernamePasswordAuthenticationToken capturedAuthRequest = authCaptor.getValue(); + assertEquals(loginRequest.getEmail(), capturedAuthRequest.getName()); + assertEquals(loginRequest.getPassword(), capturedAuthRequest.getCredentials()); + assertFalse(capturedAuthRequest.isAuthenticated()); // Ensure it was unauthenticated initially + + // Verify token generation methods were called + verify(tokenService).generateAccessToken(loginRequest.getEmail(), httpServletResponse); + verify(tokenService).generateRefreshToken(loginRequest.getEmail(), httpServletResponse); + } + + @Test + void login_shouldThrowException_whenCredentialsAreInvalid() { + // Arrange + // Mock AuthenticationManager to throw an exception for bad credentials + when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class))) + .thenThrow(new BadCredentialsException("Invalid credentials")); + + // Act & Assert + assertThrows(BadCredentialsException.class, () -> { + authenticationService.login(loginRequest, httpServletResponse); + }); + + // Verify token generation methods were NOT called + verify(tokenService, never()).generateAccessToken(anyString(), any(HttpServletResponse.class)); + verify(tokenService, never()).generateRefreshToken(anyString(), any(HttpServletResponse.class)); + } + + // --- logoutUser Tests --- + @Test + void logoutUser_shouldCallTokenServiceToRemoveTokens() { + // Arrange (no specific arrangement needed as methods are void) + + // Act + authenticationService.logoutUser(httpServletResponse); + + // Assert + verify(tokenService).removeAccessTokenFromCookie(httpServletResponse); + verify(tokenService).removeRefreshTokenFromCookieAndExpire(httpServletResponse); + } + + // --- refreshToken Tests --- + @Test + void refreshToken_shouldReturnEmailAndGenerateAccessToken_whenTokenIsValid() { + // Arrange + String expectedEmail = "test@example.com"; + String validRefreshToken = "valid-refresh-token"; + + when(tokenService.getRefreshTokenFromCookie(httpServletRequest)).thenReturn(validRefreshToken); + when(tokenService.renewRefreshToken(validRefreshToken, httpServletResponse)).thenReturn(expectedEmail); + // No need to mock generateAccessToken as it's void, we just verify it + + // Act + String actualEmail = authenticationService.refreshToken(httpServletRequest, httpServletResponse); + + // Assert + assertEquals(expectedEmail, actualEmail); + verify(tokenService).getRefreshTokenFromCookie(httpServletRequest); + verify(tokenService).renewRefreshToken(validRefreshToken, httpServletResponse); + verify(tokenService).generateAccessToken(expectedEmail, httpServletResponse); + } + + @Test + void refreshToken_shouldThrowValidationException_whenTokenIsInvalid() { + // Arrange + String invalidRefreshToken = "invalid-refresh-token"; + + when(tokenService.getRefreshTokenFromCookie(httpServletRequest)).thenReturn(invalidRefreshToken); + // Mock renewRefreshToken to throw the exception caught in the service method + when(tokenService.renewRefreshToken(invalidRefreshToken, httpServletResponse)) + .thenThrow(new IllegalArgumentException("Token invalid")); + + // Act & Assert + ValidationException exception = assertThrows(ValidationException.class, () -> { + authenticationService.refreshToken(httpServletRequest, httpServletResponse); + }); + + assertEquals("Validation error: Invalid refresh token.", + exception.getMessage()); + verify(tokenService).getRefreshTokenFromCookie(httpServletRequest); + verify(tokenService).renewRefreshToken(invalidRefreshToken, httpServletResponse); + // Verify generateAccessToken was NOT called in the failure case + verify(tokenService, never()).generateAccessToken(anyString(), any(HttpServletResponse.class)); + } +} \ No newline at end of file diff --git a/src/test/java/com/podzilla/auth/service/CustomUserDetailsServiceTest.java b/src/test/java/com/podzilla/auth/service/CustomUserDetailsServiceTest.java new file mode 100644 index 0000000..c411ed8 --- /dev/null +++ b/src/test/java/com/podzilla/auth/service/CustomUserDetailsServiceTest.java @@ -0,0 +1,149 @@ +package com.podzilla.auth.service; + +import com.podzilla.auth.dto.CustomUserDetails; +import com.podzilla.auth.exception.NotFoundException; +import com.podzilla.auth.exception.ValidationException; // Added import +import com.podzilla.auth.model.ERole; +import com.podzilla.auth.model.Role; +import com.podzilla.auth.model.User; +import com.podzilla.auth.repository.UserRepository; +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.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class CustomUserDetailsServiceTest { + + @Mock + private UserRepository userRepository; + + @InjectMocks + private CustomUserDetailsService customUserDetailsService; + + private User user; + private String userEmail; + private String userPassword; + + @BeforeEach + void setUp() { + userEmail = "test@example.com"; + userPassword = "encodedPassword"; + Role userRole = new Role(ERole.ROLE_USER); + Role adminRole = new Role(ERole.ROLE_ADMIN); + + Set roles = new HashSet<>(); + roles.add(userRole); + roles.add(adminRole); + + user = User.builder() + .id(1L) + .name("Test User") + .email(userEmail) + .password(userPassword) + .roles(roles) + .build(); + } + + @Test + void loadUserByUsername_shouldReturnUserDetails_whenUserExistsAndHasRoles() { + // Arrange + when(userRepository.findByEmail(userEmail)).thenReturn(Optional.of(user)); + + // Act + UserDetails userDetails = customUserDetailsService.loadUserByUsername(userEmail); + + // Assert + assertNotNull(userDetails); + assertEquals(userEmail, userDetails.getUsername()); + assertEquals(userPassword, userDetails.getPassword()); + assertNotNull(userDetails.getAuthorities()); + assertEquals(2, userDetails.getAuthorities().size()); // ROLE_USER and ROLE_ADMIN + + // Check specific authorities + Set expectedAuthorities = Set.of(ERole.ROLE_USER.name(), ERole.ROLE_ADMIN.name()); + Set actualAuthorities = userDetails.getAuthorities().stream() + .map(GrantedAuthority::getAuthority) + .collect(Collectors.toSet()); + assertEquals(expectedAuthorities, actualAuthorities); + + assertInstanceOf(CustomUserDetails.class, userDetails, "Should return an instance of CustomUserDetails"); + + verify(userRepository).findByEmail(userEmail); + } + + @Test + void loadUserByUsername_shouldThrowNotFoundException_whenUserDoesNotExist() { + // Arrange + String nonExistentEmail = "notfound@example.com"; + when(userRepository.findByEmail(nonExistentEmail)).thenReturn(Optional.empty()); + + // Act & Assert + NotFoundException exception = assertThrows(NotFoundException.class, () -> { + customUserDetailsService.loadUserByUsername(nonExistentEmail); + }); + + assertEquals("Not Found: " + nonExistentEmail + " not found.", + exception.getMessage()); + verify(userRepository).findByEmail(nonExistentEmail); + } + + @Test + void loadUserByUsername_shouldThrowValidationException_whenUserHasEmptyRoles() { + // Arrange + String emailWithNoRoles = "norole@example.com"; + User userWithNoRoles = User.builder() + .id(2L) + .name("No Role User") + .email(emailWithNoRoles) + .password("password123") + .roles(Collections.emptySet()) // Empty roles set + .build(); + when(userRepository.findByEmail(emailWithNoRoles)).thenReturn(Optional.of(userWithNoRoles)); + + // Act & Assert + ValidationException exception = assertThrows(ValidationException.class, () -> { + customUserDetailsService.loadUserByUsername(emailWithNoRoles); + }); + + assertEquals("Validation error: User has no roles assigned.", + exception.getMessage()); + verify(userRepository).findByEmail(emailWithNoRoles); + } + + @Test + void loadUserByUsername_shouldThrowValidationException_whenUserHasNullRoles() { + // Arrange + String emailWithNullRoles = "nullrole@example.com"; + User userWithNullRoles = User.builder() + .id(3L) + .name("Null Role User") + .email(emailWithNullRoles) + .password("password456") + .roles(null) // Null roles set + .build(); + when(userRepository.findByEmail(emailWithNullRoles)).thenReturn(Optional.of(userWithNullRoles)); + + // Act & Assert + ValidationException exception = assertThrows(ValidationException.class, () -> { + customUserDetailsService.loadUserByUsername(emailWithNullRoles); + }); + + assertEquals("Validation error: User has no roles assigned.", + exception.getMessage()); + verify(userRepository).findByEmail(emailWithNullRoles); + } +} \ No newline at end of file diff --git a/src/test/java/com/podzilla/auth/service/TokenServiceTest.java b/src/test/java/com/podzilla/auth/service/TokenServiceTest.java new file mode 100644 index 0000000..c67c256 --- /dev/null +++ b/src/test/java/com/podzilla/auth/service/TokenServiceTest.java @@ -0,0 +1,487 @@ +package com.podzilla.auth.service; + +import com.podzilla.auth.exception.ValidationException; +import com.podzilla.auth.model.RefreshToken; +import com.podzilla.auth.model.User; +import com.podzilla.auth.repository.RefreshTokenRepository; +import com.podzilla.auth.repository.UserRepository; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.web.util.WebUtils; + + +import javax.crypto.SecretKey; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Date; +import java.util.Optional; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class TokenServiceTest { + + @Mock + private UserRepository userRepository; + + @Mock + private RefreshTokenRepository refreshTokenRepository; + + @Mock + private HttpServletResponse response; + + @Mock + private HttpServletRequest request; + + // Use InjectMocks to automatically inject the mocked dependencies + @InjectMocks + private TokenService tokenService; + + // Test data + private final String testEmail = "test@example.com"; + private final String testSecret = "testSecretKeyForJwtTokenGenerationWhichIsVeryLongAndSecure"; // Use a valid Base64 encoded key if possible + private final Long testUserId = 115642L; + private final UUID testRefreshTokenId = UUID.randomUUID(); + + @BeforeEach + void setUp() { + // Use ReflectionTestUtils to set the private @Value fields + ReflectionTestUtils.setField(tokenService, "secret", testSecret); + Long testJwtExpiresMinutes = 30L; + ReflectionTestUtils.setField(tokenService, "jwtExpiresMinutes", testJwtExpiresMinutes); + // Reset claims if needed between tests (though it's mostly set during validation) + ReflectionTestUtils.setField(tokenService, "claims", null); + } + + @Test + @DisplayName("Should generate access token and add cookie") + void generateAccessToken_ShouldAddCookie() { + // Arrange + ArgumentCaptor cookieCaptor = ArgumentCaptor.forClass(Cookie.class); + + // Act + tokenService.generateAccessToken(testEmail, response); + + // Assert + verify(response).addCookie(cookieCaptor.capture()); + Cookie addedCookie = cookieCaptor.getValue(); + + assertNotNull(addedCookie); + assertEquals("accessToken", addedCookie.getName()); + assertTrue(addedCookie.isHttpOnly()); + assertTrue(addedCookie.getSecure()); + assertEquals("/", addedCookie.getPath()); // Check path + assertEquals(60 * 30, addedCookie.getMaxAge()); // Check expiration + + // Optionally, validate the JWT content (requires parsing logic similar to validateAccessToken) + assertNotNull(addedCookie.getValue()); + // You could add more detailed JWT validation if needed + } + + @Test + @DisplayName("Should generate new refresh token if none exists") + void generateRefreshToken_WhenNoneExists_ShouldCreateNewAndAddCookie() { + // Arrange + User user = User.builder().id(testUserId).email(testEmail).build(); + when(userRepository.findByEmail(testEmail)).thenReturn(Optional.of(user)); + when(refreshTokenRepository.findByUserIdAndExpiresAtAfter(eq(testUserId), any(Instant.class))) + .thenReturn(Optional.empty()); // No existing valid token + when(refreshTokenRepository.save(any(RefreshToken.class))) + .thenAnswer(invocation -> { + RefreshToken token = invocation.getArgument(0); + token.setId(testRefreshTokenId); + return token; + }); // Mock save to return the + // token itself + + ArgumentCaptor refreshTokenCaptor = ArgumentCaptor.forClass(RefreshToken.class); + ArgumentCaptor cookieCaptor = ArgumentCaptor.forClass(Cookie.class); + + // Act + tokenService.generateRefreshToken(testEmail, response); + + // Assert + verify(refreshTokenRepository).save(refreshTokenCaptor.capture()); + RefreshToken savedToken = refreshTokenCaptor.getValue(); + assertNotNull(savedToken); + assertEquals(user, savedToken.getUser()); + assertNotNull(savedToken.getCreatedAt()); + assertNotNull(savedToken.getExpiresAt()); + assertTrue(savedToken.getExpiresAt().isAfter(Instant.now())); + + verify(response).addCookie(cookieCaptor.capture()); + Cookie addedCookie = cookieCaptor.getValue(); + assertNotNull(addedCookie); + assertEquals("refreshToken", addedCookie.getName()); + assertEquals(savedToken.getId().toString(), addedCookie.getValue()); // Verify token value in cookie + assertTrue(addedCookie.isHttpOnly()); + assertTrue(addedCookie.getSecure()); + assertEquals("/api/auth/refresh-token", addedCookie.getPath()); // Check specific path + assertTrue(addedCookie.getMaxAge() > 0); // Check expiration + } + + @Test + @DisplayName("Should use existing refresh token if valid one exists") + void generateRefreshToken_WhenValidExists_ShouldUseExistingAndAddCookie() { + // Arrange + User user = User.builder().id(testUserId).email(testEmail).build(); + RefreshToken existingToken = RefreshToken.builder() + .id(testRefreshTokenId) + .user(user) + .createdAt(Instant.now().minus(1, ChronoUnit.DAYS)) + .expiresAt(Instant.now().plus(5, ChronoUnit.DAYS)) // Still valid + .build(); + + when(userRepository.findByEmail(testEmail)).thenReturn(Optional.of(user)); + when(refreshTokenRepository.findByUserIdAndExpiresAtAfter(eq(testUserId), any(Instant.class))) + .thenReturn(Optional.of(existingToken)); + + ArgumentCaptor cookieCaptor = ArgumentCaptor.forClass(Cookie.class); + + // Act + tokenService.generateRefreshToken(testEmail, response); + + // Assert + verify(refreshTokenRepository, never()).save(any(RefreshToken.class)); // Should not save a new one + + verify(response).addCookie(cookieCaptor.capture()); + Cookie addedCookie = cookieCaptor.getValue(); + assertNotNull(addedCookie); + assertEquals("refreshToken", addedCookie.getName()); + assertEquals(existingToken.getId().toString(), addedCookie.getValue()); // Uses existing token ID + assertTrue(addedCookie.isHttpOnly()); + assertTrue(addedCookie.getSecure()); + assertEquals("/api/auth/refresh-token", addedCookie.getPath()); + } + + + @Test + @DisplayName("Should throw ValidationException if user not found during refresh token generation") + void generateRefreshToken_WhenUserNotFound_ShouldThrowValidationException() { + // Arrange + when(userRepository.findByEmail(testEmail)).thenReturn(Optional.empty()); + + // Act & Assert + ValidationException exception = assertThrows(ValidationException.class, () -> { + tokenService.generateRefreshToken(testEmail, response); + }); + assertEquals("Validation error: User not found", + exception.getMessage()); + verify(refreshTokenRepository, never()).save(any()); + verify(response, never()).addCookie(any()); + } + + + @Test + @DisplayName("Should renew refresh token successfully") + void renewRefreshToken_ValidToken_ShouldExpireOldCreateNewAddCookieAndReturnEmail() { + // Arrange + User user = User.builder().id(testUserId).email(testEmail).build(); + RefreshToken oldToken = RefreshToken.builder() + .id(testRefreshTokenId) + .user(user) + .createdAt(Instant.now().minus(1, ChronoUnit.DAYS)) + .expiresAt(Instant.now().plus(5, ChronoUnit.DAYS)) + .build(); + String oldTokenString = oldToken.getId().toString(); + + when(refreshTokenRepository.findByIdAndExpiresAtAfter(eq(testRefreshTokenId), any(Instant.class))) + .thenReturn(Optional.of(oldToken)); + when(refreshTokenRepository.save(any(RefreshToken.class))) + .thenAnswer(invocation -> { + RefreshToken token = invocation.getArgument(0); + token.setId(UUID.randomUUID()); + return token; + }); // Mock save to return the token itself + + ArgumentCaptor refreshTokenCaptor = ArgumentCaptor.forClass(RefreshToken.class); + ArgumentCaptor cookieCaptor = ArgumentCaptor.forClass(Cookie.class); + + // Act + String resultEmail = tokenService.renewRefreshToken(oldTokenString, response); + + // Assert + assertEquals(testEmail, resultEmail); + + verify(refreshTokenRepository, times(2)).save(refreshTokenCaptor.capture()); + RefreshToken expiredToken = refreshTokenCaptor.getAllValues().get(0); + RefreshToken newToken = refreshTokenCaptor.getAllValues().get(1); + + // Verify old token was expired (or set to expire immediately) + assertTrue(expiredToken.getExpiresAt().isBefore(Instant.now().plusSeconds(1))); // Check if expiration is set to now or very close + + // Verify new token details + assertNotEquals(oldToken.getId(), newToken.getId()); + assertEquals(user, newToken.getUser()); + assertTrue(newToken.getExpiresAt().isAfter(Instant.now())); + + // Verify cookie for the new token + verify(response).addCookie(cookieCaptor.capture()); + Cookie addedCookie = cookieCaptor.getValue(); + assertEquals("refreshToken", addedCookie.getName()); + assertEquals(newToken.getId().toString(), addedCookie.getValue()); + assertTrue(addedCookie.isHttpOnly()); + assertTrue(addedCookie.getSecure()); + assertEquals("/api/auth/refresh-token", addedCookie.getPath()); + } + + @Test + @DisplayName("Should throw ValidationException when renewing invalid refresh token") + void renewRefreshToken_InvalidToken_ShouldThrowValidationException() { + // Arrange + String invalidTokenString = UUID.randomUUID().toString(); + when(refreshTokenRepository.findByIdAndExpiresAtAfter(eq(UUID.fromString(invalidTokenString)), any(Instant.class))) + .thenReturn(Optional.empty()); + + // Act & Assert + ValidationException exception = assertThrows(ValidationException.class, () -> { + tokenService.renewRefreshToken(invalidTokenString, response); + }); + assertEquals("Validation error: Invalid refresh token", + exception.getMessage()); + verify(refreshTokenRepository, never()).save(any()); + verify(response, never()).addCookie(any()); + } + + @Test + @DisplayName("Should return access token from cookie") + void getAccessTokenFromCookie_WhenCookieExists_ShouldReturnTokenValue() { + // Arrange + String tokenValue = "dummyAccessToken"; + Cookie accessTokenCookie = new Cookie("accessToken", tokenValue); + // Static mocking for WebUtils (alternative: inject a mock WebUtils if preferred) + // Use a try-with-resources block for mocking static methods if using mockito-inline + try (var mockedStatic = mockStatic(WebUtils.class)) { + mockedStatic.when(() -> WebUtils.getCookie(request, "accessToken")).thenReturn(accessTokenCookie); + + // Act + String retrievedToken = tokenService.getAccessTokenFromCookie(request); + + // Assert + assertEquals(tokenValue, retrievedToken); + } + } + + @Test + @DisplayName("Should return null if access token cookie does not exist") + void getAccessTokenFromCookie_WhenCookieMissing_ShouldReturnNull() { + // Arrange + try (var mockedStatic = mockStatic(WebUtils.class)) { + mockedStatic.when(() -> WebUtils.getCookie(request, "accessToken")).thenReturn(null); + // Act + String retrievedToken = tokenService.getAccessTokenFromCookie(request); + + // Assert + assertNull(retrievedToken); + } + } + + // Similar tests for getRefreshTokenFromCookie... + + @Test + @DisplayName("Should validate a valid access token") + void validateAccessToken_ValidToken_ShouldNotThrow() { + // Arrange: Generate a valid token first + // Note: This relies on the internal generation logic using the test secret. + byte[] keyBytes = Decoders.BASE64.decode(testSecret); + SecretKey key = Keys.hmacShaKeyFor(keyBytes); + String validToken = Jwts.builder() + .subject(testEmail) + .issuedAt(new Date()) + .expiration(new Date(System.currentTimeMillis() + 1000 * 60 * 5)) // Expires in 5 mins + .signWith(key) + .compact(); + + // Act & Assert: Should not throw any exception + assertDoesNotThrow(() -> tokenService.validateAccessToken(validToken)); + + // Also assert that claims are set + Claims claims = (Claims) ReflectionTestUtils.getField(tokenService, "claims"); + assertNotNull(claims); + assertEquals(testEmail, claims.getSubject()); + } + + @Test + @DisplayName("Should throw ValidationException for invalid access token (expired)") + void validateAccessToken_ExpiredToken_ShouldThrowValidationException() { + // Arrange: Generate an expired token + SecretKey key = Keys.hmacShaKeyFor(testSecret.getBytes()); + String expiredToken = Jwts.builder() + .subject(testEmail) + .issuedAt(new Date(System.currentTimeMillis() - 1000 * 60 * 10)) // Issued 10 mins ago + .expiration(new Date(System.currentTimeMillis() - 1000 * 60 * 5)) // Expired 5 mins ago + .signWith(key) + .compact(); + + // Act & Assert + assertThrows(ValidationException.class, () -> { + tokenService.validateAccessToken(expiredToken); + }); + } + + @Test + @DisplayName("Should throw ValidationException for malformed access token") + void validateAccessToken_MalformedToken_ShouldThrowValidationException() { + // Arrange + String malformedToken = "this.is.not.a.valid.jwt"; + + // Act & Assert + ValidationException exception = assertThrows(ValidationException.class, () -> { + tokenService.validateAccessToken(malformedToken); + }); + // Check if the message indicates a JWT format issue + assertTrue(exception.getMessage().toLowerCase().contains("jwt")); + } + + @Test + @DisplayName("Should remove access token cookie") + void removeAccessTokenFromCookie_ShouldAddNullCookie() { + // Arrange + ArgumentCaptor cookieCaptor = ArgumentCaptor.forClass(Cookie.class); + + // Act + tokenService.removeAccessTokenFromCookie(response); + + // Assert + verify(response).addCookie(cookieCaptor.capture()); + Cookie addedCookie = cookieCaptor.getValue(); + + assertEquals("accessToken", addedCookie.getName()); + assertNull(addedCookie.getValue()); // Value should be null to remove + assertEquals("/", addedCookie.getPath()); + // MaxAge might be 0 or not set depending on exact removal strategy, check path mainly + } + + + // --- Tests for removeRefreshTokenFromCookieAndExpire --- + // This requires setting the 'claims' field first, as extractEmail depends on it. + + private void setupClaimsForEmailExtraction() { + // Helper to simulate that validateAccessToken was called successfully before + SecretKey key = Keys.hmacShaKeyFor(testSecret.getBytes()); + Claims claims = Jwts.claims().subject(testEmail).build(); + ReflectionTestUtils.setField(tokenService, "claims", claims); + } + + @Test + @DisplayName("Should remove refresh token cookie and expire token in DB") + void removeRefreshTokenFromCookieAndExpire_ValidState_ShouldPerformActions() { + // Arrange + setupClaimsForEmailExtraction(); // Simulate prior successful access token validation + + User user = User.builder().id(testUserId).email(testEmail).build(); + RefreshToken refreshToken = RefreshToken.builder() + .id(testRefreshTokenId) + .user(user) + .createdAt(Instant.now().minus(1, ChronoUnit.DAYS)) + .expiresAt(Instant.now().plus(5, ChronoUnit.DAYS)) + .build(); + + when(userRepository.findByEmail(testEmail)).thenReturn(Optional.of(user)); + when(refreshTokenRepository.findByUserIdAndExpiresAtAfter(eq(testUserId), any(Instant.class))) + .thenReturn(Optional.of(refreshToken)); + + ArgumentCaptor tokenCaptor = ArgumentCaptor.forClass(RefreshToken.class); + ArgumentCaptor cookieCaptor = ArgumentCaptor.forClass(Cookie.class); + + // Act + tokenService.removeRefreshTokenFromCookieAndExpire(response); + + // Assert + // 1. Verify token was expired + verify(refreshTokenRepository).save(tokenCaptor.capture()); + RefreshToken expiredToken = tokenCaptor.getValue(); + assertEquals(refreshToken.getId(), expiredToken.getId()); + assertTrue(expiredToken.getExpiresAt().isBefore(Instant.now().plusSeconds(1))); // Expired now + + // 2. Verify cookie was removed + verify(response).addCookie(cookieCaptor.capture()); + Cookie removedCookie = cookieCaptor.getValue(); + assertEquals("refreshToken", removedCookie.getName()); + assertNull(removedCookie.getValue()); + assertEquals("/api/auth/refresh-token", removedCookie.getPath()); + } + + @Test + @DisplayName("removeRefreshTokenFromCookieAndExpire should throw if user not found") + void removeRefreshTokenFromCookieAndExpire_UserNotFound_ShouldThrowValidationException() { + // Arrange + setupClaimsForEmailExtraction(); + when(userRepository.findByEmail(testEmail)).thenReturn(Optional.empty()); + + // Act & Assert + ValidationException exception = assertThrows(ValidationException.class, () -> { + tokenService.removeRefreshTokenFromCookieAndExpire(response); + }); + assertEquals("Validation error: User not found", + exception.getMessage()); + verify(refreshTokenRepository, never()).findByUserIdAndExpiresAtAfter(any(), any()); + verify(refreshTokenRepository, never()).save(any()); + verify(response, never()).addCookie(any()); + } + + @Test + @DisplayName("removeRefreshTokenFromCookieAndExpire should throw if refresh token not found") + void removeRefreshTokenFromCookieAndExpire_TokenNotFound_ShouldThrowValidationException() { + // Arrange + setupClaimsForEmailExtraction(); + User user = User.builder().id(testUserId).email(testEmail).build(); + + when(userRepository.findByEmail(testEmail)).thenReturn(Optional.of(user)); + when(refreshTokenRepository.findByUserIdAndExpiresAtAfter(eq(testUserId), any(Instant.class))) + .thenReturn(Optional.empty()); // Token not found + + // Act & Assert + ValidationException exception = assertThrows(ValidationException.class, () -> { + tokenService.removeRefreshTokenFromCookieAndExpire(response); + }); + assertEquals("Validation error: Refresh token not found", + exception.getMessage()); + verify(refreshTokenRepository, never()).save(any()); + verify(response, never()).addCookie(any()); + } + + + @Test + @DisplayName("Should extract email from claims") + void extractEmail_WhenClaimsSet_ShouldReturnSubject() { + // Arrange + setupClaimsForEmailExtraction(); // Sets claims with testEmail as subject + + // Act + String extractedEmail = tokenService.extractEmail(); + + // Assert + assertEquals(testEmail, extractedEmail); + } + + @Test + @DisplayName("extractEmail should throw NullPointerException if claims not set") + void extractEmail_WhenClaimsNull_ShouldThrowNullPointerException() { + // Arrange: claims field is null by default or after reset + + // Act & Assert + assertThrows(NullPointerException.class, () -> { + tokenService.extractEmail(); + }, "Expected NullPointerException because claims object is null"); + } +} \ No newline at end of file From 7d9ab5dedb1c4d5fe9e18868ed9cd834961a84d5 Mon Sep 17 00:00:00 2001 From: Nour Eldien Ayman Date: Thu, 1 May 2025 13:09:52 +0300 Subject: [PATCH 2/5] Validate role existence before assigning to account in AuthenticationService --- .../auth/service/AuthenticationService.java | 7 ++++++- .../service/AuthenticationServiceTest.java | 18 ++++++------------ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/podzilla/auth/service/AuthenticationService.java b/src/main/java/com/podzilla/auth/service/AuthenticationService.java index 504982f..9f3a93a 100644 --- a/src/main/java/com/podzilla/auth/service/AuthenticationService.java +++ b/src/main/java/com/podzilla/auth/service/AuthenticationService.java @@ -93,7 +93,12 @@ public void registerAccount(final SignupRequest signupRequest) { signupRequest.getPassword())) .build(); Role role = roleRepository.findByErole(ERole.ROLE_USER).orElse(null); - account.setRoles(role != null ? Collections.singleton(role) : null); + + if (role == null) { + throw new ValidationException("Role_USER not found."); + } + + account.setRoles(Collections.singleton(role)); userRepository.save(account); } diff --git a/src/test/java/com/podzilla/auth/service/AuthenticationServiceTest.java b/src/test/java/com/podzilla/auth/service/AuthenticationServiceTest.java index d5b6da3..dd04c4e 100644 --- a/src/test/java/com/podzilla/auth/service/AuthenticationServiceTest.java +++ b/src/test/java/com/podzilla/auth/service/AuthenticationServiceTest.java @@ -151,25 +151,19 @@ void registerAccount_shouldHandleRoleNotFoundGracefully() { when(userRepository.existsByEmail(signupRequest.getEmail())).thenReturn(false); when(passwordEncoder.encode(signupRequest.getPassword())).thenReturn("encodedPassword"); when(roleRepository.findByErole(ERole.ROLE_USER)).thenReturn(Optional.empty()); // Role not found - when(userRepository.save(any(User.class))).thenReturn(user); // Act - authenticationService.registerAccount(signupRequest); + ValidationException exception = assertThrows(ValidationException.class, () -> { + authenticationService.registerAccount(signupRequest); + }); + + assertEquals("Validation error: Role_USER not found.", + exception.getMessage()); // Assert verify(userRepository).existsByEmail(signupRequest.getEmail()); verify(passwordEncoder).encode(signupRequest.getPassword()); verify(roleRepository).findByErole(ERole.ROLE_USER); - - ArgumentCaptor userCaptor = ArgumentCaptor.forClass(User.class); - verify(userRepository).save(userCaptor.capture()); - User savedUser = userCaptor.getValue(); - - // Check that roles are empty or null as expected when role isn't found - assertTrue(savedUser.getRoles() == null || savedUser.getRoles().isEmpty()); - assertEquals(signupRequest.getName(), savedUser.getName()); - assertEquals(signupRequest.getEmail(), savedUser.getEmail()); - assertEquals("encodedPassword", savedUser.getPassword()); } From 794a650a58dcdce97209f31056ff180400b58a57 Mon Sep 17 00:00:00 2001 From: Nour Eldien Ayman Date: Thu, 1 May 2025 13:19:26 +0300 Subject: [PATCH 3/5] test --- .../java/com/podzilla/auth/service/TokenServiceTest.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/podzilla/auth/service/TokenServiceTest.java b/src/test/java/com/podzilla/auth/service/TokenServiceTest.java index c67c256..7dd049b 100644 --- a/src/test/java/com/podzilla/auth/service/TokenServiceTest.java +++ b/src/test/java/com/podzilla/auth/service/TokenServiceTest.java @@ -148,7 +148,8 @@ void generateRefreshToken_WhenValidExists_ShouldUseExistingAndAddCookie() { .id(testRefreshTokenId) .user(user) .createdAt(Instant.now().minus(1, ChronoUnit.DAYS)) - .expiresAt(Instant.now().plus(5, ChronoUnit.DAYS)) // Still valid + .expiresAt(Instant.now().plus(50, ChronoUnit.DAYS)) // Still + // valid .build(); when(userRepository.findByEmail(testEmail)).thenReturn(Optional.of(user)); @@ -199,7 +200,7 @@ void renewRefreshToken_ValidToken_ShouldExpireOldCreateNewAddCookieAndReturnEmai RefreshToken oldToken = RefreshToken.builder() .id(testRefreshTokenId) .user(user) - .createdAt(Instant.now().minus(1, ChronoUnit.DAYS)) + .createdAt(Instant.now().minus(10, ChronoUnit.DAYS)) .expiresAt(Instant.now().plus(5, ChronoUnit.DAYS)) .build(); String oldTokenString = oldToken.getId().toString(); @@ -392,8 +393,8 @@ void removeRefreshTokenFromCookieAndExpire_ValidState_ShouldPerformActions() { RefreshToken refreshToken = RefreshToken.builder() .id(testRefreshTokenId) .user(user) - .createdAt(Instant.now().minus(1, ChronoUnit.DAYS)) - .expiresAt(Instant.now().plus(5, ChronoUnit.DAYS)) + .createdAt(Instant.now().minus(7, ChronoUnit.DAYS)) + .expiresAt(Instant.now().plus(60, ChronoUnit.DAYS)) .build(); when(userRepository.findByEmail(testEmail)).thenReturn(Optional.of(user)); From 138152047b57cbf8055c22dcacf08187b31f208f Mon Sep 17 00:00:00 2001 From: Nour Eldien Ayman Date: Thu, 1 May 2025 13:26:27 +0300 Subject: [PATCH 4/5] check linter --- src/test/java/com/podzilla/auth/service/TokenServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/podzilla/auth/service/TokenServiceTest.java b/src/test/java/com/podzilla/auth/service/TokenServiceTest.java index 7dd049b..46c80f3 100644 --- a/src/test/java/com/podzilla/auth/service/TokenServiceTest.java +++ b/src/test/java/com/podzilla/auth/service/TokenServiceTest.java @@ -394,7 +394,7 @@ void removeRefreshTokenFromCookieAndExpire_ValidState_ShouldPerformActions() { .id(testRefreshTokenId) .user(user) .createdAt(Instant.now().minus(7, ChronoUnit.DAYS)) - .expiresAt(Instant.now().plus(60, ChronoUnit.DAYS)) + .expiresAt(Instant.now().plus(21, ChronoUnit.DAYS)) .build(); when(userRepository.findByEmail(testEmail)).thenReturn(Optional.of(user)); From 97b533540ca9ac15022a122dda59ecde38f4da56 Mon Sep 17 00:00:00 2001 From: Nour Eldien Ayman Date: Thu, 1 May 2025 13:38:38 +0300 Subject: [PATCH 5/5] try linter --- src/test/java/com/podzilla/auth/service/TokenServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/podzilla/auth/service/TokenServiceTest.java b/src/test/java/com/podzilla/auth/service/TokenServiceTest.java index 46c80f3..980d619 100644 --- a/src/test/java/com/podzilla/auth/service/TokenServiceTest.java +++ b/src/test/java/com/podzilla/auth/service/TokenServiceTest.java @@ -148,7 +148,7 @@ void generateRefreshToken_WhenValidExists_ShouldUseExistingAndAddCookie() { .id(testRefreshTokenId) .user(user) .createdAt(Instant.now().minus(1, ChronoUnit.DAYS)) - .expiresAt(Instant.now().plus(50, ChronoUnit.DAYS)) // Still + .expiresAt(Instant.now().plus(51, ChronoUnit.DAYS)) // Still // valid .build();