Added integration tests for ContainerRateRepository, GroupRepository, and UserRepository for MySQL and MSSQL. Improved test coverage for pagination, filtering, UPSERT operations, and data cleanup methods.

This commit is contained in:
Jan 2026-01-28 10:36:24 +01:00
parent 5c8165c60e
commit 52116be1c3
3 changed files with 923 additions and 0 deletions

View file

@ -0,0 +1,358 @@
package de.avatic.lcc.repositories.rates;
import de.avatic.lcc.dto.generic.TransportType;
import de.avatic.lcc.model.db.rates.ContainerRate;
import de.avatic.lcc.model.db.rates.ValidityPeriodState;
import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest;
import de.avatic.lcc.repositories.pagination.SearchQueryPagination;
import de.avatic.lcc.repositories.pagination.SearchQueryResult;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
/**
* Integration tests for ContainerRateRepository.
* <p>
* Tests critical functionality across both MySQL and MSSQL:
* - Pagination (LIMIT/OFFSET vs OFFSET/FETCH)
* - UPSERT operations (ON DUPLICATE KEY UPDATE vs MERGE)
* - Complex JOIN queries with filtering
* - Transport type filtering (SEA, RAIL, POST_RUN, ROAD)
* - Boolean literals (TRUE/FALSE vs 1/0)
* <p>
* Run with:
* <pre>
* mvn test -Dspring.profiles.active=test,mysql -Dtest=ContainerRateRepositoryIntegrationTest
* mvn test -Dspring.profiles.active=test,mssql -Dtest=ContainerRateRepositoryIntegrationTest
* </pre>
*/
class ContainerRateRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest {
@Autowired
private ContainerRateRepository containerRateRepository;
private Integer testValidPeriodId;
private Integer testCountryDeId;
private Integer testCountryUsId;
private Integer testNodeHamburgId;
private Integer testNodeBremenId;
private Integer testNodeNewYorkId;
@BeforeEach
void setupTestData() {
// Clean up in correct order (foreign key constraints)
jdbcTemplate.update("DELETE FROM container_rate");
jdbcTemplate.update("DELETE FROM country_property");
jdbcTemplate.update("DELETE FROM country_matrix_rate");
jdbcTemplate.update("DELETE FROM node_predecessor_entry");
jdbcTemplate.update("DELETE FROM node_predecessor_chain");
jdbcTemplate.update("DELETE FROM node");
jdbcTemplate.update("DELETE FROM validity_period");
// Use existing countries from migrations
testCountryDeId = jdbcTemplate.queryForObject(
"SELECT id FROM country WHERE iso_code = 'DE'", Integer.class);
testCountryUsId = jdbcTemplate.queryForObject(
"SELECT id FROM country WHERE iso_code = 'US'", Integer.class);
// Create test validity period
testValidPeriodId = createTestValidityPeriod(ValidityPeriodState.VALID,
LocalDateTime.now().minusDays(1), null);
// Create test nodes
testNodeHamburgId = createTestNode("Hamburg Port", "HAM", testCountryDeId, false, 53.5, 10.0);
testNodeBremenId = createTestNode("Bremen Port", "BRE", testCountryDeId, false, 53.1, 8.8);
testNodeNewYorkId = createTestNode("New York Port", "NYC", testCountryUsId, false, 40.7, -74.0);
// Create test container rates
createTestContainerRate(testNodeHamburgId, testNodeNewYorkId, TransportType.SEA,
new BigDecimal("2000"), new BigDecimal("1000"), new BigDecimal("2200"), 14, testValidPeriodId);
createTestContainerRate(testNodeBremenId, testNodeNewYorkId, TransportType.SEA,
new BigDecimal("2100"), new BigDecimal("1050"), new BigDecimal("2300"), 15, testValidPeriodId);
createTestContainerRate(testNodeHamburgId, testNodeBremenId, TransportType.RAIL,
new BigDecimal("300"), new BigDecimal("150"), new BigDecimal("350"), 1, testValidPeriodId);
}
@Test
void testListRatesByPeriodId() {
// Given: Valid period ID
SearchQueryPagination pagination = new SearchQueryPagination(1, 10);
// When: List rates by period
SearchQueryResult<ContainerRate> result = containerRateRepository.listRatesByPeriodId(null, pagination, testValidPeriodId);
// Then: Should return all 3 rates
assertNotNull(result);
assertEquals(3, result.getTotalElements());
assertTrue(result.toList().stream()
.allMatch(rate -> rate.getValidityPeriodId().equals(testValidPeriodId)));
}
@Test
void testListRatesByPeriodIdWithFilter() {
// Given: Filter for "Hamburg"
SearchQueryPagination pagination = new SearchQueryPagination(1, 10);
// When: List rates with filter
SearchQueryResult<ContainerRate> result = containerRateRepository.listRatesByPeriodId("Hamburg", pagination, testValidPeriodId);
// Then: Should return rates involving Hamburg
assertNotNull(result);
assertTrue(result.getTotalElements() >= 2, "Should find at least 2 rates with Hamburg");
}
@Test
void testListRatesByPeriodIdWithExternalMappingIdFilter() {
// Given: Filter for "HAM"
SearchQueryPagination pagination = new SearchQueryPagination(1, 10);
// When: List rates with external mapping ID filter
SearchQueryResult<ContainerRate> result = containerRateRepository.listRatesByPeriodId("HAM", pagination, testValidPeriodId);
// Then: Should return rates involving Hamburg
assertNotNull(result);
assertTrue(result.getTotalElements() >= 2, "Should find at least 2 rates with HAM");
}
@Test
void testListRatesByPeriodIdPagination() {
// Given: Pagination with limit 2
SearchQueryPagination pagination = new SearchQueryPagination(1, 2);
// When: List rates
SearchQueryResult<ContainerRate> result = containerRateRepository.listRatesByPeriodId(null, pagination, testValidPeriodId);
// Then: Should respect limit
assertNotNull(result);
assertEquals(2, result.toList().size());
assertEquals(3, result.getTotalElements());
}
@Test
void testGetById() {
// Given: Get first rate ID
SearchQueryPagination pagination = new SearchQueryPagination(1, 1);
SearchQueryResult<ContainerRate> result = containerRateRepository.listRatesByPeriodId(null, pagination, testValidPeriodId);
Integer rateId = result.toList().getFirst().getId();
// When: Get by ID
Optional<ContainerRate> rate = containerRateRepository.getById(rateId);
// Then: Should retrieve correct rate
assertTrue(rate.isPresent());
assertEquals(rateId, rate.get().getId());
assertNotNull(rate.get().getRateFeu());
assertNotNull(rate.get().getRateTeu());
assertNotNull(rate.get().getFromNodeId());
assertNotNull(rate.get().getToNodeId());
}
@Test
void testGetByIdNotFound() {
// When: Get non-existent ID
Optional<ContainerRate> rate = containerRateRepository.getById(99999);
// Then: Should not find
assertFalse(rate.isPresent());
}
@Test
void testListAllRatesByPeriodId() {
// When: List all rates for valid period
List<ContainerRate> rates = containerRateRepository.listAllRatesByPeriodId(testValidPeriodId);
// Then: Should return all 3 rates
assertNotNull(rates);
assertEquals(3, rates.size());
assertTrue(rates.stream().allMatch(rate -> rate.getValidityPeriodId().equals(testValidPeriodId)));
}
@Test
void testFindRoutesByStartNodeIdAndDestinationCountryId() {
// When: Find routes from Hamburg to US
List<ContainerRate> routes = containerRateRepository.findRoutesByStartNodeIdAndDestinationCountryId(
testNodeHamburgId, List.of(testCountryUsId));
// Then: Should find Hamburg -> New York route
assertNotNull(routes);
assertEquals(1, routes.size());
assertEquals(testNodeHamburgId, routes.getFirst().getFromNodeId());
assertEquals(testNodeNewYorkId, routes.getFirst().getToNodeId());
assertEquals(TransportType.SEA, routes.getFirst().getType());
}
@Test
void testFindRoutesByStartNodeIdAndDestinationCountryIdMultiple() {
// When: Find routes from Hamburg to DE or US
List<ContainerRate> routes = containerRateRepository.findRoutesByStartNodeIdAndDestinationCountryId(
testNodeHamburgId, List.of(testCountryDeId, testCountryUsId));
// Then: Should find both routes (Hamburg -> Bremen and Hamburg -> New York)
assertNotNull(routes);
assertEquals(2, routes.size());
assertTrue(routes.stream().allMatch(r -> r.getFromNodeId().equals(testNodeHamburgId)));
}
@Test
void testFindRoutesByStartNodeIdAndDestinationCountryIdEmpty() {
// When: Find routes with empty destination list
List<ContainerRate> routes = containerRateRepository.findRoutesByStartNodeIdAndDestinationCountryId(
testNodeHamburgId, List.of());
// Then: Should return empty list
assertNotNull(routes);
assertTrue(routes.isEmpty());
}
@Test
void testGetPostRunsFor() {
// Given: Create a main run and post-run
Integer testNodeWarehouseId = createTestNode("Warehouse", "WH1", testCountryUsId, false, 40.8, -74.1);
createTestContainerRate(testNodeNewYorkId, testNodeWarehouseId, TransportType.POST_RUN,
new BigDecimal("100"), new BigDecimal("50"), new BigDecimal("120"), 1, testValidPeriodId);
ContainerRate mainRun = new ContainerRate();
mainRun.setToNodeId(testNodeNewYorkId);
// When: Get post runs
List<ContainerRate> postRuns = containerRateRepository.getPostRunsFor(mainRun);
// Then: Should find the post-run
assertNotNull(postRuns);
assertEquals(1, postRuns.size());
assertEquals(testNodeNewYorkId, postRuns.getFirst().getFromNodeId());
assertEquals(TransportType.POST_RUN, postRuns.getFirst().getType());
}
@Test
void testFindRouteWithPeriodId() {
// When: Find route Hamburg -> New York SEA in valid period
Optional<ContainerRate> route = containerRateRepository.findRoute(
testNodeHamburgId, testNodeNewYorkId, testValidPeriodId, TransportType.SEA);
// Then: Should find route
assertTrue(route.isPresent());
assertEquals(testNodeHamburgId, route.get().getFromNodeId());
assertEquals(testNodeNewYorkId, route.get().getToNodeId());
assertEquals(TransportType.SEA, route.get().getType());
assertEquals(0, new BigDecimal("2000").compareTo(route.get().getRateFeu()));
}
@Test
void testFindRouteWithPeriodIdNotFound() {
// When: Find route with wrong transport type
Optional<ContainerRate> route = containerRateRepository.findRoute(
testNodeHamburgId, testNodeNewYorkId, testValidPeriodId, TransportType.ROAD);
// Then: Should not find
assertFalse(route.isPresent());
}
@Test
void testFindRouteWithoutPeriodId() {
// When: Find route Hamburg -> New York SEA (uses VALID period)
Optional<ContainerRate> route = containerRateRepository.findRoute(
testNodeHamburgId, testNodeNewYorkId, TransportType.SEA);
// Then: Should find route
assertTrue(route.isPresent());
assertEquals(testNodeHamburgId, route.get().getFromNodeId());
assertEquals(testNodeNewYorkId, route.get().getToNodeId());
assertEquals(TransportType.SEA, route.get().getType());
}
@Test
void testInsertNewRate() {
// Given: New container rate
ContainerRate newRate = new ContainerRate();
newRate.setFromNodeId(testNodeBremenId);
newRate.setToNodeId(testNodeHamburgId);
newRate.setType(TransportType.ROAD);
newRate.setRateFeu(new BigDecimal("200"));
newRate.setRateTeu(new BigDecimal("100"));
newRate.setRateHc(new BigDecimal("220"));
newRate.setLeadTime(1);
newRate.setValidityPeriodId(testValidPeriodId);
// When: Insert
containerRateRepository.insert(newRate);
// Then: Should be inserted
Optional<ContainerRate> inserted = containerRateRepository.findRoute(
testNodeBremenId, testNodeHamburgId, testValidPeriodId, TransportType.ROAD);
assertTrue(inserted.isPresent());
assertEquals(0, new BigDecimal("200").compareTo(inserted.get().getRateFeu()));
}
@Test
void testInsertUpsertExisting() {
// Given: Existing rate Hamburg -> New York
ContainerRate updateRate = new ContainerRate();
updateRate.setFromNodeId(testNodeHamburgId);
updateRate.setToNodeId(testNodeNewYorkId);
updateRate.setType(TransportType.SEA);
updateRate.setRateFeu(new BigDecimal("2500")); // Different rate
updateRate.setRateTeu(new BigDecimal("1250"));
updateRate.setRateHc(new BigDecimal("2700"));
updateRate.setLeadTime(12);
updateRate.setValidityPeriodId(testValidPeriodId);
// When: Insert (should upsert)
containerRateRepository.insert(updateRate);
// Then: Rate should be updated
Optional<ContainerRate> updated = containerRateRepository.findRoute(
testNodeHamburgId, testNodeNewYorkId, testValidPeriodId, TransportType.SEA);
assertTrue(updated.isPresent());
assertEquals(0, new BigDecimal("2500").compareTo(updated.get().getRateFeu()));
assertEquals(12, updated.get().getLeadTime());
// Should still have only 3 rates total
List<ContainerRate> allRates = containerRateRepository.listAllRatesByPeriodId(testValidPeriodId);
assertEquals(3, allRates.size());
}
// ========== Helper Methods ==========
private Integer createTestValidityPeriod(ValidityPeriodState state, LocalDateTime startDate, LocalDateTime endDate) {
String sql = "INSERT INTO validity_period (state, start_date, end_date) VALUES (?, ?, ?)";
Timestamp startTs = Timestamp.valueOf(startDate);
Timestamp endTs = endDate != null ? Timestamp.valueOf(endDate) : null;
executeRawSql(sql, state.name(), startTs, endTs);
String selectSql = isMysql() ? "SELECT LAST_INSERT_ID()" : "SELECT CAST(@@IDENTITY AS INT)";
return jdbcTemplate.queryForObject(selectSql, Integer.class);
}
private Integer createTestNode(String name, String externalMappingId, Integer countryId, boolean isDeprecated,
double geoLat, double geoLng) {
String isDeprecatedValue = isDeprecated ? dialectProvider.getBooleanTrue() : dialectProvider.getBooleanFalse();
String sql = String.format(
"INSERT INTO node (name, external_mapping_id, country_id, is_deprecated, is_source, is_destination, is_intermediate, address, geo_lat, geo_lng) " +
"VALUES (?, ?, ?, %s, %s, %s, %s, 'Test Address', ?, ?)",
isDeprecatedValue,
dialectProvider.getBooleanTrue(),
dialectProvider.getBooleanTrue(),
dialectProvider.getBooleanTrue());
executeRawSql(sql, name, externalMappingId, countryId, geoLat, geoLng);
String selectSql = isMysql() ? "SELECT LAST_INSERT_ID()" : "SELECT CAST(@@IDENTITY AS INT)";
return jdbcTemplate.queryForObject(selectSql, Integer.class);
}
private void createTestContainerRate(Integer fromNodeId, Integer toNodeId, TransportType type,
BigDecimal rateFeu, BigDecimal rateTeu, BigDecimal rateHc,
int leadTime, Integer validityPeriodId) {
String sql = "INSERT INTO container_rate (from_node_id, to_node_id, container_rate_type, rate_feu, rate_teu, rate_hc, lead_time, validity_period_id) " +
"VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
executeRawSql(sql, fromNodeId, toNodeId, type.name(), rateFeu, rateTeu, rateHc, leadTime, validityPeriodId);
}
}

