Java‐based Identity Access module ‐ Test Files - Wiz-DevTech/prettygirllz GitHub Wiki
// src/test/java/com/wizdevtech/identityaccess/IdentityAccessApplicationTests.java
package com.wizdevtech.identityaccess;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
@SpringBootTest
@ActiveProfiles("test")
class IdentityAccessApplicationTests {
@Test
void contextLoads() {
// Verifies that the application context loads successfully
}
}
// src/test/java/com/wizdevtech/identityaccess/controller/AuthControllerTest.java
package com.wizdevtech.identityaccess.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wizdevtech.identityaccess.dto.AuthenticationRequest;
import com.wizdevtech.identityaccess.dto.AuthenticationResponse;
import com.wizdevtech.identityaccess.dto.RegistrationRequest;
import com.wizdevtech.identityaccess.model.User;
import com.wizdevtech.identityaccess.service.AuthenticationService;
import com.wizdevtech.identityaccess.service.JwtService;
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.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.test.web.servlet.MockMvc;
import java.util.Set;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@WebMvcTest(AuthController.class)
class AuthControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@MockBean
private AuthenticationService authService;
@MockBean
private JwtService jwtService;
private AuthenticationRequest validLoginRequest;
private RegistrationRequest validRegistrationRequest;
private AuthenticationResponse successResponse;
private User createdUser;
@BeforeEach
void setUp() {
validLoginRequest = new AuthenticationRequest("[email protected]", "password123");
validRegistrationRequest = new RegistrationRequest();
validRegistrationRequest.setEmail("[email protected]");
validRegistrationRequest.setPassword("securepass");
validRegistrationRequest.setRoles(Set.of("USER"));
createdUser = new User();
createdUser.setId(1L);
createdUser.setEmail("[email protected]");
createdUser.setRoles(Set.of("USER"));
successResponse = AuthenticationResponse.builder()
.token("jwt-token")
.id(1L)
.email("[email protected]")
.roles(Set.of("USER"))
.build();
}
@Test
void login_withValidCredentials_returnsToken() throws Exception {
// Arrange
when(authService.authenticate(any(AuthenticationRequest.class))).thenReturn(successResponse);
// Act & Assert
mockMvc.perform(post("/api/auth/login")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(validLoginRequest)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.token").value("jwt-token"))
.andExpect(jsonPath("$.id").value(1))
.andExpect(jsonPath("$.email").value("[email protected]"));
verify(authService, times(1)).authenticate(any(AuthenticationRequest.class));
}
@Test
void login_withInvalidCredentials_returns401() throws Exception {
// Arrange
when(authService.authenticate(any(AuthenticationRequest.class)))
.thenThrow(new BadCredentialsException("Invalid credentials"));
// Act & Assert
mockMvc.perform(post("/api/auth/login")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(validLoginRequest)))
.andExpect(status().isUnauthorized());
verify(authService, times(1)).authenticate(any(AuthenticationRequest.class));
}
@Test
void register_withValidData_returnsUserAndToken() throws Exception {
// Arrange
when(authService.createUser(any(User.class), anyString())).thenReturn(createdUser);
when(jwtService.generateToken(any(User.class))).thenReturn("jwt-token");
// Act & Assert
mockMvc.perform(post("/api/auth/register")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(validRegistrationRequest)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.token").exists())
.andExpect(jsonPath("$.email").value("[email protected]"));
verify(authService, times(1)).createUser(any(User.class), anyString());
verify(jwtService, times(1)).generateToken(any(User.class));
}
@Test
void validateToken_withValidToken_returnsTrue() throws Exception {
// Arrange
when(jwtService.extractAllClaims(anyString())).thenReturn(mock(Claims.class));
// Act & Assert
mockMvc.perform(post("/api/auth/validate")
.param("token", "valid-token"))
.andExpect(status().isOk())
.andExpect(content().string("true"));
verify(jwtService, times(1)).extractAllClaims(anyString());
}
@Test
void validateToken_withInvalidToken_returnsFalse() throws Exception {
// Arrange
doThrow(new JwtException("Invalid token")).when(jwtService).extractAllClaims(anyString());
// Act & Assert
mockMvc.perform(post("/api/auth/validate")
.param("token", "invalid-token"))
.andExpect(status().isOk())
.andExpect(content().string("false"));
verify(jwtService, times(1)).extractAllClaims(anyString());
}
}
// src/test/java/com/wizdevtech/identityaccess/service/AuthenticationServiceTest.java
package com.wizdevtech.identityaccess.service;
import com.wizdevtech.identityaccess.dto.AuthenticationRequest;
import com.wizdevtech.identityaccess.dto.AuthenticationResponse;
import com.wizdevtech.identityaccess.model.User;
import com.wizdevtech.identityaccess.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.authentication.BadCredentialsException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.util.Optional;
import java.util.Set;
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 UserRepository userRepository;
@Mock
private JwtService jwtService;
@Mock
private PasswordEncoder passwordEncoder;
@Mock
private EncryptionService encryptionService;
@InjectMocks
private AuthenticationService authService;
private User testUser;
private AuthenticationRequest loginRequest;
@BeforeEach
void setUp() {
testUser = new User();
testUser.setId(1L);
testUser.setEmail("[email protected]");
testUser.setPasswordHash("hashed_password");
testUser.setRoles(Set.of("USER"));
loginRequest = new AuthenticationRequest("[email protected]", "password123");
}
@Test
void authenticate_withValidCredentials_returnsToken() {
// Arrange
when(userRepository.findByEmail(anyString())).thenReturn(Optional.of(testUser));
when(passwordEncoder.matches(anyString(), anyString())).thenReturn(true);
when(jwtService.generateToken(any(User.class))).thenReturn("jwt-token");
// Act
AuthenticationResponse response = authService.authenticate(loginRequest);
// Assert
assertNotNull(response);
assertEquals("jwt-token", response.getToken());
assertEquals(testUser.getId(), response.getId());
assertEquals(testUser.getEmail(), response.getEmail());
assertEquals(testUser.getRoles(), response.getRoles());
verify(userRepository, times(1)).findByEmail("[email protected]");
verify(passwordEncoder, times(1)).matches("password123", "hashed_password");
verify(jwtService, times(1)).generateToken(testUser);
}
@Test
void authenticate_withNonExistentUser_throwsUsernameNotFoundException() {
// Arrange
when(userRepository.findByEmail(anyString())).thenReturn(Optional.empty());
// Act & Assert
assertThrows(UsernameNotFoundException.class, () -> {
authService.authenticate(loginRequest);
});
verify(userRepository, times(1)).findByEmail("[email protected]");
verify(passwordEncoder, never()).matches(anyString(), anyString());
verify(jwtService, never()).generateToken(any(User.class));
}
@Test
void authenticate_withInvalidPassword_throwsBadCredentialsException() {
// Arrange
when(userRepository.findByEmail(anyString())).thenReturn(Optional.of(testUser));
when(passwordEncoder.matches(anyString(), anyString())).thenReturn(false);
// Act & Assert
assertThrows(BadCredentialsException.class, () -> {
authService.authenticate(loginRequest);
});
verify(userRepository, times(1)).findByEmail("[email protected]");
verify(passwordEncoder, times(1)).matches("password123", "hashed_password");
verify(jwtService, never()).generateToken(any(User.class));
}
@Test
void createUser_withValidData_returnsCreatedUser() {
// Arrange
User newUser = new User();
newUser.setEmail("[email protected]");
newUser.setRoles(Set.of("USER"));
String rawPassword = "securepass";
String encryptedData = "encrypted_data";
String hashedPassword = "hashed_password";
when(userRepository.existsByEmail(anyString())).thenReturn(false);
when(passwordEncoder.encode(anyString())).thenReturn(hashedPassword);
when(encryptionService.encrypt(anyString())).thenReturn(encryptedData);
when(userRepository.save(any(User.class))).thenAnswer(invocation -> {
User savedUser = invocation.getArgument(0);
savedUser.setId(1L);
return savedUser;
});
// Set sensitive data
newUser.setSensitiveData("sensitive_info");
// Act
User result = authService.createUser(newUser, rawPassword);
// Assert
assertNotNull(result);
assertEquals(1L, result.getId());
assertEquals("[email protected]", result.getEmail());
assertEquals(hashedPassword, result.getPasswordHash());
assertEquals(encryptedData, result.getSensitiveData());
assertEquals(Set.of("USER"), result.getRoles());
verify(userRepository, times(1)).existsByEmail("[email protected]");
verify(passwordEncoder, times(1)).encode(rawPassword);
verify(encryptionService, times(1)).encrypt("sensitive_info");
verify(userRepository, times(1)).save(newUser);
}
@Test
void createUser_withExistingEmail_throwsIllegalArgumentException() {
// Arrange
User newUser = new User();
newUser.setEmail("[email protected]");
when(userRepository.existsByEmail("[email protected]")).thenReturn(true);
// Act & Assert
assertThrows(IllegalArgumentException.class, () -> {
authService.createUser(newUser, "password");
});
verify(userRepository, times(1)).existsByEmail("[email protected]");
verify(passwordEncoder, never()).encode(anyString());
verify(userRepository, never()).save(any(User.class));
}
}
// src/test/java/com/wizdevtech/identityaccess/service/JwtServiceTest.java
package com.wizdevtech.identityaccess.service;
import com.wizdevtech.identityaccess.model.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
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.junit.jupiter.MockitoExtension;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class JwtServiceTest {
@InjectMocks
private JwtService jwtService;
private User testUser;
private String validToken;
@BeforeEach
void setUp() {
// Set properties via reflection
ReflectionTestUtils.setField(jwtService, "jwtSecret", "testSecret01234567890123456789012345678901");
ReflectionTestUtils.setField(jwtService, "jwtExpiration", 3600000L); // 1 hour
ReflectionTestUtils.setField(jwtService, "issuer", "test-issuer");
// Create a test user
testUser = new User();
testUser.setId(1L);
testUser.setEmail("[email protected]");
testUser.setRoles(Set.of("USER"));
// Generate a valid token
validToken = jwtService.generateToken(testUser);
}
@Test
void generateToken_withValidUser_returnsJwtToken() {
// Act
String token = jwtService.generateToken(testUser);
// Assert
assertNotNull(token);
assertTrue(token.length() > 0);
// Verify token claims
Claims claims = jwtService.extractAllClaims(token);
assertEquals("1", claims.getSubject());
assertEquals("[email protected]", claims.get("email", String.class));
assertEquals("test-issuer", claims.getIssuer());
assertEquals(Set.of("USER"), claims.get("roles", Set.class));
// Verify expiration
assertTrue(claims.getExpiration().after(new Date()));
}
@Test
void validateToken_withValidTokenAndUser_returnsTrue() {
// Arrange
UserDetails userDetails = mock(UserDetails.class);
when(userDetails.getUsername()).thenReturn("1"); // User ID
// Act
boolean result = jwtService.validateToken(validToken, userDetails);
// Assert
assertTrue(result);
}
@Test
void validateToken_withExpiredToken_returnsFalse() {
// Arrange
// Create a token with very short expiration
ReflectionTestUtils.setField(jwtService, "jwtExpiration", 1L); // 1 millisecond
String expiredToken = jwtService.generateToken(testUser);
// Wait for token to expire
try {
Thread.sleep(10);
} catch (InterruptedException e) {
fail("Test interrupted");
}
UserDetails userDetails = mock(UserDetails.class);
when(userDetails.getUsername()).thenReturn("1");
// Act
boolean result = jwtService.validateToken(expiredToken, userDetails);
// Assert
assertFalse(result);
}
@Test
void validateToken_withInvalidSignature_throwsJwtException() {
// Arrange
String invalidToken = validToken.substring(0, validToken.length() - 5) + "12345";
UserDetails userDetails = mock(UserDetails.class);
// Act & Assert
assertThrows(JwtException.class, () -> {
jwtService.extractAllClaims(invalidToken);
});
}
@Test
void extractUsername_withValidToken_returnsSubject() {
// Act
String subject = jwtService.extractUsername(validToken);
// Assert
assertEquals("1", subject);
}
@Test
void extractExpiration_withValidToken_returnsExpirationDate() {
// Act
Date expiration = jwtService.extractExpiration(validToken);
// Assert
assertNotNull(expiration);
assertTrue(expiration.after(new Date()));
}
@Test
void extractClaim_withValidTokenAndClaimResolver_returnsClaimValue() {
// Act
String issuer = jwtService.extractClaim(validToken, Claims::getIssuer);
// Assert
assertEquals("test-issuer", issuer);
}
}
// src/test/java/com/wizdevtech/identityaccess/service/EncryptionServiceTest.java
package com.wizdevtech.identityaccess.service;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.*;
@ExtendWith(MockitoExtension.class)
class EncryptionServiceTest {
private EncryptionService encryptionService;
private final String validKey = "12345678901234567890123456789012"; // 32 chars
@BeforeEach
void setUp() {
encryptionService = new EncryptionService(validKey);
}
@Test
void constructor_withInvalidKeyLength_throwsIllegalArgumentException() {
// Arrange
String shortKey = "tooshort";
// Act & Assert
assertThrows(IllegalArgumentException.class, () -> {
new EncryptionService(shortKey);
});
}
@Test
void encrypt_withValidData_returnsEncryptedString() {
// Arrange
String plainText = "This is a secret message";
// Act
String encrypted = encryptionService.encrypt(plainText);
// Assert
assertNotNull(encrypted);
assertNotEquals(plainText, encrypted);
assertTrue(encrypted.contains(":"));
}
@Test
void encrypt_withNullData_returnsNull() {
// Act
String encrypted = encryptionService.encrypt(null);
// Assert
assertNull(encrypted);
}
@Test
void decrypt_withValidEncryptedData_returnsOriginalText() {
// Arrange
String plainText = "This is a secret message";
String encrypted = encryptionService.encrypt(plainText);
// Act
String decrypted = encryptionService.decrypt(encrypted);
// Assert
assertEquals(plainText, decrypted);
}
@Test
void decrypt_withNullData_returnsNull() {
// Act
String decrypted = encryptionService.decrypt(null);
// Assert
assertNull(decrypted);
}
@Test
void decrypt_withInvalidFormat_throwsRuntimeException() {
// Arrange
String invalidEncrypted = "not-valid-format";
// Act & Assert
assertThrows(RuntimeException.class, () -> {
encryptionService.decrypt(invalidEncrypted);
});
}
@Test
void encryptAndDecrypt_withLongText_worksCorrectly() {
// Arrange
StringBuilder longTextBuilder = new StringBuilder();
for (int i = 0; i < 1000; i++) {
longTextBuilder.append("This is a very long text that needs to be encrypted. ");
}
String longText = longTextBuilder.toString();
// Act
String encrypted = encryptionService.encrypt(longText);
String decrypted = encryptionService.decrypt(encrypted);
// Assert
assertEquals(longText, decrypted);
}
}
// src/test/java/com/wizdevtech/identityaccess/repository/UserRepositoryTest.java
package com.wizdevtech.identityaccess.repository;
import com.wizdevtech.identityaccess.model.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.ActiveProfiles;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.Optional;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.*;
@DataJpaTest
@ActiveProfiles("test")
@Testcontainers
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class UserRepositoryTest {
@Container
static PostgreSQLContainer<?> postgreSQLContainer = new PostgreSQLContainer<>("postgres:14")
.withDatabaseName("testdb")
.withUsername("test")
.withPassword("test");
@Autowired
private UserRepository userRepository;
@Test
void findByEmail_withExistingEmail_returnsUser() {
// Arrange
User user = new User();
user.setEmail("[email protected]");
user.setPasswordHash("hashedpassword");
user.setRoles(Set.of("USER"));
userRepository.save(user);
// Act
Optional<User> foundUser = userRepository.findByEmail("[email protected]");
// Assert
assertTrue(foundUser.isPresent());
assertEquals("[email protected]", foundUser.get().getEmail());
}
@Test
void findByEmail_withNonExistentEmail_returnsEmptyOptional() {
// Act
Optional<User> foundUser = userRepository.findByEmail("[email protected]");
// Assert
assertTrue(foundUser.isEmpty());
}
@Test
void existsByEmail_withExistingEmail_returnsTrue() {
// Arrange
User user = new User();
user.setEmail("[email protected]");
user.setPasswordHash("hashedpassword");
user.setRoles(Set.of("USER"));
userRepository.save(user);
// Act
boolean exists = userRepository.existsByEmail("[email protected]");
// Assert
assertTrue(exists);
}
@Test
void existsByEmail_withNonExistentEmail_returnsFalse() {
// Act
boolean exists = userRepository.existsByEmail("[email protected]");
// Assert
assertFalse(exists);
}
@Test
void save_withValidUser_persistsUserWithGeneratedId() {
// Arrange
User user = new User();
user.setEmail("[email protected]");
user.setPasswordHash("hashedpassword");
user.setSensitiveData("sensitive information");
user.setRoles(Set.of("USER", "ADMIN"));
// Act
User savedUser = userRepository.save(user);
// Assert
assertNotNull(savedUser.getId());
assertEquals("[email protected]", savedUser.getEmail());
assertEquals("hashedpassword", savedUser.getPasswordHash());
assertEquals("sensitive information", savedUser.getSensitiveData());
assertEquals(Set.of("USER", "ADMIN"), savedUser.getRoles());
assertNotNull(savedUser.getCreatedAt());
assertNotNull(savedUser.getUpdatedAt());
}
}
// src/test/java/com/wizdevtech/identityaccess/grpc/AuthServiceImplTest.java
package com.wizdevtech.identityaccess.grpc;
import com.wizdevtech.identityaccess.dto.AuthenticationRequest;
import com.wizdevtech.identityaccess.dto.AuthenticationResponse;
import com.wizdevtech.identityaccess.service.AuthenticationService;
import com.wizdevtech.identityaccess.service.JwtService;
import io.grpc.internal.testing.StreamRecorder;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
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.BadCredentialsException;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
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 AuthServiceImplTest {
@Mock
private AuthenticationService authService;
@Mock
private JwtService jwtService;
@InjectMocks
private AuthServiceImpl grpcAuthService;
private AuthenticationResponse authResponse;
private Claims mockClaims;
@BeforeEach
void setUp() {
authResponse = AuthenticationResponse.builder()
.token("test-token")
.id(1L)
.email("[email protected]")
.roles(Set.of("USER"))
.build();
mockClaims = mock(Claims.class);
}
@Test
void login_withValidCredentials_returnsSuccessResponse() throws Exception {
// Arrange
LoginRequest request = LoginRequest.newBuilder()
.setEmail("[email protected]")
.setPassword("password123")
.build();
StreamRecorder<LoginResponse> responseObserver = StreamRecorder.create();
when(authService.authenticate(any(AuthenticationRequest.class))).thenReturn(authResponse);
// Act
grpcAuthService.login(request, responseObserver);
// Assert
if (!responseObserver.awaitCompletion(5, TimeUnit.SECONDS)) {
fail("The call did not terminate in time");
}
assertNull(responseObserver.getError());
List<LoginResponse> results = responseObserver.getValues();
assertEquals(1, results.size());
LoginResponse response = results.get(0);
assertTrue(response.getSuccess());
assertEquals("test-token", response.getToken());
assertEquals(1, response.getUser().getId());
assertEquals("[email protected]", response.getUser().getEmail());
assertEquals(1, response.getUser().getRolesCount());
assertEquals("USER", response.getUser().getRoles(0));
verify(authService, times(1)).authenticate(any(AuthenticationRequest.class));
}
@Test
void login_withInvalidCredentials_returnsFailureResponse() throws Exception {
// Arrange
LoginRequest request = LoginRequest.newBuilder()
.setEmail("[email protected]")
.setPassword("wrongpass")
.build();
StreamRecorder<LoginResponse> responseObserver = StreamRecorder.create();
when(authService.authenticate(any(AuthenticationRequest.class)))
.thenThrow(new BadCredentialsException("Invalid credentials"));
// Act
grpcAuthService.login(request, responseObserver);
// Assert
if (!responseObserver.awaitCompletion(5, TimeUnit.SECONDS)) {
fail("The call did not terminate in time");
}
assertNull(responseObserver.getError());
List<LoginResponse> results = responseObserver.getValues();
assertEquals(1, results.size());
LoginResponse response = results.get(0);
assertFalse(response.getSuccess());
assertEquals("Invalid credentials", response.getMessage());
assertFalse(response.hasUser());
verify(authService, times(1)).authenticate(any(AuthenticationRequest.class));
}
@Test
void validateToken_withValidToken_returnsValidResponse() throws Exception {
// Arrange
ValidateTokenRequest request = ValidateTokenRequest.newBuilder()
.setToken("valid-token")
.build();
StreamRecorder<ValidateTokenResponse> responseObserver = StreamRecorder.create();
when(jwtService.extractAllClaims(anyString())).thenReturn(mockClaims);
when(jwtService.isTokenExpired(anyString())).thenReturn(false);
when(jwtService.extractUsername(anyString())).thenReturn("1");
when(mockClaims.get("email", String.class)).thenReturn("[email protected]");
when(mockClaims.get(eq("roles"), any())).thenReturn(List.of("USER"));
// Act
grpcAuthService.validateToken(request, responseObserver);
// Assert
if (!responseObserver.awaitCompletion(5, TimeUnit.SECONDS)) {
fail("The call did not terminate in time");
}
assertNull(responseObserver.getError());
List<ValidateTokenResponse> results = responseObserver.getValues();
assertEquals(1, results.size());
ValidateTokenResponse response = results.get(0);
assertTrue(response.getIsValid());
assertTrue(response.hasUser());
assertEquals(1, response.getUser().getId());
assertEquals("[email protected]", response.getUser().getEmail());
assertEquals(1, response.getUser().getRolesCount());
verify(jwtService, times(1)).extractAllClaims("valid-token");
verify(jwtService, times(1)).isTokenExpired("valid-token
## 5. gRPC Service Tests (continued)
```java
// src/test/java/com/wizdevtech/identityaccess/grpc/AuthServiceImplTest.java (continued)
verify(jwtService, times(1)).isTokenExpired("valid-token");
verify(jwtService, times(1)).extractUsername("valid-token");
}
@Test
void validateToken_withExpiredToken_returnsInvalidResponse() throws Exception {
// Arrange
ValidateTokenRequest request = ValidateTokenRequest.newBuilder()
.setToken("expired-token")
.build();
StreamRecorder<ValidateTokenResponse> responseObserver = StreamRecorder.create();
when(jwtService.extractAllClaims(anyString())).thenReturn(mockClaims);
when(jwtService.isTokenExpired(anyString())).thenReturn(true);
// Act
grpcAuthService.validateToken(request, responseObserver);
// Assert
if (!responseObserver.awaitCompletion(5, TimeUnit.SECONDS)) {
fail("The call did not terminate in time");
}
assertNull(responseObserver.getError());
List<ValidateTokenResponse> results = responseObserver.getValues();
assertEquals(1, results.size());
ValidateTokenResponse response = results.get(0);
assertFalse(response.getIsValid());
assertTrue(response.hasUser()); // Default empty user is present
assertEquals(0, response.getUser().getId()); // Default value
verify(jwtService, times(1)).extractAllClaims("expired-token");
verify(jwtService, times(1)).isTokenExpired("expired-token");
verify(jwtService, never()).extractUsername(anyString());
}
@Test
void validateToken_withInvalidToken_returnsInvalidResponse() throws Exception {
// Arrange
ValidateTokenRequest request = ValidateTokenRequest.newBuilder()
.setToken("invalid-token")
.build();
StreamRecorder<ValidateTokenResponse> responseObserver = StreamRecorder.create();
when(jwtService.extractAllClaims(anyString())).thenThrow(new JwtException("Invalid token"));
// Act
grpcAuthService.validateToken(request, responseObserver);
// Assert
if (!responseObserver.awaitCompletion(5, TimeUnit.SECONDS)) {
fail("The call did not terminate in time");
}
assertNull(responseObserver.getError());
List<ValidateTokenResponse> results = responseObserver.getValues();
assertEquals(1, results.size());
ValidateTokenResponse response = results.get(0);
assertFalse(response.getIsValid());
assertTrue(response.hasUser()); // Default empty user is present
verify(jwtService, times(1)).extractAllClaims("invalid-token");
verify(jwtService, never()).isTokenExpired(anyString());
}
}
// src/test/java/com/wizdevtech/identityaccess/security/JwtAuthenticationFilterTest.java
package com.wizdevtech.identityaccess.security;
import com.wizdevtech.identityaccess.service.JwtService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
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.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.core.context.SecurityContextHolder;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class JwtAuthenticationFilterTest {
@Mock
private JwtService jwtService;
@Mock
private HttpServletRequest request;
@Mock
private HttpServletResponse response;
@Mock
private FilterChain filterChain;
@InjectMocks
private JwtAuthenticationFilter jwtAuthFilter;
@BeforeEach
void setUp() {
SecurityContextHolder.clearContext();
}
@Test
void doFilterInternal_withNoAuthHeader_continuesFilterChain() throws ServletException, IOException {
// Arrange
when(request.getHeader("Authorization")).thenReturn(null);
// Act
jwtAuthFilter.doFilterInternal(request, response, filterChain);
// Assert
verify(filterChain, times(1)).doFilter(request, response);
verify(jwtService, never()).extractAllClaims(anyString());
assertNull(SecurityContextHolder.getContext().getAuthentication());
}
@Test
void doFilterInternal_withNonBearerAuthHeader_continuesFilterChain() throws ServletException, IOException {
// Arrange
when(request.getHeader("Authorization")).thenReturn("Basic abc123");
// Act
jwtAuthFilter.doFilterInternal(request, response, filterChain);
// Assert
verify(filterChain, times(1)).doFilter(request, response);
verify(jwtService, never()).extractAllClaims(anyString());
assertNull(SecurityContextHolder.getContext().getAuthentication());
}
@Test
void doFilterInternal_withValidToken_setsAuthentication() throws ServletException, IOException {
// Arrange
String token = "valid.jwt.token";
when(request.getHeader("Authorization")).thenReturn("Bearer " + token);
Map<String, Object> claims = new HashMap<>();
claims.put("roles", List.of("USER", "ADMIN"));
when(jwtService.extractAllClaims(token)).thenReturn(claims);
when(jwtService.isTokenExpired(token)).thenReturn(false);
when(jwtService.extractUsername(token)).thenReturn("1");
// Act
jwtAuthFilter.doFilterInternal(request, response, filterChain);
// Assert
verify(filterChain, times(1)).doFilter(request, response);
verify(jwtService, times(1)).extractAllClaims(token);
verify(jwtService, times(1)).isTokenExpired(token);
verify(jwtService, times(1)).extractUsername(token);
assertNotNull(SecurityContextHolder.getContext().getAuthentication());
assertEquals("1", SecurityContextHolder.getContext().getAuthentication().getPrincipal());
assertEquals(2, SecurityContextHolder.getContext().getAuthentication().getAuthorities().size());
}
@Test
void doFilterInternal_withExpiredToken_continuesFilterChainWithoutAuth() throws ServletException, IOException {
// Arrange
String token = "expired.jwt.token";
when(request.getHeader("Authorization")).thenReturn("Bearer " + token);
Map<String, Object> claims = new HashMap<>();
claims.put("roles", List.of("USER"));
when(jwtService.extractAllClaims(token)).thenReturn(claims);
when(jwtService.isTokenExpired(token)).thenReturn(true);
// Act
jwtAuthFilter.doFilterInternal(request, response, filterChain);
// Assert
verify(filterChain, times(1)).doFilter(request, response);
verify(jwtService, times(1)).extractAllClaims(token);
verify(jwtService, times(1)).isTokenExpired(token);
verify(jwtService, never()).extractUsername(anyString());
assertNull(SecurityContextHolder.getContext().getAuthentication());
}
@Test
void doFilterInternal_withInvalidToken_continuesFilterChainWithoutAuth() throws ServletException, IOException {
// Arrange
String token = "invalid.jwt.token";
when(request.getHeader("Authorization")).thenReturn("Bearer " + token);
when(jwtService.extractAllClaims(token)).thenThrow(new RuntimeException("Invalid token"));
// Act
jwtAuthFilter.doFilterInternal(request, response, filterChain);
// Assert
verify(filterChain, times(1)).doFilter(request, response);
verify(jwtService, times(1)).extractAllClaims(token);
verify(jwtService, never()).isTokenExpired(anyString());
verify(jwtService, never()).extractUsername(anyString());
assertNull(SecurityContextHolder.getContext().getAuthentication());
}
}
// src/test/java/com/wizdevtech/identityaccess/dto/AuthenticationRequestTest.java
package com.wizdevtech.identityaccess.dto;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.*;
class AuthenticationRequestTest {
private Validator validator;
@BeforeEach
void setUp() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
}
@Test
void validate_withValidData_noViolations() {
// Arrange
AuthenticationRequest request = new AuthenticationRequest("[email protected]", "password123");
// Act
Set<ConstraintViolation<AuthenticationRequest>> violations = validator.validate(request);
// Assert
assertTrue(violations.isEmpty());
}
@Test
void validate_withEmptyEmail_hasViolation() {
// Arrange
AuthenticationRequest request = new AuthenticationRequest("", "password123");
// Act
Set<ConstraintViolation<AuthenticationRequest>> violations = validator.validate(request);
// Assert
assertFalse(violations.isEmpty());
assertEquals(1, violations.size());
assertEquals("email", violations.iterator().next().getPropertyPath().toString());
}
@Test
void validate_withInvalidEmail_hasViolation() {
// Arrange
AuthenticationRequest request = new AuthenticationRequest("not-an-email", "password123");
// Act
Set<ConstraintViolation<AuthenticationRequest>> violations = validator.validate(request);
// Assert
assertFalse(violations.isEmpty());
assertEquals(1, violations.size());
assertEquals("email", violations.iterator().next().getPropertyPath().toString());
}
@Test
void validate_withEmptyPassword_hasViolation() {
// Arrange
AuthenticationRequest request = new AuthenticationRequest("[email protected]", "");
// Act
Set<ConstraintViolation<AuthenticationRequest>> violations = validator.validate(request);
// Assert
assertFalse(violations.isEmpty());
assertEquals(1, violations.size());
assertEquals("password", violations.iterator().next().getPropertyPath().toString());
}
@Test
void validate_withNullFields_hasViolations() {
// Arrange
AuthenticationRequest request = new AuthenticationRequest(null, null);
// Act
Set<ConstraintViolation<AuthenticationRequest>> violations = validator.validate(request);
// Assert
assertFalse(violations.isEmpty());
assertEquals(2, violations.size());
}
}
// src/test/java/com/wizdevtech/identityaccess/dto/RegistrationRequestTest.java
package com.wizdevtech.identityaccess.dto;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.*;
class RegistrationRequestTest {
private Validator validator;
@BeforeEach
void setUp() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
}
@Test
void validate_withValidData_noViolations() {
// Arrange
RegistrationRequest request = new RegistrationRequest();
request.setEmail("[email protected]");
request.setPassword("securePassword123");
request.setRoles(Set.of("USER"));
// Act
Set<ConstraintViolation<RegistrationRequest>> violations = validator.validate(request);
// Assert
assertTrue(violations.isEmpty());
}
@Test
void validate_withEmptyEmail_hasViolation() {
// Arrange
RegistrationRequest request = new RegistrationRequest();
request.setEmail("");
request.setPassword("securePassword123");
request.setRoles(Set.of("USER"));
// Act
Set<ConstraintViolation<RegistrationRequest>> violations = validator.validate(request);
// Assert
assertFalse(violations.isEmpty());
assertEquals(1, violations.size());
assertEquals("email", violations.iterator().next().getPropertyPath().toString());
}
@Test
void validate_withInvalidEmail_hasViolation() {
// Arrange
RegistrationRequest request = new RegistrationRequest();
request.setEmail("not-an-email");
request.setPassword("securePassword123");
request.setRoles(Set.of("USER"));
// Act
Set<ConstraintViolation<RegistrationRequest>> violations = validator.validate(request);
// Assert
assertFalse(violations.isEmpty());
assertEquals(1, violations.size());
assertEquals("email", violations.iterator().next().getPropertyPath().toString());
}
@Test
void validate_withShortPassword_hasViolation() {
// Arrange
RegistrationRequest request = new RegistrationRequest();
request.setEmail("[email protected]");
request.setPassword("short");
request.setRoles(Set.of("USER"));
// Act
Set<ConstraintViolation<RegistrationRequest>> violations = validator.validate(request);
// Assert
assertFalse(violations.isEmpty());
assertEquals(1, violations.size());
assertEquals("password", violations.iterator().next().getPropertyPath().toString());
}
@Test
void validate_withNullFields_hasViolations() {
// Arrange
RegistrationRequest request = new RegistrationRequest();
// Act
Set<ConstraintViolation<RegistrationRequest>> violations = validator.validate(request);
// Assert
assertFalse(violations.isEmpty());
assertEquals(2, violations.size()); // email and password are required
}
@Test
void validate_withEmptyRoles_isValid() {
// Arrange
RegistrationRequest request = new RegistrationRequest();
request.setEmail("[email protected]");
request.setPassword("securePassword123");
request.setRoles(Set.of()); // Empty set is valid
// Act
Set<ConstraintViolation<RegistrationRequest>> violations = validator.validate(request);
// Assert
assertTrue(violations.isEmpty());
}
}
// src/test/java/com/wizdevtech/identityaccess/integration/AuthenticationFlowIntegrationTest.java
package com.wizdevtech.identityaccess.integration;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wizdevtech.identityaccess.dto.AuthenticationRequest;
import com.wizdevtech.identityaccess.dto.RegistrationRequest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.Set;
import static org.hamcrest.Matchers.notNullValue;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
@Testcontainers
class AuthenticationFlowIntegrationTest {
@Container
static PostgreSQLContainer<?> postgreSQLContainer = new PostgreSQLContainer<>("postgres:14")
.withDatabaseName("testdb")
.withUsername("test")
.withPassword("test");
@DynamicPropertySource
static void registerPgProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url",
() -> String.format("jdbc:postgresql://localhost:%d/testdb",
postgreSQLContainer.getFirstMappedPort()));
registry.add("spring.datasource.username", () -> "test");
registry.add("spring.datasource.password", () -> "test");
}
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@Test
void fullAuthenticationFlow_registerAndLogin() throws Exception {
// 1. Register a new user
RegistrationRequest registrationRequest = new RegistrationRequest();
registrationRequest.setEmail("[email protected]");
registrationRequest.setPassword("SecurePassword123");
registrationRequest.setRoles(Set.of("USER"));
MvcResult registrationResult = mockMvc.perform(post("/api/auth/register")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(registrationRequest)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.token", notNullValue()))
.andExpect(jsonPath("$.email").value("[email protected]"))
.andExpect(jsonPath("$.roles[0]").value("USER"))
.andReturn();
// Extract token from registration response
String responseJson = registrationResult.getResponse().getContentAsString();
String token = objectMapper.readTree(responseJson).get("token").asText();
// 2. Validate the token
mockMvc.perform(post("/api/auth/validate")
.param("token", token))
.andExpect(status().isOk())
.andExpect(content().string("true"));
// 3. Log in with the created user
AuthenticationRequest loginRequest = new AuthenticationRequest(
"[email protected]", "SecurePassword123");
mockMvc.perform(post("/api/auth/login")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(loginRequest)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.token", notNullValue()))
.andExpect(jsonPath("$.email").value("[email protected]"));
// 4. Try invalid login
AuthenticationRequest invalidLoginRequest = new AuthenticationRequest(
"[email protected]", "WrongPassword");
mockMvc.perform(post("/api/auth/login")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(invalidLoginRequest)))
.andExpect(status().isUnauthorized());
}
@Test
void validateToken_withInvalidToken_returnsFalse() throws Exception {
mockMvc.perform(post("/api/auth/validate")
.param("token", "invalid.token.format"))
.andExpect(status().isOk())
.andExpect(content().string("false"));
}
}
// src/test/resources/application-test.yml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/testdb
username: test
password: test
driver-class-name: org.postgresql.Driver
jpa:
hibernate:
ddl-auto: create-drop
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
format_sql: true
show-sql: true
server:
port: 8081
grpc:
port: 9091
jwt:
secret: test_secret_key_for_testing_purposes_only_32
expiration: 3600000
issuer: test-identity-access
encryption:
key: test_encryption_key_for_tests_only_32
logging:
level:
org.springframework.security: DEBUG
com.wizdevtech: DEBUG
These comprehensive test files cover all the major components of the Java-based Identity Access module:
-
Unit Tests: Testing individual components in isolation
- Controller tests verify proper HTTP endpoint behavior
- Service tests ensure business logic works correctly
- Repository tests confirm data persistence operations
- DTO validation tests verify input validation
-
Integration Tests: Testing complete application flows
- End-to-end authentication flow (register, login, validate)
- Database interactions with TestContainers for PostgreSQL
-
Special Configuration:
- Test-specific application properties
- PostgreSQL test containers for real database testing
The tests follow established best practices:
- Proper use of mocks where appropriate
- Clear arrange-act-assert patterns
- Comprehensive assertions
- Proper test isolation
- Coverage of both success and failure scenarios
These tests will ensure that your Identity Access module is robust and reliable before deploying to production. They can also be integrated into your CI/CD pipeline to maintain quality as the codebase evolves.