diff --git a/pom.xml b/pom.xml
index 66051ebc..e81fe01f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -138,10 +138,6 @@
com.powsybl
powsybl-ws-commons
-
- io.projectreactor
- reactor-core
-
org.springframework.cloud
spring-cloud-stream
@@ -152,11 +148,11 @@
org.springframework.boot
- spring-boot-starter-webflux
+ spring-boot-starter-web
org.springdoc
- springdoc-openapi-starter-webflux-ui
+ springdoc-openapi-starter-webmvc-ui
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/WebFluxConfig.java b/src/main/java/org/gridsuite/securityanalysis/server/RestTemplateConfig.java
similarity index 52%
rename from src/main/java/org/gridsuite/securityanalysis/server/WebFluxConfig.java
rename to src/main/java/org/gridsuite/securityanalysis/server/RestTemplateConfig.java
index a597ec52..ee01e48c 100644
--- a/src/main/java/org/gridsuite/securityanalysis/server/WebFluxConfig.java
+++ b/src/main/java/org/gridsuite/securityanalysis/server/RestTemplateConfig.java
@@ -1,10 +1,11 @@
+package org.gridsuite.securityanalysis.server;
+
/**
- * Copyright (c) 2020, RTE (http://www.rte-france.com)
+ * Copyright (c) 2023, 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.securityanalysis.server;
import com.fasterxml.jackson.databind.InjectableValues;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -15,27 +16,37 @@
import com.powsybl.security.json.SecurityAnalysisJsonModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.http.codec.ServerCodecConfigurer;
-import org.springframework.http.codec.json.Jackson2JsonDecoder;
-import org.springframework.http.codec.json.Jackson2JsonEncoder;
+import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
-import org.springframework.web.reactive.config.WebFluxConfigurer;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.web.client.RestTemplate;
-/**
- * @author Geoffroy Jamgotchian
- */
@Configuration
-public class WebFluxConfig implements WebFluxConfigurer {
+public class RestTemplateConfig {
+
+ @Bean
+ public RestTemplate restTemplate() {
+ final RestTemplate restTemplate = new RestTemplate();
+
+ //find and replace Jackson message converter with our own
+ for (int i = 0; i < restTemplate.getMessageConverters().size(); i++) {
+ final HttpMessageConverter> httpMessageConverter = restTemplate.getMessageConverters().get(i);
+ if (httpMessageConverter instanceof MappingJackson2HttpMessageConverter) {
+ restTemplate.getMessageConverters().set(i, mappingJackson2HttpMessageConverter());
+ }
+ }
+
+ return restTemplate;
+ }
- @Override
- public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
- var objectMapper = objectMapper();
- configurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(objectMapper));
- configurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper));
+ public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
+ MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
+ converter.setObjectMapper(objectMapper());
+ return converter;
}
- public static ObjectMapper createObjectMapper() {
- var objectMapper = Jackson2ObjectMapperBuilder.json().build();
+ private ObjectMapper createObjectMapper() {
+ ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().build();
objectMapper.registerModule(new ContingencyJsonModule());
objectMapper.registerModule(new SecurityAnalysisJsonModule());
objectMapper.registerModule(new LoadFlowParametersJsonModule());
@@ -48,4 +59,6 @@ public static ObjectMapper createObjectMapper() {
public ObjectMapper objectMapper() {
return createObjectMapper();
}
+
}
+
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisApplication.java b/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisApplication.java
index 4b4ac4ff..bcebfa00 100644
--- a/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisApplication.java
+++ b/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisApplication.java
@@ -11,14 +11,12 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
-import org.springframework.web.reactive.config.EnableWebFlux;
/**
* @author Geoffroy Jamgotchian
*/
@SuppressWarnings("checkstyle:HideUtilityClassConstructor")
@SpringBootApplication
-@EnableWebFlux
@ComponentScan(basePackageClasses = {SecurityAnalysisApplication.class, NetworkStoreService.class})
public class SecurityAnalysisApplication {
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisController.java b/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisController.java
index 561174c3..1133cb28 100644
--- a/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisController.java
+++ b/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisController.java
@@ -15,8 +15,8 @@
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
-import org.gridsuite.securityanalysis.server.dto.SubjectLimitViolationToContingencyDTO;
-import org.gridsuite.securityanalysis.server.dto.ContingencyToSubjectLimitViolationDTO;
+import org.gridsuite.securityanalysis.server.dto.SubjectLimitViolationResultDTO;
+import org.gridsuite.securityanalysis.server.dto.ContingencyResultDTO;
import org.gridsuite.securityanalysis.server.dto.SecurityAnalysisParametersInfos;
import org.gridsuite.securityanalysis.server.dto.SecurityAnalysisStatus;
import org.gridsuite.securityanalysis.server.service.SecurityAnalysisRunContext;
@@ -25,7 +25,6 @@
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
-import reactor.core.publisher.Mono;
import java.util.Collections;
import java.util.List;
@@ -61,7 +60,7 @@ private static List getNonNullOtherNetworkUuids(List otherNetworkUui
description = "The security analysis has been performed",
content = {@Content(mediaType = APPLICATION_JSON_VALUE,
schema = @Schema(implementation = SecurityAnalysisResult.class))})})
- public ResponseEntity> run(@Parameter(description = "Network UUID") @PathVariable("networkUuid") UUID networkUuid,
+ public ResponseEntity run(@Parameter(description = "Network UUID") @PathVariable("networkUuid") UUID networkUuid,
@Parameter(description = "Variant Id") @RequestParam(name = "variantId", required = false) String variantId,
@Parameter(description = "Other networks UUID (to merge with main one))") @RequestParam(name = "networkUuid", required = false) List otherNetworkUuids,
@Parameter(description = "Contingency list name") @RequestParam(name = "contingencyListName", required = false) List contigencyListNames,
@@ -71,7 +70,7 @@ public ResponseEntity> run(@Parameter(description =
@RequestBody(required = false) SecurityAnalysisParametersInfos parameters) {
String providerToUse = provider != null ? provider : service.getDefaultProvider();
List nonNullOtherNetworkUuids = getNonNullOtherNetworkUuids(otherNetworkUuids);
- Mono result = workerService.run(new SecurityAnalysisRunContext(networkUuid, variantId, nonNullOtherNetworkUuids, contigencyListNames, null, providerToUse, parameters, reportUuid, reporterId));
+ SecurityAnalysisResult result = workerService.run(new SecurityAnalysisRunContext(networkUuid, variantId, nonNullOtherNetworkUuids, contigencyListNames, null, providerToUse, parameters, reportUuid, reporterId));
return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(result);
}
@@ -81,7 +80,7 @@ public ResponseEntity> run(@Parameter(description =
description = "The security analysis has been performed and results have been saved to database",
content = {@Content(mediaType = APPLICATION_JSON_VALUE,
schema = @Schema(implementation = SecurityAnalysisResult.class))})})
- public ResponseEntity> runAndSave(@Parameter(description = "Network UUID") @PathVariable("networkUuid") UUID networkUuid,
+ public ResponseEntity runAndSave(@Parameter(description = "Network UUID") @PathVariable("networkUuid") UUID networkUuid,
@Parameter(description = "Variant Id") @RequestParam(name = "variantId", required = false) String variantId,
@Parameter(description = "Other networks UUID (to merge with main one))") @RequestParam(name = "networkUuid", required = false) List otherNetworkUuids,
@Parameter(description = "Contingency list name") @RequestParam(name = "contingencyListName", required = false) List contigencyListNames,
@@ -92,7 +91,7 @@ public ResponseEntity> runAndSave(@Parameter(description = "Network U
@RequestBody(required = false) SecurityAnalysisParametersInfos parameters) {
String providerToUse = provider != null ? provider : service.getDefaultProvider();
List nonNullOtherNetworkUuids = getNonNullOtherNetworkUuids(otherNetworkUuids);
- Mono resultUuid = service.runAndSaveResult(new SecurityAnalysisRunContext(networkUuid, variantId, nonNullOtherNetworkUuids, contigencyListNames, receiver, providerToUse, parameters, reportUuid, reporterId));
+ UUID resultUuid = service.runAndSaveResult(new SecurityAnalysisRunContext(networkUuid, variantId, nonNullOtherNetworkUuids, contigencyListNames, receiver, providerToUse, parameters, reportUuid, reporterId));
return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(resultUuid);
}
@@ -100,73 +99,77 @@ public ResponseEntity> runAndSave(@Parameter(description = "Network U
@Operation(summary = "Get a security analysis result from the database - N result")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The security analysis result"),
@ApiResponse(responseCode = "404", description = "Security analysis result has not been found")})
- public Mono> getNResult(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid) {
+ public ResponseEntity getNResult(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid) {
+ PreContingencyResult result = service.getNResult(resultUuid);
- Mono result = service.getNResult(resultUuid);
- return result.map(r -> ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(r))
- .defaultIfEmpty(ResponseEntity.notFound().build());
+ return result != null
+ ? ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(result)
+ : ResponseEntity.notFound().build();
}
@GetMapping(value = "/results/{resultUuid}/nmk-contingencies-result", produces = APPLICATION_JSON_VALUE)
@Operation(summary = "Get a security analysis result from the database - NMK contingencies result")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The security analysis result"),
@ApiResponse(responseCode = "404", description = "Security analysis result has not been found")})
- public Mono>> getNmKContingenciesResult(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid) {
+ public ResponseEntity> getNmKContingenciesResult(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid) {
+ List result = service.getNmKContingenciesResult(resultUuid);
- Mono> result = service.getNmKContingenciesResult(resultUuid);
- return result.map(r -> ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(r))
- .defaultIfEmpty(ResponseEntity.notFound().build());
+ return result != null
+ ? ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(result)
+ : ResponseEntity.notFound().build();
}
@GetMapping(value = "/results/{resultUuid}/nmk-constraints-result", produces = APPLICATION_JSON_VALUE)
@Operation(summary = "Get a security analysis result from the database - NMK contingencies result")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The security analysis result"),
@ApiResponse(responseCode = "404", description = "Security analysis result has not been found")})
- public Mono>> getNmKConstraintsResult(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid) {
+ public ResponseEntity> getNmKConstraintsResult(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid) {
- Mono> result = service.getNmKConstraintsResult(resultUuid);
- return result.map(r -> ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(r))
- .defaultIfEmpty(ResponseEntity.notFound().build());
+ List result = service.getNmKConstraintsResult(resultUuid);
+ return result != null
+ ? ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(result)
+ : ResponseEntity.notFound().build();
}
@DeleteMapping(value = "/results/{resultUuid}", produces = APPLICATION_JSON_VALUE)
@Operation(summary = "Delete a security analysis result from the database")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The security analysis result has been deleted")})
- public ResponseEntity> deleteResult(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid) {
- Mono result = service.deleteResult(resultUuid);
- return ResponseEntity.ok().body(result);
+ public ResponseEntity deleteResult(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid) {
+ service.deleteResult(resultUuid);
+ return ResponseEntity.ok().build();
}
@DeleteMapping(value = "/results", produces = APPLICATION_JSON_VALUE)
@Operation(summary = "Delete all security analysis results from the database")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "All security analysis results have been deleted")})
- public ResponseEntity> deleteResults() {
- Mono result = service.deleteResults();
- return ResponseEntity.ok().body(result);
+ public ResponseEntity deleteResults() {
+ service.deleteResults();
+ return ResponseEntity.ok().build();
}
@GetMapping(value = "/results/{resultUuid}/status", produces = APPLICATION_JSON_VALUE)
@Operation(summary = "Get the security analysis status from the database")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The security analysis status")})
- public ResponseEntity> getStatus(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid) {
- Mono result = service.getStatus(resultUuid);
+ public ResponseEntity getStatus(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid) {
+ SecurityAnalysisStatus result = service.getStatus(resultUuid);
return ResponseEntity.ok().body(result);
}
@PutMapping(value = "/results/invalidate-status", produces = APPLICATION_JSON_VALUE)
@Operation(summary = "Invalidate the security analysis status from the database")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The security analysis status has been invalidated")})
- public ResponseEntity> invalidateStatus(@Parameter(description = "Result uuids") @RequestParam(name = "resultUuid") List resultUuids) {
- return ResponseEntity.ok().body(service.setStatus(resultUuids, SecurityAnalysisStatus.NOT_DONE));
+ public ResponseEntity invalidateStatus(@Parameter(description = "Result uuids") @RequestParam(name = "resultUuid") List resultUuids) {
+ service.setStatus(resultUuids, SecurityAnalysisStatus.NOT_DONE);
+ return ResponseEntity.ok().build();
}
@PutMapping(value = "/results/{resultUuid}/stop", produces = APPLICATION_JSON_VALUE)
@Operation(summary = "Stop a security analysis computation")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The security analysis has been stopped")})
- public ResponseEntity> stop(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid,
+ public ResponseEntity stop(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid,
@Parameter(description = "Result receiver") @RequestParam(name = "receiver", required = false) String receiver) {
- Mono result = service.stop(resultUuid, receiver);
- return ResponseEntity.ok().body(result);
+ service.stop(resultUuid, receiver);
+ return ResponseEntity.ok().build();
}
@GetMapping(value = "/providers", produces = APPLICATION_JSON_VALUE)
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyDTO.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyDTO.java
new file mode 100644
index 00000000..69b7eec4
--- /dev/null
+++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyDTO.java
@@ -0,0 +1,28 @@
+package org.gridsuite.securityanalysis.server.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import org.gridsuite.securityanalysis.server.entities.ContingencyEntity;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Getter
+@Builder
+public class ContingencyDTO {
+ private String contingencyId;
+ private String computationStatus;
+ private List elements;
+
+ public static ContingencyDTO toDto(ContingencyEntity contingency) {
+ return ContingencyDTO.builder()
+ .contingencyId(contingency.getContingencyId())
+ .computationStatus(contingency.getStatus())
+ .elements(contingency.getContingencyElements().stream().map(ContingencyElementDTO::toDto).collect(Collectors.toList()))
+ .build();
+ }
+}
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyElementDTO.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyElementDTO.java
index c69325e5..4e6b9a2f 100644
--- a/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyElementDTO.java
+++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyElementDTO.java
@@ -8,6 +8,7 @@
import com.powsybl.contingency.ContingencyElementType;
import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.gridsuite.securityanalysis.server.entities.ContingencyElementEmbeddable;
@@ -16,6 +17,7 @@
*/
@Getter
+@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ContingencyElementDTO {
@@ -23,6 +25,9 @@ public class ContingencyElementDTO {
private ContingencyElementType elementType;
public static ContingencyElementDTO toDto(ContingencyElementEmbeddable contingencyElement) {
- return new ContingencyElementDTO(contingencyElement.getElementId(), contingencyElement.getElementType());
+ return ContingencyElementDTO.builder()
+ .id(contingencyElement.getElementId())
+ .elementType(contingencyElement.getElementType())
+ .build();
}
}
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyFromSubjectLimitViolationDTO.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyFromSubjectLimitViolationDTO.java
deleted file mode 100644
index 592ebbb9..00000000
--- a/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyFromSubjectLimitViolationDTO.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/**
- * Copyright (c) 2023, 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.securityanalysis.server.dto;
-
-import com.powsybl.iidm.network.Branch;
-import com.powsybl.security.LimitViolationType;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import org.gridsuite.securityanalysis.server.entities.ContingencyEntity;
-import org.gridsuite.securityanalysis.server.entities.ContingencyLimitViolationEntity;
-
-import java.util.List;
-import java.util.stream.Collectors;
-/**
- * @author Kevin Le Saulnier
- */
-
-@Getter
-@AllArgsConstructor
-@NoArgsConstructor
-public class ContingencyFromSubjectLimitViolationDTO {
- private String contingencyId;
- private String computationStatus;
- private LimitViolationType limitType;
- private String limitName;
- private Branch.Side side;
- private int acceptableDuration;
- private double limit;
- private double limitReduction;
- private double value;
- private List elements;
- private Double loading;
-
- public ContingencyFromSubjectLimitViolationDTO(String contingencyId, String computationStatus, LimitViolationType limitType, String limitName, Branch.Side side, int acceptableDuration, double limit, double limitReduction, double value, List elements) {
- this.contingencyId = contingencyId;
- this.computationStatus = computationStatus;
- this.limitType = limitType;
- this.limitName = limitName;
- this.side = side;
- this.acceptableDuration = acceptableDuration;
- this.limit = limit;
- this.limitReduction = limitReduction;
- this.value = value;
- this.elements = elements;
-
- Double computedLoading = LimitViolationType.CURRENT.equals(limitType)
- ? (100 * value) / (limit * limitReduction)
- : null;
-
- this.loading = computedLoading;
- }
-
- public static ContingencyFromSubjectLimitViolationDTO toDto(ContingencyLimitViolationEntity limitViolation) {
- ContingencyEntity contingency = limitViolation.getContingency();
-
- return new ContingencyFromSubjectLimitViolationDTO(
- contingency.getContingencyId(),
- contingency.getStatus(),
- limitViolation.getLimitType(),
- limitViolation.getLimitName(),
- limitViolation.getSide(),
- limitViolation.getAcceptableDuration(),
- limitViolation.getLimit(),
- limitViolation.getLimitReduction(),
- limitViolation.getValue(),
- contingency.getContingencyElements().stream().map(ContingencyElementDTO::toDto).collect(Collectors.toList())
- );
- }
-}
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyLimitViolationDTO.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyLimitViolationDTO.java
new file mode 100644
index 00000000..798fd02c
--- /dev/null
+++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyLimitViolationDTO.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2023, 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.securityanalysis.server.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import org.gridsuite.securityanalysis.server.entities.ContingencyLimitViolationEntity;
+/**
+ * @author Kevin Le Saulnier
+ */
+
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class ContingencyLimitViolationDTO {
+ private ContingencyDTO contingency;
+
+ private LimitViolationDTO limitViolation;
+
+ public static ContingencyLimitViolationDTO toDto(ContingencyLimitViolationEntity limitViolation) {
+ return ContingencyLimitViolationDTO.builder()
+ .contingency(ContingencyDTO.toDto(limitViolation.getContingency()))
+ .limitViolation(LimitViolationDTO.toDto(limitViolation))
+ .build();
+ }
+}
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyResultDTO.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyResultDTO.java
new file mode 100644
index 00000000..71a61fe6
--- /dev/null
+++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyResultDTO.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2023, 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.securityanalysis.server.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import org.gridsuite.securityanalysis.server.entities.ContingencyEntity;
+
+import java.util.List;
+/**
+ * @author Kevin Le Saulnier
+ */
+
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class ContingencyResultDTO {
+ private ContingencyDTO contingency;
+
+ private List subjectLimitViolations;
+
+ public static ContingencyResultDTO toDto(ContingencyEntity contingency) {
+ List subjectLimitViolations = contingency.getContingencyLimitViolations().stream()
+ .map(SubjectLimitViolationDTO::toDto)
+ .toList();
+
+ return ContingencyResultDTO.builder()
+ .contingency(ContingencyDTO.toDto(contingency))
+ .subjectLimitViolations(subjectLimitViolations)
+ .build();
+ }
+}
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyToSubjectLimitViolationDTO.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyToSubjectLimitViolationDTO.java
deleted file mode 100644
index 8beb2c98..00000000
--- a/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyToSubjectLimitViolationDTO.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Copyright (c) 2023, 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.securityanalysis.server.dto;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-
-import java.util.List;
-/**
- * @author Kevin Le Saulnier
- */
-
-@Getter
-@AllArgsConstructor
-@NoArgsConstructor
-public class ContingencyToSubjectLimitViolationDTO {
- private String id;
- private String status;
- private List elements;
- private List subjectLimitViolations;
-}
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/LimitViolationDTO.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/LimitViolationDTO.java
new file mode 100644
index 00000000..b934565e
--- /dev/null
+++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/LimitViolationDTO.java
@@ -0,0 +1,41 @@
+package org.gridsuite.securityanalysis.server.dto;
+
+import com.powsybl.iidm.network.Branch;
+import com.powsybl.security.LimitViolationType;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import org.gridsuite.securityanalysis.server.entities.AbstractLimitViolationEntity;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@Getter
+public class LimitViolationDTO {
+ private LimitViolationType limitType;
+ private String limitName;
+ private Branch.Side side;
+ private int acceptableDuration;
+ private double limit;
+ private double limitReduction;
+ private double value;
+ private Double loading;
+
+ public static LimitViolationDTO toDto(AbstractLimitViolationEntity limitViolation) {
+ Double computedLoading = LimitViolationType.CURRENT.equals(limitViolation.getLimitType())
+ ? (100 * limitViolation.getValue()) / (limitViolation.getLimit() * limitViolation.getLimitReduction())
+ : null;
+
+ return LimitViolationDTO.builder()
+ .limitType(limitViolation.getLimitType())
+ .limitName(limitViolation.getLimitName())
+ .side(limitViolation.getSide())
+ .acceptableDuration(limitViolation.getAcceptableDuration())
+ .limit(limitViolation.getLimit())
+ .limitReduction(limitViolation.getLimitReduction())
+ .value(limitViolation.getValue())
+ .loading(computedLoading)
+ .build();
+ }
+}
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/SubjectLimitViolationDTO.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/SubjectLimitViolationDTO.java
new file mode 100644
index 00000000..67e6cad0
--- /dev/null
+++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/SubjectLimitViolationDTO.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2023, 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.securityanalysis.server.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import org.gridsuite.securityanalysis.server.entities.ContingencyLimitViolationEntity;
+/**
+ * @author Kevin Le Saulnier
+ */
+
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class SubjectLimitViolationDTO {
+ private String subjectId;
+
+ private LimitViolationDTO limitViolation;
+
+ public static SubjectLimitViolationDTO toDto(ContingencyLimitViolationEntity limitViolation) {
+ String subjectId = limitViolation.getSubjectLimitViolation() != null
+ ? limitViolation.getSubjectLimitViolation().getSubjectId()
+ : null;
+
+ return SubjectLimitViolationDTO.builder()
+ .subjectId(subjectId)
+ .limitViolation(LimitViolationDTO.toDto(limitViolation))
+ .build();
+ }
+}
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/SubjectLimitViolationFromContingencyDTO.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/SubjectLimitViolationFromContingencyDTO.java
deleted file mode 100644
index be614553..00000000
--- a/src/main/java/org/gridsuite/securityanalysis/server/dto/SubjectLimitViolationFromContingencyDTO.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * Copyright (c) 2023, 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.securityanalysis.server.dto;
-
-import com.powsybl.iidm.network.Branch;
-import com.powsybl.security.LimitViolationType;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import org.gridsuite.securityanalysis.server.entities.ContingencyLimitViolationEntity;
-/**
- * @author Kevin Le Saulnier
- */
-
-@Getter
-@AllArgsConstructor
-@NoArgsConstructor
-public class SubjectLimitViolationFromContingencyDTO {
- private String subjectId;
- private LimitViolationType limitType;
- private String limitName;
- private Branch.Side side;
- private int acceptableDuration;
- private double limit;
- private double limitReduction;
- private double value;
- private Double loading;
-
- public SubjectLimitViolationFromContingencyDTO(String subjectId, LimitViolationType limitType, String limitName, Branch.Side side, int acceptableDuration, double limit, double limitReduction, double value) {
- this.subjectId = subjectId;
- this.limitType = limitType;
- this.limitName = limitName;
- this.side = side;
- this.acceptableDuration = acceptableDuration;
- this.limit = limit;
- this.limitReduction = limitReduction;
- this.value = value;
-
- Double computedLoading = LimitViolationType.CURRENT.equals(limitType)
- ? (100 * value) / (limit * limitReduction)
- : null;
-
- this.loading = computedLoading;
- }
-
- public static SubjectLimitViolationFromContingencyDTO toDto(ContingencyLimitViolationEntity limitViolation) {
- String subjectId = limitViolation.getSubjectLimitViolation() != null
- ? limitViolation.getSubjectLimitViolation().getSubjectId()
- : null;
-
- return new SubjectLimitViolationFromContingencyDTO(subjectId, limitViolation.getLimitType(), limitViolation.getLimitName(), limitViolation.getSide(), limitViolation.getAcceptableDuration(), limitViolation.getLimit(), limitViolation.getLimitReduction(), limitViolation.getValue());
- }
-}
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/SubjectLimitViolationResultDTO.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/SubjectLimitViolationResultDTO.java
new file mode 100644
index 00000000..6b33757a
--- /dev/null
+++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/SubjectLimitViolationResultDTO.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2023, 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.securityanalysis.server.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import org.gridsuite.securityanalysis.server.entities.SubjectLimitViolationEntity;
+
+import java.util.List;
+/**
+ * @author Kevin Le Saulnier
+ */
+
+@Getter
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class SubjectLimitViolationResultDTO {
+ private String subjectId;
+
+ private List contingencies;
+
+ public static SubjectLimitViolationResultDTO toDto(SubjectLimitViolationEntity subjectLimitViolation) {
+ List contingencies = subjectLimitViolation.getContingencyLimitViolations().stream()
+ .map(ContingencyLimitViolationDTO::toDto)
+ .toList();
+
+ return SubjectLimitViolationResultDTO.builder()
+ .subjectId(subjectLimitViolation.getSubjectId())
+ .contingencies(contingencies)
+ .build();
+ }
+}
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/SubjectLimitViolationToContingencyDTO.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/SubjectLimitViolationToContingencyDTO.java
deleted file mode 100644
index 50484d51..00000000
--- a/src/main/java/org/gridsuite/securityanalysis/server/dto/SubjectLimitViolationToContingencyDTO.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * Copyright (c) 2023, 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.securityanalysis.server.dto;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-
-import java.util.List;
-/**
- * @author Kevin Le Saulnier
- */
-
-@Getter
-@AllArgsConstructor
-@NoArgsConstructor
-public class SubjectLimitViolationToContingencyDTO {
- private String subjectId;
-
- private List contingencies;
-}
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/entities/AbstractLimitViolationEntity.java b/src/main/java/org/gridsuite/securityanalysis/server/entities/AbstractLimitViolationEntity.java
index afa32568..e8fd5411 100644
--- a/src/main/java/org/gridsuite/securityanalysis/server/entities/AbstractLimitViolationEntity.java
+++ b/src/main/java/org/gridsuite/securityanalysis/server/entities/AbstractLimitViolationEntity.java
@@ -10,8 +10,8 @@
import com.powsybl.security.LimitViolation;
import com.powsybl.security.LimitViolationType;
import jakarta.persistence.*;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
+import lombok.*;
+import lombok.experimental.SuperBuilder;
import java.util.UUID;
/**
@@ -19,6 +19,8 @@
*/
@NoArgsConstructor
+@AllArgsConstructor
+@SuperBuilder
@Getter
@MappedSuperclass
public abstract class AbstractLimitViolationEntity {
@@ -30,8 +32,6 @@ public abstract class AbstractLimitViolationEntity {
@ManyToOne
private SubjectLimitViolationEntity subjectLimitViolation;
- private String subjectName;
-
@Column(name = "limitValue")
private double limit;
@@ -50,18 +50,6 @@ public abstract class AbstractLimitViolationEntity {
@Enumerated(EnumType.STRING)
private Branch.Side side;
- protected AbstractLimitViolationEntity(SubjectLimitViolationEntity subjectLimitViolation, String subjectName, double limit, String limitName, LimitViolationType limitType, int acceptableDuration, float limitReduction, double value, Branch.Side side) {
- this.subjectLimitViolation = subjectLimitViolation;
- this.subjectName = subjectName;
- this.limit = limit;
- this.limitName = limitName;
- this.limitType = limitType;
- this.acceptableDuration = acceptableDuration;
- this.limitReduction = limitReduction;
- this.value = value;
- this.side = side;
- }
-
public static LimitViolation toLimitViolation(AbstractLimitViolationEntity limitViolationEntity) {
String subjectId = limitViolationEntity.getSubjectLimitViolation() != null
? limitViolationEntity.getSubjectLimitViolation().getSubjectId()
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/entities/ContingencyElementEmbeddable.java b/src/main/java/org/gridsuite/securityanalysis/server/entities/ContingencyElementEmbeddable.java
index 6bbac0fd..5061bd79 100644
--- a/src/main/java/org/gridsuite/securityanalysis/server/entities/ContingencyElementEmbeddable.java
+++ b/src/main/java/org/gridsuite/securityanalysis/server/entities/ContingencyElementEmbeddable.java
@@ -11,6 +11,7 @@
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@@ -18,6 +19,7 @@
* @author Laurent GARNIER
*/
@Getter
+@Builder
@NoArgsConstructor
@AllArgsConstructor
@Embeddable
@@ -30,6 +32,9 @@ public class ContingencyElementEmbeddable {
private String elementId;
public static ContingencyElementEmbeddable toEntity(ContingencyElement contingencyElement) {
- return new ContingencyElementEmbeddable(contingencyElement.getType(), contingencyElement.getId());
+ return ContingencyElementEmbeddable.builder()
+ .elementType(contingencyElement.getType())
+ .elementId(contingencyElement.getId())
+ .build();
}
}
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/entities/ContingencyLimitViolationEntity.java b/src/main/java/org/gridsuite/securityanalysis/server/entities/ContingencyLimitViolationEntity.java
index 25e82aed..daa56062 100644
--- a/src/main/java/org/gridsuite/securityanalysis/server/entities/ContingencyLimitViolationEntity.java
+++ b/src/main/java/org/gridsuite/securityanalysis/server/entities/ContingencyLimitViolationEntity.java
@@ -6,37 +6,40 @@
*/
package org.gridsuite.securityanalysis.server.entities;
-import com.powsybl.iidm.network.Branch;
import com.powsybl.security.LimitViolation;
-import com.powsybl.security.LimitViolationType;
import jakarta.persistence.*;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
+import lombok.*;
+import lombok.experimental.SuperBuilder;
+
/**
* @author Kevin Le Saulnier
*/
+@Data
@NoArgsConstructor
-@Entity
+@SuperBuilder
@Getter
+@Entity
@Table(name = "contingency_limit_violation")
public class ContingencyLimitViolationEntity extends AbstractLimitViolationEntity {
@ManyToOne(fetch = FetchType.LAZY)
@Setter
private ContingencyEntity contingency;
- public ContingencyLimitViolationEntity(SubjectLimitViolationEntity subjectLimitViolation, String subjectName, double limit, String limitName, LimitViolationType limitType, int acceptableDuration, float limitReduction, double value, Branch.Side side) {
- super(subjectLimitViolation, subjectName, limit, limitName, limitType, acceptableDuration, limitReduction, value, side);
- if (subjectLimitViolation != null) {
- subjectLimitViolation.addContingencyLimitViolation(this);
- }
- }
-
public static ContingencyLimitViolationEntity toEntity(LimitViolation limitViolation, SubjectLimitViolationEntity subjectLimitViolation) {
- return new ContingencyLimitViolationEntity(subjectLimitViolation,
- limitViolation.getSubjectName(), limitViolation.getLimit(), limitViolation.getLimitName(),
- limitViolation.getLimitType(), limitViolation.getAcceptableDuration(), limitViolation.getLimitReduction(), limitViolation.getValue(),
- limitViolation.getSide());
+ ContingencyLimitViolationEntity contingencyLimitViolationEntity = ContingencyLimitViolationEntity.builder()
+ .limit(limitViolation.getLimit())
+ .limitName(limitViolation.getLimitName())
+ .limitType(limitViolation.getLimitType())
+ .acceptableDuration(limitViolation.getAcceptableDuration())
+ .limitReduction(limitViolation.getLimitReduction())
+ .value(limitViolation.getValue())
+ .side(limitViolation.getSide())
+ .subjectLimitViolation(subjectLimitViolation)
+ .build();
+
+ subjectLimitViolation.addContingencyLimitViolation(contingencyLimitViolationEntity);
+
+ return contingencyLimitViolationEntity;
}
}
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/entities/PreContingencyLimitViolationEntity.java b/src/main/java/org/gridsuite/securityanalysis/server/entities/PreContingencyLimitViolationEntity.java
index fecc4f04..35b2b881 100644
--- a/src/main/java/org/gridsuite/securityanalysis/server/entities/PreContingencyLimitViolationEntity.java
+++ b/src/main/java/org/gridsuite/securityanalysis/server/entities/PreContingencyLimitViolationEntity.java
@@ -6,16 +6,16 @@
*/
package org.gridsuite.securityanalysis.server.entities;
-import com.powsybl.iidm.network.Branch;
import com.powsybl.security.LimitViolation;
-import com.powsybl.security.LimitViolationType;
import com.powsybl.security.results.PreContingencyResult;
import jakarta.persistence.Entity;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
+import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
+import lombok.experimental.SuperBuilder;
import java.util.List;
import java.util.Map;
@@ -25,7 +25,9 @@
* @author Kevin Le Saulnier
*/
+@Data
@NoArgsConstructor
+@SuperBuilder
@Getter
@Entity
@Table(name = "pre_contingency_limit_violation")
@@ -35,18 +37,20 @@ public class PreContingencyLimitViolationEntity extends AbstractLimitViolationEn
@Setter
SecurityAnalysisResultEntity result;
- public PreContingencyLimitViolationEntity(SubjectLimitViolationEntity subjectLimitViolation, String subjectName, double limit, String limitName, LimitViolationType limitType, int acceptableDuration, float limitReduction, double value, Branch.Side side) {
- super(subjectLimitViolation, subjectName, limit, limitName, limitType, acceptableDuration, limitReduction, value, side);
- }
-
public static List toEntityList(PreContingencyResult preContingencyResult, Map subjectLimitViolationsBySubjectId) {
- return preContingencyResult.getLimitViolationsResult().getLimitViolations().stream().map(limitViolation -> toEntityList(limitViolation, subjectLimitViolationsBySubjectId.get(limitViolation.getSubjectId()))).collect(Collectors.toList());
+ return preContingencyResult.getLimitViolationsResult().getLimitViolations().stream().map(limitViolation -> toEntity(limitViolation, subjectLimitViolationsBySubjectId.get(limitViolation.getSubjectId()))).collect(Collectors.toList());
}
- public static PreContingencyLimitViolationEntity toEntityList(LimitViolation limitViolation, SubjectLimitViolationEntity subjectLimitViolation) {
- return new PreContingencyLimitViolationEntity(subjectLimitViolation,
- limitViolation.getSubjectName(), limitViolation.getLimit(), limitViolation.getLimitName(),
- limitViolation.getLimitType(), limitViolation.getAcceptableDuration(), limitViolation.getLimitReduction(), limitViolation.getValue(),
- limitViolation.getSide());
+ public static PreContingencyLimitViolationEntity toEntity(LimitViolation limitViolation, SubjectLimitViolationEntity subjectLimitViolation) {
+ return PreContingencyLimitViolationEntity.builder()
+ .subjectLimitViolation(subjectLimitViolation)
+ .limit(limitViolation.getLimit())
+ .limitName(limitViolation.getLimitName())
+ .limitType(limitViolation.getLimitType())
+ .acceptableDuration(limitViolation.getAcceptableDuration())
+ .limitReduction(limitViolation.getLimitReduction())
+ .value(limitViolation.getValue())
+ .side(limitViolation.getSide())
+ .build();
}
}
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisResultEntity.java b/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisResultEntity.java
index 9f9f790b..4c20e32b 100644
--- a/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisResultEntity.java
+++ b/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisResultEntity.java
@@ -8,9 +8,7 @@
import com.powsybl.security.SecurityAnalysisResult;
import jakarta.persistence.*;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
+import lombok.*;
import org.gridsuite.securityanalysis.server.dto.SecurityAnalysisStatus;
import org.gridsuite.securityanalysis.server.service.SecurityAnalysisResultService;
@@ -27,6 +25,8 @@
@NoArgsConstructor
@Getter
@Entity
+@AllArgsConstructor
+@Builder
@Table(name = "security_analysis_result")
public class SecurityAnalysisResultEntity {
@Id
@@ -50,46 +50,6 @@ public SecurityAnalysisResultEntity(UUID id) {
this.id = id;
}
- public SecurityAnalysisResultEntity(UUID id, SecurityAnalysisStatus status, String preContingencyStatus, List contingencies, List preContingencyLimitViolations) {
- this.id = id;
- this.status = status;
- this.preContingencyStatus = preContingencyStatus;
- setContingencies(contingencies);
- setPreContingencyLimitViolations(preContingencyLimitViolations);
-
- // extracting unique subject limit violations from all limit violations
- setSubjectLimitViolations(
- Stream.concat(
- this.contingencies.stream().flatMap(c -> c.getContingencyLimitViolations().stream()),
- this.preContingencyLimitViolations.stream()
- ).map(AbstractLimitViolationEntity::getSubjectLimitViolation)
- .distinct()
- .filter(Objects::nonNull)
- .collect(Collectors.toList())
- );
- }
-
- private void setContingencies(List contingencies) {
- if (contingencies != null) {
- this.contingencies = contingencies;
- this.contingencies.forEach(c -> c.setResult(this));
- }
- }
-
- private void setPreContingencyLimitViolations(List preContingencyLimitViolations) {
- if (preContingencyLimitViolations != null) {
- this.preContingencyLimitViolations = preContingencyLimitViolations;
- this.preContingencyLimitViolations.forEach(lm -> lm.setResult(this));
- }
- }
-
- private void setSubjectLimitViolations(List subjectLimitViolations) {
- if (subjectLimitViolations != null) {
- this.subjectLimitViolations = subjectLimitViolations;
- subjectLimitViolations.forEach(subjectLimitViolation -> subjectLimitViolation.setResult(this));
- }
- }
-
public static SecurityAnalysisResultEntity toEntity(UUID resultUuid, SecurityAnalysisResult securityAnalysisResult, SecurityAnalysisStatus securityAnalysisStatus) {
Map subjectLimitViolationsBySubjectId = SecurityAnalysisResultService.getUniqueSubjectLimitViolationsFromResult(securityAnalysisResult)
.stream().collect(Collectors.toMap(
@@ -102,6 +62,27 @@ public static SecurityAnalysisResultEntity toEntity(UUID resultUuid, SecurityAna
List preContingencyLimitViolations = PreContingencyLimitViolationEntity.toEntityList(securityAnalysisResult.getPreContingencyResult(), subjectLimitViolationsBySubjectId);
- return new SecurityAnalysisResultEntity(resultUuid, securityAnalysisStatus, securityAnalysisResult.getPreContingencyResult().getStatus().name(), contingencies, preContingencyLimitViolations);
+ List subjectLimitViolations = Stream.concat(
+ contingencies.stream().flatMap(c -> c.getContingencyLimitViolations().stream()),
+ preContingencyLimitViolations.stream()
+ ).map(AbstractLimitViolationEntity::getSubjectLimitViolation)
+ .distinct()
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+
+ SecurityAnalysisResultEntity securityAnalysisResultEntity = SecurityAnalysisResultEntity.builder()
+ .id(resultUuid)
+ .status(securityAnalysisStatus)
+ .preContingencyStatus(securityAnalysisResult.getPreContingencyResult().getStatus().name())
+ .contingencies(contingencies)
+ .preContingencyLimitViolations(preContingencyLimitViolations)
+ .subjectLimitViolations(subjectLimitViolations)
+ .build();
+
+ //bidirectionnal associations
+ contingencies.forEach(c -> c.setResult(securityAnalysisResultEntity));
+ preContingencyLimitViolations.forEach(lm -> lm.setResult(securityAnalysisResultEntity));
+ subjectLimitViolations.forEach(subjectLimitViolation -> subjectLimitViolation.setResult(securityAnalysisResultEntity));
+ return securityAnalysisResultEntity;
}
}
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/entities/SubjectLimitViolationEntity.java b/src/main/java/org/gridsuite/securityanalysis/server/entities/SubjectLimitViolationEntity.java
index ddd0738e..88eba796 100644
--- a/src/main/java/org/gridsuite/securityanalysis/server/entities/SubjectLimitViolationEntity.java
+++ b/src/main/java/org/gridsuite/securityanalysis/server/entities/SubjectLimitViolationEntity.java
@@ -22,8 +22,9 @@
@Entity
@Table(name = "subject_limit_violation")
public class SubjectLimitViolationEntity {
- public SubjectLimitViolationEntity(String subjectId) {
+ public SubjectLimitViolationEntity(String subjectId, String subjectName) {
this.subjectId = subjectId;
+ this.subjectName = subjectName;
}
@Id
@@ -33,6 +34,8 @@ public SubjectLimitViolationEntity(String subjectId) {
@Getter
public String subjectId;
+ private String subjectName;
+
@ManyToOne(fetch = FetchType.LAZY)
@Setter
@Getter
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/ActionsService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/ActionsService.java
index 0e97cf21..89d183b6 100644
--- a/src/main/java/org/gridsuite/securityanalysis/server/service/ActionsService.java
+++ b/src/main/java/org/gridsuite/securityanalysis/server/service/ActionsService.java
@@ -10,10 +10,13 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
-import org.springframework.web.reactive.function.client.WebClient;
-import reactor.core.publisher.Flux;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.UriComponentsBuilder;
+import java.net.URI;
+import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
@@ -26,30 +29,33 @@ public class ActionsService {
static final String ACTIONS_API_VERSION = "v1";
- private final WebClient webClient;
+ private static final String DELIMITER = "/";
- @Autowired
- public ActionsService(WebClient.Builder builder,
- @Value("${gridsuite.services.actions-server.base-uri:http://actions-server/}") String baseUri) {
- webClient = builder.baseUrl(baseUri)
- .build();
+ private String baseUri;
+
+ private RestTemplate restTemplate;
+
+ public void setActionServiceBaseUri(String baseUri) {
+ this.baseUri = baseUri;
}
- public ActionsService(WebClient webClient) {
- this.webClient = Objects.requireNonNull(webClient);
+ @Autowired
+ public ActionsService(
+ @Value("${gridsuite.services.actions-server.base-uri:http://actions-server/}") String baseUri,
+ RestTemplate restTemplate) {
+ this.baseUri = baseUri;
+ this.restTemplate = restTemplate;
}
- public Flux getContingencyList(String name, UUID networkUuid, String variantId) {
+ public List getContingencyList(String name, UUID networkUuid, String variantId) {
Objects.requireNonNull(name);
Objects.requireNonNull(networkUuid);
- return webClient.get()
- .uri(uriBuilder -> uriBuilder
- .path(ACTIONS_API_VERSION + "/contingency-lists/{name}/export")
- .queryParam("networkUuid", networkUuid.toString())
- .queryParamIfPresent("variantId", Optional.ofNullable(variantId))
- .build(name))
- .retrieve()
- .bodyToFlux(new ParameterizedTypeReference<>() {
- });
+
+ URI path = UriComponentsBuilder
+ .fromPath(DELIMITER + ACTIONS_API_VERSION + "/contingency-lists/{name}/export")
+ .queryParam("networkUuid", networkUuid.toString())
+ .queryParamIfPresent("variantId", Optional.ofNullable(variantId)).build(name);
+
+ return restTemplate.exchange(baseUri + path, HttpMethod.GET, null, new ParameterizedTypeReference>() { }).getBody();
}
}
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/ReportService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/ReportService.java
index 176800b7..14b4f54e 100644
--- a/src/main/java/org/gridsuite/securityanalysis/server/service/ReportService.java
+++ b/src/main/java/org/gridsuite/securityanalysis/server/service/ReportService.java
@@ -10,10 +10,10 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
-import org.springframework.web.reactive.function.BodyInserters;
-import org.springframework.web.reactive.function.client.WebClient;
-import reactor.core.publisher.Mono;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.UriComponentsBuilder;
+import java.net.URI;
import java.util.Objects;
import java.util.UUID;
@@ -25,27 +25,29 @@ public class ReportService {
static final String REPORT_API_VERSION = "v1";
- private final WebClient webClient;
+ private static final String DELIMITER = "/";
+
+ private String baseUri;
+
+ @Autowired
+ private RestTemplate restTemplate;
@Autowired
- public ReportService(WebClient.Builder builder,
- @Value("${gridsuite.services.report-server.base-uri:http://report-server/}") String baseUri) {
- webClient = builder.baseUrl(baseUri)
- .build();
+ public ReportService(@Value("${gridsuite.services.report-server.base-uri:http://report-server/}") String baseUri) {
+ this.baseUri = baseUri;
}
- public ReportService(WebClient webClient) {
- this.webClient = Objects.requireNonNull(webClient);
+ public void setReportServiceBaseUri(String baseUri) {
+ this.baseUri = baseUri;
}
- public Mono sendReport(UUID reportUuid, Reporter reporter) {
+ public void sendReport(UUID reportUuid, Reporter reporter) {
Objects.requireNonNull(reportUuid);
- return webClient.put()
- .uri(uriBuilder -> uriBuilder
- .path(REPORT_API_VERSION + "/reports/{reportUuid}")
- .build(reportUuid))
- .body(BodyInserters.fromValue(reporter))
- .retrieve()
- .bodyToMono(Void.class);
+
+ URI path = UriComponentsBuilder
+ .fromPath(DELIMITER + REPORT_API_VERSION + "/reports/{reportUuid}")
+ .build(reportUuid);
+
+ restTemplate.put(baseUri + path, reporter);
}
}
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisResultService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisResultService.java
index e52d3b6a..a9156789 100644
--- a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisResultService.java
+++ b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisResultService.java
@@ -14,6 +14,7 @@
import org.gridsuite.securityanalysis.server.entities.*;
import org.gridsuite.securityanalysis.server.repositories.*;
import org.gridsuite.securityanalysis.server.util.SecurityAnalysisException;
+import org.jgrapht.alg.util.Pair;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -60,36 +61,18 @@ public PreContingencyResult findNResult(UUID resultUuid) {
}
@Transactional(readOnly = true)
- public List findNmKContingenciesResult(UUID resultUuid) {
+ public List findNmKContingenciesResult(UUID resultUuid) {
assertResultExists(resultUuid);
List contingencies = contingencyRepository.findByResultIdAndStatusOrderByContingencyId(resultUuid, LoadFlowResult.ComponentResult.Status.CONVERGED.name());
- return contingencies.stream().map(contingency -> {
- List subjectLimitViolations = contingency.getContingencyLimitViolations().stream()
- .map(SubjectLimitViolationFromContingencyDTO::toDto)
- .toList();
- return new ContingencyToSubjectLimitViolationDTO(
- contingency.getContingencyId(),
- contingency.getStatus(),
- contingency.getContingencyElements().stream().map(ContingencyElementDTO::toDto).toList(),
- subjectLimitViolations
- );
- }).toList();
+ return contingencies.stream().map(ContingencyResultDTO::toDto).toList();
}
@Transactional(readOnly = true)
- public List findNmKConstraintsResult(UUID resultUuid) {
+ public List findNmKConstraintsResult(UUID resultUuid) {
assertResultExists(resultUuid);
List subjectLimitViolations = subjectLimitViolationRepository.findByResultIdOrderBySubjectId(resultUuid);
- return subjectLimitViolations.stream().map(subjectLimitViolation -> {
- // we only keep converged contingencies here
- List contingencies = subjectLimitViolation.getContingencyLimitViolations().stream()
- .filter(lm -> LoadFlowResult.ComponentResult.Status.CONVERGED.name().equals(lm.getContingency().getStatus()))
- .map(ContingencyFromSubjectLimitViolationDTO::toDto)
- .toList();
-
- return new SubjectLimitViolationToContingencyDTO(subjectLimitViolation.getSubjectId(), contingencies);
- }).toList();
+ return subjectLimitViolations.stream().map(SubjectLimitViolationResultDTO::toDto).toList();
}
public void assertResultExists(UUID resultUuid) {
@@ -143,10 +126,9 @@ public static List getUniqueSubjectLimitViolationsF
return Stream.concat(
securityAnalysisResult.getPostContingencyResults().stream().flatMap(pcr -> pcr.getLimitViolationsResult().getLimitViolations().stream()),
securityAnalysisResult.getPreContingencyResult().getLimitViolationsResult().getLimitViolations().stream())
- .map(LimitViolation::getSubjectId)
+ .map(lm -> new Pair<>(lm.getSubjectId(), lm.getSubjectName()))
.distinct()
- .map(SubjectLimitViolationEntity::new)
+ .map(pair -> new SubjectLimitViolationEntity(pair.getFirst(), pair.getSecond()))
.toList();
}
-
}
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisService.java
index 8d26e57d..7561bcdb 100644
--- a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisService.java
+++ b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisService.java
@@ -9,12 +9,11 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.powsybl.security.SecurityAnalysisProvider;
import com.powsybl.security.results.PreContingencyResult;
-import org.gridsuite.securityanalysis.server.dto.SubjectLimitViolationToContingencyDTO;
-import org.gridsuite.securityanalysis.server.dto.ContingencyToSubjectLimitViolationDTO;
+import org.gridsuite.securityanalysis.server.dto.SubjectLimitViolationResultDTO;
+import org.gridsuite.securityanalysis.server.dto.ContingencyResultDTO;
import org.gridsuite.securityanalysis.server.dto.SecurityAnalysisStatus;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
-import reactor.core.publisher.Mono;
import java.util.List;
import java.util.Objects;
@@ -27,7 +26,7 @@
*/
@Service
public class SecurityAnalysisService {
- private final SecurityAnalysisResultService resultRepository;
+ private final SecurityAnalysisResultService securityAnalysisResultService;
private final UuidGeneratorService uuidGeneratorService;
@@ -37,60 +36,58 @@ public class SecurityAnalysisService {
private final String defaultProvider;
- public SecurityAnalysisService(SecurityAnalysisResultService resultRepository,
+ public SecurityAnalysisService(SecurityAnalysisResultService securityAnalysisResultService,
UuidGeneratorService uuidGeneratorService,
ObjectMapper objectMapper,
NotificationService notificationService,
@Value("${security-analysis.default-provider}") String defaultProvider) {
- this.resultRepository = Objects.requireNonNull(resultRepository);
+ this.securityAnalysisResultService = Objects.requireNonNull(securityAnalysisResultService);
this.uuidGeneratorService = Objects.requireNonNull(uuidGeneratorService);
this.objectMapper = Objects.requireNonNull(objectMapper);
this.notificationService = Objects.requireNonNull(notificationService);
this.defaultProvider = Objects.requireNonNull(defaultProvider);
}
- public Mono runAndSaveResult(SecurityAnalysisRunContext runContext) {
+ public UUID runAndSaveResult(SecurityAnalysisRunContext runContext) {
Objects.requireNonNull(runContext);
var resultUuid = uuidGeneratorService.generate();
-
// update status to running status
- return setStatus(List.of(resultUuid), SecurityAnalysisStatus.RUNNING).then(
- Mono.fromRunnable(() ->
- notificationService.emitRunAnalysisMessage(new SecurityAnalysisResultContext(resultUuid, runContext).toMessage(objectMapper))
- )
- .thenReturn(resultUuid));
+ setStatus(List.of(resultUuid), SecurityAnalysisStatus.RUNNING);
+ notificationService.emitRunAnalysisMessage(new SecurityAnalysisResultContext(resultUuid, runContext).toMessage(objectMapper));
+
+ return resultUuid;
}
- public Mono getNResult(UUID resultUuid) {
- return Mono.fromCallable(() -> resultRepository.findNResult(resultUuid));
+ public PreContingencyResult getNResult(UUID resultUuid) {
+ return securityAnalysisResultService.findNResult(resultUuid);
}
- public Mono> getNmKContingenciesResult(UUID resultUuid) {
- return Mono.fromCallable(() -> resultRepository.findNmKContingenciesResult(resultUuid));
+ public List getNmKContingenciesResult(UUID resultUuid) {
+ return securityAnalysisResultService.findNmKContingenciesResult(resultUuid);
}
- public Mono> getNmKConstraintsResult(UUID resultUuid) {
- return Mono.fromCallable(() -> resultRepository.findNmKConstraintsResult(resultUuid));
+ public List getNmKConstraintsResult(UUID resultUuid) {
+ return securityAnalysisResultService.findNmKConstraintsResult(resultUuid);
}
- public Mono deleteResult(UUID resultUuid) {
- return Mono.fromRunnable(() -> resultRepository.delete(resultUuid));
+ public void deleteResult(UUID resultUuid) {
+ securityAnalysisResultService.delete(resultUuid);
}
- public Mono deleteResults() {
- return Mono.fromRunnable(() -> resultRepository.deleteAll());
+ public void deleteResults() {
+ securityAnalysisResultService.deleteAll();
}
- public Mono getStatus(UUID resultUuid) {
- return Mono.fromCallable(() -> resultRepository.findStatus(resultUuid));
+ public SecurityAnalysisStatus getStatus(UUID resultUuid) {
+ return securityAnalysisResultService.findStatus(resultUuid);
}
- public Mono setStatus(List resultUuids, SecurityAnalysisStatus status) {
- return Mono.fromRunnable(() -> resultRepository.insertStatus(resultUuids, status));
+ public void setStatus(List resultUuids, SecurityAnalysisStatus status) {
+ securityAnalysisResultService.insertStatus(resultUuids, status);
}
- public Mono stop(UUID resultUuid, String receiver) {
- return Mono.fromRunnable(() -> notificationService.emitCancelAnalysisMessage(new SecurityAnalysisCancelContext(resultUuid, receiver).toMessage())).then();
+ public void stop(UUID resultUuid, String receiver) {
+ notificationService.emitCancelAnalysisMessage(new SecurityAnalysisCancelContext(resultUuid, receiver).toMessage());
}
public List getProviders() {
diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisWorkerService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisWorkerService.java
index c625de08..17fa844f 100644
--- a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisWorkerService.java
+++ b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisWorkerService.java
@@ -33,10 +33,6 @@
import org.springframework.messaging.Message;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-import reactor.core.scheduler.Schedulers;
-import reactor.util.function.Tuple2;
import java.util.ArrayList;
import java.util.Collections;
@@ -45,10 +41,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
+import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -111,46 +104,43 @@ public void setSecurityAnalysisFactorySupplier(Function getNetwork(UUID networkUuid) {
- // FIXME to re-implement when network store service will be reactive
- return Mono.fromCallable(() -> {
- try {
- return networkStoreService.getNetwork(networkUuid, PreloadingStrategy.COLLECTION);
- } catch (PowsyblException e) {
- throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage());
- }
- })
- .subscribeOn(Schedulers.boundedElastic());
+ private Network getNetwork(UUID networkUuid) {
+ try {
+ return networkStoreService.getNetwork(networkUuid, PreloadingStrategy.COLLECTION);
+ } catch (PowsyblException e) {
+ throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage());
+ }
}
- private Mono getNetwork(UUID networkUuid, List otherNetworkUuids) {
- Mono network = getNetwork(networkUuid);
+ private Network getNetwork(UUID networkUuid, List otherNetworkUuids) {
+ Network network = getNetwork(networkUuid);
if (otherNetworkUuids.isEmpty()) {
return network;
} else {
- Mono> otherNetworks = Flux.fromIterable(otherNetworkUuids)
- .flatMap(this::getNetwork)
- .collectList();
- return Mono.zip(network, otherNetworks)
- .map(t -> {
- // creation of the merging view
- List networks = new ArrayList<>();
- networks.add(t.getT1());
- networks.addAll(t.getT2());
- MergingView mergingView = MergingView.create("merge", "iidm");
- mergingView.merge(networks.toArray(new Network[0]));
- return mergingView;
- });
+ List networks = new ArrayList<>();
+ List otherNetworks = otherNetworkUuids
+ .stream()
+ .map(this::getNetwork)
+ .collect(Collectors.toList());
+
+ networks.add(network);
+ networks.addAll(otherNetworks);
+
+ MergingView mergingView = MergingView.create("merge", "iidm");
+ mergingView.merge(networks.toArray(new Network[0]));
+
+ return mergingView;
}
}
- public Mono run(SecurityAnalysisRunContext context) {
+ public SecurityAnalysisResult run(SecurityAnalysisRunContext context) {
return run(context, null);
}
private CompletableFuture runASAsync(SecurityAnalysisRunContext context,
SecurityAnalysis.Runner securityAnalysisRunner,
- Tuple2> tuple,
+ Network network,
+ List contingencies,
Reporter reporter,
UUID resultUuid) {
lockRunAndCancelAS.lock();
@@ -161,9 +151,9 @@ private CompletableFuture runASAsync(SecurityAnalysisRun
String variantId = context.getVariantId() != null ? context.getVariantId() : VariantManagerConstants.INITIAL_VARIANT_ID;
CompletableFuture future = securityAnalysisRunner.runAsync(
- tuple.getT1(),
+ network,
variantId,
- n -> tuple.getT2(),
+ n -> contingencies,
context.getParameters(),
securityAnalysisExecutionService.getLocalComputationManager(),
LimitViolationFilter.load(),
@@ -206,95 +196,87 @@ private void cleanASResultsAndPublishCancel(UUID resultUuid, String receiver) {
LOGGER.info(CANCEL_MESSAGE + " (resultUuid='{}')", resultUuid);
}
- private Mono run(SecurityAnalysisRunContext context, UUID resultUuid) {
+ private SecurityAnalysisResult run(SecurityAnalysisRunContext context, UUID resultUuid) {
Objects.requireNonNull(context);
LOGGER.info("Run security analysis on contingency lists: {}", context.getContingencyListNames().stream().map(LogUtils::sanitizeParam).collect(Collectors.toList()));
- Mono network = getNetwork(context.getNetworkUuid(), context.getOtherNetworkUuids());
-
- Mono> contingencies = Flux.fromIterable(context.getContingencyListNames())
- .flatMap(contingencyListName -> actionsService.getContingencyList(contingencyListName, context.getNetworkUuid(), context.getVariantId()))
- .collectList();
+ Network network = getNetwork(context.getNetworkUuid(), context.getOtherNetworkUuids());
- return Mono.zip(network, contingencies)
- .flatMap(tuple -> {
+ List contingencies = context.getContingencyListNames().stream()
+ .map(contingencyListName -> actionsService.getContingencyList(contingencyListName, context.getNetworkUuid(), context.getVariantId()))
+ .flatMap(List::stream)
+ .collect(Collectors.toList());
- SecurityAnalysis.Runner securityAnalysisRunner = securityAnalysisFactorySupplier.apply(context.getProvider());
+ SecurityAnalysis.Runner securityAnalysisRunner = securityAnalysisFactorySupplier.apply(context.getProvider());
- Reporter rootReporter = Reporter.NO_OP;
- Reporter reporter = Reporter.NO_OP;
- if (context.getReportUuid() != null) {
- String rootReporterId = context.getReporterId() == null ? AS_TYPE_REPORT : context.getReporterId() + "@" + AS_TYPE_REPORT;
- rootReporter = new ReporterModel(rootReporterId, rootReporterId);
- reporter = rootReporter.createSubReporter(AS_TYPE_REPORT, AS_TYPE_REPORT + " (${providerToUse})", "providerToUse", securityAnalysisRunner.getName());
- }
+ Reporter rootReporter = Reporter.NO_OP;
+ Reporter reporter = Reporter.NO_OP;
+ if (context.getReportUuid() != null) {
+ String rootReporterId = context.getReporterId() == null ? AS_TYPE_REPORT : context.getReporterId() + "@" + AS_TYPE_REPORT;
+ rootReporter = new ReporterModel(rootReporterId, rootReporterId);
+ reporter = rootReporter.createSubReporter(AS_TYPE_REPORT, AS_TYPE_REPORT + " (${providerToUse})", "providerToUse", securityAnalysisRunner.getName());
+ }
- CompletableFuture future = runASAsync(context, securityAnalysisRunner, tuple, reporter, resultUuid);
+ CompletableFuture future = runASAsync(context, securityAnalysisRunner, network, contingencies, reporter, resultUuid);
- Mono result = future == null ? Mono.empty() : Mono.fromCompletionStage(future);
- if (context.getReportUuid() != null) {
- Reporter finalRootReporter = rootReporter;
- return result.zipWhen(r -> reportService.sendReport(context.getReportUuid(), finalRootReporter)
- .thenReturn("") /* because zipWhen needs 2 non empty mono */)
- .map(Tuple2::getT1);
- } else {
- return result;
- }
- });
+ SecurityAnalysisResult result;
+ try {
+ result = future == null ? null : future.get();
+ } catch (CancellationException | InterruptedException | ExecutionException e) {
+ Thread.currentThread().interrupt();
+ throw new CancellationException(e.getMessage());
+ }
+ if (context.getReportUuid() != null) {
+ Reporter finalRootReporter = rootReporter;
+ reportService.sendReport(context.getReportUuid(), finalRootReporter);
+ }
+ return result;
}
@Bean
public Consumer> consumeRun() {
return message -> {
+ SecurityAnalysisResultContext resultContext = SecurityAnalysisResultContext.fromMessage(message, objectMapper);
try {
- SecurityAnalysisResultContext resultContext = SecurityAnalysisResultContext.fromMessage(message, objectMapper);
runRequests.add(resultContext.getResultUuid());
AtomicReference startTime = new AtomicReference<>();
- run(resultContext.getRunContext(), resultContext.getResultUuid())
- .doOnSubscribe(x -> startTime.set(System.nanoTime()))
- .flatMap(result -> {
- long nanoTime = System.nanoTime();
- LOGGER.info("Just run in {}s", TimeUnit.NANOSECONDS.toSeconds(nanoTime - startTime.getAndSet(nanoTime)));
- return Mono.fromRunnable(() -> securityAnalysisResultService.insert(resultContext.getResultUuid(),
- result,
- result.getPreContingencyResult().getStatus() == LoadFlowResult.ComponentResult.Status.CONVERGED ? SecurityAnalysisStatus.CONVERGED : SecurityAnalysisStatus.DIVERGED))
- .then(Mono.just(result))
- .doFinally(ignored -> {
- long finalNanoTime = System.nanoTime();
- LOGGER.info("Stored in {}s", TimeUnit.NANOSECONDS.toSeconds(finalNanoTime - startTime.getAndSet(finalNanoTime)));
- });
- })
- .doOnSuccess(result -> {
- if (result != null) { // result available
- notificationService.emitAnalysisResultsMessage(resultContext.getResultUuid().toString(), resultContext.getRunContext().getReceiver());
- LOGGER.info("Security analysis complete (resultUuid='{}')", resultContext.getResultUuid());
- } else { // result not available : stop computation request
- if (cancelComputationRequests.get(resultContext.getResultUuid()) != null) {
- cleanASResultsAndPublishCancel(resultContext.getResultUuid(), cancelComputationRequests.get(resultContext.getResultUuid()).getReceiver());
- }
- }
- })
- .onErrorResume(throwable -> {
- if (!(throwable instanceof CancellationException)) {
- LOGGER.error(FAIL_MESSAGE, throwable);
- notificationService.emitFailAnalysisMessage(resultContext.getResultUuid().toString(),
- resultContext.getRunContext().getReceiver(),
- throwable.getMessage());
- securityAnalysisResultService.delete(resultContext.getResultUuid());
- return Mono.empty();
- }
- return Mono.empty();
- })
- .doFinally(s -> {
- futures.remove(resultContext.getResultUuid());
- cancelComputationRequests.remove(resultContext.getResultUuid());
- runRequests.remove(resultContext.getResultUuid());
- })
- .block();
+ startTime.set(System.nanoTime());
+ SecurityAnalysisResult result = run(resultContext.getRunContext(), resultContext.getResultUuid());
+ long nanoTime = System.nanoTime();
+ LOGGER.info("Just run in {}s", TimeUnit.NANOSECONDS.toSeconds(nanoTime - startTime.getAndSet(nanoTime)));
+
+ securityAnalysisResultService.insert(
+ resultContext.getResultUuid(),
+ result,
+ result.getPreContingencyResult().getStatus() == LoadFlowResult.ComponentResult.Status.CONVERGED
+ ? SecurityAnalysisStatus.CONVERGED
+ : SecurityAnalysisStatus.DIVERGED);
+
+ long finalNanoTime = System.nanoTime();
+ LOGGER.info("Stored in {}s", TimeUnit.NANOSECONDS.toSeconds(finalNanoTime - startTime.getAndSet(finalNanoTime)));
+
+ if (result != null) { // result available
+ notificationService.emitAnalysisResultsMessage(resultContext.getResultUuid().toString(), resultContext.getRunContext().getReceiver());
+ LOGGER.info("Security analysis complete (resultUuid='{}')", resultContext.getResultUuid());
+ } else { // result not available : stop computation request
+ if (cancelComputationRequests.get(resultContext.getResultUuid()) != null) {
+ cleanASResultsAndPublishCancel(resultContext.getResultUuid(), cancelComputationRequests.get(resultContext.getResultUuid()).getReceiver());
+ }
+ }
} catch (Exception e) {
- LOGGER.error("Exception in consumeRun", e);
+ if (!(e instanceof CancellationException)) {
+ LOGGER.error(FAIL_MESSAGE, e);
+ notificationService.emitFailAnalysisMessage(resultContext.getResultUuid().toString(),
+ resultContext.getRunContext().getReceiver(),
+ e.getMessage());
+ securityAnalysisResultService.delete(resultContext.getResultUuid());
+ }
+ } finally {
+ futures.remove(resultContext.getResultUuid());
+ cancelComputationRequests.remove(resultContext.getResultUuid());
+ runRequests.remove(resultContext.getResultUuid());
}
};
}
diff --git a/src/main/resources/db/changelog/changesets/changelog_20231012T095523Z.xml b/src/main/resources/db/changelog/changesets/changelog_20231012T095523Z.xml
index 3ab7c0e4..f60bb5f4 100644
--- a/src/main/resources/db/changelog/changesets/changelog_20231012T095523Z.xml
+++ b/src/main/resources/db/changelog/changesets/changelog_20231012T095523Z.xml
@@ -15,7 +15,6 @@
-
@@ -36,7 +35,6 @@
-
@@ -57,6 +55,7 @@
+
diff --git a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisControllerTest.java b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisControllerTest.java
index c3fde1ed..2b577335 100644
--- a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisControllerTest.java
+++ b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisControllerTest.java
@@ -6,6 +6,7 @@
*/
package org.gridsuite.securityanalysis.server;
+import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.powsybl.commons.reporter.Reporter;
import com.powsybl.iidm.network.Network;
@@ -20,9 +21,15 @@
import com.powsybl.security.SecurityAnalysisResult;
import com.powsybl.security.results.PreContingencyResult;
import lombok.SneakyThrows;
+import org.gridsuite.securityanalysis.server.dto.ContingencyResultDTO;
import org.gridsuite.securityanalysis.server.dto.SecurityAnalysisParametersInfos;
import org.gridsuite.securityanalysis.server.dto.SecurityAnalysisStatus;
-import org.gridsuite.securityanalysis.server.service.*;
+import org.gridsuite.securityanalysis.server.dto.SubjectLimitViolationResultDTO;
+import org.gridsuite.securityanalysis.server.service.ActionsService;
+import org.gridsuite.securityanalysis.server.service.ReportService;
+import org.gridsuite.securityanalysis.server.service.SecurityAnalysisWorkerService;
+import org.gridsuite.securityanalysis.server.service.UuidGeneratorService;
+import org.gridsuite.securityanalysis.server.util.ContextConfigurationWithTestChannel;
import org.gridsuite.securityanalysis.server.util.MatcherJson;
import org.junit.After;
import org.junit.Before;
@@ -31,44 +38,45 @@
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.cloud.stream.binder.test.OutputDestination;
-import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration;
import org.springframework.http.MediaType;
import org.springframework.messaging.Message;
-import org.springframework.test.context.ContextConfiguration;
-import org.springframework.test.context.ContextHierarchy;
import org.springframework.test.context.junit4.SpringRunner;
-import org.springframework.test.web.reactive.server.WebTestClient;
-import org.springframework.web.reactive.config.EnableWebFlux;
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
import java.lang.reflect.Constructor;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
import static com.powsybl.network.store.model.NetworkStoreApi.VERSION;
import static org.gridsuite.securityanalysis.server.SecurityAnalysisProviderMock.*;
import static org.gridsuite.securityanalysis.server.service.NotificationService.CANCEL_MESSAGE;
import static org.gridsuite.securityanalysis.server.service.NotificationService.FAIL_MESSAGE;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* @author Geoffroy Jamgotchian
*/
+
@RunWith(SpringRunner.class)
-@AutoConfigureWebTestClient
-@EnableWebFlux
+@AutoConfigureMockMvc
@SpringBootTest
-@ContextHierarchy({@ContextConfiguration(classes = {SecurityAnalysisApplication.class, TestChannelBinderConfiguration.class})})
+@ContextConfigurationWithTestChannel
public class SecurityAnalysisControllerTest {
private static final UUID NETWORK_UUID = UUID.fromString("7928181c-7977-4592-ba19-88027e4254e4");
@@ -87,7 +95,7 @@ public class SecurityAnalysisControllerTest {
private OutputDestination output;
@Autowired
- private WebTestClient webTestClient;
+ private MockMvc mockMvc;
@MockBean
private NetworkStoreService networkStoreService;
@@ -127,39 +135,39 @@ public void setUp() throws Exception {
when(networkStoreService.getNetwork(NETWORK_STOP_UUID, PreloadingStrategy.COLLECTION)).thenAnswer((Answer) invocation -> {
//Needed so the stop call doesn't arrive too late
- Thread.sleep(2000);
Network network1 = new NetworkFactoryImpl().createNetwork("other", "test");
- network1.getVariantManager().cloneVariant(VariantManagerConstants.INITIAL_VARIANT_ID, VARIANT_2_ID);
+ network1.getVariantManager().cloneVariant(VariantManagerConstants.INITIAL_VARIANT_ID, VARIANT_TO_STOP_ID);
return network1;
});
// action service mocking
given(actionsService.getContingencyList(CONTINGENCY_LIST_NAME, NETWORK_UUID, VARIANT_1_ID))
- .willReturn(Flux.fromIterable(SecurityAnalysisProviderMock.CONTINGENCIES));
+ .willReturn(SecurityAnalysisProviderMock.CONTINGENCIES);
given(actionsService.getContingencyList(CONTINGENCY_LIST_NAME_VARIANT, NETWORK_UUID, VARIANT_3_ID))
- .willReturn(Flux.fromIterable(SecurityAnalysisProviderMock.CONTINGENCIES_VARIANT));
+ .willReturn(SecurityAnalysisProviderMock.CONTINGENCIES_VARIANT);
given(actionsService.getContingencyList(CONTINGENCY_LIST_NAME, NETWORK_UUID, VARIANT_2_ID))
- .willReturn(Flux.fromIterable(SecurityAnalysisProviderMock.CONTINGENCIES));
+ .willReturn(SecurityAnalysisProviderMock.CONTINGENCIES);
given(actionsService.getContingencyList(CONTINGENCY_LIST_NAME, NETWORK_UUID, null))
- .willReturn(Flux.fromIterable(SecurityAnalysisProviderMock.CONTINGENCIES));
+ .willReturn(SecurityAnalysisProviderMock.CONTINGENCIES);
given(actionsService.getContingencyList(CONTINGENCY_LIST2_NAME, NETWORK_UUID, VARIANT_1_ID))
- .willReturn(Flux.fromIterable(SecurityAnalysisProviderMock.CONTINGENCIES));
+ .willReturn(SecurityAnalysisProviderMock.CONTINGENCIES);
given(actionsService.getContingencyList(CONTINGENCY_LIST_NAME, NETWORK_STOP_UUID, VARIANT_2_ID))
- .willReturn(Flux.fromIterable(SecurityAnalysisProviderMock.CONTINGENCIES));
+ .willReturn(SecurityAnalysisProviderMock.CONTINGENCIES);
given(actionsService.getContingencyList(CONTINGENCY_LIST2_NAME, NETWORK_STOP_UUID, VARIANT_2_ID))
- .willReturn(Flux.fromIterable(SecurityAnalysisProviderMock.CONTINGENCIES));
+ .willReturn(SecurityAnalysisProviderMock.CONTINGENCIES);
given(actionsService.getContingencyList(CONTINGENCY_LIST_ERROR_NAME, NETWORK_UUID, VARIANT_1_ID))
- .willReturn(Flux.fromIterable(SecurityAnalysisProviderMock.CONTINGENCIES).thenMany(Flux.error(new RuntimeException(ERROR_MESSAGE))));
+ .willReturn(SecurityAnalysisProviderMock.CONTINGENCIES);
+ given(actionsService.getContingencyList(CONTINGENCY_LIST_NAME, NETWORK_STOP_UUID, VARIANT_TO_STOP_ID))
+ .willReturn(SecurityAnalysisProviderMock.CONTINGENCIES);
given(actionsService.getContingencyList(CONTINGENCY_LIST_NAME, NETWORK_FOR_MERGING_VIEW_UUID, null))
- .willReturn(Flux.fromIterable(SecurityAnalysisProviderMock.CONTINGENCIES));
+ .willReturn(SecurityAnalysisProviderMock.CONTINGENCIES);
given(actionsService.getContingencyList(CONTINGENCY_LIST_NAME, OTHER_NETWORK_FOR_MERGING_VIEW_UUID, null))
- .willReturn(Flux.fromIterable(SecurityAnalysisProviderMock.CONTINGENCIES));
+ .willReturn(SecurityAnalysisProviderMock.CONTINGENCIES);
// UUID service mocking to always generate the same result UUID
given(uuidGeneratorService.generate()).willReturn(RESULT_UUID);
- given(reportService.sendReport(any(UUID.class), any(Reporter.class)))
- .willReturn(Mono.empty());
+ doNothing().when(reportService).sendReport(any(UUID.class), any(Reporter.class));
// SecurityAnalysis.Runner constructor is private..
Constructor constructor = SecurityAnalysis.Runner.class.getDeclaredConstructor(SecurityAnalysisProvider.class);
@@ -184,22 +192,23 @@ public void setUp() throws Exception {
// added for testStatus can return null, after runTest
@After
- public void tearDown() {
- webTestClient.delete().uri("/" + VERSION + "/results")
- .exchange()
- .expectStatus().isOk();
+ public void tearDown() throws Exception {
+ mockMvc.perform(delete("/" + VERSION + "/results"))
+ .andExpect(status().isOk());
}
@SneakyThrows
public void simpleRunRequest(SecurityAnalysisParametersInfos lfParams) {
- webTestClient.post()
- .uri("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?contingencyListName=" + CONTINGENCY_LIST_NAME_VARIANT + "&variantId=" + VARIANT_3_ID)
- .bodyValue(lfParams)
- .exchange()
- .expectStatus().isOk()
- .expectHeader().contentType(MediaType.APPLICATION_JSON)
- .expectBody(SecurityAnalysisResult.class)
- .value(new MatcherJson<>(mapper, RESULT_VARIANT));
+ MvcResult mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?contingencyListName=" + CONTINGENCY_LIST_NAME_VARIANT + "&variantId=" + VARIANT_3_ID)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(mapper.writeValueAsString(lfParams)))
+ .andExpectAll(
+ status().isOk(),
+ content().contentType(MediaType.APPLICATION_JSON)).andReturn();
+ String resultAsString = mvcResult.getResponse().getContentAsString();
+ SecurityAnalysisResult securityAnalysisResult = mapper.readValue(resultAsString, SecurityAnalysisResult.class);
+
+ assertThat(RESULT_VARIANT, new MatcherJson<>(mapper, securityAnalysisResult));
}
@Test
@@ -219,190 +228,238 @@ public void runTestWithLFParams() {
}
@Test
- public void runTest() {
+ public void runTest() throws Exception {
+ MvcResult mvcResult;
+ String resultAsString;
+
// run with specific variant
- webTestClient.post()
- .uri("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?contingencyListName=" + CONTINGENCY_LIST_NAME_VARIANT + "&variantId=" + VARIANT_3_ID + "&provider=OpenLoadFlow")
- .exchange()
- .expectStatus().isOk()
- .expectHeader().contentType(MediaType.APPLICATION_JSON)
- .expectBody(SecurityAnalysisResult.class)
- .value(new MatcherJson<>(mapper, RESULT_VARIANT));
+ mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?contingencyListName=" + CONTINGENCY_LIST_NAME_VARIANT + "&variantId=" + VARIANT_3_ID + "&provider=OpenLoadFlow"))
+ .andExpectAll(
+ status().isOk(),
+ content().contentType(MediaType.APPLICATION_JSON)
+ ).andReturn();
+
+ resultAsString = mvcResult.getResponse().getContentAsString();
+ SecurityAnalysisResult securityAnalysisResult = mapper.readValue(resultAsString, SecurityAnalysisResult.class);
+ assertThat(RESULT_VARIANT, new MatcherJson<>(mapper, securityAnalysisResult));
// run with implicit initial variant
- webTestClient.post()
- .uri("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?contingencyListName=" + CONTINGENCY_LIST_NAME)
- .exchange()
- .expectStatus().isOk()
- .expectHeader().contentType(MediaType.APPLICATION_JSON)
- .expectBody(SecurityAnalysisResult.class)
- .value(new MatcherJson<>(mapper, RESULT));
+ mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?contingencyListName=" + CONTINGENCY_LIST_NAME))
+ .andExpectAll(
+ status().isOk(),
+ content().contentType(MediaType.APPLICATION_JSON)
+ ).andReturn();
+
+ resultAsString = mvcResult.getResponse().getContentAsString();
+ securityAnalysisResult = mapper.readValue(resultAsString, SecurityAnalysisResult.class);
+ assertThat(RESULT, new MatcherJson<>(mapper, securityAnalysisResult));
}
@Test
- public void runAndSaveTest() {
- webTestClient.post()
- .uri("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?contingencyListName=" + CONTINGENCY_LIST_NAME
- + "&receiver=me&variantId=" + VARIANT_2_ID + "&provider=OpenLoadFlow")
- .exchange()
- .expectStatus().isOk()
- .expectHeader().contentType(MediaType.APPLICATION_JSON)
- .expectBody(UUID.class)
- .isEqualTo(RESULT_UUID);
+ public void runAndSaveTest() throws Exception {
+ MvcResult mvcResult;
+ String resultAsString;
+
+ mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?contingencyListName=" + CONTINGENCY_LIST_NAME
+ + "&receiver=me&variantId=" + VARIANT_2_ID + "&provider=OpenLoadFlow"))
+ .andExpectAll(
+ status().isOk(),
+ content().contentType(MediaType.APPLICATION_JSON)
+ ).andReturn();
+
+ resultAsString = mvcResult.getResponse().getContentAsString();
+ UUID resultUuid = mapper.readValue(resultAsString, UUID.class);
+ assertEquals(RESULT_UUID, resultUuid);
Message resultMessage = output.receive(TIMEOUT, "sa.result");
assertEquals(RESULT_UUID.toString(), resultMessage.getHeaders().get("resultUuid"));
assertEquals("me", resultMessage.getHeaders().get("receiver"));
- webTestClient.get()
- .uri("/" + VERSION + "/results/" + RESULT_UUID + "/n-result")
- .exchange()
- .expectStatus().isOk()
- .expectHeader().contentType(MediaType.APPLICATION_JSON)
- .expectBody(PreContingencyResult.class)
- .value(new MatcherJson<>(mapper, RESULT.getPreContingencyResult()));
-
- webTestClient.get()
- .uri("/" + VERSION + "/results/" + RESULT_UUID + "/nmk-contingencies-result")
- .exchange()
- .expectStatus().isOk()
- .expectHeader().contentType(MediaType.APPLICATION_JSON)
- .expectBody(List.class)
- .value(new MatcherJson<>(mapper, RESULT_CONTINGENCIES));
-
- webTestClient.get()
- .uri("/" + VERSION + "/results/" + RESULT_UUID + "/nmk-constraints-result")
- .exchange()
- .expectStatus().isOk()
- .expectHeader().contentType(MediaType.APPLICATION_JSON)
- .expectBody(List.class)
- .value(new MatcherJson<>(mapper, RESULT_CONSTRAINTS));
+ mvcResult = mockMvc.perform(get("/" + VERSION + "/results/" + RESULT_UUID + "/n-result"))
+ .andExpectAll(
+ status().isOk(),
+ content().contentType(MediaType.APPLICATION_JSON)
+ ).andReturn();
+
+ resultAsString = mvcResult.getResponse().getContentAsString();
+ PreContingencyResult preContingencyResult = mapper.readValue(resultAsString, PreContingencyResult.class);
+ assertThat(RESULT.getPreContingencyResult(), new MatcherJson<>(mapper, preContingencyResult));
+
+ mvcResult = mockMvc.perform(get("/" + VERSION + "/results/" + RESULT_UUID + "/nmk-contingencies-result"))
+ .andExpectAll(
+ status().isOk(),
+ content().contentType(MediaType.APPLICATION_JSON)
+ ).andReturn();
+
+ resultAsString = mvcResult.getResponse().getContentAsString();
+ List contingenciesToConstraints = mapper.readValue(resultAsString, new TypeReference>() { });
+ assertThat(RESULT_CONTINGENCIES, new MatcherJson<>(mapper, contingenciesToConstraints));
+
+ mvcResult = mockMvc.perform(get("/" + VERSION + "/results/" + RESULT_UUID + "/nmk-constraints-result"))
+ .andExpectAll(
+ status().isOk(),
+ content().contentType(MediaType.APPLICATION_JSON)
+ ).andReturn();
+
+ resultAsString = mvcResult.getResponse().getContentAsString();
+ List constraintsToContingencies = mapper.readValue(resultAsString, new TypeReference>() { });
+ assertThat(RESULT_CONSTRAINTS, new MatcherJson<>(mapper, constraintsToContingencies));
// should throw not found if result does not exist
assertResultNotFound(OTHER_RESULT_UUID);
// test one result deletion
- webTestClient.delete()
- .uri("/" + VERSION + "/results/" + RESULT_UUID)
- .exchange()
- .expectStatus().isOk();
+ mockMvc.perform(delete("/" + VERSION + "/results/" + RESULT_UUID))
+ .andExpect(status().isOk());
assertResultNotFound(RESULT_UUID);
}
@Test
- public void runWithTwoLists() {
- webTestClient.post()
- .uri("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?contingencyListName=" + CONTINGENCY_LIST_NAME +
- "&contingencyListName=" + CONTINGENCY_LIST2_NAME + "&variantId=" + VARIANT_1_ID)
- .exchange()
- .expectStatus().isOk()
- .expectHeader().contentType(MediaType.APPLICATION_JSON)
- .expectBody(SecurityAnalysisResult.class)
- .value(new MatcherJson<>(mapper, RESULT));
+ public void runWithTwoLists() throws Exception {
+ MvcResult mvcResult;
+ String resultAsString;
+
+ mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?contingencyListName=" + CONTINGENCY_LIST_NAME +
+ "&contingencyListName=" + CONTINGENCY_LIST2_NAME + "&variantId=" + VARIANT_1_ID))
+ .andExpectAll(
+ status().isOk(),
+ content().contentType(MediaType.APPLICATION_JSON)
+ ).andReturn();
+ resultAsString = mvcResult.getResponse().getContentAsString();
+ SecurityAnalysisResult securityAnalysisResult = mapper.readValue(resultAsString, SecurityAnalysisResult.class);
+ assertThat(RESULT, new MatcherJson<>(mapper, securityAnalysisResult));
}
@Test
- public void deleteResultsTest() {
- webTestClient.post()
- .uri("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?contingencyListName=" + CONTINGENCY_LIST_NAME)
- .exchange()
- .expectStatus().isOk()
- .expectHeader().contentType(MediaType.APPLICATION_JSON)
- .expectBody(UUID.class)
- .isEqualTo(RESULT_UUID);
+ public void deleteResultsTest() throws Exception {
+ MvcResult mvcResult;
+ String resultAsString;
+
+ mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?contingencyListName=" + CONTINGENCY_LIST_NAME))
+ .andExpectAll(
+ status().isOk(),
+ content().contentType(MediaType.APPLICATION_JSON)
+ ).andReturn();
+
+ resultAsString = mvcResult.getResponse().getContentAsString();
+ UUID resultUuid = mapper.readValue(resultAsString, UUID.class);
+ assertEquals(RESULT_UUID, resultUuid);
output.receive(TIMEOUT, "sa.result");
- webTestClient.delete()
- .uri("/" + VERSION + "/results")
- .exchange()
- .expectStatus().isOk();
+ mockMvc.perform(delete("/" + VERSION + "/results"))
+ .andExpect(status().isOk());
assertResultNotFound(RESULT_UUID);
}
@Test
- public void mergingViewTest() {
- webTestClient.post()
- .uri("/" + VERSION + "/networks/" + NETWORK_FOR_MERGING_VIEW_UUID + "/run?contingencyListName=" + CONTINGENCY_LIST_NAME + "&networkUuid=" + OTHER_NETWORK_FOR_MERGING_VIEW_UUID)
- .exchange()
- .expectStatus().isOk()
- .expectHeader().contentType(MediaType.APPLICATION_JSON)
- .expectBody(SecurityAnalysisResult.class)
- .value(new MatcherJson<>(mapper, RESULT));
+ public void mergingViewTest() throws Exception {
+ MvcResult mvcResult;
+ String resultAsString;
+
+ mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_FOR_MERGING_VIEW_UUID + "/run?contingencyListName=" + CONTINGENCY_LIST_NAME + "&networkUuid=" + OTHER_NETWORK_FOR_MERGING_VIEW_UUID))
+ .andExpectAll(
+ status().isOk(),
+ content().contentType(MediaType.APPLICATION_JSON)
+ ).andReturn();
+
+ resultAsString = mvcResult.getResponse().getContentAsString();
+ SecurityAnalysisResult securityAnalysisResult = mapper.readValue(resultAsString, SecurityAnalysisResult.class);
+ assertThat(RESULT, new MatcherJson<>(mapper, securityAnalysisResult));
}
@Test
- public void testStatus() {
- webTestClient.get()
- .uri("/" + VERSION + "/results/" + RESULT_UUID + "/status")
- .exchange()
- .expectStatus().isOk()
- .expectBody(SecurityAnalysisStatus.class)
- .isEqualTo(null);
-
- webTestClient.put()
- .uri("/" + VERSION + "/results/invalidate-status?resultUuid=" + RESULT_UUID)
- .exchange()
- .expectStatus().isOk();
-
- webTestClient.get()
- .uri("/" + VERSION + "/results/" + RESULT_UUID + "/status")
- .exchange()
- .expectStatus().isOk()
- .expectBody(SecurityAnalysisStatus.class)
- .isEqualTo(SecurityAnalysisStatus.NOT_DONE);
-
- webTestClient.post()
- .uri("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?contingencyListName=" + CONTINGENCY_LIST_NAME
- + "&receiver=me&variantId=" + VARIANT_2_ID + "&provider=OpenLoadFlow")
- .exchange()
- .expectStatus().isOk()
- .expectHeader().contentType(MediaType.APPLICATION_JSON)
- .expectBody(UUID.class)
- .isEqualTo(RESULT_UUID);
+ public void testStatus() throws Exception {
+ MvcResult mvcResult;
+ String resultAsString;
+
+ // getting status when result does not exist
+ mockMvc.perform(get("/" + VERSION + "/results/" + RESULT_UUID + "/status"))
+ .andExpectAll(
+ status().isOk(),
+ content().string("")
+ );
+
+ // invalidating unexisting result
+ mockMvc.perform(put("/" + VERSION + "/results/invalidate-status?resultUuid=" + RESULT_UUID))
+ .andExpect(status().isOk());
+
+ // checking status is updated anyway
+ mvcResult = mockMvc.perform(get("/" + VERSION + "/results/" + RESULT_UUID + "/status"))
+ .andExpect(status().isOk()).andReturn();
+
+ resultAsString = mvcResult.getResponse().getContentAsString();
+ SecurityAnalysisStatus securityAnalysisStatus = mapper.readValue(resultAsString, SecurityAnalysisStatus.class);
+ assertEquals(SecurityAnalysisStatus.NOT_DONE, securityAnalysisStatus);
+
+ // running computation to create result
+ mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?contingencyListName=" + CONTINGENCY_LIST_NAME
+ + "&receiver=me&variantId=" + VARIANT_2_ID + "&provider=OpenLoadFlow"))
+ .andExpectAll(
+ status().isOk(),
+ content().contentType(MediaType.APPLICATION_JSON)
+ ).andReturn();
+
+ resultAsString = mvcResult.getResponse().getContentAsString();
+ UUID resultUuid = mapper.readValue(resultAsString, UUID.class);
+ assertEquals(RESULT_UUID, resultUuid);
Message resultMessage = output.receive(TIMEOUT, "sa.result");
assertEquals(RESULT_UUID.toString(), resultMessage.getHeaders().get("resultUuid"));
assertEquals("me", resultMessage.getHeaders().get("receiver"));
- webTestClient.get()
- .uri("/" + VERSION + "/results/" + RESULT_UUID + "/status")
- .exchange()
- .expectStatus().isOk()
- .expectBody(SecurityAnalysisStatus.class)
- .isEqualTo(SecurityAnalysisStatus.CONVERGED);
-
- webTestClient.put()
- .uri("/" + VERSION + "/results/invalidate-status?resultUuid=" + RESULT_UUID)
- .exchange()
- .expectStatus().isOk();
-
- webTestClient.get()
- .uri("/" + VERSION + "/results/" + RESULT_UUID + "/status")
- .exchange()
- .expectStatus().isOk()
- .expectBody(SecurityAnalysisStatus.class)
- .isEqualTo(SecurityAnalysisStatus.NOT_DONE);
+ // getting status of this result
+ mvcResult = mockMvc.perform(get("/" + VERSION + "/results/" + RESULT_UUID + "/status"))
+ .andExpect(status().isOk()).andReturn();
+
+ resultAsString = mvcResult.getResponse().getContentAsString();
+ securityAnalysisStatus = mapper.readValue(resultAsString, SecurityAnalysisStatus.class);
+ assertEquals(SecurityAnalysisStatus.CONVERGED, securityAnalysisStatus);
+
+ // invalidating existing result
+ mockMvc.perform(put("/" + VERSION + "/results/invalidate-status?resultUuid=" + RESULT_UUID))
+ .andExpect(status().isOk());
+
+ // checking invalidated status
+ mvcResult = mockMvc.perform(get("/" + VERSION + "/results/" + RESULT_UUID + "/status"))
+ .andExpect(status().isOk()).andReturn();
+
+ resultAsString = mvcResult.getResponse().getContentAsString();
+ securityAnalysisStatus = mapper.readValue(resultAsString, SecurityAnalysisStatus.class);
+ assertEquals(SecurityAnalysisStatus.NOT_DONE, securityAnalysisStatus);
}
@Test
- public void stopTest() {
- webTestClient.post()
- .uri("/" + VERSION + "/networks/" + NETWORK_STOP_UUID + "/run-and-save?contingencyListName=" + CONTINGENCY_LIST_NAME
- + "&receiver=me&variantId=" + VARIANT_2_ID)
- .exchange()
- .expectStatus().isOk()
- .expectHeader().contentType(MediaType.APPLICATION_JSON)
- .expectBody(UUID.class)
- .isEqualTo(RESULT_UUID);
-
- webTestClient.put()
- .uri("/" + VERSION + "/results/" + RESULT_UUID + "/stop"
- + "?receiver=me")
- .exchange()
- .expectStatus().isOk();
+ public void stopTest() throws Exception {
+ countDownLatch = new CountDownLatch(1);
+
+ new Thread(() -> {
+ try {
+ MvcResult mvcResult;
+ String resultAsString;
+ mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_STOP_UUID + "/run-and-save?contingencyListName=" + CONTINGENCY_LIST_NAME
+ + "&receiver=me&variantId=" + VARIANT_TO_STOP_ID))
+ .andExpectAll(
+ status().isOk(),
+ content().contentType(MediaType.APPLICATION_JSON)
+ ).andReturn();
+
+ resultAsString = mvcResult.getResponse().getContentAsString();
+ UUID resultUuid = mapper.readValue(resultAsString, UUID.class);
+ assertEquals(RESULT_UUID, resultUuid);
+ } catch (Exception e) {
+ throw new RuntimeException(e.getMessage());
+ }
+ }).start();
+
+ // wait for security analysis to actually run before trying to stop it
+ countDownLatch.await();
+
+ mockMvc.perform(put("/" + VERSION + "/results/" + RESULT_UUID + "/stop"
+ + "?receiver=me"))
+ .andExpect(status().isOk());
Message message = output.receive(TIMEOUT * 3, "sa.stopped");
assertEquals(RESULT_UUID.toString(), message.getHeaders().get("resultUuid"));
@@ -411,15 +468,23 @@ public void stopTest() {
}
@Test
- public void runTestWithError() {
- webTestClient.post()
- .uri("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?contingencyListName=" + CONTINGENCY_LIST_ERROR_NAME
- + "&receiver=me&variantId=" + VARIANT_1_ID)
- .exchange()
- .expectStatus().isOk() // Because fully asynchronous (just publish a message)
- .expectHeader().contentType(MediaType.APPLICATION_JSON)
- .expectBody(UUID.class)
- .isEqualTo(RESULT_UUID);
+ public void runTestWithError() throws Exception {
+ MvcResult mvcResult;
+ String resultAsString;
+
+ given(actionsService.getContingencyList(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?contingencyListName=" + CONTINGENCY_LIST_ERROR_NAME
+ + "&receiver=me&variantId=" + VARIANT_1_ID))
+ .andExpectAll(
+ status().isOk(),
+ content().contentType(MediaType.APPLICATION_JSON)
+ ).andReturn();
+
+ resultAsString = mvcResult.getResponse().getContentAsString();
+ UUID resultUuid = mapper.readValue(resultAsString, UUID.class);
+ assertEquals(RESULT_UUID, resultUuid);
// Message stopped has been sent
Message cancelMessage = output.receive(TIMEOUT, "sa.failed");
@@ -432,52 +497,55 @@ public void runTestWithError() {
}
@Test
- public void runWithReportTest() {
- webTestClient.post()
- .uri("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?contingencyListName=" + CONTINGENCY_LIST_NAME + "&provider=testProvider" + "&reportUuid=" + REPORT_UUID + "&reporterId=" + UUID.randomUUID())
- .exchange()
- .expectStatus().isOk()
- .expectHeader().contentType(MediaType.APPLICATION_JSON)
- .expectBody(SecurityAnalysisResult.class)
- .value(new MatcherJson<>(mapper, RESULT));
+ public void runWithReportTest() throws Exception {
+ MvcResult mvcResult;
+ String resultAsString;
+
+ mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?contingencyListName=" + CONTINGENCY_LIST_NAME + "&provider=testProvider" + "&reportUuid=" + REPORT_UUID + "&reporterId=" + UUID.randomUUID()).contentType(MediaType.APPLICATION_JSON))
+ .andExpectAll(
+ status().isOk(),
+ content().contentType(MediaType.APPLICATION_JSON))
+ .andReturn();
+
+ resultAsString = mvcResult.getResponse().getContentAsString();
+ SecurityAnalysisResult securityAnalysisResult = mapper.readValue(resultAsString, SecurityAnalysisResult.class);
+ assertThat(RESULT, new MatcherJson<>(mapper, securityAnalysisResult));
}
@Test
- public void getProvidersTest() {
- webTestClient.get()
- .uri("/" + VERSION + "/providers")
- .exchange()
- .expectStatus().isOk()
- .expectHeader().contentType(MediaType.APPLICATION_JSON)
- .expectBody(List.class)
- .isEqualTo(List.of("DynaFlow", "OpenLoadFlow", "Hades2"));
+ public void getProvidersTest() throws Exception {
+ MvcResult mvcResult;
+ String resultAsString;
+
+ mvcResult = mockMvc.perform(get("/" + VERSION + "/providers"))
+ .andExpectAll(
+ status().isOk(),
+ content().contentType(MediaType.APPLICATION_JSON)
+ ).andReturn();
+
+ resultAsString = mvcResult.getResponse().getContentAsString();
+ List providers = mapper.readValue(resultAsString, new TypeReference>() { });
+ assertEquals(List.of("DynaFlow", "OpenLoadFlow", "Hades2"), providers);
}
@Test
- public void getDefaultProviderTest() {
- webTestClient.get()
- .uri("/" + VERSION + "/default-provider")
- .exchange()
- .expectStatus().isOk()
- .expectHeader().contentType(new MediaType(MediaType.TEXT_PLAIN, StandardCharsets.UTF_8))
- .expectBody(String.class)
- .isEqualTo("OpenLoadFlow");
+ public void getDefaultProviderTest() throws Exception {
+ mockMvc.perform(get("/" + VERSION + "/default-provider"))
+ .andExpectAll(
+ status().isOk(),
+ content().contentType(new MediaType(MediaType.TEXT_PLAIN, StandardCharsets.UTF_8)),
+ content().string("OpenLoadFlow")
+ );
}
- private void assertResultNotFound(UUID resultUuid) {
- webTestClient.get()
- .uri("/" + VERSION + "/results/" + resultUuid + "/n-result")
- .exchange()
- .expectStatus().isNotFound();
-
- webTestClient.get()
- .uri("/" + VERSION + "/results/" + resultUuid + "/nmk-contingencies-result")
- .exchange()
- .expectStatus().isNotFound();
-
- webTestClient.get()
- .uri("/" + VERSION + "/results/" + resultUuid + "/nmk-constraints-result")
- .exchange()
- .expectStatus().isNotFound();
+ private void assertResultNotFound(UUID resultUuid) throws Exception {
+ mockMvc.perform(get("/" + VERSION + "/results/" + resultUuid + "/n-result"))
+ .andExpect(status().isNotFound());
+
+ mockMvc.perform(get("/" + VERSION + "/results/" + resultUuid + "/nmk-contingencies-result"))
+ .andExpect(status().isNotFound());
+
+ mockMvc.perform(get("/" + VERSION + "/results/" + resultUuid + "/nmk-constraints-result"))
+ .andExpect(status().isNotFound());
}
}
diff --git a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisProviderMock.java b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisProviderMock.java
index 8233fc4b..add48213 100644
--- a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisProviderMock.java
+++ b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisProviderMock.java
@@ -8,6 +8,8 @@
import java.util.List;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import com.powsybl.commons.reporter.Reporter;
@@ -81,40 +83,29 @@ public class SecurityAnalysisProviderMock implements SecurityAnalysisProvider {
CONTINGENCIES_VARIANT.stream().map(contingency -> new PostContingencyResult(contingency, PostContingencyComputationStatus.CONVERGED, List.of(LIMIT_VIOLATION_4)))
.collect(Collectors.toList()));
- static final List RESULT_CONTINGENCIES = CONTINGENCIES.stream().map(c ->
- new ContingencyToSubjectLimitViolationDTO(
- c.getId(),
- LoadFlowResult.ComponentResult.Status.CONVERGED.name(),
- c.getElements().stream().map(e -> new ContingencyElementDTO(e.getId(), e.getType())).collect(Collectors.toList()),
- List.of(new SubjectLimitViolationFromContingencyDTO(
+ static final List RESULT_CONTINGENCIES = CONTINGENCIES.stream().map(c ->
+ new ContingencyResultDTO(
+ new ContingencyDTO(
+ c.getId(),
+ LoadFlowResult.ComponentResult.Status.CONVERGED.name(),
+ c.getElements().stream().map(e -> new ContingencyElementDTO(e.getId(), e.getType())).collect(Collectors.toList())
+ ),
+ List.of(new SubjectLimitViolationDTO(
LIMIT_VIOLATION_2.getSubjectId(),
- LIMIT_VIOLATION_2.getLimitType(),
- LIMIT_VIOLATION_2.getLimitName(),
- LIMIT_VIOLATION_2.getSide(),
- LIMIT_VIOLATION_2.getAcceptableDuration(),
- LIMIT_VIOLATION_2.getLimit(),
- LIMIT_VIOLATION_2.getLimitReduction(),
- LIMIT_VIOLATION_2.getValue())
+ toLimitViolationDTO(LIMIT_VIOLATION_2)
)
- )).collect(Collectors.toList()
+ ))).collect(Collectors.toList()
);
- static final List RESULT_CONSTRAINTS = List.of(
- new SubjectLimitViolationToContingencyDTO(LIMIT_VIOLATION_1.getSubjectId(), List.of()),
- new SubjectLimitViolationToContingencyDTO(
+ static final List RESULT_CONSTRAINTS = List.of(
+ new SubjectLimitViolationResultDTO(LIMIT_VIOLATION_1.getSubjectId(), List.of()),
+ new SubjectLimitViolationResultDTO(
LIMIT_VIOLATION_2.getSubjectId(),
- CONTINGENCIES.stream().map(c -> new ContingencyFromSubjectLimitViolationDTO(
- c.getId(),
- LoadFlowResult.ComponentResult.Status.CONVERGED.name(),
- LIMIT_VIOLATION_2.getLimitType(),
- LIMIT_VIOLATION_2.getLimitName(),
- LIMIT_VIOLATION_2.getSide(),
- LIMIT_VIOLATION_2.getAcceptableDuration(),
- LIMIT_VIOLATION_2.getLimit(),
- LIMIT_VIOLATION_2.getLimitReduction(),
- LIMIT_VIOLATION_2.getValue(),
- c.getElements().stream().map(e -> new ContingencyElementDTO(e.getId(), e.getType())).collect(Collectors.toList())))
- .collect(Collectors.toList())
+ CONTINGENCIES.stream().map(c -> new ContingencyLimitViolationDTO(
+ new ContingencyDTO(c.getId(), LoadFlowResult.ComponentResult.Status.CONVERGED.name(), c.getElements().stream().map(e -> new ContingencyElementDTO(e.getId(), e.getType())).collect(Collectors.toList())),
+ toLimitViolationDTO(LIMIT_VIOLATION_2)
+ )
+ ).collect(Collectors.toList())
));
static final SecurityAnalysisReport REPORT = new SecurityAnalysisReport(RESULT);
@@ -123,6 +114,9 @@ public class SecurityAnalysisProviderMock implements SecurityAnalysisProvider {
static final String VARIANT_1_ID = "variant_1";
static final String VARIANT_2_ID = "variant_2";
static final String VARIANT_3_ID = "variant_3";
+ static final String VARIANT_TO_STOP_ID = "variant_to_stop";
+
+ static CountDownLatch countDownLatch;
public CompletableFuture run(Network network,
String workingVariantId,
@@ -137,10 +131,17 @@ public CompletableFuture run(Network network,
List monitors,
Reporter reporter) {
LOGGER.info("Run security analysis mock");
- if (workingVariantId.equals(VARIANT_3_ID)) {
- return CompletableFuture.completedFuture(REPORT_VARIANT);
+ switch (workingVariantId) {
+ case VARIANT_3_ID:
+ return CompletableFuture.completedFuture(REPORT_VARIANT);
+ case VARIANT_TO_STOP_ID:
+ countDownLatch.countDown();
+ // creating a long completable future which is here to be canceled
+ return new CompletableFuture().completeOnTimeout(REPORT, 3, TimeUnit.SECONDS);
+ default:
+ return CompletableFuture.completedFuture(REPORT);
}
- return CompletableFuture.completedFuture(REPORT);
+
}
@Override
@@ -152,4 +153,20 @@ public String getName() {
public String getVersion() {
return "1";
}
+
+ private static LimitViolationDTO toLimitViolationDTO(LimitViolation limitViolation) {
+ Double computedLoading = limitViolation.getLimitType().equals(LimitViolationType.CURRENT)
+ ? (100 * limitViolation.getValue()) / (limitViolation.getLimit() * limitViolation.getLimitReduction())
+ : null;
+ return new LimitViolationDTO(
+ limitViolation.getLimitType(),
+ limitViolation.getLimitName(),
+ limitViolation.getSide(),
+ limitViolation.getAcceptableDuration(),
+ limitViolation.getLimit(),
+ limitViolation.getLimitReduction(),
+ limitViolation.getValue(),
+ computedLoading
+ );
+ }
}
diff --git a/src/test/java/org/gridsuite/securityanalysis/server/SupervisionControllerTest.java b/src/test/java/org/gridsuite/securityanalysis/server/SupervisionControllerTest.java
index 746e6684..8f9da956 100644
--- a/src/test/java/org/gridsuite/securityanalysis/server/SupervisionControllerTest.java
+++ b/src/test/java/org/gridsuite/securityanalysis/server/SupervisionControllerTest.java
@@ -9,35 +9,32 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
-import org.springframework.test.web.reactive.server.EntityExchangeResult;
-import org.springframework.test.web.reactive.server.WebTestClient;
-import static org.junit.Assert.assertEquals;
+import org.springframework.test.web.servlet.MockMvc;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
/**
* @author Hugo Marcellin
*/
@RunWith(SpringRunner.class)
-@AutoConfigureWebTestClient
+@AutoConfigureMockMvc
@SpringBootTest
public class SupervisionControllerTest {
@Autowired
- private WebTestClient webTestClient;
+ private MockMvc mockMvc;
@Test
- public void testResultCount() {
+ public void testResultCount() throws Exception {
//get the result timeline uuid of the calculation
- EntityExchangeResult entityExchangeResult = webTestClient.get()
- .uri("/v1/supervision/results-count")
- .exchange()
- .expectStatus().isOk()
- .expectBody(Integer.class).returnResult();
-
- int resultCount = entityExchangeResult.getResponseBody();
- assertEquals(0, resultCount);
-
+ mockMvc.perform(get("/v1/supervision/results-count"))
+ .andExpectAll(
+ status().isOk(),
+ content().string("0")
+ );
}
}
diff --git a/src/test/java/org/gridsuite/securityanalysis/server/service/ActionsServiceTest.java b/src/test/java/org/gridsuite/securityanalysis/server/service/ActionsServiceTest.java
index d56026eb..b3078ae6 100644
--- a/src/test/java/org/gridsuite/securityanalysis/server/service/ActionsServiceTest.java
+++ b/src/test/java/org/gridsuite/securityanalysis/server/service/ActionsServiceTest.java
@@ -14,18 +14,15 @@
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
-import org.gridsuite.securityanalysis.server.WebFluxConfig;
+import org.gridsuite.securityanalysis.server.util.ContextConfigurationWithTestChannel;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.http.codec.json.Jackson2JsonDecoder;
-import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.test.context.junit4.SpringRunner;
-import org.springframework.web.reactive.function.client.ExchangeStrategies;
-import org.springframework.web.reactive.function.client.WebClient;
import java.io.IOException;
import java.util.List;
@@ -40,7 +37,9 @@
* @author Geoffroy Jamgotchian
* @author Slimane Amar
*/
+@SpringBootTest
@RunWith(SpringRunner.class)
+@ContextConfigurationWithTestChannel
public class ActionsServiceTest {
private static final int DATA_BUFFER_LIMIT = 256 * 1024; // AbstractJackson2Decoder.maxInMemorySize
@@ -57,27 +56,18 @@ public class ActionsServiceTest {
private static final Contingency CONTINGENCY_VARIANT = new Contingency("c2", new BranchContingency("b2"));
- private final ObjectMapper objectMapper = WebFluxConfig.createObjectMapper();
-
- private WebClient.Builder webClientBuilder;
+ @Autowired
+ private ObjectMapper objectMapper;
private MockWebServer server;
+ @Autowired
private ActionsService actionsService;
@Before
public void setUp() throws IOException {
- webClientBuilder = WebClient.builder();
- ExchangeStrategies strategies = ExchangeStrategies
- .builder()
- .codecs(clientDefaultCodecsConfigurer -> {
- clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(objectMapper, MediaType.APPLICATION_JSON));
- clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper, MediaType.APPLICATION_JSON));
-
- }).build();
- webClientBuilder.exchangeStrategies(strategies);
-
- actionsService = new ActionsService(webClientBuilder, initMockWebServer());
+ String mockServerUri = initMockWebServer();
+ actionsService.setActionServiceBaseUri(mockServerUri);
}
@After
@@ -134,18 +124,18 @@ private List createVeryLargeList() {
@Test
public void test() {
- List list = actionsService.getContingencyList(LIST_NAME, UUID.fromString(NETWORK_UUID), null).collectList().block();
+ List list = actionsService.getContingencyList(LIST_NAME, UUID.fromString(NETWORK_UUID), null);
assertEquals(List.of(CONTINGENCY), list);
- list = actionsService.getContingencyList(LIST_NAME, UUID.fromString(NETWORK_UUID), VARIANT_ID).collectList().block();
+ list = actionsService.getContingencyList(LIST_NAME, UUID.fromString(NETWORK_UUID), VARIANT_ID);
assertEquals(List.of(CONTINGENCY_VARIANT), list);
}
@Test
public void testVeryLargeList() {
// DataBufferLimitException should not be thrown with this message : "Exceeded limit on max bytes to buffer : DATA_BUFFER_LIMIT"
- List list = actionsService.getContingencyList(VERY_LARGE_LIST_NAME, UUID.fromString(NETWORK_UUID), null).collectList().block();
+ List list = actionsService.getContingencyList(VERY_LARGE_LIST_NAME, UUID.fromString(NETWORK_UUID), null);
assertEquals(createVeryLargeList(), list);
- list = actionsService.getContingencyList(VERY_LARGE_LIST_NAME, UUID.fromString(NETWORK_UUID), VARIANT_ID).collectList().block();
+ list = actionsService.getContingencyList(VERY_LARGE_LIST_NAME, UUID.fromString(NETWORK_UUID), VARIANT_ID);
assertEquals(createVeryLargeList(), list);
}
}
diff --git a/src/test/java/org/gridsuite/securityanalysis/server/service/ReportServiceTest.java b/src/test/java/org/gridsuite/securityanalysis/server/service/ReportServiceTest.java
index 18f7c03e..7fceaa85 100644
--- a/src/test/java/org/gridsuite/securityanalysis/server/service/ReportServiceTest.java
+++ b/src/test/java/org/gridsuite/securityanalysis/server/service/ReportServiceTest.java
@@ -6,7 +6,6 @@
*/
package org.gridsuite.securityanalysis.server.service;
-import com.fasterxml.jackson.databind.ObjectMapper;
import com.powsybl.commons.reporter.Reporter;
import com.powsybl.commons.reporter.ReporterModel;
import okhttp3.HttpUrl;
@@ -14,57 +13,43 @@
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
-import org.gridsuite.securityanalysis.server.WebFluxConfig;
+import org.gridsuite.securityanalysis.server.util.ContextConfigurationWithTestChannel;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.http.codec.json.Jackson2JsonDecoder;
-import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.test.context.junit4.SpringRunner;
-import org.springframework.web.reactive.function.client.ExchangeStrategies;
-import org.springframework.web.reactive.function.client.WebClient;
import java.io.IOException;
import java.util.Objects;
import java.util.UUID;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
/**
* @author Geoffroy Jamgotchian
*/
+@SpringBootTest
@RunWith(SpringRunner.class)
+@ContextConfigurationWithTestChannel
public class ReportServiceTest {
private static final UUID REPORT_UUID = UUID.fromString("7928181c-7977-4592-ba19-88027e4254e4");
private static final String REPORT_JSON = "{\"version\":\"1.0\",\"reportTree\":{\"taskKey\":\"test\"},\"dics\":{\"default\":{\"test\":\"a test\"}}}";
- private final ObjectMapper objectMapper = WebFluxConfig.createObjectMapper();
-
- private WebClient.Builder webClientBuilder;
-
private MockWebServer server;
+ @Autowired
private ReportService reportService;
@Before
public void setUp() throws IOException {
- webClientBuilder = WebClient.builder();
- ExchangeStrategies strategies = ExchangeStrategies
- .builder()
- .codecs(clientDefaultCodecsConfigurer -> {
- clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(objectMapper, MediaType.APPLICATION_JSON));
- clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper, MediaType.APPLICATION_JSON));
-
- }).build();
- webClientBuilder.exchangeStrategies(strategies);
-
- reportService = new ReportService(webClientBuilder, initMockWebServer());
+ String mockServerUri = initMockWebServer();
+ reportService.setReportServiceBaseUri(mockServerUri);
}
@After
@@ -104,6 +89,6 @@ public MockResponse dispatch(RecordedRequest request) {
@Test
public void test() {
Reporter reporter = new ReporterModel("test", "a test");
- assertNull(reportService.sendReport(REPORT_UUID, reporter).block());
+ reportService.sendReport(REPORT_UUID, reporter);
}
}
diff --git a/src/test/java/org/gridsuite/securityanalysis/server/util/ContextConfigurationWithTestChannel.java b/src/test/java/org/gridsuite/securityanalysis/server/util/ContextConfigurationWithTestChannel.java
new file mode 100644
index 00000000..23a926c6
--- /dev/null
+++ b/src/test/java/org/gridsuite/securityanalysis/server/util/ContextConfigurationWithTestChannel.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2023, 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.securityanalysis.server.util;
+
+import org.gridsuite.securityanalysis.server.SecurityAnalysisApplication;
+import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration;
+import org.springframework.test.context.ContextConfiguration;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author Slimane Amar
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@ContextConfiguration(classes = {SecurityAnalysisApplication.class, TestChannelBinderConfiguration.class})
+public @interface ContextConfigurationWithTestChannel {
+}