View file

@ -0,0 +1,215 @@
package de.avatic.lcc.repositories.users;
import de.avatic.lcc.model.db.users.Group;
import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest;
import de.avatic.lcc.repositories.pagination.SearchQueryPagination;
import de.avatic.lcc.repositories.pagination.SearchQueryResult;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* Integration tests for GroupRepository.
* <p>
* Tests critical functionality across both MySQL and MSSQL:
* - Pagination (LIMIT/OFFSET vs OFFSET/FETCH)
* - UPSERT operations (ON DUPLICATE KEY UPDATE vs MERGE)
* - IN clause with dynamic parameters
* <p>
* Run with:
* <pre>
* mvn test -Dspring.profiles.active=test,mysql -Dtest=GroupRepositoryIntegrationTest
* mvn test -Dspring.profiles.active=test,mssql -Dtest=GroupRepositoryIntegrationTest
* </pre>
*/
class GroupRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest {
@Autowired
private GroupRepository groupRepository;
@BeforeEach
void setupTestData() {
// Clean up groups
jdbcTemplate.update("DELETE FROM sys_user_group_mapping");
jdbcTemplate.update("DELETE FROM sys_group");
// Create test groups
createTestGroup("Administrators", "Admin users with full access");
createTestGroup("Developers", "Software developers");
createTestGroup("Analysts", "Data analysts");
createTestGroup("Viewers", "Read-only users");
}
@Test
void testListGroups() {
// Given: Pagination
SearchQueryPagination pagination = new SearchQueryPagination(1, 10);
// When: List groups
SearchQueryResult<Group> result = groupRepository.listGroups(pagination);
// Then: Should return all groups
assertNotNull(result);
assertEquals(4, result.getTotalElements());
assertFalse(result.toList().isEmpty());
}
@Test
void testListGroupsPagination() {
// Given: Pagination with limit 2
SearchQueryPagination pagination = new SearchQueryPagination(1, 2);
// When: List groups
SearchQueryResult<Group> result = groupRepository.listGroups(pagination);
// Then: Should respect limit
assertNotNull(result);
assertEquals(2, result.toList().size());
assertEquals(4, result.getTotalElements());
}
@Test
void testListGroupsOrdering() {
// Given: Pagination
SearchQueryPagination pagination = new SearchQueryPagination(1, 10);
// When: List groups
SearchQueryResult<Group> result = groupRepository.listGroups(pagination);
// Then: Should be ordered by group_name
assertNotNull(result);
List<Group> groups = result.toList();
for (int i = 1; i < groups.size(); i++) {
assertTrue(groups.get(i - 1).getName().compareTo(groups.get(i).getName()) <= 0,
"Groups should be ordered alphabetically by name");
}
}
@Test
void testFindGroupIds() {
// When: Find group IDs by names
List<Integer> ids = groupRepository.findGroupIds(List.of("Administrators", "Developers"));
// Then: Should find 2 groups
assertNotNull(ids);
assertEquals(2, ids.size());
}
@Test
void testFindGroupIdsSingle() {
// When: Find single group ID
List<Integer> ids = groupRepository.findGroupIds(List.of("Administrators"));
// Then: Should find 1 group
assertNotNull(ids);
assertEquals(1, ids.size());
}
@Test
void testFindGroupIdsNotFound() {
// When: Find non-existent group
List<Integer> ids = groupRepository.findGroupIds(List.of("NonExistent"));
// Then: Should return empty list
assertNotNull(ids);
assertTrue(ids.isEmpty());
}
@Test
void testFindGroupIdsEmptyList() {
// When: Find with empty list
List<Integer> ids = groupRepository.findGroupIds(List.of());
// Then: Should return empty list
assertNotNull(ids);
assertTrue(ids.isEmpty());
}
@Test
void testFindGroupIdsNull() {
// When: Find with null
List<Integer> ids = groupRepository.findGroupIds(null);
// Then: Should return empty list
assertNotNull(ids);
assertTrue(ids.isEmpty());
}
@Test
void testUpdateGroupInsert() {
// Given: New group
Group newGroup = new Group();
newGroup.setName("Testers");
newGroup.setDescription("QA testers");
// When: Update (insert)
groupRepository.updateGroup(newGroup);
// Then: Should be inserted
SearchQueryPagination pagination = new SearchQueryPagination(1, 10);
SearchQueryResult<Group> result = groupRepository.listGroups(pagination);
assertEquals(5, result.getTotalElements());
// Verify the new group exists
List<Integer> ids = groupRepository.findGroupIds(List.of("Testers"));
assertEquals(1, ids.size());
}
@Test
void testUpdateGroupUpsert() {
// Given: Existing group name
Group updateGroup = new Group();
updateGroup.setName("Administrators");
updateGroup.setDescription("Updated admin description");
// When: Update (upsert)
groupRepository.updateGroup(updateGroup);
// Then: Should update description
SearchQueryPagination pagination = new SearchQueryPagination(1, 10);
SearchQueryResult<Group> result = groupRepository.listGroups(pagination);
// Should still have 4 groups
assertEquals(4, result.getTotalElements());
// Find the updated group
Group updated = result.toList().stream()
.filter(g -> "Administrators".equals(g.getName()))
.findFirst()
.orElseThrow();
assertEquals("Updated admin description", updated.getDescription());
}
@Test
void testFindGroupIdsMultiple() {
// When: Find multiple group IDs
List<Integer> ids = groupRepository.findGroupIds(
List.of("Administrators", "Developers", "Analysts"));
// Then: Should find 3 groups
assertNotNull(ids);
assertEquals(3, ids.size());
}
@Test
void testFindGroupIdsPartialMatch() {
// When: Find mix of existing and non-existing groups
List<Integer> ids = groupRepository.findGroupIds(
List.of("Administrators", "NonExistent", "Developers"));
// Then: Should find only existing groups
assertNotNull(ids);
assertEquals(2, ids.size());
}
// ========== Helper Methods ==========
private void createTestGroup(String name, String description) {
String sql = "INSERT INTO sys_group (group_name, group_description) VALUES (?, ?)";
executeRawSql(sql, name, description);
}
}

