Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Append unique Order to Pageable param when necessary to get deterministic Page content #72

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down Expand Up @@ -150,12 +153,13 @@ public Page<FaultResult> getFaultResultsPage(UUID resultUuid, FaultResultsMode m
result = resultRepository.find(resultUuid);
if (result.isPresent()) {
Page<FaultResultEntity> faultResultEntitiesPage = Page.empty();
Pageable deterministicPageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), appendUniqueOrderIfNecessary(pageable.getSort(), new Order(Sort.Direction.ASC, "fault.id")));
switch (mode) {
case BASIC, FULL:
faultResultEntitiesPage = resultRepository.findFaultResultsPage(result.get(), resourceFilters, pageable, mode);
faultResultEntitiesPage = resultRepository.findFaultResultsPage(result.get(), resourceFilters, deterministicPageable, mode);
break;
case WITH_LIMIT_VIOLATIONS:
faultResultEntitiesPage = resultRepository.findFaultResultsWithLimitViolationsPage(result.get(), resourceFilters, pageable);
faultResultEntitiesPage = resultRepository.findFaultResultsWithLimitViolationsPage(result.get(), resourceFilters, deterministicPageable);
break;
case NONE:
default:
Expand All @@ -164,7 +168,7 @@ public Page<FaultResult> getFaultResultsPage(UUID resultUuid, FaultResultsMode m
Page<FaultResult> faultResultsPage = faultResultEntitiesPage.map(fr -> fromEntity(fr, mode));
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Get ShortCircuit Results {} in {}ms", resultUuid, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime.get()));
LOGGER.info("pageable = {}", LogUtils.sanitizeParam(pageable.toString()));
LOGGER.info("pageable = {}", LogUtils.sanitizeParam(deterministicPageable.toString()));
}
return faultResultsPage;
}
Expand All @@ -177,11 +181,12 @@ public Page<FeederResult> getFeederResultsPage(UUID resultUuid, List<ResourceFil
startTime.set(System.nanoTime());
Optional<ShortCircuitAnalysisResultEntity> result = resultRepository.find(resultUuid);
if (result.isPresent()) {
Page<FeederResultEntity> feederResultEntitiesPage = resultRepository.findFeederResultsPage(result.get(), resourceFilters, pageable);
Pageable deterministicPageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), appendUniqueOrderIfNecessary(pageable.getSort(), new Order(Sort.Direction.ASC, "feederResultUuid")));
Page<FeederResultEntity> feederResultEntitiesPage = resultRepository.findFeederResultsPage(result.get(), resourceFilters, deterministicPageable);
Page<FeederResult> feederResultsPage = feederResultEntitiesPage.map(ShortCircuitService::fromEntity);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Get ShortCircuit Results {} in {}ms", resultUuid, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime.get()));
LOGGER.info("pageable = {}", LogUtils.sanitizeParam(pageable.toString()));
LOGGER.info("pageable = {}", LogUtils.sanitizeParam(deterministicPageable.toString()));
}
return feederResultsPage;
}
Expand All @@ -207,4 +212,15 @@ public void setStatus(List<UUID> resultUuids, String status) {
public void stop(UUID resultUuid, String receiver) {
notificationService.sendCancelMessage(new ShortCircuitCancelContext(resultUuid, receiver).toMessage());
}

// If the Sort Orders in Pageable contains already a sort Order on the property column then do not append it
// otherwise append it at THE END to allow sorting rules to happen with rows containing same value on the sorted column
// and then finally define a deterministic order.
private Sort appendUniqueOrderIfNecessary(Sort sourceSort, Order uniqueOrder) {
Order order = sourceSort.getOrderFor(uniqueOrder.getProperty());
if (order == null) {
return sourceSort.and(Sort.by(uniqueOrder));
}
return sourceSort;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ private static final class ShortCircuitAnalysisResultMock {
static final FaultResult FAULT_RESULT_4 = new FortescueFaultResult(new BusFault("VLHV2_0", "ELEMENT_ID_2"), 18.0,
List.of(FEEDER_RESULT_4, FEEDER_RESULT_5, FEEDER_RESULT_6), List.of(LIMIT_VIOLATION_1, LIMIT_VIOLATION_2, LIMIT_VIOLATION_3),
new FortescueValue(21.328664779663086, -80.73799896240234, Double.NaN, Double.NaN, Double.NaN, Double.NaN), new FortescueValue(21.328664779663086, -80.73799896240234, Double.NaN, Double.NaN, Double.NaN, Double.NaN), Collections.emptyList(), null, FaultResult.Status.SUCCESS);
static final FaultResult FAULT_RESULT_4_PAGE_0 = new FortescueFaultResult(new BusFault("VLHV2_0", "ELEMENT_ID_2"), 18.0,
List.of(FEEDER_RESULT_4, FEEDER_RESULT_5), List.of(LIMIT_VIOLATION_1, LIMIT_VIOLATION_2, LIMIT_VIOLATION_3),
new FortescueValue(21.328664779663086, -80.73799896240234, Double.NaN, Double.NaN, Double.NaN, Double.NaN), new FortescueValue(21.328664779663086, -80.73799896240234, Double.NaN, Double.NaN, Double.NaN, Double.NaN), Collections.emptyList(), null, FaultResult.Status.SUCCESS);
static final FaultResult FAULT_RESULT_BASIC_1 = new MagnitudeFaultResult(new BusFault("VLHV1_0", "ELEMENT_ID_1"), 17.0,
List.of(), List.of(),
45.3, FaultResult.Status.SUCCESS);
Expand All @@ -129,9 +132,12 @@ private static final class ShortCircuitAnalysisResultMock {

static final ShortCircuitAnalysisResult RESULT_MAGNITUDE_FULL = new ShortCircuitAnalysisResult(List.of(FAULT_RESULT_1, FAULT_RESULT_2, FAULT_RESULT_3));
static final ShortCircuitAnalysisResult RESULT_FORTESCUE_FULL = new ShortCircuitAnalysisResult(List.of(FAULT_RESULT_4));
static final ShortCircuitAnalysisResult RESULT_SORTED_PAGE_0 = new ShortCircuitAnalysisResult(List.of(FAULT_RESULT_1, FAULT_RESULT_3));
static final ShortCircuitAnalysisResult RESULT_SORTED_PAGE_1 = new ShortCircuitAnalysisResult(List.of(FAULT_RESULT_3));
static final ShortCircuitAnalysisResult RESULT_FORTESCUE_PAGE_0 = new ShortCircuitAnalysisResult(List.of(FAULT_RESULT_4_PAGE_0));
static final ShortCircuitAnalysisResult RESULT_DEFAULT_SORTED_PAGE_0 = new ShortCircuitAnalysisResult(List.of(FAULT_RESULT_3, FAULT_RESULT_1));
static final ShortCircuitAnalysisResult RESULT_SORTED_PAGE_0 = new ShortCircuitAnalysisResult(List.of(FAULT_RESULT_3, FAULT_RESULT_1));
static final ShortCircuitAnalysisResult RESULT_SORTED_DESC_PAGE_1 = new ShortCircuitAnalysisResult(List.of(FAULT_RESULT_3));
static final ShortCircuitAnalysisResult RESULT_WITH_LIMIT_VIOLATIONS = new ShortCircuitAnalysisResult(List.of(FAULT_RESULT_1, FAULT_RESULT_3));
static final ShortCircuitAnalysisResult RESULT_WITH_LIMIT_VIOLATIONS_PAGE_0 = new ShortCircuitAnalysisResult(List.of(FAULT_RESULT_3, FAULT_RESULT_1));
static final ShortCircuitAnalysisResult RESULT_BASIC = new ShortCircuitAnalysisResult(List.of(FAULT_RESULT_BASIC_1, FAULT_RESULT_BASIC_2, FAULT_RESULT_BASIC_3));
}

Expand Down Expand Up @@ -189,9 +195,9 @@ private static void assertResultsEquals(ShortCircuitAnalysisResult result, org.g

private static void assertPagedFaultResultsEquals(ShortCircuitAnalysisResult result, List<org.gridsuite.shortcircuit.server.dto.FaultResult> faultResults) {
assertEquals(result.getFaultResults().size(), faultResults.size());
List<FaultResult> orderedFaultResults = result.getFaultResults().stream().sorted(Comparator.comparing(fr -> fr.getFault().getId())).collect(Collectors.toList());
// List<FaultResult> orderedFaultResults = result.getFaultResults().stream().sorted(Comparator.comparing(fr -> fr.getFault().getId())).collect(Collectors.toList());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove it ?

// don't need to sort here it's done in the paged request
assertFaultResultsEquals(orderedFaultResults, faultResults);
assertFaultResultsEquals(result.getFaultResults(), faultResults);
}

private static void assertFaultResultsEquals(List<FaultResult> faultResults, List<org.gridsuite.shortcircuit.server.dto.FaultResult> faultResultsDto) {
Expand Down Expand Up @@ -353,7 +359,19 @@ public void runTest() throws Exception {
JsonNode faultResultsPageNode = mapper.readTree(result.getResponse().getContentAsString());
ObjectReader faultResultsReader = mapper.readerFor(new TypeReference<List<org.gridsuite.shortcircuit.server.dto.FaultResult>>() { });
List<org.gridsuite.shortcircuit.server.dto.FaultResult> faultResultsPageDto0 = faultResultsReader.readValue(faultResultsPageNode.get("content"));
assertPagedFaultResultsEquals(ShortCircuitAnalysisResultMock.RESULT_WITH_LIMIT_VIOLATIONS, faultResultsPageDto0);
assertPagedFaultResultsEquals(ShortCircuitAnalysisResultMock.RESULT_WITH_LIMIT_VIOLATIONS_PAGE_0, faultResultsPageDto0);

result = mockMvc.perform(get(
"/" + VERSION + "/results/{resultUuid}/fault_results/paged", RESULT_UUID)
.param("mode", "FULL")
.param("page", "0")
.param("size", "2"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andReturn();
JsonNode faultResultsDefaultPageNode0 = mapper.readTree(result.getResponse().getContentAsString());
List<org.gridsuite.shortcircuit.server.dto.FaultResult> faultResultsDefaultPageDto0Full = faultResultsReader.readValue(faultResultsDefaultPageNode0.get("content"));
assertPagedFaultResultsEquals(ShortCircuitAnalysisResultMock.RESULT_DEFAULT_SORTED_PAGE_0, faultResultsDefaultPageDto0Full);

result = mockMvc.perform(get(
"/" + VERSION + "/results/{resultUuid}/fault_results/paged", RESULT_UUID)
Expand All @@ -379,7 +397,7 @@ public void runTest() throws Exception {
.andReturn();
JsonNode faultResultsPageNode1 = mapper.readTree(result.getResponse().getContentAsString());
List<org.gridsuite.shortcircuit.server.dto.FaultResult> faultResultsPageDto1Full = faultResultsReader.readValue(faultResultsPageNode1.get("content"));
assertPagedFaultResultsEquals(ShortCircuitAnalysisResultMock.RESULT_SORTED_PAGE_1, faultResultsPageDto1Full);
assertPagedFaultResultsEquals(ShortCircuitAnalysisResultMock.RESULT_SORTED_DESC_PAGE_1, faultResultsPageDto1Full);

// should throw not found if result does not exist
mockMvc.perform(get("/" + VERSION + "/results/{resultUuid}", OTHER_RESULT_UUID))
Expand Down Expand Up @@ -440,7 +458,8 @@ public void runWithBusIdTest() throws Exception {
result = mockMvc.perform(get(
"/" + VERSION + "/results/{resultUuid}/feeder_results/paged", RESULT_UUID)
.param("page", "0")
.param("size", "3"))
.param("size", "2")
.param("sort", "connectableId")) // to be predictive
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andReturn();
Expand All @@ -450,7 +469,7 @@ public void runWithBusIdTest() throws Exception {
List<org.gridsuite.shortcircuit.server.dto.FeederResult> feederResults = reader.readValue(feederResultsPage.get("content"));
// we update the fault result with the feeders we just get to be able to use the assertion
org.gridsuite.shortcircuit.server.dto.FaultResult formattedFaultResult = new org.gridsuite.shortcircuit.server.dto.FaultResult(faultResult.getFault(), faultResult.getCurrent(), faultResult.getPositiveMagnitude(), faultResult.getShortCircuitPower(), faultResult.getLimitViolations(), feederResults, faultResult.getShortCircuitLimits());
assertPagedFaultResultsEquals(ShortCircuitAnalysisResultMock.RESULT_FORTESCUE_FULL, List.of(formattedFaultResult));
assertPagedFaultResultsEquals(ShortCircuitAnalysisResultMock.RESULT_FORTESCUE_PAGE_0, List.of(formattedFaultResult));
}
}

Expand Down
Loading