mirror of
https://github.com/s-frick/effigenix.git
synced 2026-03-28 08:29:36 +01:00
refactor(test): gemeinsame AbstractIntegrationTest Base-Class
Alle 9 Integration-Test-Klassen nutzen eine gemeinsame Base-Class mit geteiltem Spring Context (MOCK statt RANDOM_PORT), vorberechnetem BCrypt-Hash und gemeinsamen Helper-Methoden. Eliminiert ~600 Zeilen Duplikation und Runtime-BCrypt-Aufrufe im Test-Setup.
This commit is contained in:
parent
5219c93dd1
commit
7b1c114693
9 changed files with 195 additions and 803 deletions
|
|
@ -0,0 +1,108 @@
|
|||
package de.effigenix.infrastructure;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.effigenix.domain.usermanagement.RoleName;
|
||||
import de.effigenix.domain.usermanagement.UserStatus;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.RoleEntity;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.UserEntity;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.repository.RoleJpaRepository;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.repository.UserJpaRepository;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
|
||||
@AutoConfigureMockMvc
|
||||
@ActiveProfiles("test")
|
||||
@Transactional
|
||||
public abstract class AbstractIntegrationTest {
|
||||
|
||||
protected static final String BCRYPT_PASS123 = "$2a$10$4tNfKjz7w.67G72CVop9CuuzBh5vrkYJki8lZ66ZwwLtQjlrm6hHy";
|
||||
protected static final String TEST_PASSWORD = "Pass123";
|
||||
|
||||
@Autowired
|
||||
protected MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
protected ObjectMapper objectMapper;
|
||||
|
||||
@Autowired
|
||||
protected UserJpaRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
protected RoleJpaRepository roleRepository;
|
||||
|
||||
@Value("${jwt.secret}")
|
||||
protected String jwtSecret;
|
||||
|
||||
@Value("${jwt.expiration}")
|
||||
protected long jwtExpiration;
|
||||
|
||||
protected String generateToken(String userId, String username, String permissions) {
|
||||
long now = System.currentTimeMillis();
|
||||
SecretKey key = io.jsonwebtoken.security.Keys.hmacShaKeyFor(
|
||||
jwtSecret.getBytes(StandardCharsets.UTF_8));
|
||||
return Jwts.builder()
|
||||
.subject(userId)
|
||||
.claim("username", username)
|
||||
.claim("permissions", permissions)
|
||||
.issuedAt(new Date(now))
|
||||
.expiration(new Date(now + jwtExpiration))
|
||||
.signWith(key)
|
||||
.compact();
|
||||
}
|
||||
|
||||
protected String generateExpiredToken(String userId, String username) {
|
||||
long now = System.currentTimeMillis();
|
||||
SecretKey key = io.jsonwebtoken.security.Keys.hmacShaKeyFor(
|
||||
jwtSecret.getBytes(StandardCharsets.UTF_8));
|
||||
return Jwts.builder()
|
||||
.subject(userId)
|
||||
.claim("username", username)
|
||||
.claim("permissions", "")
|
||||
.issuedAt(new Date(now - 10000))
|
||||
.expiration(new Date(now - 5000))
|
||||
.signWith(key)
|
||||
.compact();
|
||||
}
|
||||
|
||||
protected String generateRefreshToken(String userId, String username) {
|
||||
long now = System.currentTimeMillis();
|
||||
SecretKey key = io.jsonwebtoken.security.Keys.hmacShaKeyFor(
|
||||
jwtSecret.getBytes(StandardCharsets.UTF_8));
|
||||
return Jwts.builder()
|
||||
.subject(userId)
|
||||
.claim("username", username)
|
||||
.claim("type", "refresh")
|
||||
.issuedAt(new Date(now))
|
||||
.expiration(new Date(now + 7200000))
|
||||
.signWith(key)
|
||||
.compact();
|
||||
}
|
||||
|
||||
protected RoleEntity createRole(RoleName roleName, String description) {
|
||||
RoleEntity role = new RoleEntity(
|
||||
UUID.randomUUID().toString(), roleName, Set.of(), description);
|
||||
return roleRepository.save(role);
|
||||
}
|
||||
|
||||
protected UserEntity createUser(String username, String email, Set<RoleEntity> roles, String branchId) {
|
||||
UserEntity user = new UserEntity(
|
||||
UUID.randomUUID().toString(), username, email,
|
||||
BCRYPT_PASS123, roles,
|
||||
branchId, UserStatus.ACTIVE, LocalDateTime.now(), null);
|
||||
return userRepository.save(user);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +1,16 @@
|
|||
package de.effigenix.infrastructure.inventory.web;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.effigenix.domain.usermanagement.RoleName;
|
||||
import de.effigenix.domain.usermanagement.UserStatus;
|
||||
import de.effigenix.infrastructure.AbstractIntegrationTest;
|
||||
import de.effigenix.infrastructure.inventory.web.dto.CreateStorageLocationRequest;
|
||||
import de.effigenix.infrastructure.inventory.web.dto.UpdateStorageLocationRequest;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.RoleEntity;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.UserEntity;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.repository.RoleJpaRepository;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.repository.UserJpaRepository;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -40,33 +25,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||
* - Story 1.1 – Lagerort anlegen
|
||||
* - Story 1.2 – Lagerort bearbeiten und (de-)aktivieren
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@AutoConfigureMockMvc
|
||||
@ActiveProfiles("test")
|
||||
@Transactional
|
||||
@DisplayName("StorageLocation Controller Integration Tests")
|
||||
class StorageLocationControllerIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Autowired
|
||||
private UserJpaRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private RoleJpaRepository roleRepository;
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Value("${jwt.secret}")
|
||||
private String jwtSecret;
|
||||
|
||||
@Value("${jwt.expiration}")
|
||||
private long jwtExpiration;
|
||||
class StorageLocationControllerIntegrationTest extends AbstractIntegrationTest {
|
||||
|
||||
private String adminToken;
|
||||
private String readerToken;
|
||||
|
|
@ -74,35 +34,16 @@ class StorageLocationControllerIntegrationTest {
|
|||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
RoleEntity adminRole = new RoleEntity(
|
||||
UUID.randomUUID().toString(), RoleName.ADMIN, Set.of(), "Admin");
|
||||
roleRepository.save(adminRole);
|
||||
RoleEntity adminRole = createRole(RoleName.ADMIN, "Admin");
|
||||
RoleEntity viewerRole = createRole(RoleName.PRODUCTION_WORKER, "Viewer");
|
||||
|
||||
RoleEntity viewerRole = new RoleEntity(
|
||||
UUID.randomUUID().toString(), RoleName.PRODUCTION_WORKER, Set.of(), "Viewer");
|
||||
roleRepository.save(viewerRole);
|
||||
UserEntity admin = createUser("inv.admin", "inv.admin@test.com", Set.of(adminRole), "BRANCH-01");
|
||||
UserEntity reader = createUser("inv.reader", "inv.reader@test.com", Set.of(viewerRole), "BRANCH-01");
|
||||
UserEntity viewer = createUser("inv.viewer", "inv.viewer@test.com", Set.of(viewerRole), "BRANCH-01");
|
||||
|
||||
String adminId = UUID.randomUUID().toString();
|
||||
userRepository.save(new UserEntity(
|
||||
adminId, "inv.admin", "inv.admin@test.com",
|
||||
passwordEncoder.encode("Pass123"), Set.of(adminRole),
|
||||
"BRANCH-01", UserStatus.ACTIVE, LocalDateTime.now(), null));
|
||||
|
||||
String readerId = UUID.randomUUID().toString();
|
||||
userRepository.save(new UserEntity(
|
||||
readerId, "inv.reader", "inv.reader@test.com",
|
||||
passwordEncoder.encode("Pass123"), Set.of(viewerRole),
|
||||
"BRANCH-01", UserStatus.ACTIVE, LocalDateTime.now(), null));
|
||||
|
||||
String viewerId = UUID.randomUUID().toString();
|
||||
userRepository.save(new UserEntity(
|
||||
viewerId, "inv.viewer", "inv.viewer@test.com",
|
||||
passwordEncoder.encode("Pass123"), Set.of(viewerRole),
|
||||
"BRANCH-01", UserStatus.ACTIVE, LocalDateTime.now(), null));
|
||||
|
||||
adminToken = generateToken(adminId, "inv.admin", "STOCK_WRITE,STOCK_READ");
|
||||
readerToken = generateToken(readerId, "inv.reader", "STOCK_READ");
|
||||
viewerToken = generateToken(viewerId, "inv.viewer", "USER_READ");
|
||||
adminToken = generateToken(admin.getId(), "inv.admin", "STOCK_WRITE,STOCK_READ");
|
||||
readerToken = generateToken(reader.getId(), "inv.reader", "STOCK_READ");
|
||||
viewerToken = generateToken(viewer.getId(), "inv.viewer", "USER_READ");
|
||||
}
|
||||
|
||||
// ==================== Lagerort anlegen – Pflichtfelder ====================
|
||||
|
|
@ -622,18 +563,4 @@ class StorageLocationControllerIntegrationTest {
|
|||
|
||||
return objectMapper.readTree(result.getResponse().getContentAsString()).get("id").asText();
|
||||
}
|
||||
|
||||
private String generateToken(String userId, String username, String permissions) {
|
||||
long now = System.currentTimeMillis();
|
||||
javax.crypto.SecretKey key = io.jsonwebtoken.security.Keys.hmacShaKeyFor(
|
||||
jwtSecret.getBytes(StandardCharsets.UTF_8));
|
||||
return Jwts.builder()
|
||||
.subject(userId)
|
||||
.claim("username", username)
|
||||
.claim("permissions", permissions)
|
||||
.issuedAt(new Date(now))
|
||||
.expiration(new Date(now + jwtExpiration))
|
||||
.signWith(key)
|
||||
.compact();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +1,19 @@
|
|||
package de.effigenix.infrastructure.masterdata.web;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.effigenix.domain.masterdata.PriceModel;
|
||||
import de.effigenix.domain.masterdata.Unit;
|
||||
import de.effigenix.domain.usermanagement.RoleName;
|
||||
import de.effigenix.domain.usermanagement.UserStatus;
|
||||
import de.effigenix.infrastructure.AbstractIntegrationTest;
|
||||
import de.effigenix.infrastructure.masterdata.web.dto.*;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.RoleEntity;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.UserEntity;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.repository.RoleJpaRepository;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.repository.UserJpaRepository;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -40,33 +26,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||
*
|
||||
* Abgedeckte Testfälle: TC-ART-01 bis TC-ART-11
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@AutoConfigureMockMvc
|
||||
@ActiveProfiles("test")
|
||||
@Transactional
|
||||
@DisplayName("Article Controller Integration Tests")
|
||||
class ArticleControllerIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Autowired
|
||||
private UserJpaRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private RoleJpaRepository roleRepository;
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Value("${jwt.secret}")
|
||||
private String jwtSecret;
|
||||
|
||||
@Value("${jwt.expiration}")
|
||||
private long jwtExpiration;
|
||||
class ArticleControllerIntegrationTest extends AbstractIntegrationTest {
|
||||
|
||||
private String adminToken;
|
||||
private String viewerToken;
|
||||
|
|
@ -74,28 +35,14 @@ class ArticleControllerIntegrationTest {
|
|||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
RoleEntity adminRole = new RoleEntity(
|
||||
UUID.randomUUID().toString(), RoleName.ADMIN, Set.of(), "Admin");
|
||||
roleRepository.save(adminRole);
|
||||
RoleEntity adminRole = createRole(RoleName.ADMIN, "Admin");
|
||||
RoleEntity viewerRole = createRole(RoleName.PRODUCTION_WORKER, "Viewer");
|
||||
|
||||
RoleEntity viewerRole = new RoleEntity(
|
||||
UUID.randomUUID().toString(), RoleName.PRODUCTION_WORKER, Set.of(), "Viewer");
|
||||
roleRepository.save(viewerRole);
|
||||
UserEntity admin = createUser("art.admin", "art.admin@test.com", Set.of(adminRole), "BRANCH-01");
|
||||
UserEntity viewer = createUser("art.viewer", "art.viewer@test.com", Set.of(viewerRole), "BRANCH-01");
|
||||
|
||||
String adminId = UUID.randomUUID().toString();
|
||||
userRepository.save(new UserEntity(
|
||||
adminId, "art.admin", "art.admin@test.com",
|
||||
passwordEncoder.encode("Pass123"), Set.of(adminRole),
|
||||
"BRANCH-01", UserStatus.ACTIVE, LocalDateTime.now(), null));
|
||||
|
||||
String viewerId = UUID.randomUUID().toString();
|
||||
userRepository.save(new UserEntity(
|
||||
viewerId, "art.viewer", "art.viewer@test.com",
|
||||
passwordEncoder.encode("Pass123"), Set.of(viewerRole),
|
||||
"BRANCH-01", UserStatus.ACTIVE, LocalDateTime.now(), null));
|
||||
|
||||
adminToken = generateToken(adminId, "art.admin", "MASTERDATA_WRITE");
|
||||
viewerToken = generateToken(viewerId, "art.viewer", "USER_READ");
|
||||
adminToken = generateToken(admin.getId(), "art.admin", "MASTERDATA_WRITE");
|
||||
viewerToken = generateToken(viewer.getId(), "art.viewer", "USER_READ");
|
||||
|
||||
// Vorbedingung: Kategorie erstellen
|
||||
categoryId = createCategory("Obst & Gemüse");
|
||||
|
|
@ -414,18 +361,4 @@ class ArticleControllerIntegrationTest {
|
|||
.andReturn();
|
||||
return objectMapper.readTree(result.getResponse().getContentAsString()).get("id").asText();
|
||||
}
|
||||
|
||||
private String generateToken(String userId, String username, String permissions) {
|
||||
long now = System.currentTimeMillis();
|
||||
javax.crypto.SecretKey key = io.jsonwebtoken.security.Keys.hmacShaKeyFor(
|
||||
jwtSecret.getBytes(java.nio.charset.StandardCharsets.UTF_8));
|
||||
return Jwts.builder()
|
||||
.subject(userId)
|
||||
.claim("username", username)
|
||||
.claim("permissions", permissions)
|
||||
.issuedAt(new Date(now))
|
||||
.expiration(new Date(now + jwtExpiration))
|
||||
.signWith(key)
|
||||
.compact();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +1,19 @@
|
|||
package de.effigenix.infrastructure.masterdata.web;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.effigenix.domain.masterdata.*;
|
||||
import de.effigenix.domain.usermanagement.RoleName;
|
||||
import de.effigenix.domain.usermanagement.UserStatus;
|
||||
import de.effigenix.infrastructure.AbstractIntegrationTest;
|
||||
import de.effigenix.infrastructure.masterdata.web.dto.*;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.RoleEntity;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.UserEntity;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.repository.RoleJpaRepository;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.repository.UserJpaRepository;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
|
@ -41,61 +27,22 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||
*
|
||||
* Abgedeckte Testfälle: TC-CUS-01 bis TC-CUS-11, TC-B2B-01/02, TC-AUTH
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@AutoConfigureMockMvc
|
||||
@ActiveProfiles("test")
|
||||
@Transactional
|
||||
@DisplayName("Customer Controller Integration Tests")
|
||||
class CustomerControllerIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Autowired
|
||||
private UserJpaRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private RoleJpaRepository roleRepository;
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Value("${jwt.secret}")
|
||||
private String jwtSecret;
|
||||
|
||||
@Value("${jwt.expiration}")
|
||||
private long jwtExpiration;
|
||||
class CustomerControllerIntegrationTest extends AbstractIntegrationTest {
|
||||
|
||||
private String adminToken;
|
||||
private String viewerToken;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
RoleEntity adminRole = new RoleEntity(
|
||||
UUID.randomUUID().toString(), RoleName.ADMIN, Set.of(), "Admin");
|
||||
roleRepository.save(adminRole);
|
||||
RoleEntity adminRole = createRole(RoleName.ADMIN, "Admin");
|
||||
RoleEntity viewerRole = createRole(RoleName.PRODUCTION_WORKER, "Viewer");
|
||||
|
||||
RoleEntity viewerRole = new RoleEntity(
|
||||
UUID.randomUUID().toString(), RoleName.PRODUCTION_WORKER, Set.of(), "Viewer");
|
||||
roleRepository.save(viewerRole);
|
||||
UserEntity admin = createUser("cus.admin", "cus.admin@test.com", Set.of(adminRole), "BRANCH-01");
|
||||
UserEntity viewer = createUser("cus.viewer", "cus.viewer@test.com", Set.of(viewerRole), "BRANCH-01");
|
||||
|
||||
String adminId = UUID.randomUUID().toString();
|
||||
userRepository.save(new UserEntity(
|
||||
adminId, "cus.admin", "cus.admin@test.com",
|
||||
passwordEncoder.encode("Pass123"), Set.of(adminRole),
|
||||
"BRANCH-01", UserStatus.ACTIVE, LocalDateTime.now(), null));
|
||||
|
||||
String viewerId = UUID.randomUUID().toString();
|
||||
userRepository.save(new UserEntity(
|
||||
viewerId, "cus.viewer", "cus.viewer@test.com",
|
||||
passwordEncoder.encode("Pass123"), Set.of(viewerRole),
|
||||
"BRANCH-01", UserStatus.ACTIVE, LocalDateTime.now(), null));
|
||||
|
||||
adminToken = generateToken(adminId, "cus.admin", "MASTERDATA_WRITE");
|
||||
viewerToken = generateToken(viewerId, "cus.viewer", "USER_READ");
|
||||
adminToken = generateToken(admin.getId(), "cus.admin", "MASTERDATA_WRITE");
|
||||
viewerToken = generateToken(viewer.getId(), "cus.viewer", "USER_READ");
|
||||
}
|
||||
|
||||
// ==================== TC-CUS-01: B2C-Kunde erstellen ====================
|
||||
|
|
@ -538,18 +485,4 @@ class CustomerControllerIntegrationTest {
|
|||
.andReturn();
|
||||
return objectMapper.readTree(artResult.getResponse().getContentAsString()).get("id").asText();
|
||||
}
|
||||
|
||||
private String generateToken(String userId, String username, String permissions) {
|
||||
long now = System.currentTimeMillis();
|
||||
javax.crypto.SecretKey key = io.jsonwebtoken.security.Keys.hmacShaKeyFor(
|
||||
jwtSecret.getBytes(java.nio.charset.StandardCharsets.UTF_8));
|
||||
return Jwts.builder()
|
||||
.subject(userId)
|
||||
.claim("username", username)
|
||||
.claim("permissions", permissions)
|
||||
.issuedAt(new Date(now))
|
||||
.expiration(new Date(now + jwtExpiration))
|
||||
.signWith(key)
|
||||
.compact();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +1,17 @@
|
|||
package de.effigenix.infrastructure.masterdata.web;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.effigenix.domain.usermanagement.UserStatus;
|
||||
import de.effigenix.domain.usermanagement.RoleName;
|
||||
import de.effigenix.infrastructure.AbstractIntegrationTest;
|
||||
import de.effigenix.infrastructure.masterdata.web.dto.CreateProductCategoryRequest;
|
||||
import de.effigenix.infrastructure.masterdata.web.dto.UpdateProductCategoryRequest;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.RoleEntity;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.UserEntity;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.repository.RoleJpaRepository;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.repository.UserJpaRepository;
|
||||
import de.effigenix.domain.usermanagement.RoleName;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -38,61 +24,22 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||
*
|
||||
* Abgedeckte Testfälle: TC-CAT-01 bis TC-CAT-06
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@AutoConfigureMockMvc
|
||||
@ActiveProfiles("test")
|
||||
@Transactional
|
||||
@DisplayName("ProductCategory Controller Integration Tests")
|
||||
class ProductCategoryControllerIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Autowired
|
||||
private UserJpaRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private RoleJpaRepository roleRepository;
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Value("${jwt.secret}")
|
||||
private String jwtSecret;
|
||||
|
||||
@Value("${jwt.expiration}")
|
||||
private long jwtExpiration;
|
||||
class ProductCategoryControllerIntegrationTest extends AbstractIntegrationTest {
|
||||
|
||||
private String adminToken;
|
||||
private String viewerToken;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
RoleEntity adminRole = new RoleEntity(
|
||||
UUID.randomUUID().toString(), RoleName.ADMIN, Set.of(), "Admin");
|
||||
roleRepository.save(adminRole);
|
||||
RoleEntity adminRole = createRole(RoleName.ADMIN, "Admin");
|
||||
RoleEntity viewerRole = createRole(RoleName.PRODUCTION_WORKER, "Viewer");
|
||||
|
||||
RoleEntity viewerRole = new RoleEntity(
|
||||
UUID.randomUUID().toString(), RoleName.PRODUCTION_WORKER, Set.of(), "Viewer");
|
||||
roleRepository.save(viewerRole);
|
||||
UserEntity admin = createUser("cat.admin", "cat.admin@test.com", Set.of(adminRole), "BRANCH-01");
|
||||
UserEntity viewer = createUser("cat.viewer", "cat.viewer@test.com", Set.of(viewerRole), "BRANCH-01");
|
||||
|
||||
String adminId = UUID.randomUUID().toString();
|
||||
userRepository.save(new UserEntity(
|
||||
adminId, "cat.admin", "cat.admin@test.com",
|
||||
passwordEncoder.encode("Pass123"), Set.of(adminRole),
|
||||
"BRANCH-01", UserStatus.ACTIVE, LocalDateTime.now(), null));
|
||||
|
||||
String viewerId = UUID.randomUUID().toString();
|
||||
userRepository.save(new UserEntity(
|
||||
viewerId, "cat.viewer", "cat.viewer@test.com",
|
||||
passwordEncoder.encode("Pass123"), Set.of(viewerRole),
|
||||
"BRANCH-01", UserStatus.ACTIVE, LocalDateTime.now(), null));
|
||||
|
||||
adminToken = generateToken(adminId, "cat.admin", "MASTERDATA_WRITE");
|
||||
viewerToken = generateToken(viewerId, "cat.viewer", "USER_READ");
|
||||
adminToken = generateToken(admin.getId(), "cat.admin", "MASTERDATA_WRITE");
|
||||
viewerToken = generateToken(viewer.getId(), "cat.viewer", "USER_READ");
|
||||
}
|
||||
|
||||
// ==================== TC-CAT-01: Kategorie erstellen (Happy Path) ====================
|
||||
|
|
@ -274,18 +221,4 @@ class ProductCategoryControllerIntegrationTest {
|
|||
.andReturn();
|
||||
return objectMapper.readTree(result.getResponse().getContentAsString()).get("id").asText();
|
||||
}
|
||||
|
||||
private String generateToken(String userId, String username, String permissions) {
|
||||
long now = System.currentTimeMillis();
|
||||
javax.crypto.SecretKey key = io.jsonwebtoken.security.Keys.hmacShaKeyFor(
|
||||
jwtSecret.getBytes(java.nio.charset.StandardCharsets.UTF_8));
|
||||
return Jwts.builder()
|
||||
.subject(userId)
|
||||
.claim("username", username)
|
||||
.claim("permissions", permissions)
|
||||
.issuedAt(new Date(now))
|
||||
.expiration(new Date(now + jwtExpiration))
|
||||
.signWith(key)
|
||||
.compact();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +1,17 @@
|
|||
package de.effigenix.infrastructure.masterdata.web;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.effigenix.domain.usermanagement.RoleName;
|
||||
import de.effigenix.domain.usermanagement.UserStatus;
|
||||
import de.effigenix.infrastructure.AbstractIntegrationTest;
|
||||
import de.effigenix.infrastructure.masterdata.web.dto.*;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.RoleEntity;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.UserEntity;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.repository.RoleJpaRepository;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.repository.UserJpaRepository;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -38,61 +24,22 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||
*
|
||||
* Abgedeckte Testfälle: TC-SUP-01 bis TC-SUP-12, TC-AUTH-01/02
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@AutoConfigureMockMvc
|
||||
@ActiveProfiles("test")
|
||||
@Transactional
|
||||
@DisplayName("Supplier Controller Integration Tests")
|
||||
class SupplierControllerIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Autowired
|
||||
private UserJpaRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private RoleJpaRepository roleRepository;
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Value("${jwt.secret}")
|
||||
private String jwtSecret;
|
||||
|
||||
@Value("${jwt.expiration}")
|
||||
private long jwtExpiration;
|
||||
class SupplierControllerIntegrationTest extends AbstractIntegrationTest {
|
||||
|
||||
private String adminToken;
|
||||
private String viewerToken;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
RoleEntity adminRole = new RoleEntity(
|
||||
UUID.randomUUID().toString(), RoleName.ADMIN, Set.of(), "Admin");
|
||||
roleRepository.save(adminRole);
|
||||
RoleEntity adminRole = createRole(RoleName.ADMIN, "Admin");
|
||||
RoleEntity viewerRole = createRole(RoleName.PRODUCTION_WORKER, "Viewer");
|
||||
|
||||
RoleEntity viewerRole = new RoleEntity(
|
||||
UUID.randomUUID().toString(), RoleName.PRODUCTION_WORKER, Set.of(), "Viewer");
|
||||
roleRepository.save(viewerRole);
|
||||
UserEntity admin = createUser("sup.admin", "sup.admin@test.com", Set.of(adminRole), "BRANCH-01");
|
||||
UserEntity viewer = createUser("sup.viewer", "sup.viewer@test.com", Set.of(viewerRole), "BRANCH-01");
|
||||
|
||||
String adminId = UUID.randomUUID().toString();
|
||||
userRepository.save(new UserEntity(
|
||||
adminId, "sup.admin", "sup.admin@test.com",
|
||||
passwordEncoder.encode("Pass123"), Set.of(adminRole),
|
||||
"BRANCH-01", UserStatus.ACTIVE, LocalDateTime.now(), null));
|
||||
|
||||
String viewerId = UUID.randomUUID().toString();
|
||||
userRepository.save(new UserEntity(
|
||||
viewerId, "sup.viewer", "sup.viewer@test.com",
|
||||
passwordEncoder.encode("Pass123"), Set.of(viewerRole),
|
||||
"BRANCH-01", UserStatus.ACTIVE, LocalDateTime.now(), null));
|
||||
|
||||
adminToken = generateToken(adminId, "sup.admin", "MASTERDATA_WRITE");
|
||||
viewerToken = generateToken(viewerId, "sup.viewer", "USER_READ");
|
||||
adminToken = generateToken(admin.getId(), "sup.admin", "MASTERDATA_WRITE");
|
||||
viewerToken = generateToken(viewer.getId(), "sup.viewer", "USER_READ");
|
||||
}
|
||||
|
||||
// ==================== TC-SUP-01: Lieferant erstellen – Pflichtfelder ====================
|
||||
|
|
@ -449,18 +396,4 @@ class SupplierControllerIntegrationTest {
|
|||
.andReturn();
|
||||
return objectMapper.readTree(result.getResponse().getContentAsString()).get("id").asText();
|
||||
}
|
||||
|
||||
private String generateToken(String userId, String username, String permissions) {
|
||||
long now = System.currentTimeMillis();
|
||||
javax.crypto.SecretKey key = io.jsonwebtoken.security.Keys.hmacShaKeyFor(
|
||||
jwtSecret.getBytes(java.nio.charset.StandardCharsets.UTF_8));
|
||||
return Jwts.builder()
|
||||
.subject(userId)
|
||||
.claim("username", username)
|
||||
.claim("permissions", permissions)
|
||||
.issuedAt(new Date(now))
|
||||
.expiration(new Date(now + jwtExpiration))
|
||||
.signWith(key)
|
||||
.compact();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,35 +1,19 @@
|
|||
package de.effigenix.infrastructure.usermanagement.web;
|
||||
|
||||
import de.effigenix.application.usermanagement.dto.SessionToken;
|
||||
import de.effigenix.domain.usermanagement.RoleName;
|
||||
import de.effigenix.domain.usermanagement.UserStatus;
|
||||
import de.effigenix.infrastructure.AbstractIntegrationTest;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.RoleEntity;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.UserEntity;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.repository.RoleJpaRepository;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.repository.UserJpaRepository;
|
||||
import de.effigenix.infrastructure.usermanagement.web.dto.LoginRequest;
|
||||
import de.effigenix.infrastructure.usermanagement.web.dto.LoginResponse;
|
||||
import de.effigenix.infrastructure.usermanagement.web.dto.RefreshTokenRequest;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -39,89 +23,25 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||
|
||||
/**
|
||||
* Integration tests for Authentication Controller.
|
||||
*
|
||||
* Tests authentication flows:
|
||||
* - Login with valid/invalid credentials
|
||||
* - JWT token validation
|
||||
* - Logout flow
|
||||
* - Refresh token flow
|
||||
*
|
||||
* Uses:
|
||||
* - @SpringBootTest for full application context
|
||||
* - @AutoConfigureMockMvc for MockMvc HTTP testing
|
||||
* - @Transactional for test isolation
|
||||
* - H2 in-memory database (configured in application-test.yml)
|
||||
*
|
||||
* Test Database:
|
||||
* - H2 in-memory database
|
||||
* - ddl-auto: create-drop (schema recreated for each test)
|
||||
* - Each test runs in a transaction and is rolled back after completion
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@AutoConfigureMockMvc
|
||||
@ActiveProfiles("test")
|
||||
@Transactional
|
||||
@DisplayName("Authentication Controller Integration Tests")
|
||||
class AuthControllerIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Autowired
|
||||
private UserJpaRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private RoleJpaRepository roleRepository;
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Value("${jwt.secret}")
|
||||
private String jwtSecret;
|
||||
|
||||
@Value("${jwt.expiration}")
|
||||
private long jwtExpiration;
|
||||
class AuthControllerIntegrationTest extends AbstractIntegrationTest {
|
||||
|
||||
private String validUsername;
|
||||
private String validEmail;
|
||||
private String validPassword;
|
||||
private String validUserId;
|
||||
private String validRefreshToken;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
validUsername = "auth.test.user";
|
||||
validEmail = "auth.test@example.com";
|
||||
validPassword = "SecurePass123";
|
||||
validUserId = UUID.randomUUID().toString();
|
||||
|
||||
// Create test user with ADMIN role
|
||||
RoleEntity adminRole = new RoleEntity(
|
||||
UUID.randomUUID().toString(),
|
||||
RoleName.ADMIN,
|
||||
Set.of(), // Empty permissions for testing
|
||||
"Admin role"
|
||||
);
|
||||
roleRepository.save(adminRole);
|
||||
RoleEntity adminRole = createRole(RoleName.ADMIN, "Admin role");
|
||||
|
||||
UserEntity testUser = new UserEntity(
|
||||
validUserId,
|
||||
validUsername,
|
||||
validEmail,
|
||||
passwordEncoder.encode(validPassword),
|
||||
Set.of(adminRole),
|
||||
"BRANCH-TEST-001",
|
||||
UserStatus.ACTIVE,
|
||||
LocalDateTime.now(),
|
||||
null
|
||||
);
|
||||
userRepository.save(testUser);
|
||||
UserEntity testUser = createUser(validUsername, "auth.test@example.com",
|
||||
Set.of(adminRole), "BRANCH-TEST-001");
|
||||
validUserId = testUser.getId();
|
||||
|
||||
// Create a valid refresh token
|
||||
validRefreshToken = generateTestRefreshToken(validUserId, validUsername);
|
||||
validRefreshToken = generateRefreshToken(validUserId, validUsername);
|
||||
}
|
||||
|
||||
// ==================== LOGIN TESTS ====================
|
||||
|
|
@ -129,7 +49,7 @@ class AuthControllerIntegrationTest {
|
|||
@Test
|
||||
@DisplayName("Login with valid credentials should return 200 with JWT tokens")
|
||||
void testLoginWithValidCredentials() throws Exception {
|
||||
LoginRequest request = new LoginRequest(validUsername, validPassword);
|
||||
LoginRequest request = new LoginRequest(validUsername, TEST_PASSWORD);
|
||||
|
||||
MvcResult result = mockMvc.perform(post("/api/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
|
|
@ -154,7 +74,7 @@ class AuthControllerIntegrationTest {
|
|||
@Test
|
||||
@DisplayName("Login with invalid username should return 401 Unauthorized")
|
||||
void testLoginWithInvalidUsername() throws Exception {
|
||||
LoginRequest request = new LoginRequest("non.existent.user", validPassword);
|
||||
LoginRequest request = new LoginRequest("non.existent.user", TEST_PASSWORD);
|
||||
|
||||
mockMvc.perform(post("/api/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
|
|
@ -179,12 +99,11 @@ class AuthControllerIntegrationTest {
|
|||
@Test
|
||||
@DisplayName("Login with locked user should return 401 Unauthorized")
|
||||
void testLoginWithLockedUser() throws Exception {
|
||||
// Lock the user
|
||||
UserEntity user = userRepository.findByUsername(validUsername).orElseThrow();
|
||||
user.setStatus(UserStatus.LOCKED);
|
||||
userRepository.save(user);
|
||||
|
||||
LoginRequest request = new LoginRequest(validUsername, validPassword);
|
||||
LoginRequest request = new LoginRequest(validUsername, TEST_PASSWORD);
|
||||
|
||||
mockMvc.perform(post("/api/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
|
|
@ -196,12 +115,11 @@ class AuthControllerIntegrationTest {
|
|||
@Test
|
||||
@DisplayName("Login with inactive user should return 401 Unauthorized")
|
||||
void testLoginWithInactiveUser() throws Exception {
|
||||
// Set user to inactive
|
||||
UserEntity user = userRepository.findByUsername(validUsername).orElseThrow();
|
||||
user.setStatus(UserStatus.INACTIVE);
|
||||
userRepository.save(user);
|
||||
|
||||
LoginRequest request = new LoginRequest(validUsername, validPassword);
|
||||
LoginRequest request = new LoginRequest(validUsername, TEST_PASSWORD);
|
||||
|
||||
mockMvc.perform(post("/api/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
|
|
@ -213,7 +131,7 @@ class AuthControllerIntegrationTest {
|
|||
@Test
|
||||
@DisplayName("Login with missing username should return 400 Bad Request")
|
||||
void testLoginWithMissingUsername() throws Exception {
|
||||
LoginRequest request = new LoginRequest("", validPassword);
|
||||
LoginRequest request = new LoginRequest("", TEST_PASSWORD);
|
||||
|
||||
mockMvc.perform(post("/api/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
|
|
@ -250,7 +168,7 @@ class AuthControllerIntegrationTest {
|
|||
@DisplayName("Logout with valid JWT token should return 204 No Content")
|
||||
void testLogoutWithValidToken() throws Exception {
|
||||
// First login to get a valid token
|
||||
LoginRequest loginRequest = new LoginRequest(validUsername, validPassword);
|
||||
LoginRequest loginRequest = new LoginRequest(validUsername, TEST_PASSWORD);
|
||||
MvcResult loginResult = mockMvc.perform(post("/api/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(loginRequest)))
|
||||
|
|
@ -303,8 +221,6 @@ class AuthControllerIntegrationTest {
|
|||
void testRefreshTokenWithValidToken() throws Exception {
|
||||
RefreshTokenRequest request = new RefreshTokenRequest(validRefreshToken);
|
||||
|
||||
// Note: refreshSession() is not yet implemented in JwtSessionManager,
|
||||
// so it throws UnsupportedOperationException which maps to 401
|
||||
mockMvc.perform(post("/api/auth/refresh")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
|
|
@ -351,8 +267,6 @@ class AuthControllerIntegrationTest {
|
|||
void testRefreshTokenIsPublic() throws Exception {
|
||||
RefreshTokenRequest request = new RefreshTokenRequest(validRefreshToken);
|
||||
|
||||
// Endpoint is public (permitAll) - the 401 comes from the unimplemented
|
||||
// refreshSession(), not from missing JWT authentication
|
||||
mockMvc.perform(post("/api/auth/refresh")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
|
|
@ -365,7 +279,7 @@ class AuthControllerIntegrationTest {
|
|||
@Test
|
||||
@DisplayName("JWT token should contain valid payload information")
|
||||
void testJWTTokenContainsValidPayload() throws Exception {
|
||||
LoginRequest request = new LoginRequest(validUsername, validPassword);
|
||||
LoginRequest request = new LoginRequest(validUsername, TEST_PASSWORD);
|
||||
|
||||
MvcResult result = mockMvc.perform(post("/api/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
|
|
@ -385,7 +299,7 @@ class AuthControllerIntegrationTest {
|
|||
@Test
|
||||
@DisplayName("Token expiration time should match configured expiration")
|
||||
void testTokenExpirationTime() throws Exception {
|
||||
LoginRequest request = new LoginRequest(validUsername, validPassword);
|
||||
LoginRequest request = new LoginRequest(validUsername, TEST_PASSWORD);
|
||||
|
||||
MvcResult result = mockMvc.perform(post("/api/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
|
|
@ -405,7 +319,7 @@ class AuthControllerIntegrationTest {
|
|||
@Test
|
||||
@DisplayName("Multiple logins should return different tokens")
|
||||
void testMultipleLoginsReturnDifferentTokens() throws Exception {
|
||||
LoginRequest request = new LoginRequest(validUsername, validPassword);
|
||||
LoginRequest request = new LoginRequest(validUsername, TEST_PASSWORD);
|
||||
|
||||
// First login
|
||||
MvcResult result1 = mockMvc.perform(post("/api/auth/login")
|
||||
|
|
@ -433,24 +347,4 @@ class AuthControllerIntegrationTest {
|
|||
// Tokens should be different
|
||||
assertThat(response1.accessToken()).isNotEqualTo(response2.accessToken());
|
||||
}
|
||||
|
||||
// ==================== HELPER METHODS ====================
|
||||
|
||||
/**
|
||||
* Generates a test refresh token for testing refresh endpoint.
|
||||
* In production, refresh tokens are managed by SessionManager.
|
||||
*/
|
||||
private String generateTestRefreshToken(String userId, String username) {
|
||||
long now = System.currentTimeMillis();
|
||||
javax.crypto.SecretKey key = io.jsonwebtoken.security.Keys.hmacShaKeyFor(
|
||||
jwtSecret.getBytes(java.nio.charset.StandardCharsets.UTF_8));
|
||||
return Jwts.builder()
|
||||
.subject(userId)
|
||||
.claim("username", username)
|
||||
.claim("type", "refresh")
|
||||
.issuedAt(new Date(now))
|
||||
.expiration(new Date(now + 7200000)) // 2 hours
|
||||
.signWith(key)
|
||||
.compact();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,36 +2,23 @@ package de.effigenix.infrastructure.usermanagement.web;
|
|||
|
||||
import de.effigenix.domain.usermanagement.RoleName;
|
||||
import de.effigenix.domain.usermanagement.UserStatus;
|
||||
import de.effigenix.infrastructure.AbstractIntegrationTest;
|
||||
import de.effigenix.infrastructure.audit.AuditLogEntity;
|
||||
import de.effigenix.infrastructure.audit.AuditLogJpaRepository;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.RoleEntity;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.UserEntity;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.repository.RoleJpaRepository;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.repository.UserJpaRepository;
|
||||
import de.effigenix.infrastructure.usermanagement.web.dto.CreateUserRequest;
|
||||
import de.effigenix.infrastructure.usermanagement.web.dto.LoginRequest;
|
||||
import de.effigenix.infrastructure.usermanagement.web.dto.LoginResponse;
|
||||
import de.effigenix.infrastructure.usermanagement.web.dto.UpdateUserRequest;
|
||||
import de.effigenix.application.usermanagement.AuditEvent;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
|
@ -42,51 +29,13 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||
|
||||
/**
|
||||
* Integration tests for Security and Authorization.
|
||||
*
|
||||
* Tests:
|
||||
* - Authorization (ADMIN-only endpoints reject non-admin users)
|
||||
* - Branch-based filtering
|
||||
* - Missing/expired JWT returns 401
|
||||
* - Audit logging for critical operations
|
||||
* - Verify audit logs contain actor, timestamp, IP address
|
||||
*
|
||||
* Uses:
|
||||
* - @SpringBootTest for full application context
|
||||
* - @AutoConfigureMockMvc for MockMvc HTTP testing
|
||||
* - @Transactional for test isolation
|
||||
* - H2 in-memory database (configured in application-test.yml)
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@AutoConfigureMockMvc
|
||||
@ActiveProfiles("test")
|
||||
@Transactional
|
||||
@DisplayName("Security and Authorization Integration Tests")
|
||||
class SecurityIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Autowired
|
||||
private UserJpaRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private RoleJpaRepository roleRepository;
|
||||
class SecurityIntegrationTest extends AbstractIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private AuditLogJpaRepository auditLogRepository;
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Value("${jwt.secret}")
|
||||
private String jwtSecret;
|
||||
|
||||
@Value("${jwt.expiration}")
|
||||
private long jwtExpiration;
|
||||
|
||||
private String adminToken;
|
||||
private String regularUserToken;
|
||||
private String expiredToken;
|
||||
|
|
@ -100,54 +49,17 @@ class SecurityIntegrationTest {
|
|||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
// Create roles
|
||||
adminRole = new RoleEntity(
|
||||
UUID.randomUUID().toString(),
|
||||
RoleName.ADMIN,
|
||||
Set.of(), // Empty permissions for testing
|
||||
"Admin role"
|
||||
);
|
||||
roleRepository.save(adminRole);
|
||||
adminRole = createRole(RoleName.ADMIN, "Admin role");
|
||||
userRole = createRole(RoleName.PRODUCTION_WORKER, "Production worker role");
|
||||
|
||||
userRole = new RoleEntity(
|
||||
UUID.randomUUID().toString(),
|
||||
RoleName.PRODUCTION_WORKER,
|
||||
Set.of(), // Empty permissions for testing
|
||||
"Production worker role"
|
||||
);
|
||||
roleRepository.save(userRole);
|
||||
UserEntity adminUser = createUser("security.admin", "admin@security.test",
|
||||
Set.of(adminRole), "BRANCH-ADMIN");
|
||||
adminUserId = adminUser.getId();
|
||||
|
||||
// Create admin user
|
||||
adminUserId = UUID.randomUUID().toString();
|
||||
UserEntity adminUser = new UserEntity(
|
||||
adminUserId,
|
||||
"security.admin",
|
||||
"admin@security.test",
|
||||
passwordEncoder.encode("AdminPass123"),
|
||||
Set.of(adminRole),
|
||||
"BRANCH-ADMIN",
|
||||
UserStatus.ACTIVE,
|
||||
LocalDateTime.now(),
|
||||
null
|
||||
);
|
||||
userRepository.save(adminUser);
|
||||
UserEntity regularUser = createUser("security.user", "user@security.test",
|
||||
Set.of(userRole), "BRANCH-USER");
|
||||
regularUserId = regularUser.getId();
|
||||
|
||||
// Create regular user
|
||||
regularUserId = UUID.randomUUID().toString();
|
||||
UserEntity regularUser = new UserEntity(
|
||||
regularUserId,
|
||||
"security.user",
|
||||
"user@security.test",
|
||||
passwordEncoder.encode("UserPass123"),
|
||||
Set.of(userRole),
|
||||
"BRANCH-USER",
|
||||
UserStatus.ACTIVE,
|
||||
LocalDateTime.now(),
|
||||
null
|
||||
);
|
||||
userRepository.save(regularUser);
|
||||
|
||||
// Generate tokens
|
||||
adminToken = generateTestJWT(adminUserId, "security.admin", true);
|
||||
regularUserToken = generateTestJWT(regularUserId, "security.user", false);
|
||||
expiredToken = generateExpiredToken(adminUserId, "security.admin");
|
||||
|
|
@ -283,7 +195,7 @@ class SecurityIntegrationTest {
|
|||
@Test
|
||||
@DisplayName("Login endpoint without authentication should return 401 or 200 depending on credentials")
|
||||
void testLoginEndpointIsPublic() throws Exception {
|
||||
LoginRequest request = new LoginRequest("security.admin", "AdminPass123");
|
||||
LoginRequest request = new LoginRequest("security.admin", TEST_PASSWORD);
|
||||
|
||||
mockMvc.perform(post("/api/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
|
|
@ -295,11 +207,8 @@ class SecurityIntegrationTest {
|
|||
@Test
|
||||
@DisplayName("Refresh token endpoint without authentication should be public")
|
||||
void testRefreshEndpointIsPublic() throws Exception {
|
||||
// Generate a valid refresh token
|
||||
String refreshToken = generateTestRefreshToken(adminUserId, "security.admin");
|
||||
String refreshToken = generateRefreshToken(adminUserId, "security.admin");
|
||||
|
||||
// Endpoint is public (permitAll) - the 401 comes from unimplemented
|
||||
// refreshSession(), not from missing JWT authentication
|
||||
mockMvc.perform(post("/api/auth/refresh")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"refreshToken\":\"" + refreshToken + "\"}"))
|
||||
|
|
@ -312,29 +221,13 @@ class SecurityIntegrationTest {
|
|||
@Test
|
||||
@DisplayName("Users should see data filtered by their branch (if filtering is implemented)")
|
||||
void testBranchBasedDataVisibility() throws Exception {
|
||||
// Create user in different branch
|
||||
String otherBranchUserId = UUID.randomUUID().toString();
|
||||
UserEntity otherBranchUser = new UserEntity(
|
||||
otherBranchUserId,
|
||||
"other.branch.user",
|
||||
"other@branch.test",
|
||||
passwordEncoder.encode("OtherPass123"),
|
||||
Set.of(userRole),
|
||||
"BRANCH-OTHER",
|
||||
UserStatus.ACTIVE,
|
||||
LocalDateTime.now(),
|
||||
null
|
||||
);
|
||||
userRepository.save(otherBranchUser);
|
||||
UserEntity otherBranchUser = createUser("other.branch.user", "other@branch.test",
|
||||
Set.of(userRole), "BRANCH-OTHER");
|
||||
|
||||
// Regular user token for BRANCH-USER
|
||||
mockMvc.perform(get("/api/users")
|
||||
.header("Authorization", "Bearer " + regularUserToken))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn();
|
||||
|
||||
// Both branches should be visible in list (if no filtering is implemented)
|
||||
// This test documents the current behavior
|
||||
}
|
||||
|
||||
// ==================== AUDIT LOGGING TESTS ====================
|
||||
|
|
@ -342,7 +235,6 @@ class SecurityIntegrationTest {
|
|||
@Test
|
||||
@DisplayName("Create user operation should create audit log entry")
|
||||
void testCreateUserAuditLogging() throws Exception {
|
||||
// Clear existing audit logs
|
||||
auditLogRepository.deleteAll();
|
||||
|
||||
CreateUserRequest request = new CreateUserRequest(
|
||||
|
|
@ -360,7 +252,6 @@ class SecurityIntegrationTest {
|
|||
.andExpect(status().isCreated())
|
||||
.andReturn();
|
||||
|
||||
// Verify audit log was created
|
||||
List<AuditLogEntity> logs = auditLogRepository.findAll();
|
||||
assertThat(logs)
|
||||
.filteredOn(log -> log.getEvent() == AuditEvent.USER_CREATED)
|
||||
|
|
@ -402,7 +293,6 @@ class SecurityIntegrationTest {
|
|||
.findFirst()
|
||||
.orElseThrow();
|
||||
|
||||
// Verify actor is the admin user
|
||||
assertThat(auditLog.getPerformedBy()).isEqualTo(adminUserId);
|
||||
assertThat(auditLog.getPerformedBy()).isNotBlank();
|
||||
}
|
||||
|
|
@ -436,7 +326,6 @@ class SecurityIntegrationTest {
|
|||
.findFirst()
|
||||
.orElseThrow();
|
||||
|
||||
// Verify timestamp is present and recent (within last minute)
|
||||
assertThat(auditLog.getTimestamp()).isNotNull();
|
||||
assertThat(auditLog.getTimestamp()).isAfter(LocalDateTime.now().minusMinutes(1));
|
||||
}
|
||||
|
|
@ -451,7 +340,6 @@ class SecurityIntegrationTest {
|
|||
.andExpect(status().isOk())
|
||||
.andReturn();
|
||||
|
||||
// Verify audit log was created
|
||||
List<AuditLogEntity> logs = auditLogRepository.findAll();
|
||||
assertThat(logs)
|
||||
.filteredOn(log -> log.getEvent() == AuditEvent.USER_LOCKED)
|
||||
|
|
@ -471,18 +359,15 @@ class SecurityIntegrationTest {
|
|||
void testUnlockUserAuditLogging() throws Exception {
|
||||
auditLogRepository.deleteAll();
|
||||
|
||||
// First lock the user
|
||||
UserEntity user = userRepository.findById(regularUserId).orElseThrow();
|
||||
user.setStatus(UserStatus.LOCKED);
|
||||
userRepository.save(user);
|
||||
|
||||
// Then unlock
|
||||
mockMvc.perform(post("/api/users/{id}/unlock", regularUserId)
|
||||
.header("Authorization", "Bearer " + adminToken))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn();
|
||||
|
||||
// Verify audit log was created
|
||||
List<AuditLogEntity> logs = auditLogRepository.findAll();
|
||||
assertThat(logs)
|
||||
.filteredOn(log -> log.getEvent() == AuditEvent.USER_UNLOCKED)
|
||||
|
|
@ -506,7 +391,6 @@ class SecurityIntegrationTest {
|
|||
.andExpect(status().isOk())
|
||||
.andReturn();
|
||||
|
||||
// Verify audit log was created
|
||||
List<AuditLogEntity> logs = auditLogRepository.findAll();
|
||||
assertThat(logs)
|
||||
.filteredOn(log -> log.getEvent() == AuditEvent.USER_UPDATED)
|
||||
|
|
@ -526,7 +410,7 @@ class SecurityIntegrationTest {
|
|||
void testLoginSuccessAuditLogging() throws Exception {
|
||||
auditLogRepository.deleteAll();
|
||||
|
||||
LoginRequest request = new LoginRequest("security.admin", "AdminPass123");
|
||||
LoginRequest request = new LoginRequest("security.admin", TEST_PASSWORD);
|
||||
|
||||
mockMvc.perform(post("/api/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
|
|
@ -534,7 +418,6 @@ class SecurityIntegrationTest {
|
|||
.andExpect(status().isOk())
|
||||
.andReturn();
|
||||
|
||||
// Verify audit log was created
|
||||
List<AuditLogEntity> logs = auditLogRepository.findAll();
|
||||
assertThat(logs)
|
||||
.filteredOn(log -> log.getEvent() == AuditEvent.LOGIN_SUCCESS)
|
||||
|
|
@ -554,7 +437,6 @@ class SecurityIntegrationTest {
|
|||
.andExpect(status().isUnauthorized())
|
||||
.andReturn();
|
||||
|
||||
// Verify audit log was created
|
||||
List<AuditLogEntity> logs = auditLogRepository.findAll();
|
||||
assertThat(logs)
|
||||
.filteredOn(log -> log.getEvent() == AuditEvent.LOGIN_FAILED)
|
||||
|
|
@ -563,58 +445,10 @@ class SecurityIntegrationTest {
|
|||
|
||||
// ==================== HELPER METHODS ====================
|
||||
|
||||
/**
|
||||
* Generates a test JWT token with admin permissions.
|
||||
*/
|
||||
private String generateTestJWT(String userId, String username, boolean isAdmin) {
|
||||
long now = System.currentTimeMillis();
|
||||
String permissions = isAdmin
|
||||
? "USER_READ,USER_WRITE,USER_DELETE,USER_LOCK,USER_UNLOCK,ROLE_READ,ROLE_WRITE,ROLE_ASSIGN,ROLE_REMOVE"
|
||||
: "USER_READ";
|
||||
javax.crypto.SecretKey key = io.jsonwebtoken.security.Keys.hmacShaKeyFor(
|
||||
jwtSecret.getBytes(java.nio.charset.StandardCharsets.UTF_8));
|
||||
|
||||
return Jwts.builder()
|
||||
.subject(userId)
|
||||
.claim("username", username)
|
||||
.claim("permissions", permissions)
|
||||
.issuedAt(new Date(now))
|
||||
.expiration(new Date(now + jwtExpiration))
|
||||
.signWith(key)
|
||||
.compact();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an expired JWT token for testing expired token handling.
|
||||
*/
|
||||
private String generateExpiredToken(String userId, String username) {
|
||||
long now = System.currentTimeMillis();
|
||||
javax.crypto.SecretKey key = io.jsonwebtoken.security.Keys.hmacShaKeyFor(
|
||||
jwtSecret.getBytes(java.nio.charset.StandardCharsets.UTF_8));
|
||||
return Jwts.builder()
|
||||
.subject(userId)
|
||||
.claim("username", username)
|
||||
.claim("permissions", "")
|
||||
.issuedAt(new Date(now - 10000))
|
||||
.expiration(new Date(now - 5000)) // Expired 5 seconds ago
|
||||
.signWith(key)
|
||||
.compact();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a test refresh token.
|
||||
*/
|
||||
private String generateTestRefreshToken(String userId, String username) {
|
||||
long now = System.currentTimeMillis();
|
||||
javax.crypto.SecretKey key = io.jsonwebtoken.security.Keys.hmacShaKeyFor(
|
||||
jwtSecret.getBytes(java.nio.charset.StandardCharsets.UTF_8));
|
||||
return Jwts.builder()
|
||||
.subject(userId)
|
||||
.claim("username", username)
|
||||
.claim("type", "refresh")
|
||||
.issuedAt(new Date(now))
|
||||
.expiration(new Date(now + 7200000))
|
||||
.signWith(key)
|
||||
.compact();
|
||||
return generateToken(userId, username, permissions);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +1,18 @@
|
|||
package de.effigenix.infrastructure.usermanagement.web;
|
||||
|
||||
import de.effigenix.application.usermanagement.dto.UserDTO;
|
||||
import de.effigenix.domain.usermanagement.RoleName;
|
||||
import de.effigenix.domain.usermanagement.UserStatus;
|
||||
import de.effigenix.infrastructure.AbstractIntegrationTest;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.RoleEntity;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.entity.UserEntity;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.repository.RoleJpaRepository;
|
||||
import de.effigenix.infrastructure.usermanagement.persistence.repository.UserJpaRepository;
|
||||
import de.effigenix.infrastructure.usermanagement.web.dto.*;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -38,49 +23,13 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||
|
||||
/**
|
||||
* Integration tests for User Management Controller.
|
||||
*
|
||||
* Tests user management operations:
|
||||
* - Create user (success, validation errors, duplicates)
|
||||
* - List users
|
||||
* - Get user by ID
|
||||
* - Update user
|
||||
* - Lock/unlock user
|
||||
* - Change password
|
||||
*
|
||||
* Uses:
|
||||
* - @SpringBootTest for full application context
|
||||
* - @AutoConfigureMockMvc for MockMvc HTTP testing
|
||||
* - @Transactional for test isolation
|
||||
* - H2 in-memory database (configured in application-test.yml)
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@AutoConfigureMockMvc
|
||||
@ActiveProfiles("test")
|
||||
@Transactional
|
||||
@DisplayName("User Controller Integration Tests")
|
||||
class UserControllerIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Autowired
|
||||
private UserJpaRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private RoleJpaRepository roleRepository;
|
||||
class UserControllerIntegrationTest extends AbstractIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Value("${jwt.secret}")
|
||||
private String jwtSecret;
|
||||
|
||||
@Value("${jwt.expiration}")
|
||||
private long jwtExpiration;
|
||||
|
||||
private String adminToken;
|
||||
private String regularUserToken;
|
||||
private String adminUserId;
|
||||
|
|
@ -91,54 +40,15 @@ class UserControllerIntegrationTest {
|
|||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
// Create roles
|
||||
adminRole = new RoleEntity(
|
||||
UUID.randomUUID().toString(),
|
||||
RoleName.ADMIN,
|
||||
Set.of(), // Empty permissions for testing
|
||||
"Admin role"
|
||||
);
|
||||
roleRepository.save(adminRole);
|
||||
adminRole = createRole(RoleName.ADMIN, "Admin role");
|
||||
userRole = createRole(RoleName.PRODUCTION_WORKER, "Production worker role");
|
||||
|
||||
userRole = new RoleEntity(
|
||||
UUID.randomUUID().toString(),
|
||||
RoleName.PRODUCTION_WORKER,
|
||||
Set.of(), // Empty permissions for testing
|
||||
"Production worker role"
|
||||
);
|
||||
roleRepository.save(userRole);
|
||||
UserEntity adminUser = createUser("admin.user", "admin@example.com", Set.of(adminRole), "BRANCH-001");
|
||||
adminUserId = adminUser.getId();
|
||||
|
||||
// Create admin user
|
||||
adminUserId = UUID.randomUUID().toString();
|
||||
UserEntity adminUser = new UserEntity(
|
||||
adminUserId,
|
||||
"admin.user",
|
||||
"admin@example.com",
|
||||
passwordEncoder.encode("AdminPass123"),
|
||||
Set.of(adminRole),
|
||||
"BRANCH-001",
|
||||
UserStatus.ACTIVE,
|
||||
LocalDateTime.now(),
|
||||
null
|
||||
);
|
||||
userRepository.save(adminUser);
|
||||
UserEntity regularUser = createUser("regular.user", "regular@example.com", Set.of(userRole), "BRANCH-001");
|
||||
regularUserId = regularUser.getId();
|
||||
|
||||
// Create regular user
|
||||
regularUserId = UUID.randomUUID().toString();
|
||||
UserEntity regularUser = new UserEntity(
|
||||
regularUserId,
|
||||
"regular.user",
|
||||
"regular@example.com",
|
||||
passwordEncoder.encode("RegularPass123"),
|
||||
Set.of(userRole),
|
||||
"BRANCH-001",
|
||||
UserStatus.ACTIVE,
|
||||
LocalDateTime.now(),
|
||||
null
|
||||
);
|
||||
userRepository.save(regularUser);
|
||||
|
||||
// Generate JWT tokens
|
||||
adminToken = generateTestJWT(adminUserId, "admin.user", true);
|
||||
regularUserToken = generateTestJWT(regularUserId, "regular.user", false);
|
||||
}
|
||||
|
|
@ -515,7 +425,7 @@ class UserControllerIntegrationTest {
|
|||
@DisplayName("Change password with correct current password should return 204 No Content")
|
||||
void testChangePasswordWithValidCurrentPassword() throws Exception {
|
||||
ChangePasswordRequest request = new ChangePasswordRequest(
|
||||
"RegularPass123", // Current password
|
||||
TEST_PASSWORD, // Current password
|
||||
"NewSecurePass456!"
|
||||
);
|
||||
|
||||
|
|
@ -551,7 +461,7 @@ class UserControllerIntegrationTest {
|
|||
@DisplayName("Change password with new password too short should return 400 Bad Request")
|
||||
void testChangePasswordWithShortNewPassword() throws Exception {
|
||||
ChangePasswordRequest request = new ChangePasswordRequest(
|
||||
"RegularPass123",
|
||||
TEST_PASSWORD,
|
||||
"Short1" // Less than 8 characters
|
||||
);
|
||||
|
||||
|
|
@ -585,7 +495,7 @@ class UserControllerIntegrationTest {
|
|||
@DisplayName("Change password without authentication should return 401 Unauthorized")
|
||||
void testChangePasswordWithoutAuthentication() throws Exception {
|
||||
ChangePasswordRequest request = new ChangePasswordRequest(
|
||||
"RegularPass123",
|
||||
TEST_PASSWORD,
|
||||
"NewSecurePass456!"
|
||||
);
|
||||
|
||||
|
|
@ -598,23 +508,10 @@ class UserControllerIntegrationTest {
|
|||
|
||||
// ==================== HELPER METHODS ====================
|
||||
|
||||
/**
|
||||
* Generates a test JWT token with USER_MANAGEMENT permission for admin.
|
||||
*/
|
||||
private String generateTestJWT(String userId, String username, boolean isAdmin) {
|
||||
long now = System.currentTimeMillis();
|
||||
javax.crypto.SecretKey key = io.jsonwebtoken.security.Keys.hmacShaKeyFor(
|
||||
jwtSecret.getBytes(java.nio.charset.StandardCharsets.UTF_8));
|
||||
String permissions = isAdmin
|
||||
? "USER_READ,USER_WRITE,USER_DELETE,USER_LOCK,USER_UNLOCK,ROLE_READ,ROLE_WRITE,ROLE_ASSIGN,ROLE_REMOVE"
|
||||
: "USER_READ";
|
||||
return Jwts.builder()
|
||||
.subject(userId)
|
||||
.claim("username", username)
|
||||
.claim("permissions", permissions)
|
||||
.issuedAt(new Date(now))
|
||||
.expiration(new Date(now + jwtExpiration))
|
||||
.signWith(key)
|
||||
.compact();
|
||||
return generateToken(userId, username, permissions);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue