Skip to content

Commit

Permalink
perf improvement get contingencies in one request (#135)
Browse files Browse the repository at this point in the history
add endpoint to get a list of contengecies in one call
---------

Signed-off-by: jamal-khey <myjamal89@gmail.com>
  • Loading branch information
jamal-khey authored Jul 10, 2024
1 parent 65f05c4 commit 75a5bfa
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,19 @@ public ActionsService(
this.restTemplate = restTemplate;
}

public List<ContingencyInfos> getContingencyList(String name, UUID networkUuid, String variantId) {
Objects.requireNonNull(name);
public List<ContingencyInfos> getContingencyList(List<String> ids, UUID networkUuid, String variantId) {
Objects.requireNonNull(ids);
Objects.requireNonNull(networkUuid);
if (ids.isEmpty()) {
throw new IllegalArgumentException("List 'ids' must not be null or empty");
}

URI path = UriComponentsBuilder
.fromPath(DELIMITER + ACTIONS_API_VERSION + "/contingency-lists/contingency-infos/{name}/export")
.queryParam("networkUuid", networkUuid.toString())
.queryParamIfPresent("variantId", Optional.ofNullable(variantId)).build(name);
.fromPath(DELIMITER + ACTIONS_API_VERSION + "/contingency-lists/contingency-infos/export")
.queryParam("networkUuid", networkUuid.toString())
.queryParamIfPresent("variantId", Optional.ofNullable(variantId))
.queryParam("ids", ids)
.build().toUri();

return restTemplate.exchange(baseUri + path, HttpMethod.GET, null, new ParameterizedTypeReference<List<ContingencyInfos>>() { }).getBody();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,9 @@ protected void preRun(SecurityAnalysisRunContext runContext) {
LOGGER.info("Run security analysis on contingency lists: {}", runContext.getContingencyListNames().stream().map(LogUtils::sanitizeParam).toList());

List<ContingencyInfos> contingencies = observer.observe("contingencies.fetch", runContext,
() -> runContext.getContingencyListNames()
.stream()
.flatMap(contingencyListName -> actionsService.getContingencyList(contingencyListName, runContext.getNetworkUuid(), runContext.getVariantId()).stream())
.toList());
() ->
actionsService.getContingencyList(runContext.getContingencyListNames(), runContext.getNetworkUuid(), runContext.getVariantId())
);

runContext.setContingencies(contingencies);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

Expand Down Expand Up @@ -178,26 +177,6 @@ public void setUp() throws Exception {
return network1;
});

// action service mocking
given(actionsService.getContingencyList(CONTINGENCY_LIST_NAME, NETWORK_UUID, VARIANT_1_ID))
.willReturn(SecurityAnalysisProviderMock.CONTINGENCIES);
given(actionsService.getContingencyList(CONTINGENCY_LIST_NAME_VARIANT, NETWORK_UUID, VARIANT_3_ID))
.willReturn(SecurityAnalysisProviderMock.CONTINGENCIES_VARIANT.stream().map(ContingencyInfos::new).collect(Collectors.toList()));
given(actionsService.getContingencyList(CONTINGENCY_LIST_NAME, NETWORK_UUID, VARIANT_2_ID))
.willReturn(SecurityAnalysisProviderMock.CONTINGENCIES);
given(actionsService.getContingencyList(CONTINGENCY_LIST_NAME, NETWORK_UUID, null))
.willReturn(SecurityAnalysisProviderMock.CONTINGENCIES);
given(actionsService.getContingencyList(CONTINGENCY_LIST2_NAME, NETWORK_UUID, VARIANT_1_ID))
.willReturn(SecurityAnalysisProviderMock.CONTINGENCIES);
given(actionsService.getContingencyList(CONTINGENCY_LIST_NAME, NETWORK_STOP_UUID, VARIANT_2_ID))
.willReturn(SecurityAnalysisProviderMock.CONTINGENCIES);
given(actionsService.getContingencyList(CONTINGENCY_LIST2_NAME, NETWORK_STOP_UUID, VARIANT_2_ID))
.willReturn(SecurityAnalysisProviderMock.CONTINGENCIES);
given(actionsService.getContingencyList(CONTINGENCY_LIST_ERROR_NAME, NETWORK_UUID, VARIANT_1_ID))
.willReturn(SecurityAnalysisProviderMock.CONTINGENCIES);
given(actionsService.getContingencyList(CONTINGENCY_LIST_NAME, NETWORK_STOP_UUID, VARIANT_TO_STOP_ID))
.willReturn(SecurityAnalysisProviderMock.CONTINGENCIES);

// UUID service mocking to always generate the same result UUID
given(uuidGeneratorService.generate()).willReturn(RESULT_UUID);

Expand Down Expand Up @@ -684,7 +663,7 @@ public void runTestWithError() throws Exception {
MvcResult mvcResult;
String resultAsString;

given(actionsService.getContingencyList(CONTINGENCY_LIST_ERROR_NAME, NETWORK_UUID, VARIANT_1_ID))
given(actionsService.getContingencyList(List.of(CONTINGENCY_LIST_ERROR_NAME), NETWORK_UUID, VARIANT_1_ID))
.willThrow(new RuntimeException(ERROR_MESSAGE));

mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_ERROR_NAME
Expand Down Expand Up @@ -735,6 +714,8 @@ public void runWithReportTestElementsNotFoundAndNotConnected() throws Exception

Network network = EurostagTutorialExample1Factory.create(new NetworkFactoryImpl());
given(networkStoreService.getNetwork(NETWORK_UUID, PreloadingStrategy.COLLECTION)).willReturn(network);
given(actionsService.getContingencyList(List.of(CONTINGENCY_LIST_NAME), NETWORK_UUID, null))
.willReturn(SecurityAnalysisProviderMock.CONTINGENCIES);

mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_NAME + "&provider=testProvider" + "&reportUuid=" + REPORT_UUID + "&reporterId=" + UUID.randomUUID() + "&loadFlowParametersUuid=" + UUID.randomUUID()).contentType(MediaType.APPLICATION_JSON)
.header(HEADER_USER_ID, "testUserId")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public class ActionsServiceTest {
private static final String VARIANT_ID = "variant_id";

private static final String LIST_NAME = "myList";
private static final String LIST_NAME_VARIANT = "myListVariant";

private static final String VERY_LARGE_LIST_NAME = "veryLargelist";

Expand Down Expand Up @@ -92,25 +93,31 @@ private String initMockWebServer() throws IOException {
String jsonExpected = objectMapper.writeValueAsString(List.of(CONTINGENCY));
String veryLargeJsonExpected = objectMapper.writeValueAsString(createVeryLargeList());
String jsonVariantExpected = objectMapper.writeValueAsString(List.of(CONTINGENCY_VARIANT));
String jsonExpectedForList = objectMapper.writeValueAsString(List.of(CONTINGENCY, CONTINGENCY_VARIANT));

final Dispatcher dispatcher = new Dispatcher() {
@NotNull
@Override
public MockResponse dispatch(RecordedRequest request) {
String requestPath = Objects.requireNonNull(request.getPath());
if (requestPath.equals(String.format("/v1/contingency-lists/contingency-infos/%s/export?networkUuid=%s&variantId=%s", LIST_NAME, NETWORK_UUID, VARIANT_ID))) {

if (requestPath.equals(String.format("/v1/contingency-lists/contingency-infos/export?networkUuid=%s&variantId=%s&ids=%s", NETWORK_UUID, VARIANT_ID, LIST_NAME))) {
return new MockResponse().setResponseCode(HttpStatus.OK.value())
.setBody(jsonVariantExpected)
.addHeader("Content-Type", "application/json; charset=utf-8");
} else if (requestPath.equals(String.format("/v1/contingency-lists/contingency-infos/%s/export?networkUuid=%s", LIST_NAME, NETWORK_UUID))) {
} else if (requestPath.equals(String.format("/v1/contingency-lists/contingency-infos/export?networkUuid=%s&ids=%s", NETWORK_UUID, LIST_NAME))) {
return new MockResponse().setResponseCode(HttpStatus.OK.value())
.setBody(jsonExpected)
.addHeader("Content-Type", "application/json; charset=utf-8");
} else if (requestPath.equals(String.format("/v1/contingency-lists/contingency-infos/%s/export?networkUuid=%s&variantId=%s", VERY_LARGE_LIST_NAME, NETWORK_UUID, VARIANT_ID))
|| requestPath.equals(String.format("/v1/contingency-lists/contingency-infos/%s/export?networkUuid=%s", VERY_LARGE_LIST_NAME, NETWORK_UUID))) {
} else if (requestPath.equals(String.format("/v1/contingency-lists/contingency-infos/export?networkUuid=%s&variantId=%s&ids=%s", NETWORK_UUID, VARIANT_ID, VERY_LARGE_LIST_NAME))
|| requestPath.equals(String.format("/v1/contingency-lists/contingency-infos/export?networkUuid=%s&ids=%s", NETWORK_UUID, VERY_LARGE_LIST_NAME))) {
return new MockResponse().setResponseCode(HttpStatus.OK.value())
.setBody(veryLargeJsonExpected)
.addHeader("Content-Type", "application/json; charset=utf-8");
} else if (requestPath.equals(String.format("/v1/contingency-lists/contingency-infos/export?networkUuid=%s&ids=%s&ids=%s", NETWORK_UUID, LIST_NAME, LIST_NAME_VARIANT))) {
return new MockResponse().setResponseCode(HttpStatus.OK.value())
.setBody(jsonExpectedForList)
.addHeader("Content-Type", "application/json; charset=utf-8");
} else {
return new MockResponse().setResponseCode(HttpStatus.NOT_FOUND.value()).setBody("Path not supported: " + request.getPath());
}
Expand All @@ -131,20 +138,26 @@ private List<ContingencyInfos> createVeryLargeList() {

@Test
public void test() {
List<ContingencyInfos> list = actionsService.getContingencyList(LIST_NAME, UUID.fromString(NETWORK_UUID), null);
List<ContingencyInfos> list = actionsService.getContingencyList(List.of(LIST_NAME), UUID.fromString(NETWORK_UUID), null);
list.forEach(contingencyInfos -> assertArrayEquals(List.of(WRONG_ID).toArray(new Object[0]), contingencyInfos.getNotFoundElements().toArray(new String[0])));
assertEquals(Stream.of(CONTINGENCY).map(ContingencyInfos::getContingency).toList(), list.stream().map(ContingencyInfos::getContingency).collect(Collectors.toList()));
list = actionsService.getContingencyList(LIST_NAME, UUID.fromString(NETWORK_UUID), VARIANT_ID);
list = actionsService.getContingencyList(List.of(LIST_NAME), UUID.fromString(NETWORK_UUID), VARIANT_ID);
assertEquals(Stream.of(CONTINGENCY_VARIANT).map(ContingencyInfos::getContingency).toList(), list.stream().map(ContingencyInfos::getContingency).collect(Collectors.toList()));
}

@Test
public void testVeryLargeList() {
// DataBufferLimitException should not be thrown with this message : "Exceeded limit on max bytes to buffer : DATA_BUFFER_LIMIT"
List<ContingencyInfos> list = actionsService.getContingencyList(VERY_LARGE_LIST_NAME, UUID.fromString(NETWORK_UUID), null);
List<ContingencyInfos> list = actionsService.getContingencyList(List.of(VERY_LARGE_LIST_NAME), UUID.fromString(NETWORK_UUID), null);
list.forEach(contingencyInfos -> assertArrayEquals(List.of().toArray(new Object[0]), contingencyInfos.getNotFoundElements().toArray(new String[0])));
assertEquals(createVeryLargeList().stream().map(ContingencyInfos::getContingency).collect(Collectors.toList()), list.stream().map(ContingencyInfos::getContingency).collect(Collectors.toList()));
list = actionsService.getContingencyList(VERY_LARGE_LIST_NAME, UUID.fromString(NETWORK_UUID), VARIANT_ID);
list = actionsService.getContingencyList(List.of(VERY_LARGE_LIST_NAME), UUID.fromString(NETWORK_UUID), VARIANT_ID);
assertEquals(createVeryLargeList().stream().map(ContingencyInfos::getContingency).collect(Collectors.toList()), list.stream().map(ContingencyInfos::getContingency).collect(Collectors.toList()));
}

@Test
public void testGetContingenciesByListOfIds() {
List<ContingencyInfos> list = actionsService.getContingencyList(List.of(LIST_NAME, LIST_NAME_VARIANT), UUID.fromString(NETWORK_UUID), null);
assertEquals(Stream.of(CONTINGENCY, CONTINGENCY_VARIANT).map(ContingencyInfos::getContingency).toList(), list.stream().map(ContingencyInfos::getContingency).collect(Collectors.toList()));
}
}

0 comments on commit 75a5bfa

Please sign in to comment.