View file

@ -0,0 +1,350 @@
package de.avatic.lcc.repositories.users;
import de.avatic.lcc.model.db.users.Group;
import de.avatic.lcc.model.db.users.User;
import de.avatic.lcc.repositories.AbstractRepositoryIntegrationTest;
import de.avatic.lcc.repositories.pagination.SearchQueryPagination;
import de.avatic.lcc.repositories.pagination.SearchQueryResult;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
/**
* Integration tests for UserRepository.
* <p>
* Tests critical functionality across both MySQL and MSSQL:
* - Pagination (LIMIT/OFFSET vs OFFSET/FETCH)
* - INSERT IGNORE (MySQL) vs MERGE (MSSQL)
* - Complex group mapping operations
* - User lookup by various fields
* <p>
* Run with:
* <pre>
* mvn test -Dspring.profiles.active=test,mysql -Dtest=UserRepositoryIntegrationTest
* mvn test -Dspring.profiles.active=test,mssql -Dtest=UserRepositoryIntegrationTest
* </pre>
*/
class UserRepositoryIntegrationTest extends AbstractRepositoryIntegrationTest {
@Autowired
private UserRepository userRepository;
@Autowired
private GroupRepository groupRepository;
private Integer testGroupAdminId;
private Integer testGroupDevId;
@BeforeEach
void setupTestData() {
// Clean up in correct order
jdbcTemplate.update("DELETE FROM sys_user_group_mapping");
jdbcTemplate.update("DELETE FROM sys_user");
jdbcTemplate.update("DELETE FROM sys_group");
// Create test groups
createTestGroup("Administrators", "Admin users");
createTestGroup("Developers", "Dev users");
createTestGroup("Viewers", "Read-only users");
// Get group IDs
testGroupAdminId = groupRepository.findGroupIds(List.of("Administrators")).getFirst();
testGroupDevId = groupRepository.findGroupIds(List.of("Developers")).getFirst();
// Create test users
createTestUser("WD001", "john.doe@example.com", "John", "Doe", true);
createTestUser("WD002", "jane.smith@example.com", "Jane", "Smith", true);
createTestUser("WD003", "bob.inactive@example.com", "Bob", "Inactive", false);
// Create group mappings
createUserGroupMapping(getUserIdByWorkday("WD001"), testGroupAdminId);
createUserGroupMapping(getUserIdByWorkday("WD002"), testGroupDevId);
}
@Test
void testListUsers() {
// Given: Pagination
SearchQueryPagination pagination = new SearchQueryPagination(1, 10);
// When: List users
SearchQueryResult<User> result = userRepository.listUsers(pagination);
// Then: Should return all users
assertNotNull(result);
assertEquals(3, result.getTotalElements());
assertFalse(result.toList().isEmpty());
}
@Test
void testListUsersPagination() {
// Given: Pagination with limit 2
SearchQueryPagination pagination = new SearchQueryPagination(1, 2);
// When: List users
SearchQueryResult<User> result = userRepository.listUsers(pagination);
// Then: Should respect limit
assertNotNull(result);
assertEquals(2, result.toList().size());
assertEquals(3, result.getTotalElements());
}
@Test
void testListUsersOrdering() {
// Given: Pagination
SearchQueryPagination pagination = new SearchQueryPagination(1, 10);
// When: List users
SearchQueryResult<User> result = userRepository.listUsers(pagination);
// Then: Should be ordered by workday_id
assertNotNull(result);
List<User> users = result.toList();
for (int i = 1; i < users.size(); i++) {
assertTrue(users.get(i - 1).getWorkdayId().compareTo(users.get(i).getWorkdayId()) <= 0,
"Users should be ordered by workday_id");
}
}
@Test
void testUpdateInsertNewUser() {
// Given: New user
User newUser = new User();
newUser.setWorkdayId("WD004");
newUser.setEmail("new.user@example.com");
newUser.setFirstName("New");
newUser.setLastName("User");
newUser.setActive(true);
newUser.setGroups(List.of());
// When: Update (insert)
Integer userId = userRepository.update(newUser);
// Then: Should be inserted
assertNotNull(userId);
assertTrue(userId > 0);
User inserted = userRepository.getById(userId);
assertNotNull(inserted);
assertEquals("WD004", inserted.getWorkdayId());
assertEquals("new.user@example.com", inserted.getEmail());
}
@Test
void testUpdateExistingUser() {
// Given: Existing user
User user = userRepository.getByWorkdayId("WD001").orElseThrow();
user.setEmail("john.updated@example.com");
user.setFirstName("Johnny");
// When: Update
Integer userId = userRepository.update(user);
// Then: Should be updated
assertNotNull(userId);
User updated = userRepository.getById(userId);
assertEquals("john.updated@example.com", updated.getEmail());
assertEquals("Johnny", updated.getFirstName());
assertEquals("Doe", updated.getLastName()); // Unchanged
}
@Test
void testUpdateUserWithGroups() {
// Given: New user with groups
User newUser = new User();
newUser.setWorkdayId("WD005");
newUser.setEmail("grouped.user@example.com");
newUser.setFirstName("Grouped");
newUser.setLastName("User");
newUser.setActive(true);
Group adminGroup = new Group();
adminGroup.setName("Administrators");
Group devGroup = new Group();
devGroup.setName("Developers");
newUser.setGroups(List.of(adminGroup, devGroup));
// When: Update (insert)
Integer userId = userRepository.update(newUser);
// Then: Should have groups
User inserted = userRepository.getById(userId);
assertNotNull(inserted.getGroups());
assertEquals(2, inserted.getGroups().size());
}
@Test
void testUpdateUserRemoveGroups() {
// Given: User with groups
User user = userRepository.getByWorkdayId("WD001").orElseThrow();
assertEquals(1, user.getGroups().size());
// When: Update with empty groups
user.setGroups(List.of());
userRepository.update(user);
// Then: Groups should be removed
User updated = userRepository.getById(user.getId());
assertTrue(updated.getGroups().isEmpty());
}
@Test
void testUpdateUserChangeGroups() {
// Given: User with Admin group
User user = userRepository.getByWorkdayId("WD001").orElseThrow();
assertEquals("Administrators", user.getGroups().getFirst().getName());
// When: Change to Dev group
Group devGroup = new Group();
devGroup.setName("Developers");
user.setGroups(List.of(devGroup));
userRepository.update(user);
// Then: Should have Dev group
User updated = userRepository.getById(user.getId());
assertEquals(1, updated.getGroups().size());
assertEquals("Developers", updated.getGroups().getFirst().getName());
}
@Test
void testCount() {
// When: Count users
Integer count = userRepository.count();
// Then: Should return 3
assertEquals(3, count);
}
@Test
void testGetUserIdByWorkdayId() {
// When: Get user ID by workday ID
Integer userId = userRepository.getUserIdByWorkdayId("WD001");
// Then: Should find user
assertNotNull(userId);
assertTrue(userId > 0);
}
@Test
void testGetUserIdByWorkdayIdNotFound() {
// When: Get non-existent user
Integer userId = userRepository.getUserIdByWorkdayId("NONEXISTENT");
// Then: Should return null
assertNull(userId);
}
@Test
void testGetByWorkdayId() {
// When: Get user by workday ID
Optional<User> user = userRepository.getByWorkdayId("WD001");
// Then: Should find user
assertTrue(user.isPresent());
assertEquals("WD001", user.get().getWorkdayId());
assertEquals("john.doe@example.com", user.get().getEmail());
assertEquals("John", user.get().getFirstName());
}
@Test
void testGetByWorkdayIdNotFound() {
// When: Get non-existent user
Optional<User> user = userRepository.getByWorkdayId("NONEXISTENT");
// Then: Should not find
assertFalse(user.isPresent());
}
@Test
void testGetById() {
// Given: User ID
Integer userId = userRepository.getUserIdByWorkdayId("WD001");
// When: Get by ID
User user = userRepository.getById(userId);
// Then: Should find user
assertNotNull(user);
assertEquals("WD001", user.getWorkdayId());
}
@Test
void testGetByIdNotFound() {
// When: Get non-existent ID
User user = userRepository.getById(99999);
// Then: Should return null
assertNull(user);
}
@Test
void testGetByEmail() {
// When: Get user by email
User user = userRepository.getByEmail("john.doe@example.com");
// Then: Should find user
assertNotNull(user);
assertEquals("WD001", user.getWorkdayId());
assertEquals("john.doe@example.com", user.getEmail());
}
@Test
void testGetByEmailNotFound() {
// When: Get non-existent email
User user = userRepository.getByEmail("nonexistent@example.com");
// Then: Should return null
assertNull(user);
}
@Test
void testUserWithGroupMemberships() {
// When: Get user with groups
User user = userRepository.getByWorkdayId("WD001").orElseThrow();
// Then: Should have group memberships
assertNotNull(user.getGroups());
assertEquals(1, user.getGroups().size());
assertEquals("Administrators", user.getGroups().getFirst().getName());
}
@Test
void testUserWithoutGroupMemberships() {
// When: Get user without groups
User user = userRepository.getByWorkdayId("WD003").orElseThrow();
// Then: Should have empty groups
assertNotNull(user.getGroups());
assertTrue(user.getGroups().isEmpty());
}
// ========== Helper Methods ==========
private void createTestGroup(String name, String description) {
String sql = "INSERT INTO sys_group (group_name, group_description) VALUES (?, ?)";
executeRawSql(sql, name, description);
}
private void createTestUser(String workdayId, String email, String firstName, String lastName, boolean isActive) {
String isActiveValue = isActive ? dialectProvider.getBooleanTrue() : dialectProvider.getBooleanFalse();
String sql = String.format(
"INSERT INTO sys_user (workday_id, email, firstname, lastname, is_active) VALUES (?, ?, ?, ?, %s)",
isActiveValue);
executeRawSql(sql, workdayId, email, firstName, lastName);
}
private Integer getUserIdByWorkday(String workdayId) {
return jdbcTemplate.queryForObject("SELECT id FROM sys_user WHERE workday_id = ?", Integer.class, workdayId);
}
private void createUserGroupMapping(Integer userId, Integer groupId) {
String sql = "INSERT INTO sys_user_group_mapping (user_id, group_id) VALUES (?, ?)";
executeRawSql(sql, userId, groupId);
}
}