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:
parent
5c8165c60e
commit
52116be1c3
3 changed files with 923 additions and 0 deletions
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue