From 8e717e9f45c43b980a91cc1ffd364563b5bbef9d Mon Sep 17 00:00:00 2001 From: achour94 Date: Tue, 24 Feb 2026 11:21:39 +0100 Subject: [PATCH] Implement state estimation result provider and service Signed-off-by: achour94 --- .../gridsuite/monitor/commons/ResultType.java | 1 + .../StateEstimationResultProvider.java | 39 ++++++++ .../services/StateEstimationService.java | 67 +++++++++++++ .../src/main/resources/application-local.yaml | 4 +- .../StateEstimationResultProviderTest.java | 59 +++++++++++ .../services/StateEstimationServiceTest.java | 98 +++++++++++++++++++ 6 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 monitor-server/src/main/java/org/gridsuite/monitor/server/services/StateEstimationResultProvider.java create mode 100644 monitor-server/src/main/java/org/gridsuite/monitor/server/services/StateEstimationService.java create mode 100644 monitor-server/src/test/java/org/gridsuite/monitor/server/services/StateEstimationResultProviderTest.java create mode 100644 monitor-server/src/test/java/org/gridsuite/monitor/server/services/StateEstimationServiceTest.java diff --git a/monitor-commons/src/main/java/org/gridsuite/monitor/commons/ResultType.java b/monitor-commons/src/main/java/org/gridsuite/monitor/commons/ResultType.java index 19864a79..78be8dda 100644 --- a/monitor-commons/src/main/java/org/gridsuite/monitor/commons/ResultType.java +++ b/monitor-commons/src/main/java/org/gridsuite/monitor/commons/ResultType.java @@ -11,4 +11,5 @@ */ public enum ResultType { SECURITY_ANALYSIS, + STATE_ESTIMATION } diff --git a/monitor-server/src/main/java/org/gridsuite/monitor/server/services/StateEstimationResultProvider.java b/monitor-server/src/main/java/org/gridsuite/monitor/server/services/StateEstimationResultProvider.java new file mode 100644 index 00000000..cb1faa9c --- /dev/null +++ b/monitor-server/src/main/java/org/gridsuite/monitor/server/services/StateEstimationResultProvider.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2026, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.monitor.server.services; + +import org.gridsuite.monitor.commons.ResultType; +import org.springframework.stereotype.Service; + +import java.util.UUID; + +/** + * @author Achour BERRAHMA + */ +@Service +public class StateEstimationResultProvider implements ResultProvider { + private final StateEstimationService stateEstimationService; + + public StateEstimationResultProvider(StateEstimationService stateEstimationService) { + this.stateEstimationService = stateEstimationService; + } + + @Override + public ResultType getType() { + return ResultType.STATE_ESTIMATION; + } + + @Override + public String getResult(UUID resultId) { + return stateEstimationService.getResult(resultId); + } + + @Override + public void deleteResult(UUID resultId) { + stateEstimationService.deleteResult(resultId); + } +} diff --git a/monitor-server/src/main/java/org/gridsuite/monitor/server/services/StateEstimationService.java b/monitor-server/src/main/java/org/gridsuite/monitor/server/services/StateEstimationService.java new file mode 100644 index 00000000..052b17c6 --- /dev/null +++ b/monitor-server/src/main/java/org/gridsuite/monitor/server/services/StateEstimationService.java @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2026, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.monitor.server.services; + +import lombok.Setter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.List; +import java.util.UUID; + +/** + * @author Achour BERRAHMA + */ +@Service +public class StateEstimationService { + private static final Logger LOGGER = LoggerFactory.getLogger(StateEstimationService.class); + static final String SE_API_VERSION = "v1"; + private static final String DELIMITER = "/"; + + private final RestTemplate restTemplate; + + @Setter + private String stateEstimationServerBaseUri; + + private String getStateEstimationServerBaseUri() { + return this.stateEstimationServerBaseUri + DELIMITER + SE_API_VERSION + DELIMITER; + } + + public StateEstimationService( + RestTemplateBuilder restTemplateBuilder, + @Value("${gridsuite.services.state-estimation-server.base-uri:http://state-estimation-server/}") String stateEstimationServerBaseUri) { + this.stateEstimationServerBaseUri = stateEstimationServerBaseUri; + this.restTemplate = restTemplateBuilder.build(); + } + + public String getResult(UUID resultUuid) { + LOGGER.info("Fetching state estimation result {}", resultUuid); + + var path = UriComponentsBuilder.fromPath("/results/{resultUuid}") + .buildAndExpand(resultUuid) + .toUriString(); + + return restTemplate.exchange(getStateEstimationServerBaseUri() + path, HttpMethod.GET, null, String.class).getBody(); + } + + public void deleteResult(UUID resultUuid) { + LOGGER.info("Deleting state estimation result {}", resultUuid); + + var path = UriComponentsBuilder.fromPath("/results") + .queryParam("resultsUuids", List.of(resultUuid)) + .build() + .toUriString(); + + restTemplate.delete(getStateEstimationServerBaseUri() + path); + } +} diff --git a/monitor-server/src/main/resources/application-local.yaml b/monitor-server/src/main/resources/application-local.yaml index a72bc10d..6ee5eb42 100644 --- a/monitor-server/src/main/resources/application-local.yaml +++ b/monitor-server/src/main/resources/application-local.yaml @@ -14,4 +14,6 @@ gridsuite: report-server: base-uri: http://localhost:5028 security-analysis-server: - base-uri: http://localhost:5023 \ No newline at end of file + base-uri: http://localhost:5023 + state-estimation-server: + base-uri: http://localhost:6040 \ No newline at end of file diff --git a/monitor-server/src/test/java/org/gridsuite/monitor/server/services/StateEstimationResultProviderTest.java b/monitor-server/src/test/java/org/gridsuite/monitor/server/services/StateEstimationResultProviderTest.java new file mode 100644 index 00000000..81589f1d --- /dev/null +++ b/monitor-server/src/test/java/org/gridsuite/monitor/server/services/StateEstimationResultProviderTest.java @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2026, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.monitor.server.services; + +import org.gridsuite.monitor.commons.ResultType; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.*; + +/** + * @author Achour BERRAHMA + */ +class StateEstimationResultProviderTest { + private final StateEstimationService stateEstimationService = + Mockito.mock(StateEstimationService.class); + + private final StateEstimationResultProvider provider = + new StateEstimationResultProvider(stateEstimationService); + + @Test + void getTypeShouldReturnStateEstimation() { + assertThat(provider.getType()) + .isEqualTo(ResultType.STATE_ESTIMATION); + } + + @Test + void getResultShouldDelegateToStateEstimationService() { + UUID id = UUID.randomUUID(); + String expected = "result"; + + when(stateEstimationService.getResult(id)).thenReturn(expected); + + String result = provider.getResult(id); + + assertThat(result).isEqualTo(expected); + verify(stateEstimationService).getResult(id); + verifyNoMoreInteractions(stateEstimationService); + } + + @Test + void deleteResultShouldDelegateToStateEstimationService() { + UUID id = UUID.randomUUID(); + + doNothing().when(stateEstimationService).deleteResult(id); + + provider.deleteResult(id); + + verify(stateEstimationService).deleteResult(id); + verifyNoMoreInteractions(stateEstimationService); + } +} diff --git a/monitor-server/src/test/java/org/gridsuite/monitor/server/services/StateEstimationServiceTest.java b/monitor-server/src/test/java/org/gridsuite/monitor/server/services/StateEstimationServiceTest.java new file mode 100644 index 00000000..c7ff33a5 --- /dev/null +++ b/monitor-server/src/test/java/org/gridsuite/monitor/server/services/StateEstimationServiceTest.java @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2026, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.monitor.server.services; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.client.RestClientTest; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.test.web.client.match.MockRestRequestMatchers; +import org.springframework.test.web.client.response.MockRestResponseCreators; +import org.springframework.web.client.RestClientException; + +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +/** + * @author Achour BERRAHMA + */ +@RestClientTest(StateEstimationService.class) +@ContextConfiguration(classes = { StateEstimationService.class }) +class StateEstimationServiceTest { + + private static final UUID RESULT_UUID = UUID.randomUUID(); + private static final String RESULT_BODY = "{\"status\":\"OK\"}"; + + @Autowired + private StateEstimationService stateEstimationService; + + @Autowired + private MockRestServiceServer server; + + @AfterEach + void tearDown() { + server.verify(); + } + + @Test + void getResult() { + server.expect(MockRestRequestMatchers.method(HttpMethod.GET)) + .andExpect(MockRestRequestMatchers.requestTo( + "http://state-estimation-server/v1/results/" + RESULT_UUID + )) + .andRespond(MockRestResponseCreators.withSuccess( + RESULT_BODY, + MediaType.APPLICATION_JSON + )); + + String result = stateEstimationService.getResult(RESULT_UUID); + + assertThat(result).isEqualTo(RESULT_BODY); + } + + @Test + void getResultFailed() { + server.expect(MockRestRequestMatchers.method(HttpMethod.GET)) + .andExpect(MockRestRequestMatchers.requestTo( + "http://state-estimation-server/v1/results/" + RESULT_UUID + )) + .andRespond(MockRestResponseCreators.withServerError()); + + assertThatThrownBy(() -> stateEstimationService.getResult(RESULT_UUID)) + .isInstanceOf(RestClientException.class); + } + + @Test + void deleteResult() { + server.expect(MockRestRequestMatchers.method(HttpMethod.DELETE)) + .andExpect(MockRestRequestMatchers.requestTo( + "http://state-estimation-server/v1/results?resultsUuids=" + RESULT_UUID + )) + .andRespond(MockRestResponseCreators.withSuccess()); + + assertThatNoException().isThrownBy(() -> stateEstimationService.deleteResult(RESULT_UUID)); + } + + @Test + void deleteResultFailed() { + server.expect(MockRestRequestMatchers.method(HttpMethod.DELETE)) + .andExpect(MockRestRequestMatchers.requestTo( + "http://state-estimation-server/v1/results?resultsUuids=" + RESULT_UUID + )) + .andRespond(MockRestResponseCreators.withServerError()); + + assertThatThrownBy(() -> stateEstimationService.deleteResult(RESULT_UUID)) + .isInstanceOf(RestClientException.class); + } +}