package com.danielbohry.authservice.service.auth; import com.danielbohry.authservice.api.dto.AuthenticationRequest; import com.danielbohry.authservice.api.dto.AuthenticationResponse; import com.danielbohry.authservice.domain.ApplicationUser; import com.danielbohry.authservice.domain.Role; import com.danielbohry.authservice.service.user.UserService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; import java.time.Instant; import java.util.List; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.*; class AuthServiceTest { @Mock private UserService userService; @Mock private JwtService jwtService; @Mock private AuthenticationManager authenticationManager; @Mock private PasswordEncoder passwordEncoder; private AuthService authService; private ApplicationUser testUser; private Authentication testAuthentication; private AuthenticationRequest testRequest; @BeforeEach void setUp() { MockitoAnnotations.openMocks(this); authService = new AuthService(userService, jwtService, authenticationManager, passwordEncoder); testUser = ApplicationUser.builder() .id("user-id-123") .username("testuser") .password("encodedPassword") .email("test@example.com") .roles(List.of(Role.USER)) .active(true) .build(); testAuthentication = new Authentication( "jwt-token-123", Instant.now().plusSeconds(3600), "testuser", List.of("ROLE_USER") ); testRequest = new AuthenticationRequest("testuser", "password123"); } @Test void shouldLoadUserByUsername() { // given when(userService.findByUsername("testuser")).thenReturn(testUser); // when UserDetails result = authService.loadUserByUsername("testuser"); // then assertNotNull(result); assertEquals("testuser", result.getUsername()); assertEquals("encodedPassword", result.getPassword()); assertTrue(result.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_USER"))); verify(userService).findByUsername("testuser"); } @Test void shouldThrowExceptionForUnknownUser() { // given when(userService.findByUsername("unknown")).thenThrow(new RuntimeException("User not found")); // when/then assertThrows(RuntimeException.class, () -> authService.loadUserByUsername("unknown")); verify(userService).findByUsername("unknown"); } @Test void shouldRegisterNewUser() { // given when(passwordEncoder.encode("password123")).thenReturn("encodedPassword"); when(userService.create(any(ApplicationUser.class))).thenReturn(testUser); when(jwtService.generateToken(testUser)).thenReturn(testAuthentication); // when AuthenticationResponse result = authService.register(testRequest); // then assertNotNull(result); assertEquals("user-id-123", result.getId()); assertEquals("testuser", result.getUsername()); assertEquals("jwt-token-123", result.getToken()); assertEquals(testAuthentication.expirationDate(), result.getExpirationDate()); assertEquals(List.of("ROLE_USER"), result.getRoles()); verify(passwordEncoder).encode("password123"); verify(userService).create(any(ApplicationUser.class)); verify(jwtService).generateToken(testUser); } @Test void shouldAuthenticateValidUser() { // given when(userService.findByUsername("testuser")).thenReturn(testUser); when(jwtService.generateToken(testUser)).thenReturn(testAuthentication); // when AuthenticationResponse result = authService.authenticate(testRequest); // then assertNotNull(result); assertEquals("user-id-123", result.getId()); assertEquals("testuser", result.getUsername()); assertEquals("jwt-token-123", result.getToken()); assertEquals(testAuthentication.expirationDate(), result.getExpirationDate()); assertEquals(List.of("ROLE_USER"), result.getRoles()); verify(authenticationManager).authenticate(any(UsernamePasswordAuthenticationToken.class)); verify(userService).findByUsername("testuser"); verify(jwtService).generateToken(testUser); } @Test void shouldFailAuthenticationWithInvalidCredentials() { // given when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class))) .thenThrow(new RuntimeException("Bad credentials")); // when/then assertThrows(RuntimeException.class, () -> authService.authenticate(testRequest)); verify(authenticationManager).authenticate(any(UsernamePasswordAuthenticationToken.class)); verifyNoInteractions(userService); verifyNoInteractions(jwtService); } @Test void shouldChangePassword() { // given String userId = "user-id-123"; String currentPassword = "oldPassword"; String newPassword = "newPassword"; ApplicationUser updatedUser = ApplicationUser.builder() .id(userId) .username("testuser") .password("newEncodedPassword") .email("test@example.com") .roles(List.of(Role.USER)) .active(true) .build(); when(userService.changePassword(userId, currentPassword, newPassword, passwordEncoder)) .thenReturn(updatedUser); when(jwtService.generateToken(updatedUser)).thenReturn(testAuthentication); // when AuthenticationResponse result = authService.changePassword(userId, currentPassword, newPassword); // then assertNotNull(result); assertEquals("user-id-123", result.getId()); assertEquals("testuser", result.getUsername()); assertEquals("jwt-token-123", result.getToken()); assertEquals(testAuthentication.expirationDate(), result.getExpirationDate()); assertEquals(List.of("ROLE_USER"), result.getRoles()); verify(userService).changePassword(userId, currentPassword, newPassword, passwordEncoder); verify(jwtService).generateToken(updatedUser); } @Test void shouldBuildCorrectUserAuthorities() { // given ApplicationUser multiRoleUser = ApplicationUser.builder() .id("user-id-123") .username("admin") .password("encodedPassword") .email("admin@example.com") .roles(List.of(Role.ADMIN, Role.USER)) .active(true) .build(); when(userService.findByUsername("admin")).thenReturn(multiRoleUser); // when UserDetails result = authService.loadUserByUsername("admin"); // then assertNotNull(result); assertEquals(2, result.getAuthorities().size()); assertTrue(result.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_ADMIN"))); assertTrue(result.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_USER"))); } @Test void shouldEncodePasswordDuringRegistration() { // given when(passwordEncoder.encode("plainPassword")).thenReturn("encodedPassword123"); when(userService.create(any(ApplicationUser.class))).thenReturn(testUser); when(jwtService.generateToken(testUser)).thenReturn(testAuthentication); AuthenticationRequest request = new AuthenticationRequest("newuser", "plainPassword"); // when authService.register(request); // then verify(passwordEncoder).encode("plainPassword"); verify(userService).create(argThat(user -> "encodedPassword123".equals(user.getPassword()) && "newuser".equals(user.getUsername()) )); } @Test void shouldCreateUserWithDefaultUserRole() { // given when(passwordEncoder.encode(anyString())).thenReturn("encodedPassword"); when(userService.create(any(ApplicationUser.class))).thenReturn(testUser); when(jwtService.generateToken(testUser)).thenReturn(testAuthentication); // when authService.register(testRequest); // then verify(userService).create(argThat(user -> user.getRoles() == null || user.getRoles().isEmpty())); // Note: UserService.create sets default USER role internally } @Test void shouldCallAuthenticationManagerWithCorrectCredentials() { // given when(userService.findByUsername("testuser")).thenReturn(testUser); when(jwtService.generateToken(testUser)).thenReturn(testAuthentication); // when authService.authenticate(testRequest); // then verify(authenticationManager).authenticate(argThat(auth -> auth instanceof UsernamePasswordAuthenticationToken && "testuser".equals(auth.getName()) && "password123".equals(auth.getCredentials()) )); } }