From 49f5a769d8d1b571b18e229e0d3d3544a0fb052a Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Mon, 29 Jul 2024 10:38:04 +0200 Subject: [PATCH 01/22] add indexed attribute Signed-off-by: jamal-khey --- .../java/com/powsybl/caseserver/CaseController.java | 5 +++-- src/main/java/com/powsybl/caseserver/CaseService.java | 8 +++++--- .../caseserver/repository/CaseMetadataEntity.java | 3 +++ .../changesets/changelog_20240726T144717Z.xml | 10 ++++++++++ .../resources/db/changelog/db.changelog-master.yaml | 7 ++++++- .../powsybl/caseserver/ScheduledCaseCleanerTest.java | 6 +++--- 6 files changed, 30 insertions(+), 9 deletions(-) create mode 100644 src/main/resources/db/changelog/changesets/changelog_20240726T144717Z.xml diff --git a/src/main/java/com/powsybl/caseserver/CaseController.java b/src/main/java/com/powsybl/caseserver/CaseController.java index 17776ad..60c7167 100644 --- a/src/main/java/com/powsybl/caseserver/CaseController.java +++ b/src/main/java/com/powsybl/caseserver/CaseController.java @@ -152,9 +152,10 @@ public ResponseEntity exists(@PathVariable("caseUuid") UUID caseUuid) { @Operation(summary = "import a case") @SuppressWarnings("javasecurity:S5145") public ResponseEntity importCase(@RequestParam("file") MultipartFile file, - @RequestParam(value = "withExpiration", required = false, defaultValue = "false") boolean withExpiration) { + @RequestParam(value = "withExpiration", required = false, defaultValue = "false") boolean withExpiration, + @RequestParam(value = "indexed", required = false, defaultValue = "false") boolean indexed) { LOGGER.debug("importCase request received with file = {}", file.getName()); - UUID caseUuid = caseService.importCase(file, withExpiration); + UUID caseUuid = caseService.importCase(file, withExpiration, indexed); return ResponseEntity.ok().body(caseUuid); } diff --git a/src/main/java/com/powsybl/caseserver/CaseService.java b/src/main/java/com/powsybl/caseserver/CaseService.java index 27b9fdd..5f99d8b 100644 --- a/src/main/java/com/powsybl/caseserver/CaseService.java +++ b/src/main/java/com/powsybl/caseserver/CaseService.java @@ -179,7 +179,7 @@ boolean caseExists(UUID caseName) { return Files.exists(caseFile) && Files.isRegularFile(caseFile); } - UUID importCase(MultipartFile mpf, boolean withExpiration) { + UUID importCase(MultipartFile mpf, boolean withExpiration, boolean indexed) { checkStorageInitialization(); UUID caseUuid = UUID.randomUUID(); @@ -216,7 +216,9 @@ UUID importCase(MultipartFile mpf, boolean withExpiration) { createCaseMetadataEntity(caseUuid, withExpiration); CaseInfos caseInfos = createInfos(caseFile.getFileName().toString(), caseUuid, importer.getFormat()); - caseInfosService.addCaseInfos(caseInfos); + if(indexed) { + caseInfosService.addCaseInfos(caseInfos); + } sendImportMessage(caseInfos.createMessage()); return caseUuid; } @@ -253,7 +255,7 @@ private void createCaseMetadataEntity(UUID newCaseUuid, boolean withExpiration) if (withExpiration) { expirationTime = Instant.now().plus(1, ChronoUnit.HOURS); } - caseMetadataRepository.save(new CaseMetadataEntity(newCaseUuid, expirationTime)); + caseMetadataRepository.save(new CaseMetadataEntity(newCaseUuid, expirationTime, false)); } CaseInfos createInfos(String fileBaseName, UUID caseUuid, String format) { diff --git a/src/main/java/com/powsybl/caseserver/repository/CaseMetadataEntity.java b/src/main/java/com/powsybl/caseserver/repository/CaseMetadataEntity.java index ebacd0e..2bca67f 100644 --- a/src/main/java/com/powsybl/caseserver/repository/CaseMetadataEntity.java +++ b/src/main/java/com/powsybl/caseserver/repository/CaseMetadataEntity.java @@ -33,4 +33,7 @@ public class CaseMetadataEntity { @Column(name = "expirationDate", columnDefinition = "timestamptz") private Instant expirationDate; + + @Column(name = "indexed", columnDefinition = "boolean default false", nullable = false) + private boolean indexed = false; } diff --git a/src/main/resources/db/changelog/changesets/changelog_20240726T144717Z.xml b/src/main/resources/db/changelog/changesets/changelog_20240726T144717Z.xml new file mode 100644 index 0000000..3681251 --- /dev/null +++ b/src/main/resources/db/changelog/changesets/changelog_20240726T144717Z.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index 7768178..5ad8263 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -5,4 +5,9 @@ databaseChangeLog: - include: file: changesets/changelog_20240620T100317Z.xml - relativeToChangelogFile: true \ No newline at end of file + relativeToChangelogFile: true + + - include: + file: changesets/changelog_20240726T144717Z.xml + relativeToChangelogFile: true + diff --git a/src/test/java/com/powsybl/caseserver/ScheduledCaseCleanerTest.java b/src/test/java/com/powsybl/caseserver/ScheduledCaseCleanerTest.java index 6408a1e..23e7724 100644 --- a/src/test/java/com/powsybl/caseserver/ScheduledCaseCleanerTest.java +++ b/src/test/java/com/powsybl/caseserver/ScheduledCaseCleanerTest.java @@ -60,9 +60,9 @@ private void cleanDB() { public void test() { Instant now = Instant.now(); Instant yesterday = now.minus(1, ChronoUnit.DAYS); - CaseMetadataEntity shouldNotExpireEntity = new CaseMetadataEntity(UUID.randomUUID(), now.plus(1, ChronoUnit.HOURS)); - CaseMetadataEntity shouldExpireEntity = new CaseMetadataEntity(UUID.randomUUID(), yesterday.plus(1, ChronoUnit.HOURS)); - CaseMetadataEntity noExpireDateEntity = new CaseMetadataEntity(UUID.randomUUID(), null); + CaseMetadataEntity shouldNotExpireEntity = new CaseMetadataEntity(UUID.randomUUID(), now.plus(1, ChronoUnit.HOURS), false); + CaseMetadataEntity shouldExpireEntity = new CaseMetadataEntity(UUID.randomUUID(), yesterday.plus(1, ChronoUnit.HOURS), false); + CaseMetadataEntity noExpireDateEntity = new CaseMetadataEntity(UUID.randomUUID(), null, false); caseMetadataRepository.save(shouldExpireEntity); caseMetadataRepository.save(shouldNotExpireEntity); caseMetadataRepository.save(noExpireDateEntity); From eb500350fc9153f98e9209f0fc0961d82dc2eb77 Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Mon, 29 Jul 2024 16:57:15 +0200 Subject: [PATCH 02/22] index only elements marked for indexation Signed-off-by: jamal-khey --- .../powsybl/caseserver/CaseController.java | 13 +--- .../com/powsybl/caseserver/CaseService.java | 37 ++++----- .../caseserver/SupervisionController.java | 76 +++++++++++++++++++ .../elasticsearch/CaseInfosService.java | 6 ++ .../caseserver/elasticsearch/ESConfig.java | 3 + .../repository/CaseMetadataRepository.java | 5 ++ .../services/SupervisionService.java | 41 ++++++++++ 7 files changed, 153 insertions(+), 28 deletions(-) create mode 100644 src/main/java/com/powsybl/caseserver/SupervisionController.java create mode 100644 src/main/java/com/powsybl/caseserver/services/SupervisionService.java diff --git a/src/main/java/com/powsybl/caseserver/CaseController.java b/src/main/java/com/powsybl/caseserver/CaseController.java index 60c7167..9b841c2 100644 --- a/src/main/java/com/powsybl/caseserver/CaseController.java +++ b/src/main/java/com/powsybl/caseserver/CaseController.java @@ -166,9 +166,10 @@ public ResponseEntity importCase(@RequestParam("file") MultipartFile file, @ApiResponse(responseCode = "500", description = "An error occurred during the case file duplication")}) public ResponseEntity duplicateCase( @RequestParam("duplicateFrom") UUID caseId, - @RequestParam(value = "withExpiration", required = false, defaultValue = "false") boolean withExpiration) { + @RequestParam(value = "withExpiration", required = false, defaultValue = "false") boolean withExpiration, + @RequestParam(value = "indexed", required = false, defaultValue = "false") boolean indexed) { LOGGER.debug("duplicateCase request received with parameter sourceCaseUuid = {}", caseId); - UUID newCaseUuid = caseService.duplicateCase(caseId, withExpiration); + UUID newCaseUuid = caseService.duplicateCase(caseId, withExpiration, indexed); return ResponseEntity.ok().body(newCaseUuid); } @@ -207,14 +208,6 @@ public ResponseEntity> searchCases(@RequestParam(value = "q") St return ResponseEntity.ok().body(cases); } - @PostMapping(value = "/cases/reindex-all") - @Operation(summary = "reindex all cases") - public ResponseEntity reindexAllCases() { - LOGGER.debug("reindex all cases request received"); - caseService.reindexAllCases(); - return ResponseEntity.ok().build(); - } - @GetMapping(value = "/cases/metadata") @Operation(summary = "Get cases Metadata") public ResponseEntity> getMetadata(@RequestParam("ids") List ids) { diff --git a/src/main/java/com/powsybl/caseserver/CaseService.java b/src/main/java/com/powsybl/caseserver/CaseService.java index 5f99d8b..f93c6fb 100644 --- a/src/main/java/com/powsybl/caseserver/CaseService.java +++ b/src/main/java/com/powsybl/caseserver/CaseService.java @@ -8,6 +8,7 @@ import com.powsybl.caseserver.dto.CaseInfos; import com.powsybl.caseserver.dto.ExportCaseInfos; +import com.powsybl.caseserver.elasticsearch.CaseInfosRepository; import com.powsybl.caseserver.elasticsearch.CaseInfosService; import com.powsybl.caseserver.parsers.FileNameInfos; import com.powsybl.caseserver.parsers.FileNameParser; @@ -46,14 +47,7 @@ import java.nio.file.StandardCopyOption; import java.time.Instant; import java.time.temporal.ChronoUnit; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Properties; -import java.util.UUID; +import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.zip.ZipEntry; @@ -89,6 +83,8 @@ public class CaseService { @Value("${case-store-directory:#{systemProperties['user.home'].concat(\"/cases\")}}") private String rootDirectory; + @Autowired + private CaseInfosRepository caseInfosRepository; public CaseService(CaseMetadataRepository caseMetadataRepository) { this.caseMetadataRepository = caseMetadataRepository; @@ -214,7 +210,7 @@ UUID importCase(MultipartFile mpf, boolean withExpiration, boolean indexed) { throw e; } - createCaseMetadataEntity(caseUuid, withExpiration); + createCaseMetadataEntity(caseUuid, withExpiration, indexed); CaseInfos caseInfos = createInfos(caseFile.getFileName().toString(), caseUuid, importer.getFormat()); if(indexed) { caseInfosService.addCaseInfos(caseInfos); @@ -223,7 +219,7 @@ UUID importCase(MultipartFile mpf, boolean withExpiration, boolean indexed) { return caseUuid; } - UUID duplicateCase(UUID sourceCaseUuid, boolean withExpiration) { + UUID duplicateCase(UUID sourceCaseUuid, boolean withExpiration, boolean indexed) { try { Path existingCaseFile = getCaseFile(sourceCaseUuid); if (existingCaseFile == null || existingCaseFile.getParent() == null) { @@ -239,8 +235,10 @@ UUID duplicateCase(UUID sourceCaseUuid, boolean withExpiration) { CaseInfos existingCaseInfos = caseInfosService.getCaseInfosByUuid(sourceCaseUuid.toString()).orElseThrow(); CaseInfos caseInfos = createInfos(existingCaseInfos.getName(), newCaseUuid, existingCaseInfos.getFormat()); - caseInfosService.addCaseInfos(caseInfos); - createCaseMetadataEntity(newCaseUuid, withExpiration); + if(indexed) { + caseInfosService.addCaseInfos(caseInfos); + } + createCaseMetadataEntity(newCaseUuid, withExpiration, indexed); sendImportMessage(caseInfos.createMessage()); return newCaseUuid; @@ -250,12 +248,19 @@ UUID duplicateCase(UUID sourceCaseUuid, boolean withExpiration) { } } - private void createCaseMetadataEntity(UUID newCaseUuid, boolean withExpiration) { + private void createCaseMetadataEntity(UUID newCaseUuid, boolean withExpiration, boolean indexed) { Instant expirationTime = null; if (withExpiration) { expirationTime = Instant.now().plus(1, ChronoUnit.HOURS); } - caseMetadataRepository.save(new CaseMetadataEntity(newCaseUuid, expirationTime, false)); + caseMetadataRepository.save(new CaseMetadataEntity(newCaseUuid, expirationTime, indexed)); + } + + public Set getCaseToReindex() { + return caseMetadataRepository.findAllByIndexedTrue() + .stream() + .map(CaseMetadataEntity::getId) + .collect(Collectors.toSet()); } CaseInfos createInfos(String fileBaseName, UUID caseUuid, String format) { @@ -375,10 +380,6 @@ private void sendImportMessage(Message message) { caseInfosPublisher.send("publishCaseImport-out-0", message); } - public void reindexAllCases() { - caseInfosService.recreateAllCaseInfos(getCases(getStorageRootDir())); - } - public List getMetadata(List ids) { List cases = new ArrayList<>(); ids.forEach(caseUuid -> { diff --git a/src/main/java/com/powsybl/caseserver/SupervisionController.java b/src/main/java/com/powsybl/caseserver/SupervisionController.java new file mode 100644 index 0000000..b2d32dd --- /dev/null +++ b/src/main/java/com/powsybl/caseserver/SupervisionController.java @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2024, 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 com.powsybl.caseserver; + +import com.powsybl.caseserver.elasticsearch.CaseInfosService; +import com.powsybl.caseserver.services.SupervisionService; +import io.swagger.v3.oas.annotations.Operation; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.elasticsearch.client.ClientConfiguration; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author Jamal KHEYYAD + */ +@RestController +@RequestMapping(value = "/" + CaseConstants.API_VERSION + "/supervision") +@Tag(name = "case-server - Supervision") +public class SupervisionController { + private static final Logger LOGGER = LoggerFactory.getLogger(SupervisionController.class); + + private final SupervisionService supervisionService; + private final ClientConfiguration elasticsearchClientConfiguration; + private final CaseInfosService caseInfosService; + + public SupervisionController(SupervisionService supervisionService, ClientConfiguration elasticsearchClientConfiguration, CaseInfosService caseInfosService) { + this.supervisionService = supervisionService; + this.elasticsearchClientConfiguration = elasticsearchClientConfiguration; + this.caseInfosService = caseInfosService; + } + + @PostMapping(value = "/cases/reindex-all") + @Operation(summary = "reindex all cases") + public ResponseEntity reindexAllCases() { + LOGGER.debug("reindex all cases request received"); + supervisionService.reindexAllCases(); + return ResponseEntity.ok().build(); + } + + @GetMapping(value = "/elasticsearch-host") + @Operation(summary = "get the elasticsearch address") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "the elasticsearch address")}) + public ResponseEntity getElasticsearchHost() { + String host = elasticsearchClientConfiguration.getEndpoints().get(0).getHostName() + + ":" + + elasticsearchClientConfiguration.getEndpoints().get(0).getPort(); + return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(host); + } + + @GetMapping(value = "/elements/index-name") + @Operation(summary = "get the indexed directory elements index name") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Indexed directory elements index name")}) + public ResponseEntity getIndexedDirectoryElementsIndexName() { + return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(caseInfosService.getDirectoryElementsIndexName()); + } + +// @GetMapping(value = "/elements/indexation-count") +// @Operation(summary = "get indexed directory elements count") +// @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Indexed directory elements count")}) +// public ResponseEntity getIndexedDirectoryElementsCount() { +// return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(Long.toString(caseInfosService.getIndexedDirectoryElementsCount())); +// } + +} diff --git a/src/main/java/com/powsybl/caseserver/elasticsearch/CaseInfosService.java b/src/main/java/com/powsybl/caseserver/elasticsearch/CaseInfosService.java index 7c539c1..e46463b 100644 --- a/src/main/java/com/powsybl/caseserver/elasticsearch/CaseInfosService.java +++ b/src/main/java/com/powsybl/caseserver/elasticsearch/CaseInfosService.java @@ -9,7 +9,9 @@ import co.elastic.clients.elasticsearch._types.query_dsl.QueryStringQuery; import com.google.common.collect.Lists; import com.powsybl.caseserver.dto.CaseInfos; +import lombok.Getter; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.ComponentScan; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -42,6 +44,10 @@ public class CaseInfosService { @Autowired private ElasticsearchOperations operations; + @Value(ESConfig.CASE_INFOS_INDEX_NAME) + @Getter + private String directoryElementsIndexName; + public CaseInfos addCaseInfos(@NonNull final CaseInfos ci) { caseInfosRepository.save(ci); return ci; diff --git a/src/main/java/com/powsybl/caseserver/elasticsearch/ESConfig.java b/src/main/java/com/powsybl/caseserver/elasticsearch/ESConfig.java index bc35d05..b1db495 100644 --- a/src/main/java/com/powsybl/caseserver/elasticsearch/ESConfig.java +++ b/src/main/java/com/powsybl/caseserver/elasticsearch/ESConfig.java @@ -32,6 +32,9 @@ @EnableElasticsearchRepositories public class ESConfig extends ElasticsearchConfiguration { + public static final String CASE_INFOS_INDEX_NAME = "#{@environment.getProperty('powsybl-ws.elasticsearch.index.prefix')}cases";//FIXME (jamal) check this name + + @Value("#{'${spring.data.elasticsearch.embedded:false}' ? 'localhost' : '${spring.data.elasticsearch.host}'}") private String esHost; diff --git a/src/main/java/com/powsybl/caseserver/repository/CaseMetadataRepository.java b/src/main/java/com/powsybl/caseserver/repository/CaseMetadataRepository.java index 79c9cca..97a5da0 100644 --- a/src/main/java/com/powsybl/caseserver/repository/CaseMetadataRepository.java +++ b/src/main/java/com/powsybl/caseserver/repository/CaseMetadataRepository.java @@ -9,6 +9,7 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.List; import java.util.UUID; /** @@ -17,4 +18,8 @@ @Repository public interface CaseMetadataRepository extends JpaRepository { + @Override + List findAllById(Iterable uuids); + + List findAllByIndexedTrue(); } diff --git a/src/main/java/com/powsybl/caseserver/services/SupervisionService.java b/src/main/java/com/powsybl/caseserver/services/SupervisionService.java new file mode 100644 index 0000000..16bb922 --- /dev/null +++ b/src/main/java/com/powsybl/caseserver/services/SupervisionService.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2024, 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 com.powsybl.caseserver.services; + +import com.powsybl.caseserver.CaseService; +import com.powsybl.caseserver.dto.CaseInfos; +import com.powsybl.caseserver.elasticsearch.CaseInfosService; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Set; +import java.util.UUID; + +/** + * @author Jamal KHEYYAD + */ +@Service +public class SupervisionService { + private final CaseInfosService caseInfosService; + private final CaseService caseService; + + + public SupervisionService(CaseInfosService caseInfosService, CaseService caseService) { + this.caseInfosService = caseInfosService; + this.caseService = caseService; + + } + + public void reindexAllCases() { + List allCases= caseService.getCases(caseService.getStorageRootDir()); + Set casesToIndex = caseService.getCaseToReindex(); + List data = allCases.stream().filter(c -> casesToIndex.contains(c.getUuid())).toList(); + caseInfosService.recreateAllCaseInfos(data); + } + + +} From 3faccb18789181d9a37d39b2f4fe928ec88c4b66 Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Tue, 30 Jul 2024 21:19:39 +0200 Subject: [PATCH 03/22] fix syles Signed-off-by: jamal-khey --- src/main/java/com/powsybl/caseserver/CaseService.java | 4 ++-- .../java/com/powsybl/caseserver/elasticsearch/ESConfig.java | 3 +-- .../com/powsybl/caseserver/services/SupervisionService.java | 5 +---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/powsybl/caseserver/CaseService.java b/src/main/java/com/powsybl/caseserver/CaseService.java index f93c6fb..aa7f9c6 100644 --- a/src/main/java/com/powsybl/caseserver/CaseService.java +++ b/src/main/java/com/powsybl/caseserver/CaseService.java @@ -212,7 +212,7 @@ UUID importCase(MultipartFile mpf, boolean withExpiration, boolean indexed) { createCaseMetadataEntity(caseUuid, withExpiration, indexed); CaseInfos caseInfos = createInfos(caseFile.getFileName().toString(), caseUuid, importer.getFormat()); - if(indexed) { + if (indexed) { caseInfosService.addCaseInfos(caseInfos); } sendImportMessage(caseInfos.createMessage()); @@ -235,7 +235,7 @@ UUID duplicateCase(UUID sourceCaseUuid, boolean withExpiration, boolean indexed) CaseInfos existingCaseInfos = caseInfosService.getCaseInfosByUuid(sourceCaseUuid.toString()).orElseThrow(); CaseInfos caseInfos = createInfos(existingCaseInfos.getName(), newCaseUuid, existingCaseInfos.getFormat()); - if(indexed) { + if (indexed) { caseInfosService.addCaseInfos(caseInfos); } createCaseMetadataEntity(newCaseUuid, withExpiration, indexed); diff --git a/src/main/java/com/powsybl/caseserver/elasticsearch/ESConfig.java b/src/main/java/com/powsybl/caseserver/elasticsearch/ESConfig.java index b1db495..1972b2e 100644 --- a/src/main/java/com/powsybl/caseserver/elasticsearch/ESConfig.java +++ b/src/main/java/com/powsybl/caseserver/elasticsearch/ESConfig.java @@ -32,8 +32,7 @@ @EnableElasticsearchRepositories public class ESConfig extends ElasticsearchConfiguration { - public static final String CASE_INFOS_INDEX_NAME = "#{@environment.getProperty('powsybl-ws.elasticsearch.index.prefix')}cases";//FIXME (jamal) check this name - + public static final String CASE_INFOS_INDEX_NAME = "#{@environment.getProperty('powsybl-ws.elasticsearch.index.prefix')}cases"; @Value("#{'${spring.data.elasticsearch.embedded:false}' ? 'localhost' : '${spring.data.elasticsearch.host}'}") private String esHost; diff --git a/src/main/java/com/powsybl/caseserver/services/SupervisionService.java b/src/main/java/com/powsybl/caseserver/services/SupervisionService.java index 16bb922..6a5e0ad 100644 --- a/src/main/java/com/powsybl/caseserver/services/SupervisionService.java +++ b/src/main/java/com/powsybl/caseserver/services/SupervisionService.java @@ -23,19 +23,16 @@ public class SupervisionService { private final CaseInfosService caseInfosService; private final CaseService caseService; - public SupervisionService(CaseInfosService caseInfosService, CaseService caseService) { this.caseInfosService = caseInfosService; this.caseService = caseService; - } public void reindexAllCases() { - List allCases= caseService.getCases(caseService.getStorageRootDir()); + List allCases = caseService.getCases(caseService.getStorageRootDir()); Set casesToIndex = caseService.getCaseToReindex(); List data = allCases.stream().filter(c -> casesToIndex.contains(c.getUuid())).toList(); caseInfosService.recreateAllCaseInfos(data); } - } From 397d9c4588e0b7b33cd5aa7fc9fd43994105dd67 Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Wed, 31 Jul 2024 11:38:10 +0200 Subject: [PATCH 04/22] add delete index Signed-off-by: jamal-khey --- .../caseserver/SupervisionController.java | 33 +++++++++---------- .../services/SupervisionService.java | 24 +++++++++++++- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/powsybl/caseserver/SupervisionController.java b/src/main/java/com/powsybl/caseserver/SupervisionController.java index b2d32dd..a894ca7 100644 --- a/src/main/java/com/powsybl/caseserver/SupervisionController.java +++ b/src/main/java/com/powsybl/caseserver/SupervisionController.java @@ -17,10 +17,7 @@ import org.springframework.data.elasticsearch.client.ClientConfiguration; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; /** * @author Jamal KHEYYAD @@ -41,14 +38,6 @@ public SupervisionController(SupervisionService supervisionService, ClientConfig this.caseInfosService = caseInfosService; } - @PostMapping(value = "/cases/reindex-all") - @Operation(summary = "reindex all cases") - public ResponseEntity reindexAllCases() { - LOGGER.debug("reindex all cases request received"); - supervisionService.reindexAllCases(); - return ResponseEntity.ok().build(); - } - @GetMapping(value = "/elasticsearch-host") @Operation(summary = "get the elasticsearch address") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "the elasticsearch address")}) @@ -66,11 +55,19 @@ public ResponseEntity getIndexedDirectoryElementsIndexName() { return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(caseInfosService.getDirectoryElementsIndexName()); } -// @GetMapping(value = "/elements/indexation-count") -// @Operation(summary = "get indexed directory elements count") -// @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Indexed directory elements count")}) -// public ResponseEntity getIndexedDirectoryElementsCount() { -// return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(Long.toString(caseInfosService.getIndexedDirectoryElementsCount())); -// } + @PostMapping(value = "/cases/reindex") + @Operation(summary = "reindex all cases") + public ResponseEntity reindexAllCases() { + LOGGER.debug("reindex all cases request received"); + supervisionService.reindexAllCases(); + return ResponseEntity.ok().build(); + } + + @DeleteMapping(value = "/elements/indexation") + @Operation(summary = "delete indexed elements") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "all indexed elements have been deleted")}) + public ResponseEntity deleteIndexedDirectoryElements() { + return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(Long.toString(supervisionService.deleteIndexedDirectoryElements())); + } } diff --git a/src/main/java/com/powsybl/caseserver/services/SupervisionService.java b/src/main/java/com/powsybl/caseserver/services/SupervisionService.java index 6a5e0ad..1a334af 100644 --- a/src/main/java/com/powsybl/caseserver/services/SupervisionService.java +++ b/src/main/java/com/powsybl/caseserver/services/SupervisionService.java @@ -8,24 +8,33 @@ import com.powsybl.caseserver.CaseService; import com.powsybl.caseserver.dto.CaseInfos; +import com.powsybl.caseserver.elasticsearch.CaseInfosRepository; import com.powsybl.caseserver.elasticsearch.CaseInfosService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import java.util.List; import java.util.Set; import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; /** * @author Jamal KHEYYAD */ @Service public class SupervisionService { + private static final Logger LOGGER = LoggerFactory.getLogger(SupervisionService.class); + private final CaseInfosService caseInfosService; private final CaseService caseService; + private final CaseInfosRepository caseInfosRepository; - public SupervisionService(CaseInfosService caseInfosService, CaseService caseService) { + public SupervisionService(CaseInfosService caseInfosService, CaseService caseService, CaseInfosRepository caseInfosRepository) { this.caseInfosService = caseInfosService; this.caseService = caseService; + this.caseInfosRepository = caseInfosRepository; } public void reindexAllCases() { @@ -35,4 +44,17 @@ public void reindexAllCases() { caseInfosService.recreateAllCaseInfos(data); } + public long deleteIndexedDirectoryElements() { + AtomicReference startTime = new AtomicReference<>(); + startTime.set(System.nanoTime()); + + long nbIndexesToDelete = getIndexedDirectoryElementsCount(); + caseInfosRepository.deleteAll(); + LOGGER.trace("Indexed directory elements deletion : {} seconds", TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime.get())); + return nbIndexesToDelete; + } + + private long getIndexedDirectoryElementsCount() { + return caseInfosRepository.count(); + } } From 4fb0ead64bdd06a2b95e4d96754c34ba8a87d911 Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Wed, 31 Jul 2024 17:17:48 +0200 Subject: [PATCH 05/22] renaming endpoints Signed-off-by: jamal-khey --- .../java/com/powsybl/caseserver/SupervisionController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/powsybl/caseserver/SupervisionController.java b/src/main/java/com/powsybl/caseserver/SupervisionController.java index a894ca7..19fa0f1 100644 --- a/src/main/java/com/powsybl/caseserver/SupervisionController.java +++ b/src/main/java/com/powsybl/caseserver/SupervisionController.java @@ -48,7 +48,7 @@ public ResponseEntity getElasticsearchHost() { return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(host); } - @GetMapping(value = "/elements/index-name") + @GetMapping(value = "/cases/index-name") @Operation(summary = "get the indexed directory elements index name") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Indexed directory elements index name")}) public ResponseEntity getIndexedDirectoryElementsIndexName() { @@ -63,7 +63,7 @@ public ResponseEntity reindexAllCases() { return ResponseEntity.ok().build(); } - @DeleteMapping(value = "/elements/indexation") + @DeleteMapping(value = "/cases/indexation") @Operation(summary = "delete indexed elements") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "all indexed elements have been deleted")}) public ResponseEntity deleteIndexedDirectoryElements() { From dff605149537adc1011f5fbe404943de4cd2c567 Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Thu, 1 Aug 2024 15:12:38 +0200 Subject: [PATCH 06/22] add tests Signed-off-by: jamal-khey --- .../com/powsybl/caseserver/CaseService.java | 3 + .../services/SupervisionService.java | 6 +- .../powsybl/caseserver/SupervisionTest.java | 58 +++++++++++++++++++ 3 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 src/test/java/com/powsybl/caseserver/SupervisionTest.java diff --git a/src/main/java/com/powsybl/caseserver/CaseService.java b/src/main/java/com/powsybl/caseserver/CaseService.java index aa7f9c6..1aa4474 100644 --- a/src/main/java/com/powsybl/caseserver/CaseService.java +++ b/src/main/java/com/powsybl/caseserver/CaseService.java @@ -262,6 +262,9 @@ public Set getCaseToReindex() { .map(CaseMetadataEntity::getId) .collect(Collectors.toSet()); } + public List getAllCases() { + return getCases(getStorageRootDir()); + } CaseInfos createInfos(String fileBaseName, UUID caseUuid, String format) { FileNameParser parser = FileNameParsers.findParser(fileBaseName); diff --git a/src/main/java/com/powsybl/caseserver/services/SupervisionService.java b/src/main/java/com/powsybl/caseserver/services/SupervisionService.java index 1a334af..94dbf17 100644 --- a/src/main/java/com/powsybl/caseserver/services/SupervisionService.java +++ b/src/main/java/com/powsybl/caseserver/services/SupervisionService.java @@ -38,7 +38,7 @@ public SupervisionService(CaseInfosService caseInfosService, CaseService caseSer } public void reindexAllCases() { - List allCases = caseService.getCases(caseService.getStorageRootDir()); + List allCases = caseService.getAllCases(); Set casesToIndex = caseService.getCaseToReindex(); List data = allCases.stream().filter(c -> casesToIndex.contains(c.getUuid())).toList(); caseInfosService.recreateAllCaseInfos(data); @@ -48,13 +48,13 @@ public long deleteIndexedDirectoryElements() { AtomicReference startTime = new AtomicReference<>(); startTime.set(System.nanoTime()); - long nbIndexesToDelete = getIndexedDirectoryElementsCount(); + long nbIndexesToDelete = getIndexedCaseElementsCount(); caseInfosRepository.deleteAll(); LOGGER.trace("Indexed directory elements deletion : {} seconds", TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime.get())); return nbIndexesToDelete; } - private long getIndexedDirectoryElementsCount() { + public long getIndexedCaseElementsCount() { return caseInfosRepository.count(); } } diff --git a/src/test/java/com/powsybl/caseserver/SupervisionTest.java b/src/test/java/com/powsybl/caseserver/SupervisionTest.java new file mode 100644 index 0000000..f73d3dd --- /dev/null +++ b/src/test/java/com/powsybl/caseserver/SupervisionTest.java @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2024, 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 com.powsybl.caseserver; + +import com.powsybl.caseserver.elasticsearch.CaseInfosRepository; +import com.powsybl.caseserver.repository.CaseMetadataRepository; +import com.powsybl.caseserver.services.SupervisionService; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +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.servlet.MockMvc; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +/** + * @author Jamal KHEYYAD + */ +@RunWith(SpringRunner.class) +@AutoConfigureMockMvc +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, properties = {"case-store-directory=/cases"}) +@ContextConfigurationWithTestChannel +public class SupervisionTest { + @Autowired + SupervisionService supervisionService; + @Autowired + CaseInfosRepository caseInfosRepository; + @Autowired + CaseMetadataRepository caseMetadataRepository; + @Autowired + CaseService caseService; + + @Autowired + private MockMvc mvc; + + @Test + public void testGetElementInfosCount() { + supervisionService.getIndexedCaseElementsCount(); + verify(caseInfosRepository, times(1)).count(); + } + + @Test + public void testDeleteElementInfos() { + supervisionService.deleteIndexedDirectoryElements(); + + verify(caseInfosRepository, times(1)).count(); + verify(caseInfosRepository, times(1)).deleteAll(); + } + + +} From f8761fae17491d4aae8a3d747891c5d975ffc4f8 Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Mon, 5 Aug 2024 12:02:55 +0200 Subject: [PATCH 07/22] fix old tests Signed-off-by: jamal-khey --- .../com/powsybl/caseserver/CaseService.java | 1 + .../caseserver/CaseControllerTest.java | 23 ++++++++++++------- .../powsybl/caseserver/SupervisionTest.java | 1 - 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/powsybl/caseserver/CaseService.java b/src/main/java/com/powsybl/caseserver/CaseService.java index 1aa4474..3ae80d1 100644 --- a/src/main/java/com/powsybl/caseserver/CaseService.java +++ b/src/main/java/com/powsybl/caseserver/CaseService.java @@ -262,6 +262,7 @@ public Set getCaseToReindex() { .map(CaseMetadataEntity::getId) .collect(Collectors.toSet()); } + public List getAllCases() { return getCases(getStorageRootDir()); } diff --git a/src/test/java/com/powsybl/caseserver/CaseControllerTest.java b/src/test/java/com/powsybl/caseserver/CaseControllerTest.java index f53be5e..dafbb16 100644 --- a/src/test/java/com/powsybl/caseserver/CaseControllerTest.java +++ b/src/test/java/com/powsybl/caseserver/CaseControllerTest.java @@ -422,12 +422,14 @@ private UUID importCase(String testCase, Boolean withExpiration) throws Exceptio if (withExpiration) { importedCase = mvc.perform(multipart("/v1/cases") .file(createMockMultipartFile(testCase)) - .param("withExpiration", withExpiration.toString())) + .param("withExpiration", withExpiration.toString()) + .param("indexed", "true")) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); } else { importedCase = mvc.perform(multipart("/v1/cases") - .file(createMockMultipartFile(testCase))) + .file(createMockMultipartFile(testCase)) + .param("indexed", "true")) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); } @@ -470,7 +472,8 @@ public void searchCaseTest() throws Exception { // import IIDM test case String aCase = mvc.perform(multipart("/v1/cases") - .file(createMockMultipartFile("testCase.xiidm"))) + .file(createMockMultipartFile("testCase.xiidm")) + .param("indexed", "true")) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); @@ -486,7 +489,8 @@ public void searchCaseTest() throws Exception { // import CGMES french file aCase = mvc.perform(multipart("/v1/cases") - .file(createMockMultipartFile("20200424T1330Z_2D_RTEFRANCE_001.zip"))) + .file(createMockMultipartFile("20200424T1330Z_2D_RTEFRANCE_001.zip")) + .param("indexed", "true")) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); @@ -502,7 +506,8 @@ public void searchCaseTest() throws Exception { // import UCTE french file aCase = mvc.perform(multipart("/v1/cases") - .file(createMockMultipartFile("20200103_0915_FO5_FR0.UCT"))) + .file(createMockMultipartFile("20200103_0915_FO5_FR0.UCT")) + .param("indexed", "true")) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); @@ -518,7 +523,8 @@ public void searchCaseTest() throws Exception { // import UCTE german file aCase = mvc.perform(multipart("/v1/cases") - .file(createMockMultipartFile("20200103_0915_SN5_D80.UCT"))) + .file(createMockMultipartFile("20200103_0915_SN5_D80.UCT")) + .param("indexed", "true")) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); @@ -534,7 +540,8 @@ public void searchCaseTest() throws Exception { // import UCTE swiss file aCase = mvc.perform(multipart("/v1/cases") - .file(createMockMultipartFile("20200103_0915_135_CH2.UCT"))) + .file(createMockMultipartFile("20200103_0915_135_CH2.UCT")) + .param("indexed", "true")) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); @@ -656,7 +663,7 @@ public void searchCaseTest() throws Exception { assertFalse(response.contains("\"name\":\"20200103_0915_135_CH2.UCT\"")); // reindex all cases - mvc.perform(post("/v1/cases/reindex-all")) + mvc.perform(post("/v1/supervision/cases/reindex")) .andExpect(status().isOk()); mvcResult = mvc.perform(get("/v1/cases/search") diff --git a/src/test/java/com/powsybl/caseserver/SupervisionTest.java b/src/test/java/com/powsybl/caseserver/SupervisionTest.java index f73d3dd..39cbb83 100644 --- a/src/test/java/com/powsybl/caseserver/SupervisionTest.java +++ b/src/test/java/com/powsybl/caseserver/SupervisionTest.java @@ -54,5 +54,4 @@ public void testDeleteElementInfos() { verify(caseInfosRepository, times(1)).deleteAll(); } - } From 82643ee6b5abd2c9ec150cd74bc2774a77fcc69d Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Mon, 5 Aug 2024 14:53:35 +0200 Subject: [PATCH 08/22] add tests for supervision controller Signed-off-by: jamal-khey --- .../caseserver/SupervisionControllerTest.java | 136 ++++++++++++++++++ .../powsybl/caseserver/SupervisionTest.java | 57 -------- 2 files changed, 136 insertions(+), 57 deletions(-) create mode 100644 src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java delete mode 100644 src/test/java/com/powsybl/caseserver/SupervisionTest.java diff --git a/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java b/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java new file mode 100644 index 0000000..fb00cc2 --- /dev/null +++ b/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java @@ -0,0 +1,136 @@ +/** + * Copyright (c) 2024, 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 com.powsybl.caseserver; + +import com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; +import com.powsybl.caseserver.elasticsearch.CaseInfosRepository; +import com.powsybl.caseserver.repository.CaseMetadataRepository; +import com.powsybl.caseserver.services.SupervisionService; +import com.powsybl.computation.ComputationManager; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.UUID; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * @author Jamal KHEYYAD + */ +@RunWith(SpringRunner.class) +@AutoConfigureMockMvc +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, properties = {"case-store-directory=/cases"}) +@ContextConfigurationWithTestChannel +public class SupervisionControllerTest { + @Autowired + SupervisionService supervisionService; + @Autowired + CaseInfosRepository caseInfosRepository; + @Autowired + CaseMetadataRepository caseMetadataRepository; + @Autowired + CaseService caseService; + + @Autowired + private MockMvc mockMvc; + + @Value("${case-store-directory}") + private String rootDirectory; + + private static final String TEST_CASE = "testCase.xiidm"; + private FileSystem fileSystem; + + @Test + public void testGetElementInfosCount() throws Exception { + createStorageDir(); + importCase(TEST_CASE, true); + importCase(TEST_CASE, true); + importCase(TEST_CASE, false); + + mockMvc.perform(post("/v1/supervision/cases/reindex")) + .andExpect(status().isOk()); + + Assert.assertEquals(2, supervisionService.getIndexedCaseElementsCount()); + + } + + @Test + public void testDeleteElementInfos() throws Exception { + createStorageDir(); + importCase(TEST_CASE, true); + importCase(TEST_CASE, true); + + mockMvc.perform(delete("/v1/supervision/cases/indexation")) + .andExpect(status().isOk()); + Assert.assertEquals(0, supervisionService.getIndexedCaseElementsCount()); + + //reindex + mockMvc.perform(post("/v1/supervision/cases/reindex")) + .andExpect(status().isOk()); + + Assert.assertEquals(2, supervisionService.getIndexedCaseElementsCount()); + } + + private UUID importCase(String testCase, Boolean indexed) throws Exception { + String importedCase = mockMvc.perform(multipart("/v1/cases") + .file(createMockMultipartFile(testCase)) + .param("indexed", indexed.toString())) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(); + + return UUID.fromString(importedCase.substring(1, importedCase.length() - 1)); + } + + private static MockMultipartFile createMockMultipartFile(String fileName) throws IOException { + try (InputStream inputStream = CaseControllerTest.class.getResourceAsStream("/" + fileName)) { + return new MockMultipartFile("file", fileName, MediaType.TEXT_PLAIN_VALUE, inputStream); + } + } + + @Before + public void setUp() { + fileSystem = Jimfs.newFileSystem(Configuration.unix()); + caseService.setFileSystem(fileSystem); + caseService.setComputationManager(Mockito.mock(ComputationManager.class)); + cleanDB(); + } + + @After + public void tearDown() throws Exception { + fileSystem.close(); + } + + private void cleanDB() { + caseMetadataRepository.deleteAll(); + } + + private void createStorageDir() throws IOException { + Path path = fileSystem.getPath(rootDirectory); + if (!Files.exists(path)) { + Files.createDirectories(path); + } + } +} diff --git a/src/test/java/com/powsybl/caseserver/SupervisionTest.java b/src/test/java/com/powsybl/caseserver/SupervisionTest.java deleted file mode 100644 index 39cbb83..0000000 --- a/src/test/java/com/powsybl/caseserver/SupervisionTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (c) 2024, 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 com.powsybl.caseserver; - -import com.powsybl.caseserver.elasticsearch.CaseInfosRepository; -import com.powsybl.caseserver.repository.CaseMetadataRepository; -import com.powsybl.caseserver.services.SupervisionService; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -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.servlet.MockMvc; - -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -/** - * @author Jamal KHEYYAD - */ -@RunWith(SpringRunner.class) -@AutoConfigureMockMvc -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, properties = {"case-store-directory=/cases"}) -@ContextConfigurationWithTestChannel -public class SupervisionTest { - @Autowired - SupervisionService supervisionService; - @Autowired - CaseInfosRepository caseInfosRepository; - @Autowired - CaseMetadataRepository caseMetadataRepository; - @Autowired - CaseService caseService; - - @Autowired - private MockMvc mvc; - - @Test - public void testGetElementInfosCount() { - supervisionService.getIndexedCaseElementsCount(); - verify(caseInfosRepository, times(1)).count(); - } - - @Test - public void testDeleteElementInfos() { - supervisionService.deleteIndexedDirectoryElements(); - - verify(caseInfosRepository, times(1)).count(); - verify(caseInfosRepository, times(1)).deleteAll(); - } - -} From 66fafa8609ee0651ca6219243640a4328a697117 Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Mon, 5 Aug 2024 15:33:16 +0200 Subject: [PATCH 09/22] clean conde Signed-off-by: jamal-khey --- .../com/powsybl/caseserver/SupervisionControllerTest.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java b/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java index fb00cc2..2ae5f27 100644 --- a/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java +++ b/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java @@ -94,14 +94,12 @@ public void testDeleteElementInfos() throws Exception { Assert.assertEquals(2, supervisionService.getIndexedCaseElementsCount()); } - private UUID importCase(String testCase, Boolean indexed) throws Exception { - String importedCase = mockMvc.perform(multipart("/v1/cases") + private void importCase(String testCase, Boolean indexed) throws Exception { + mockMvc.perform(multipart("/v1/cases") .file(createMockMultipartFile(testCase)) .param("indexed", indexed.toString())) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); - - return UUID.fromString(importedCase.substring(1, importedCase.length() - 1)); } private static MockMultipartFile createMockMultipartFile(String fileName) throws IOException { From 571a8510ebfc63fd2c93d586b0ccbb811ab341e7 Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Mon, 5 Aug 2024 16:04:31 +0200 Subject: [PATCH 10/22] check styles Signed-off-by: jamal-khey --- .../caseserver/SupervisionControllerTest.java | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java b/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java index 2ae5f27..0e1e1fc 100644 --- a/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java +++ b/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java @@ -32,7 +32,6 @@ import java.nio.file.FileSystem; import java.nio.file.Files; import java.nio.file.Path; -import java.util.UUID; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -66,9 +65,9 @@ public class SupervisionControllerTest { @Test public void testGetElementInfosCount() throws Exception { createStorageDir(); - importCase(TEST_CASE, true); - importCase(TEST_CASE, true); - importCase(TEST_CASE, false); + importCase(true); + importCase(true); + importCase(false); mockMvc.perform(post("/v1/supervision/cases/reindex")) .andExpect(status().isOk()); @@ -80,8 +79,8 @@ public void testGetElementInfosCount() throws Exception { @Test public void testDeleteElementInfos() throws Exception { createStorageDir(); - importCase(TEST_CASE, true); - importCase(TEST_CASE, true); + importCase(true); + importCase(true); mockMvc.perform(delete("/v1/supervision/cases/indexation")) .andExpect(status().isOk()); @@ -94,17 +93,17 @@ public void testDeleteElementInfos() throws Exception { Assert.assertEquals(2, supervisionService.getIndexedCaseElementsCount()); } - private void importCase(String testCase, Boolean indexed) throws Exception { + private void importCase(Boolean indexed) throws Exception { mockMvc.perform(multipart("/v1/cases") - .file(createMockMultipartFile(testCase)) + .file(createMockMultipartFile()) .param("indexed", indexed.toString())) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); } - private static MockMultipartFile createMockMultipartFile(String fileName) throws IOException { - try (InputStream inputStream = CaseControllerTest.class.getResourceAsStream("/" + fileName)) { - return new MockMultipartFile("file", fileName, MediaType.TEXT_PLAIN_VALUE, inputStream); + private static MockMultipartFile createMockMultipartFile() throws IOException { + try (InputStream inputStream = CaseControllerTest.class.getResourceAsStream("/" + SupervisionControllerTest.TEST_CASE)) { + return new MockMultipartFile("file", SupervisionControllerTest.TEST_CASE, MediaType.TEXT_PLAIN_VALUE, inputStream); } } From 4abc90ca4d04667388aea1f0c06c2b2c531176b9 Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Mon, 5 Aug 2024 17:19:26 +0200 Subject: [PATCH 11/22] split test Signed-off-by: jamal-khey --- .../powsybl/caseserver/CaseControllerTest.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/powsybl/caseserver/CaseControllerTest.java b/src/test/java/com/powsybl/caseserver/CaseControllerTest.java index dafbb16..9fa5f37 100644 --- a/src/test/java/com/powsybl/caseserver/CaseControllerTest.java +++ b/src/test/java/com/powsybl/caseserver/CaseControllerTest.java @@ -136,23 +136,37 @@ private static MockMultipartFile createMockMultipartFile(String fileName) throws } @Test - public void test() throws Exception { + public void testStorageNotCreated() throws Exception { // expect a fail since the storage dir. is not created mvc.perform(delete("/v1/cases")) .andExpect(status().isUnprocessableEntity()); - + } + @Test + public void testDeleteCases() throws Exception { // create the storage dir createStorageDir(); // now it must work mvc.perform(delete("/v1/cases")) .andExpect(status().isOk()); + } + + @Test + public void testCheckNonExistingCase() throws Exception { + // create the storage dir + createStorageDir(); // check if the case exists (except a false) mvc.perform(get("/v1/cases/{caseUuid}/exists", RANDOM_UUID)) .andExpect(status().isOk()) .andExpect(content().string("false")) .andReturn(); + } + + @Test + public void test() throws Exception { + // create the storage dir + createStorageDir(); // import a case UUID firstCaseUuid = importCase(TEST_CASE, false); From d787751a9587b4b3d596654f34890a17cb3aa02c Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Mon, 5 Aug 2024 17:27:52 +0200 Subject: [PATCH 12/22] split test Signed-off-by: jamal-khey --- src/test/java/com/powsybl/caseserver/CaseControllerTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/com/powsybl/caseserver/CaseControllerTest.java b/src/test/java/com/powsybl/caseserver/CaseControllerTest.java index 9fa5f37..47d7215 100644 --- a/src/test/java/com/powsybl/caseserver/CaseControllerTest.java +++ b/src/test/java/com/powsybl/caseserver/CaseControllerTest.java @@ -141,6 +141,7 @@ public void testStorageNotCreated() throws Exception { mvc.perform(delete("/v1/cases")) .andExpect(status().isUnprocessableEntity()); } + @Test public void testDeleteCases() throws Exception { // create the storage dir From 51bbe76fd099b886a92aa1f4aaa36ee0d73312f7 Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Mon, 5 Aug 2024 18:19:02 +0200 Subject: [PATCH 13/22] split test Signed-off-by: jamal-khey --- .../caseserver/CaseControllerTest.java | 67 +++++++++++++------ 1 file changed, 45 insertions(+), 22 deletions(-) diff --git a/src/test/java/com/powsybl/caseserver/CaseControllerTest.java b/src/test/java/com/powsybl/caseserver/CaseControllerTest.java index 47d7215..95004ba 100644 --- a/src/test/java/com/powsybl/caseserver/CaseControllerTest.java +++ b/src/test/java/com/powsybl/caseserver/CaseControllerTest.java @@ -111,6 +111,7 @@ public void setUp() { caseService.setFileSystem(fileSystem); caseService.setComputationManager(Mockito.mock(ComputationManager.class)); cleanDB(); + outputDestination.clear(); } private void cleanDB() { @@ -165,8 +166,7 @@ public void testCheckNonExistingCase() throws Exception { } @Test - public void test() throws Exception { - // create the storage dir + public void testImportValidCase() throws Exception { createStorageDir(); // import a case @@ -218,20 +218,56 @@ public void test() throws Exception { .andExpect(status().isOk()) .andExpect(content().string("true")) .andReturn(); + } + + @Test + public void testImportInvalidFile() throws Exception { + createStorageDir(); // import a non valid case and expect a fail mvc.perform(multipart("/v1/cases") - .file(createMockMultipartFile(NOT_A_NETWORK))) + .file(createMockMultipartFile(NOT_A_NETWORK))) .andExpect(status().isUnprocessableEntity()) .andExpect(content().string(startsWith("This file cannot be imported"))) .andReturn(); // import a non valid case with a valid extension and expect a fail mvc.perform(multipart("/v1/cases") - .file(createMockMultipartFile(STILL_NOT_A_NETWORK))) + .file(createMockMultipartFile(STILL_NOT_A_NETWORK))) .andExpect(status().isUnprocessableEntity()) .andExpect(content().string(startsWith("This file cannot be imported"))) .andReturn(); + } + + @Test + public void testDownloadNonExistingCase() throws Exception { + createStorageDir(); + + // download a non existing case + mvc.perform(get(GET_CASE_URL, UUID.randomUUID())) + .andExpect(status().isNoContent()) + .andReturn(); + } + + @Test + public void testExportNonExistingCaseFromat() throws Exception { + createStorageDir(); + + // import a case + UUID firstCaseUuid = importCase(TEST_CASE, false); + + // export a case in a non-existing format + mvc.perform(post(GET_CASE_URL, firstCaseUuid).param("format", "JPEG")) + .andExpect(status().isUnprocessableEntity()); + } + + @Test + public void test() throws Exception { + // create the storage dir + createStorageDir(); + + // import a case + UUID firstCaseUuid = importCase(TEST_CASE, false); // list the cases and expect the one imported before mvc.perform(get("/v1/cases")) @@ -252,17 +288,12 @@ public void test() throws Exception { .andReturn(); assertThat(mvcResult.getResponse().getHeader("content-disposition")).contains("attachment;"); - // downlaod a case + // download a case mvc.perform(get(GET_CASE_URL, firstCaseUuid)) .andExpect(status().isOk()) .andExpect(content().xml(testCaseContent)) .andReturn(); - // downlaod a non existing case - mvc.perform(get(GET_CASE_URL, UUID.randomUUID())) - .andExpect(status().isNoContent()) - .andReturn(); - // export a case in CGMES format mvcResult = mvc.perform(post(GET_CASE_URL, firstCaseUuid).param("format", "CGMES")) .andExpect(status().isOk()) @@ -270,15 +301,6 @@ public void test() throws Exception { .andReturn(); assertThat(mvcResult.getResponse().getHeader("content-disposition")).contains("attachment;"); - // export a non-existing case - mvc.perform(post(GET_CASE_URL, UUID.randomUUID()).param("format", "XIIDM")) - .andExpect(status().isNoContent()) - .andReturn(); - - // export a case in a non-existing format - mvc.perform(post(GET_CASE_URL, firstCaseUuid).param("format", "JPEG")) - .andExpect(status().isUnprocessableEntity()); - // delete the case mvc.perform(delete(GET_CASE_URL, firstCaseUuid)) .andExpect(status().isOk()); @@ -288,6 +310,7 @@ public void test() throws Exception { .andExpect(content().string(startsWith("The directory with the following uuid doesn't exist:"))) .andReturn(); + outputDestination.clear(); // import a case to delete it UUID secondCaseUuid = importCase(TEST_CASE, false); @@ -300,7 +323,7 @@ public void test() throws Exception { assertEquals("XIIDM", headersPrivateCase2.get(CaseInfos.FORMAT_HEADER_KEY)); //check that the case doesn't have an expiration date - caseMetadataEntity = caseMetadataRepository.findById(secondCaseUuid).orElseThrow(); + CaseMetadataEntity caseMetadataEntity = caseMetadataRepository.findById(secondCaseUuid).orElseThrow(); assertEquals(secondCaseUuid, caseMetadataEntity.getId()); assertNull(caseMetadataEntity.getExpirationDate()); @@ -314,9 +337,9 @@ public void test() throws Exception { UUID caseUuid = importCase(TEST_CASE, false); // assert that the broker message has been sent - messageImport = outputDestination.receive(1000, "case.import.destination"); + Message messageImport = outputDestination.receive(1000, "case.import.destination"); assertEquals("", new String(messageImport.getPayload())); - headersCase = messageImport.getHeaders(); + MessageHeaders headersCase = messageImport.getHeaders(); assertEquals("testCase.xiidm", headersCase.get(CaseInfos.NAME_HEADER_KEY)); assertEquals(caseUuid, headersCase.get(CaseInfos.UUID_HEADER_KEY)); assertEquals("XIIDM", headersCase.get(CaseInfos.FORMAT_HEADER_KEY)); From 11f42d1f81b6f41b0d6bdc82fd1d48f65d24909e Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Tue, 6 Aug 2024 10:58:52 +0200 Subject: [PATCH 14/22] assert queues are empty after each test Signed-off-by: jamal-khey --- .../caseserver/CaseControllerTest.java | 55 +++++++++++++------ .../powsybl/caseserver/utils/TestUtils.java | 36 ++++++++++++ 2 files changed, 74 insertions(+), 17 deletions(-) create mode 100644 src/test/java/com/powsybl/caseserver/utils/TestUtils.java diff --git a/src/test/java/com/powsybl/caseserver/CaseControllerTest.java b/src/test/java/com/powsybl/caseserver/CaseControllerTest.java index 95004ba..a1842c7 100644 --- a/src/test/java/com/powsybl/caseserver/CaseControllerTest.java +++ b/src/test/java/com/powsybl/caseserver/CaseControllerTest.java @@ -15,6 +15,7 @@ import com.powsybl.caseserver.parsers.entsoe.EntsoeFileNameParser; import com.powsybl.caseserver.repository.CaseMetadataEntity; import com.powsybl.caseserver.repository.CaseMetadataRepository; +import com.powsybl.caseserver.utils.TestUtils; import com.powsybl.computation.ComputationManager; import org.junit.After; import org.junit.Before; @@ -105,6 +106,8 @@ public class CaseControllerTest { private FileSystem fileSystem; + private final String caseUpdateDestination = "case.import.destination"; + @Before public void setUp() { fileSystem = Jimfs.newFileSystem(Configuration.unix()); @@ -121,6 +124,8 @@ private void cleanDB() { @After public void tearDown() throws Exception { fileSystem.close(); + List destinations = List.of(caseUpdateDestination); + TestUtils.assertQueuesEmptyThenClear(destinations, outputDestination); } private void createStorageDir() throws IOException { @@ -173,7 +178,7 @@ public void testImportValidCase() throws Exception { UUID firstCaseUuid = importCase(TEST_CASE, false); // assert that the broker message has been sent - Message messageImport = outputDestination.receive(1000, "case.import.destination"); + Message messageImport = outputDestination.receive(1000, caseUpdateDestination); assertEquals("", new String(messageImport.getPayload())); MessageHeaders headersCase = messageImport.getHeaders(); assertEquals("testCase.xiidm", headersCase.get(CaseInfos.NAME_HEADER_KEY)); @@ -259,6 +264,26 @@ public void testExportNonExistingCaseFromat() throws Exception { // export a case in a non-existing format mvc.perform(post(GET_CASE_URL, firstCaseUuid).param("format", "JPEG")) .andExpect(status().isUnprocessableEntity()); + assertNotNull(outputDestination.receive(1000, caseUpdateDestination)); + } + + @Test + public void deleteNonExistingCase() throws Exception { + createStorageDir(); + + // import a case + UUID caseaseUuid = importCase(TEST_CASE, false); + assertNotNull(outputDestination.receive(1000, caseUpdateDestination)); + + // delete the case + mvc.perform(delete(GET_CASE_URL, caseaseUuid)) + .andExpect(status().isOk()); + + // delete non existing file + mvc.perform(delete(GET_CASE_URL, caseaseUuid)) + .andExpect(content().string(startsWith("The directory with the following uuid doesn't exist:"))) + .andReturn(); + } @Test @@ -287,6 +312,7 @@ public void test() throws Exception { .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_OCTET_STREAM)) .andReturn(); assertThat(mvcResult.getResponse().getHeader("content-disposition")).contains("attachment;"); + assertNotNull(outputDestination.receive(1000, caseUpdateDestination)); // download a case mvc.perform(get(GET_CASE_URL, firstCaseUuid)) @@ -305,17 +331,11 @@ public void test() throws Exception { mvc.perform(delete(GET_CASE_URL, firstCaseUuid)) .andExpect(status().isOk()); - // delete non existing file - mvc.perform(delete(GET_CASE_URL, firstCaseUuid)) - .andExpect(content().string(startsWith("The directory with the following uuid doesn't exist:"))) - .andReturn(); - - outputDestination.clear(); // import a case to delete it UUID secondCaseUuid = importCase(TEST_CASE, false); // assert that the broker message has been sent - Message messageImportPrivate2 = outputDestination.receive(1000, "case.import.destination"); + Message messageImportPrivate2 = outputDestination.receive(1000, caseUpdateDestination); assertEquals("", new String(messageImportPrivate2.getPayload())); MessageHeaders headersPrivateCase2 = messageImportPrivate2.getHeaders(); assertEquals("testCase.xiidm", headersPrivateCase2.get(CaseInfos.NAME_HEADER_KEY)); @@ -337,7 +357,7 @@ public void test() throws Exception { UUID caseUuid = importCase(TEST_CASE, false); // assert that the broker message has been sent - Message messageImport = outputDestination.receive(1000, "case.import.destination"); + Message messageImport = outputDestination.receive(1000, caseUpdateDestination); assertEquals("", new String(messageImport.getPayload())); MessageHeaders headersCase = messageImport.getHeaders(); assertEquals("testCase.xiidm", headersCase.get(CaseInfos.NAME_HEADER_KEY)); @@ -357,7 +377,7 @@ public void test() throws Exception { String duplicateCaseUuid = duplicateResult.getResponse().getContentAsString().replace("\"", ""); // assert that broker message has been sent after duplication - messageImport = outputDestination.receive(1000, "case.import.destination"); + messageImport = outputDestination.receive(1000, caseUpdateDestination); assertEquals("", new String(messageImport.getPayload())); headersCase = messageImport.getHeaders(); assertEquals(UUID.fromString(duplicateCaseUuid), headersCase.get(CaseInfos.UUID_HEADER_KEY)); @@ -375,7 +395,7 @@ public void test() throws Exception { Instant afterImportDate = Instant.now().plus(1, ChronoUnit.HOURS); // assert that the broker message has been sent - messageImport = outputDestination.receive(1000, "case.import.destination"); + messageImport = outputDestination.receive(1000, caseUpdateDestination); assertEquals("", new String(messageImport.getPayload())); headersCase = messageImport.getHeaders(); assertEquals("testCase.xiidm", headersCase.get(CaseInfos.NAME_HEADER_KEY)); @@ -400,7 +420,7 @@ public void test() throws Exception { assertNotEquals(caseUuid.toString(), duplicateCaseUuid2); // assert that broker message has been sent after duplication - messageImport = outputDestination.receive(1000, "case.import.destination"); + messageImport = outputDestination.receive(1000, caseUpdateDestination); assertEquals("", new String(messageImport.getPayload())); headersCase = messageImport.getHeaders(); assertEquals(UUID.fromString(duplicateCaseUuid2), headersCase.get(CaseInfos.UUID_HEADER_KEY)); @@ -518,7 +538,7 @@ public void searchCaseTest() throws Exception { UUID aCaseUuid = UUID.fromString(aCase.substring(1, aCase.length() - 1)); // assert that broker message has been sent and properties are the right ones - Message messageImport = outputDestination.receive(1000, "case.import.destination"); + Message messageImport = outputDestination.receive(1000, caseUpdateDestination); assertEquals("", new String(messageImport.getPayload())); MessageHeaders headersCase = messageImport.getHeaders(); assertEquals("testCase.xiidm", headersCase.get(CaseInfos.NAME_HEADER_KEY)); @@ -535,7 +555,7 @@ public void searchCaseTest() throws Exception { aCaseUuid = UUID.fromString(aCase.substring(1, aCase.length() - 1)); // assert that broker message has been sent and properties are the right ones - messageImport = outputDestination.receive(1000, "case.import.destination"); + messageImport = outputDestination.receive(1000, caseUpdateDestination); assertEquals("", new String(messageImport.getPayload())); headersCase = messageImport.getHeaders(); assertEquals("20200424T1330Z_2D_RTEFRANCE_001.zip", headersCase.get(CaseInfos.NAME_HEADER_KEY)); @@ -552,7 +572,7 @@ public void searchCaseTest() throws Exception { aCaseUuid = UUID.fromString(aCase.substring(1, aCase.length() - 1)); // assert that broker message has been sent and properties are the right ones - messageImport = outputDestination.receive(1000, "case.import.destination"); + messageImport = outputDestination.receive(1000, caseUpdateDestination); assertEquals("", new String(messageImport.getPayload())); headersCase = messageImport.getHeaders(); assertEquals("20200103_0915_FO5_FR0.UCT", headersCase.get(CaseInfos.NAME_HEADER_KEY)); @@ -569,7 +589,7 @@ public void searchCaseTest() throws Exception { aCaseUuid = UUID.fromString(aCase.substring(1, aCase.length() - 1)); // assert that broker message has been sent and properties are the right ones - messageImport = outputDestination.receive(1000, "case.import.destination"); + messageImport = outputDestination.receive(1000, caseUpdateDestination); assertEquals("", new String(messageImport.getPayload())); headersCase = messageImport.getHeaders(); assertEquals("20200103_0915_SN5_D80.UCT", headersCase.get(CaseInfos.NAME_HEADER_KEY)); @@ -586,7 +606,7 @@ public void searchCaseTest() throws Exception { aCaseUuid = UUID.fromString(aCase.substring(1, aCase.length() - 1)); // assert that broker message has been sent and properties are the right ones - messageImport = outputDestination.receive(1000, "case.import.destination"); + messageImport = outputDestination.receive(1000, caseUpdateDestination); assertEquals("", new String(messageImport.getPayload())); headersCase = messageImport.getHeaders(); assertEquals("20200103_0915_135_CH2.UCT", headersCase.get(CaseInfos.NAME_HEADER_KEY)); @@ -753,5 +773,6 @@ public void invalidFileInCaseDirectoryShouldBeIgnored() throws Exception { Files.delete(filePath); mvc.perform(delete("/v1/cases")) .andExpect(status().isOk()); + assertNotNull(outputDestination.receive(1000, caseUpdateDestination)); } } diff --git a/src/test/java/com/powsybl/caseserver/utils/TestUtils.java b/src/test/java/com/powsybl/caseserver/utils/TestUtils.java new file mode 100644 index 0000000..f4fd835 --- /dev/null +++ b/src/test/java/com/powsybl/caseserver/utils/TestUtils.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2024, 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 com.powsybl.caseserver.utils; + +import org.springframework.cloud.stream.binder.test.OutputDestination; + +import java.util.List; + +import static org.junit.Assert.assertNull; + +/** + * @author Jamal KHEYYAD + */ +public final class TestUtils { + + private static final long TIMEOUT = 100; + + private TestUtils() { + + } + + public static void assertQueuesEmptyThenClear(List destinations, OutputDestination output) { + try { + destinations.forEach(destination -> assertNull("Should not be any messages in queue " + destination + " : ", output.receive(TIMEOUT, destination))); + } catch (NullPointerException e) { + // Ignoring + } finally { + output.clear(); // purge in order to not fail the other tests + } + } +} From 809b6201554d08eee1e593df79aed42fbd690a3b Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Tue, 6 Aug 2024 11:05:00 +0200 Subject: [PATCH 15/22] clean code Signed-off-by: jamal-khey --- .../caseserver/CaseControllerTest.java | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/test/java/com/powsybl/caseserver/CaseControllerTest.java b/src/test/java/com/powsybl/caseserver/CaseControllerTest.java index a1842c7..7f783f0 100644 --- a/src/test/java/com/powsybl/caseserver/CaseControllerTest.java +++ b/src/test/java/com/powsybl/caseserver/CaseControllerTest.java @@ -106,7 +106,7 @@ public class CaseControllerTest { private FileSystem fileSystem; - private final String caseUpdateDestination = "case.import.destination"; + private final String caseImportDestination = "case.import.destination"; @Before public void setUp() { @@ -124,7 +124,7 @@ private void cleanDB() { @After public void tearDown() throws Exception { fileSystem.close(); - List destinations = List.of(caseUpdateDestination); + List destinations = List.of(caseImportDestination); TestUtils.assertQueuesEmptyThenClear(destinations, outputDestination); } @@ -153,7 +153,6 @@ public void testDeleteCases() throws Exception { // create the storage dir createStorageDir(); - // now it must work mvc.perform(delete("/v1/cases")) .andExpect(status().isOk()); } @@ -178,7 +177,7 @@ public void testImportValidCase() throws Exception { UUID firstCaseUuid = importCase(TEST_CASE, false); // assert that the broker message has been sent - Message messageImport = outputDestination.receive(1000, caseUpdateDestination); + Message messageImport = outputDestination.receive(1000, caseImportDestination); assertEquals("", new String(messageImport.getPayload())); MessageHeaders headersCase = messageImport.getHeaders(); assertEquals("testCase.xiidm", headersCase.get(CaseInfos.NAME_HEADER_KEY)); @@ -264,7 +263,7 @@ public void testExportNonExistingCaseFromat() throws Exception { // export a case in a non-existing format mvc.perform(post(GET_CASE_URL, firstCaseUuid).param("format", "JPEG")) .andExpect(status().isUnprocessableEntity()); - assertNotNull(outputDestination.receive(1000, caseUpdateDestination)); + assertNotNull(outputDestination.receive(1000, caseImportDestination)); } @Test @@ -273,7 +272,7 @@ public void deleteNonExistingCase() throws Exception { // import a case UUID caseaseUuid = importCase(TEST_CASE, false); - assertNotNull(outputDestination.receive(1000, caseUpdateDestination)); + assertNotNull(outputDestination.receive(1000, caseImportDestination)); // delete the case mvc.perform(delete(GET_CASE_URL, caseaseUuid)) @@ -312,7 +311,7 @@ public void test() throws Exception { .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_OCTET_STREAM)) .andReturn(); assertThat(mvcResult.getResponse().getHeader("content-disposition")).contains("attachment;"); - assertNotNull(outputDestination.receive(1000, caseUpdateDestination)); + assertNotNull(outputDestination.receive(1000, caseImportDestination)); // download a case mvc.perform(get(GET_CASE_URL, firstCaseUuid)) @@ -335,7 +334,7 @@ public void test() throws Exception { UUID secondCaseUuid = importCase(TEST_CASE, false); // assert that the broker message has been sent - Message messageImportPrivate2 = outputDestination.receive(1000, caseUpdateDestination); + Message messageImportPrivate2 = outputDestination.receive(1000, caseImportDestination); assertEquals("", new String(messageImportPrivate2.getPayload())); MessageHeaders headersPrivateCase2 = messageImportPrivate2.getHeaders(); assertEquals("testCase.xiidm", headersPrivateCase2.get(CaseInfos.NAME_HEADER_KEY)); @@ -357,7 +356,7 @@ public void test() throws Exception { UUID caseUuid = importCase(TEST_CASE, false); // assert that the broker message has been sent - Message messageImport = outputDestination.receive(1000, caseUpdateDestination); + Message messageImport = outputDestination.receive(1000, caseImportDestination); assertEquals("", new String(messageImport.getPayload())); MessageHeaders headersCase = messageImport.getHeaders(); assertEquals("testCase.xiidm", headersCase.get(CaseInfos.NAME_HEADER_KEY)); @@ -377,7 +376,7 @@ public void test() throws Exception { String duplicateCaseUuid = duplicateResult.getResponse().getContentAsString().replace("\"", ""); // assert that broker message has been sent after duplication - messageImport = outputDestination.receive(1000, caseUpdateDestination); + messageImport = outputDestination.receive(1000, caseImportDestination); assertEquals("", new String(messageImport.getPayload())); headersCase = messageImport.getHeaders(); assertEquals(UUID.fromString(duplicateCaseUuid), headersCase.get(CaseInfos.UUID_HEADER_KEY)); @@ -395,7 +394,7 @@ public void test() throws Exception { Instant afterImportDate = Instant.now().plus(1, ChronoUnit.HOURS); // assert that the broker message has been sent - messageImport = outputDestination.receive(1000, caseUpdateDestination); + messageImport = outputDestination.receive(1000, caseImportDestination); assertEquals("", new String(messageImport.getPayload())); headersCase = messageImport.getHeaders(); assertEquals("testCase.xiidm", headersCase.get(CaseInfos.NAME_HEADER_KEY)); @@ -420,7 +419,7 @@ public void test() throws Exception { assertNotEquals(caseUuid.toString(), duplicateCaseUuid2); // assert that broker message has been sent after duplication - messageImport = outputDestination.receive(1000, caseUpdateDestination); + messageImport = outputDestination.receive(1000, caseImportDestination); assertEquals("", new String(messageImport.getPayload())); headersCase = messageImport.getHeaders(); assertEquals(UUID.fromString(duplicateCaseUuid2), headersCase.get(CaseInfos.UUID_HEADER_KEY)); @@ -538,7 +537,7 @@ public void searchCaseTest() throws Exception { UUID aCaseUuid = UUID.fromString(aCase.substring(1, aCase.length() - 1)); // assert that broker message has been sent and properties are the right ones - Message messageImport = outputDestination.receive(1000, caseUpdateDestination); + Message messageImport = outputDestination.receive(1000, caseImportDestination); assertEquals("", new String(messageImport.getPayload())); MessageHeaders headersCase = messageImport.getHeaders(); assertEquals("testCase.xiidm", headersCase.get(CaseInfos.NAME_HEADER_KEY)); @@ -555,7 +554,7 @@ public void searchCaseTest() throws Exception { aCaseUuid = UUID.fromString(aCase.substring(1, aCase.length() - 1)); // assert that broker message has been sent and properties are the right ones - messageImport = outputDestination.receive(1000, caseUpdateDestination); + messageImport = outputDestination.receive(1000, caseImportDestination); assertEquals("", new String(messageImport.getPayload())); headersCase = messageImport.getHeaders(); assertEquals("20200424T1330Z_2D_RTEFRANCE_001.zip", headersCase.get(CaseInfos.NAME_HEADER_KEY)); @@ -572,7 +571,7 @@ public void searchCaseTest() throws Exception { aCaseUuid = UUID.fromString(aCase.substring(1, aCase.length() - 1)); // assert that broker message has been sent and properties are the right ones - messageImport = outputDestination.receive(1000, caseUpdateDestination); + messageImport = outputDestination.receive(1000, caseImportDestination); assertEquals("", new String(messageImport.getPayload())); headersCase = messageImport.getHeaders(); assertEquals("20200103_0915_FO5_FR0.UCT", headersCase.get(CaseInfos.NAME_HEADER_KEY)); @@ -589,7 +588,7 @@ public void searchCaseTest() throws Exception { aCaseUuid = UUID.fromString(aCase.substring(1, aCase.length() - 1)); // assert that broker message has been sent and properties are the right ones - messageImport = outputDestination.receive(1000, caseUpdateDestination); + messageImport = outputDestination.receive(1000, caseImportDestination); assertEquals("", new String(messageImport.getPayload())); headersCase = messageImport.getHeaders(); assertEquals("20200103_0915_SN5_D80.UCT", headersCase.get(CaseInfos.NAME_HEADER_KEY)); @@ -606,7 +605,7 @@ public void searchCaseTest() throws Exception { aCaseUuid = UUID.fromString(aCase.substring(1, aCase.length() - 1)); // assert that broker message has been sent and properties are the right ones - messageImport = outputDestination.receive(1000, caseUpdateDestination); + messageImport = outputDestination.receive(1000, caseImportDestination); assertEquals("", new String(messageImport.getPayload())); headersCase = messageImport.getHeaders(); assertEquals("20200103_0915_135_CH2.UCT", headersCase.get(CaseInfos.NAME_HEADER_KEY)); @@ -773,6 +772,6 @@ public void invalidFileInCaseDirectoryShouldBeIgnored() throws Exception { Files.delete(filePath); mvc.perform(delete("/v1/cases")) .andExpect(status().isOk()); - assertNotNull(outputDestination.receive(1000, caseUpdateDestination)); + assertNotNull(outputDestination.receive(1000, caseImportDestination)); } } From cb2680319903c441996e70b648e0613cfad8a058 Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Tue, 6 Aug 2024 14:32:16 +0200 Subject: [PATCH 16/22] impove test and coverage Signed-off-by: jamal-khey --- .../com/powsybl/caseserver/CaseController.java | 11 +++++++++++ .../java/com/powsybl/caseserver/CaseService.java | 6 ++++++ .../caseserver/SupervisionController.java | 7 +++++++ .../powsybl/caseserver/CaseControllerTest.java | 16 ++++++++++++++++ .../caseserver/SupervisionControllerTest.java | 7 +++++++ 5 files changed, 47 insertions(+) diff --git a/src/main/java/com/powsybl/caseserver/CaseController.java b/src/main/java/com/powsybl/caseserver/CaseController.java index 9b841c2..1bab238 100644 --- a/src/main/java/com/powsybl/caseserver/CaseController.java +++ b/src/main/java/com/powsybl/caseserver/CaseController.java @@ -184,6 +184,17 @@ public ResponseEntity disableCaseExpiration(@PathVariable("caseUuid") UUID return ResponseEntity.ok().build(); } + @PutMapping(value = "/cases/{caseUuid}/indexation") + @Operation(summary = "enable automatic indexation of the case") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "The case index has been changed"), + @ApiResponse(responseCode = "404", description = "Source case not found")}) + public ResponseEntity enableCaseIndexation(@PathVariable("caseUuid") UUID caseUuid, @RequestParam("indexed") boolean indexed) { + LOGGER.debug("enableIndexation request received for caseUuid = {}", caseUuid); + caseService.enableCaseIndexation(caseUuid, indexed); + return ResponseEntity.ok().build(); + } + @DeleteMapping(value = "/cases/{caseUuid}") @Operation(summary = "delete a case") public ResponseEntity deleteCase(@PathVariable("caseUuid") UUID caseUuid) { diff --git a/src/main/java/com/powsybl/caseserver/CaseService.java b/src/main/java/com/powsybl/caseserver/CaseService.java index 3ae80d1..880af96 100644 --- a/src/main/java/com/powsybl/caseserver/CaseService.java +++ b/src/main/java/com/powsybl/caseserver/CaseService.java @@ -284,6 +284,12 @@ public void disableCaseExpiration(UUID caseUuid) { caseMetadataEntity.setExpirationDate(null); } + @Transactional + public void enableCaseIndexation(UUID caseUuid, boolean indexed) { + CaseMetadataEntity caseMetadataEntity = caseMetadataRepository.findById(caseUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "case " + caseUuid + " not found")); + caseMetadataEntity.setIndexed(indexed); + } + Optional loadNetwork(UUID caseUuid) { checkStorageInitialization(); diff --git a/src/main/java/com/powsybl/caseserver/SupervisionController.java b/src/main/java/com/powsybl/caseserver/SupervisionController.java index 19fa0f1..34e6987 100644 --- a/src/main/java/com/powsybl/caseserver/SupervisionController.java +++ b/src/main/java/com/powsybl/caseserver/SupervisionController.java @@ -70,4 +70,11 @@ public ResponseEntity deleteIndexedDirectoryElements() { return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(Long.toString(supervisionService.deleteIndexedDirectoryElements())); } + @GetMapping(value = "/cases/indexation-count") + @Operation(summary = "get indexed cases count") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Indexed cases count")}) + public ResponseEntity getIndexedDirectoryElementsCount() { + return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(Long.toString(supervisionService.getIndexedCaseElementsCount())); + } + } diff --git a/src/test/java/com/powsybl/caseserver/CaseControllerTest.java b/src/test/java/com/powsybl/caseserver/CaseControllerTest.java index 7f783f0..8a99daf 100644 --- a/src/test/java/com/powsybl/caseserver/CaseControllerTest.java +++ b/src/test/java/com/powsybl/caseserver/CaseControllerTest.java @@ -474,6 +474,22 @@ public void test() throws Exception { assertTrue(response.contains("\"format\":\"XIIDM\"")); } + @Test + public void testChangeIndexation() throws Exception { + createStorageDir(); + + // import a case + UUID caseUuid = importCase(TEST_CASE, false); + assertNotNull(outputDestination.receive(1000, caseImportDestination)); + assertTrue(caseMetadataRepository.findAllById(List.of(caseUuid)).get(0).isIndexed()); + + // disable indexation + mvc.perform(put("/v1/cases/{caseUuid}/indexation", caseUuid).param("indexed", "false")) + .andExpect(status().isOk()); + + assertFalse(caseMetadataRepository.findAllById(List.of(caseUuid)).get(0).isIndexed()); + } + private UUID importCase(String testCase, Boolean withExpiration) throws Exception { String importedCase; if (withExpiration) { diff --git a/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java b/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java index 0e1e1fc..88fee6e 100644 --- a/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java +++ b/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java @@ -81,16 +81,23 @@ public void testDeleteElementInfos() throws Exception { createStorageDir(); importCase(true); importCase(true); + importCase(false); mockMvc.perform(delete("/v1/supervision/cases/indexation")) .andExpect(status().isOk()); + Assert.assertEquals(0, supervisionService.getIndexedCaseElementsCount()); //reindex mockMvc.perform(post("/v1/supervision/cases/reindex")) .andExpect(status().isOk()); + String countStr = mockMvc.perform(get("/v1/supervision/cases/indexation-count")) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(); + Assert.assertEquals("2", countStr); Assert.assertEquals(2, supervisionService.getIndexedCaseElementsCount()); + } private void importCase(Boolean indexed) throws Exception { From 5524154ab0f59de9d8dd41808db59206f7b0adab Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Wed, 14 Aug 2024 16:51:44 +0200 Subject: [PATCH 17/22] fix review comments Signed-off-by: jamal-khey --- .../powsybl/caseserver/CaseController.java | 20 +++-------- .../com/powsybl/caseserver/CaseService.java | 36 ++++++++----------- .../caseserver/SupervisionController.java | 10 +++--- .../repository/CaseMetadataRepository.java | 4 --- .../services/SupervisionService.java | 23 ++---------- .../caseserver/CaseControllerTest.java | 30 ++++------------ .../caseserver/SupervisionControllerTest.java | 20 +++++------ 7 files changed, 43 insertions(+), 100 deletions(-) diff --git a/src/main/java/com/powsybl/caseserver/CaseController.java b/src/main/java/com/powsybl/caseserver/CaseController.java index 1bab238..0f480f9 100644 --- a/src/main/java/com/powsybl/caseserver/CaseController.java +++ b/src/main/java/com/powsybl/caseserver/CaseController.java @@ -153,9 +153,9 @@ public ResponseEntity exists(@PathVariable("caseUuid") UUID caseUuid) { @SuppressWarnings("javasecurity:S5145") public ResponseEntity importCase(@RequestParam("file") MultipartFile file, @RequestParam(value = "withExpiration", required = false, defaultValue = "false") boolean withExpiration, - @RequestParam(value = "indexed", required = false, defaultValue = "false") boolean indexed) { + @RequestParam(value = "withIndexation", required = false, defaultValue = "false") boolean withIndexation) { LOGGER.debug("importCase request received with file = {}", file.getName()); - UUID caseUuid = caseService.importCase(file, withExpiration, indexed); + UUID caseUuid = caseService.importCase(file, withExpiration, withIndexation); return ResponseEntity.ok().body(caseUuid); } @@ -166,10 +166,9 @@ public ResponseEntity importCase(@RequestParam("file") MultipartFile file, @ApiResponse(responseCode = "500", description = "An error occurred during the case file duplication")}) public ResponseEntity duplicateCase( @RequestParam("duplicateFrom") UUID caseId, - @RequestParam(value = "withExpiration", required = false, defaultValue = "false") boolean withExpiration, - @RequestParam(value = "indexed", required = false, defaultValue = "false") boolean indexed) { + @RequestParam(value = "withExpiration", required = false, defaultValue = "false") boolean withExpiration) { LOGGER.debug("duplicateCase request received with parameter sourceCaseUuid = {}", caseId); - UUID newCaseUuid = caseService.duplicateCase(caseId, withExpiration, indexed); + UUID newCaseUuid = caseService.duplicateCase(caseId, withExpiration); return ResponseEntity.ok().body(newCaseUuid); } @@ -184,17 +183,6 @@ public ResponseEntity disableCaseExpiration(@PathVariable("caseUuid") UUID return ResponseEntity.ok().build(); } - @PutMapping(value = "/cases/{caseUuid}/indexation") - @Operation(summary = "enable automatic indexation of the case") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "The case index has been changed"), - @ApiResponse(responseCode = "404", description = "Source case not found")}) - public ResponseEntity enableCaseIndexation(@PathVariable("caseUuid") UUID caseUuid, @RequestParam("indexed") boolean indexed) { - LOGGER.debug("enableIndexation request received for caseUuid = {}", caseUuid); - caseService.enableCaseIndexation(caseUuid, indexed); - return ResponseEntity.ok().build(); - } - @DeleteMapping(value = "/cases/{caseUuid}") @Operation(summary = "delete a case") public ResponseEntity deleteCase(@PathVariable("caseUuid") UUID caseUuid) { diff --git a/src/main/java/com/powsybl/caseserver/CaseService.java b/src/main/java/com/powsybl/caseserver/CaseService.java index 880af96..3807b19 100644 --- a/src/main/java/com/powsybl/caseserver/CaseService.java +++ b/src/main/java/com/powsybl/caseserver/CaseService.java @@ -175,7 +175,7 @@ boolean caseExists(UUID caseName) { return Files.exists(caseFile) && Files.isRegularFile(caseFile); } - UUID importCase(MultipartFile mpf, boolean withExpiration, boolean indexed) { + UUID importCase(MultipartFile mpf, boolean withExpiration, boolean withIndexation) { checkStorageInitialization(); UUID caseUuid = UUID.randomUUID(); @@ -210,16 +210,16 @@ UUID importCase(MultipartFile mpf, boolean withExpiration, boolean indexed) { throw e; } - createCaseMetadataEntity(caseUuid, withExpiration, indexed); + createCaseMetadataEntity(caseUuid, withExpiration, withIndexation); CaseInfos caseInfos = createInfos(caseFile.getFileName().toString(), caseUuid, importer.getFormat()); - if (indexed) { + if (withIndexation) { caseInfosService.addCaseInfos(caseInfos); } sendImportMessage(caseInfos.createMessage()); return caseUuid; } - UUID duplicateCase(UUID sourceCaseUuid, boolean withExpiration, boolean indexed) { + UUID duplicateCase(UUID sourceCaseUuid, boolean withExpiration) { try { Path existingCaseFile = getCaseFile(sourceCaseUuid); if (existingCaseFile == null || existingCaseFile.getParent() == null) { @@ -235,10 +235,11 @@ UUID duplicateCase(UUID sourceCaseUuid, boolean withExpiration, boolean indexed) CaseInfos existingCaseInfos = caseInfosService.getCaseInfosByUuid(sourceCaseUuid.toString()).orElseThrow(); CaseInfos caseInfos = createInfos(existingCaseInfos.getName(), newCaseUuid, existingCaseInfos.getFormat()); - if (indexed) { - caseInfosService.addCaseInfos(caseInfos); - } - createCaseMetadataEntity(newCaseUuid, withExpiration, indexed); + caseInfosService.addCaseInfos(caseInfos); + + Optional existingCase = caseMetadataRepository.findById(sourceCaseUuid); + existingCase.ifPresentOrElse(caseMetadataEntity -> createCaseMetadataEntity(newCaseUuid, withExpiration, caseMetadataEntity.isIndexed()), + () -> createCaseMetadataEntity(newCaseUuid, withExpiration, false)); sendImportMessage(caseInfos.createMessage()); return newCaseUuid; @@ -248,23 +249,20 @@ UUID duplicateCase(UUID sourceCaseUuid, boolean withExpiration, boolean indexed) } } - private void createCaseMetadataEntity(UUID newCaseUuid, boolean withExpiration, boolean indexed) { + private void createCaseMetadataEntity(UUID newCaseUuid, boolean withExpiration, boolean withIndexation) { Instant expirationTime = null; if (withExpiration) { expirationTime = Instant.now().plus(1, ChronoUnit.HOURS); } - caseMetadataRepository.save(new CaseMetadataEntity(newCaseUuid, expirationTime, indexed)); + caseMetadataRepository.save(new CaseMetadataEntity(newCaseUuid, expirationTime, withIndexation)); } - public Set getCaseToReindex() { - return caseMetadataRepository.findAllByIndexedTrue() + public List getCasesToReindex() { + Set casesToReindex = caseMetadataRepository.findAllByIndexedTrue() .stream() .map(CaseMetadataEntity::getId) .collect(Collectors.toSet()); - } - - public List getAllCases() { - return getCases(getStorageRootDir()); + return getCases(getStorageRootDir()).stream().filter(c -> casesToReindex.contains(c.getUuid())).toList(); } CaseInfos createInfos(String fileBaseName, UUID caseUuid, String format) { @@ -284,12 +282,6 @@ public void disableCaseExpiration(UUID caseUuid) { caseMetadataEntity.setExpirationDate(null); } - @Transactional - public void enableCaseIndexation(UUID caseUuid, boolean indexed) { - CaseMetadataEntity caseMetadataEntity = caseMetadataRepository.findById(caseUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "case " + caseUuid + " not found")); - caseMetadataEntity.setIndexed(indexed); - } - Optional loadNetwork(UUID caseUuid) { checkStorageInitialization(); diff --git a/src/main/java/com/powsybl/caseserver/SupervisionController.java b/src/main/java/com/powsybl/caseserver/SupervisionController.java index 34e6987..e796cc7 100644 --- a/src/main/java/com/powsybl/caseserver/SupervisionController.java +++ b/src/main/java/com/powsybl/caseserver/SupervisionController.java @@ -29,11 +29,13 @@ public class SupervisionController { private static final Logger LOGGER = LoggerFactory.getLogger(SupervisionController.class); private final SupervisionService supervisionService; + private final CaseService caseService; private final ClientConfiguration elasticsearchClientConfiguration; private final CaseInfosService caseInfosService; - public SupervisionController(SupervisionService supervisionService, ClientConfiguration elasticsearchClientConfiguration, CaseInfosService caseInfosService) { + public SupervisionController(SupervisionService supervisionService, CaseService caseService, ClientConfiguration elasticsearchClientConfiguration, CaseInfosService caseInfosService) { this.supervisionService = supervisionService; + this.caseService = caseService; this.elasticsearchClientConfiguration = elasticsearchClientConfiguration; this.caseInfosService = caseInfosService; } @@ -59,7 +61,7 @@ public ResponseEntity getIndexedDirectoryElementsIndexName() { @Operation(summary = "reindex all cases") public ResponseEntity reindexAllCases() { LOGGER.debug("reindex all cases request received"); - supervisionService.reindexAllCases(); + caseInfosService.recreateAllCaseInfos(caseService.getCasesToReindex()); return ResponseEntity.ok().build(); } @@ -73,8 +75,8 @@ public ResponseEntity deleteIndexedDirectoryElements() { @GetMapping(value = "/cases/indexation-count") @Operation(summary = "get indexed cases count") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Indexed cases count")}) - public ResponseEntity getIndexedDirectoryElementsCount() { - return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(Long.toString(supervisionService.getIndexedCaseElementsCount())); + public ResponseEntity getIndexedCasesCount() { + return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(Long.toString(supervisionService.getIndexedCasesCount())); } } diff --git a/src/main/java/com/powsybl/caseserver/repository/CaseMetadataRepository.java b/src/main/java/com/powsybl/caseserver/repository/CaseMetadataRepository.java index 97a5da0..c44b383 100644 --- a/src/main/java/com/powsybl/caseserver/repository/CaseMetadataRepository.java +++ b/src/main/java/com/powsybl/caseserver/repository/CaseMetadataRepository.java @@ -17,9 +17,5 @@ */ @Repository public interface CaseMetadataRepository extends JpaRepository { - - @Override - List findAllById(Iterable uuids); - List findAllByIndexedTrue(); } diff --git a/src/main/java/com/powsybl/caseserver/services/SupervisionService.java b/src/main/java/com/powsybl/caseserver/services/SupervisionService.java index 94dbf17..6c6e53a 100644 --- a/src/main/java/com/powsybl/caseserver/services/SupervisionService.java +++ b/src/main/java/com/powsybl/caseserver/services/SupervisionService.java @@ -6,17 +6,11 @@ */ package com.powsybl.caseserver.services; -import com.powsybl.caseserver.CaseService; -import com.powsybl.caseserver.dto.CaseInfos; import com.powsybl.caseserver.elasticsearch.CaseInfosRepository; -import com.powsybl.caseserver.elasticsearch.CaseInfosService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Set; -import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; @@ -27,34 +21,23 @@ public class SupervisionService { private static final Logger LOGGER = LoggerFactory.getLogger(SupervisionService.class); - private final CaseInfosService caseInfosService; - private final CaseService caseService; private final CaseInfosRepository caseInfosRepository; - public SupervisionService(CaseInfosService caseInfosService, CaseService caseService, CaseInfosRepository caseInfosRepository) { - this.caseInfosService = caseInfosService; - this.caseService = caseService; + public SupervisionService(CaseInfosRepository caseInfosRepository) { this.caseInfosRepository = caseInfosRepository; } - public void reindexAllCases() { - List allCases = caseService.getAllCases(); - Set casesToIndex = caseService.getCaseToReindex(); - List data = allCases.stream().filter(c -> casesToIndex.contains(c.getUuid())).toList(); - caseInfosService.recreateAllCaseInfos(data); - } - public long deleteIndexedDirectoryElements() { AtomicReference startTime = new AtomicReference<>(); startTime.set(System.nanoTime()); - long nbIndexesToDelete = getIndexedCaseElementsCount(); + long nbIndexesToDelete = getIndexedCasesCount(); caseInfosRepository.deleteAll(); LOGGER.trace("Indexed directory elements deletion : {} seconds", TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime.get())); return nbIndexesToDelete; } - public long getIndexedCaseElementsCount() { + public long getIndexedCasesCount() { return caseInfosRepository.count(); } } diff --git a/src/test/java/com/powsybl/caseserver/CaseControllerTest.java b/src/test/java/com/powsybl/caseserver/CaseControllerTest.java index 8a99daf..e92b746 100644 --- a/src/test/java/com/powsybl/caseserver/CaseControllerTest.java +++ b/src/test/java/com/powsybl/caseserver/CaseControllerTest.java @@ -474,35 +474,19 @@ public void test() throws Exception { assertTrue(response.contains("\"format\":\"XIIDM\"")); } - @Test - public void testChangeIndexation() throws Exception { - createStorageDir(); - - // import a case - UUID caseUuid = importCase(TEST_CASE, false); - assertNotNull(outputDestination.receive(1000, caseImportDestination)); - assertTrue(caseMetadataRepository.findAllById(List.of(caseUuid)).get(0).isIndexed()); - - // disable indexation - mvc.perform(put("/v1/cases/{caseUuid}/indexation", caseUuid).param("indexed", "false")) - .andExpect(status().isOk()); - - assertFalse(caseMetadataRepository.findAllById(List.of(caseUuid)).get(0).isIndexed()); - } - private UUID importCase(String testCase, Boolean withExpiration) throws Exception { String importedCase; if (withExpiration) { importedCase = mvc.perform(multipart("/v1/cases") .file(createMockMultipartFile(testCase)) .param("withExpiration", withExpiration.toString()) - .param("indexed", "true")) + .param("withIndexation", "true")) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); } else { importedCase = mvc.perform(multipart("/v1/cases") .file(createMockMultipartFile(testCase)) - .param("indexed", "true")) + .param("withIndexation", "true")) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); } @@ -546,7 +530,7 @@ public void searchCaseTest() throws Exception { // import IIDM test case String aCase = mvc.perform(multipart("/v1/cases") .file(createMockMultipartFile("testCase.xiidm")) - .param("indexed", "true")) + .param("withIndexation", "true")) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); @@ -563,7 +547,7 @@ public void searchCaseTest() throws Exception { // import CGMES french file aCase = mvc.perform(multipart("/v1/cases") .file(createMockMultipartFile("20200424T1330Z_2D_RTEFRANCE_001.zip")) - .param("indexed", "true")) + .param("withIndexation", "true")) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); @@ -580,7 +564,7 @@ public void searchCaseTest() throws Exception { // import UCTE french file aCase = mvc.perform(multipart("/v1/cases") .file(createMockMultipartFile("20200103_0915_FO5_FR0.UCT")) - .param("indexed", "true")) + .param("withIndexation", "true")) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); @@ -597,7 +581,7 @@ public void searchCaseTest() throws Exception { // import UCTE german file aCase = mvc.perform(multipart("/v1/cases") .file(createMockMultipartFile("20200103_0915_SN5_D80.UCT")) - .param("indexed", "true")) + .param("withIndexation", "true")) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); @@ -614,7 +598,7 @@ public void searchCaseTest() throws Exception { // import UCTE swiss file aCase = mvc.perform(multipart("/v1/cases") .file(createMockMultipartFile("20200103_0915_135_CH2.UCT")) - .param("indexed", "true")) + .param("withIndexation", "true")) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); diff --git a/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java b/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java index 88fee6e..184ce38 100644 --- a/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java +++ b/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java @@ -8,7 +8,6 @@ import com.google.common.jimfs.Configuration; import com.google.common.jimfs.Jimfs; -import com.powsybl.caseserver.elasticsearch.CaseInfosRepository; import com.powsybl.caseserver.repository.CaseMetadataRepository; import com.powsybl.caseserver.services.SupervisionService; import com.powsybl.computation.ComputationManager; @@ -24,6 +23,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; @@ -41,14 +41,12 @@ */ @RunWith(SpringRunner.class) @AutoConfigureMockMvc -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, properties = {"case-store-directory=/cases"}) -@ContextConfigurationWithTestChannel +@SpringBootTest(properties = {"case-store-directory=/cases"}) +@ContextConfiguration(classes = {CaseApplication.class}) public class SupervisionControllerTest { @Autowired SupervisionService supervisionService; @Autowired - CaseInfosRepository caseInfosRepository; - @Autowired CaseMetadataRepository caseMetadataRepository; @Autowired CaseService caseService; @@ -63,7 +61,7 @@ public class SupervisionControllerTest { private FileSystem fileSystem; @Test - public void testGetElementInfosCount() throws Exception { + public void testGetCaseInfosCount() throws Exception { createStorageDir(); importCase(true); importCase(true); @@ -72,7 +70,7 @@ public void testGetElementInfosCount() throws Exception { mockMvc.perform(post("/v1/supervision/cases/reindex")) .andExpect(status().isOk()); - Assert.assertEquals(2, supervisionService.getIndexedCaseElementsCount()); + Assert.assertEquals(2, supervisionService.getIndexedCasesCount()); } @@ -86,7 +84,7 @@ public void testDeleteElementInfos() throws Exception { mockMvc.perform(delete("/v1/supervision/cases/indexation")) .andExpect(status().isOk()); - Assert.assertEquals(0, supervisionService.getIndexedCaseElementsCount()); + Assert.assertEquals(0, supervisionService.getIndexedCasesCount()); //reindex mockMvc.perform(post("/v1/supervision/cases/reindex")) @@ -96,14 +94,14 @@ public void testDeleteElementInfos() throws Exception { .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); Assert.assertEquals("2", countStr); - Assert.assertEquals(2, supervisionService.getIndexedCaseElementsCount()); + Assert.assertEquals(2, supervisionService.getIndexedCasesCount()); } private void importCase(Boolean indexed) throws Exception { mockMvc.perform(multipart("/v1/cases") .file(createMockMultipartFile()) - .param("indexed", indexed.toString())) + .param("withIndexation", indexed.toString())) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); } @@ -119,12 +117,12 @@ public void setUp() { fileSystem = Jimfs.newFileSystem(Configuration.unix()); caseService.setFileSystem(fileSystem); caseService.setComputationManager(Mockito.mock(ComputationManager.class)); - cleanDB(); } @After public void tearDown() throws Exception { fileSystem.close(); + cleanDB(); } private void cleanDB() { From 9f80c6731aad743d539560e5cdb3c0886842b90f Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Fri, 16 Aug 2024 13:04:47 +0200 Subject: [PATCH 18/22] fix review comments Signed-off-by: jamal-khey --- .../powsybl/caseserver/SupervisionControllerTest.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java b/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java index 184ce38..454aba8 100644 --- a/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java +++ b/src/test/java/com/powsybl/caseserver/SupervisionControllerTest.java @@ -75,7 +75,7 @@ public void testGetCaseInfosCount() throws Exception { } @Test - public void testDeleteElementInfos() throws Exception { + public void testReindexAll() throws Exception { createStorageDir(); importCase(true); importCase(true); @@ -98,6 +98,14 @@ public void testDeleteElementInfos() throws Exception { } + @Test + public void testGetIndexName() throws Exception { + String result = mockMvc.perform(get("/v1/supervision/cases/index-name")) + .andReturn().getResponse().getContentAsString(); + + Assert.assertEquals("cases", result); + } + private void importCase(Boolean indexed) throws Exception { mockMvc.perform(multipart("/v1/cases") .file(createMockMultipartFile()) From d4f5b02956eebbd5f6043aa9fb4c1e8a1be582d1 Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Mon, 19 Aug 2024 14:37:25 +0200 Subject: [PATCH 19/22] remove any ref to elements Signed-off-by: jamal-khey --- .../caseserver/SupervisionController.java | 16 ++++++++-------- .../elasticsearch/CaseInfosService.java | 2 +- .../caseserver/services/SupervisionService.java | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/powsybl/caseserver/SupervisionController.java b/src/main/java/com/powsybl/caseserver/SupervisionController.java index e796cc7..cf826a9 100644 --- a/src/main/java/com/powsybl/caseserver/SupervisionController.java +++ b/src/main/java/com/powsybl/caseserver/SupervisionController.java @@ -51,10 +51,10 @@ public ResponseEntity getElasticsearchHost() { } @GetMapping(value = "/cases/index-name") - @Operation(summary = "get the indexed directory elements index name") - @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Indexed directory elements index name")}) - public ResponseEntity getIndexedDirectoryElementsIndexName() { - return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(caseInfosService.getDirectoryElementsIndexName()); + @Operation(summary = "get the indexed cases index name") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Indexed directory cases index name")}) + public ResponseEntity getIndexedCasesFIndexName() { + return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(caseInfosService.getDirectoryCasesIndexName()); } @PostMapping(value = "/cases/reindex") @@ -66,10 +66,10 @@ public ResponseEntity reindexAllCases() { } @DeleteMapping(value = "/cases/indexation") - @Operation(summary = "delete indexed elements") - @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "all indexed elements have been deleted")}) - public ResponseEntity deleteIndexedDirectoryElements() { - return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(Long.toString(supervisionService.deleteIndexedDirectoryElements())); + @Operation(summary = "delete indexed cases") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "all indexed cases have been deleted")}) + public ResponseEntity deleteIndexedCases() { + return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(Long.toString(supervisionService.deleteIndexedCases())); } @GetMapping(value = "/cases/indexation-count") diff --git a/src/main/java/com/powsybl/caseserver/elasticsearch/CaseInfosService.java b/src/main/java/com/powsybl/caseserver/elasticsearch/CaseInfosService.java index e46463b..3286410 100644 --- a/src/main/java/com/powsybl/caseserver/elasticsearch/CaseInfosService.java +++ b/src/main/java/com/powsybl/caseserver/elasticsearch/CaseInfosService.java @@ -46,7 +46,7 @@ public class CaseInfosService { @Value(ESConfig.CASE_INFOS_INDEX_NAME) @Getter - private String directoryElementsIndexName; + private String directoryCasesIndexName; public CaseInfos addCaseInfos(@NonNull final CaseInfos ci) { caseInfosRepository.save(ci); diff --git a/src/main/java/com/powsybl/caseserver/services/SupervisionService.java b/src/main/java/com/powsybl/caseserver/services/SupervisionService.java index 6c6e53a..5a11ab6 100644 --- a/src/main/java/com/powsybl/caseserver/services/SupervisionService.java +++ b/src/main/java/com/powsybl/caseserver/services/SupervisionService.java @@ -27,13 +27,13 @@ public SupervisionService(CaseInfosRepository caseInfosRepository) { this.caseInfosRepository = caseInfosRepository; } - public long deleteIndexedDirectoryElements() { + public long deleteIndexedCases() { AtomicReference startTime = new AtomicReference<>(); startTime.set(System.nanoTime()); long nbIndexesToDelete = getIndexedCasesCount(); caseInfosRepository.deleteAll(); - LOGGER.trace("Indexed directory elements deletion : {} seconds", TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime.get())); + LOGGER.trace("Indexed cases deletion : {} seconds", TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime.get())); return nbIndexesToDelete; } From 08a7a2d8bd721918cc19965a7294f23919f12492 Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Mon, 19 Aug 2024 14:41:28 +0200 Subject: [PATCH 20/22] throw NOT_Found Signed-off-by: jamal-khey --- src/main/java/com/powsybl/caseserver/CaseService.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/powsybl/caseserver/CaseService.java b/src/main/java/com/powsybl/caseserver/CaseService.java index 3807b19..54697f1 100644 --- a/src/main/java/com/powsybl/caseserver/CaseService.java +++ b/src/main/java/com/powsybl/caseserver/CaseService.java @@ -237,10 +237,8 @@ UUID duplicateCase(UUID sourceCaseUuid, boolean withExpiration) { CaseInfos caseInfos = createInfos(existingCaseInfos.getName(), newCaseUuid, existingCaseInfos.getFormat()); caseInfosService.addCaseInfos(caseInfos); - Optional existingCase = caseMetadataRepository.findById(sourceCaseUuid); - existingCase.ifPresentOrElse(caseMetadataEntity -> createCaseMetadataEntity(newCaseUuid, withExpiration, caseMetadataEntity.isIndexed()), - () -> createCaseMetadataEntity(newCaseUuid, withExpiration, false)); - + CaseMetadataEntity existingCase = caseMetadataRepository.findById(sourceCaseUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "case " + sourceCaseUuid + " not found")); + createCaseMetadataEntity(newCaseUuid, withExpiration, existingCase.isIndexed()); sendImportMessage(caseInfos.createMessage()); return newCaseUuid; From e821fe61038e2e04d06cffa0d97ca33b6171230f Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Tue, 20 Aug 2024 10:41:33 +0200 Subject: [PATCH 21/22] extract getCaseMetaDataEntity into a function Signed-off-by: jamal-khey --- src/main/java/com/powsybl/caseserver/CaseService.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/powsybl/caseserver/CaseService.java b/src/main/java/com/powsybl/caseserver/CaseService.java index 54697f1..7d1c92c 100644 --- a/src/main/java/com/powsybl/caseserver/CaseService.java +++ b/src/main/java/com/powsybl/caseserver/CaseService.java @@ -8,7 +8,6 @@ import com.powsybl.caseserver.dto.CaseInfos; import com.powsybl.caseserver.dto.ExportCaseInfos; -import com.powsybl.caseserver.elasticsearch.CaseInfosRepository; import com.powsybl.caseserver.elasticsearch.CaseInfosService; import com.powsybl.caseserver.parsers.FileNameInfos; import com.powsybl.caseserver.parsers.FileNameParser; @@ -83,8 +82,6 @@ public class CaseService { @Value("${case-store-directory:#{systemProperties['user.home'].concat(\"/cases\")}}") private String rootDirectory; - @Autowired - private CaseInfosRepository caseInfosRepository; public CaseService(CaseMetadataRepository caseMetadataRepository) { this.caseMetadataRepository = caseMetadataRepository; @@ -237,7 +234,7 @@ UUID duplicateCase(UUID sourceCaseUuid, boolean withExpiration) { CaseInfos caseInfos = createInfos(existingCaseInfos.getName(), newCaseUuid, existingCaseInfos.getFormat()); caseInfosService.addCaseInfos(caseInfos); - CaseMetadataEntity existingCase = caseMetadataRepository.findById(sourceCaseUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "case " + sourceCaseUuid + " not found")); + CaseMetadataEntity existingCase = getCaseMetaDataEntity(sourceCaseUuid); createCaseMetadataEntity(newCaseUuid, withExpiration, existingCase.isIndexed()); sendImportMessage(caseInfos.createMessage()); return newCaseUuid; @@ -247,6 +244,10 @@ UUID duplicateCase(UUID sourceCaseUuid, boolean withExpiration) { } } + CaseMetadataEntity getCaseMetaDataEntity(UUID caseUuid) { + return caseMetadataRepository.findById(caseUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "case " + caseUuid + " not found")); + } + private void createCaseMetadataEntity(UUID newCaseUuid, boolean withExpiration, boolean withIndexation) { Instant expirationTime = null; if (withExpiration) { @@ -276,7 +277,7 @@ CaseInfos createInfos(String fileBaseName, UUID caseUuid, String format) { @Transactional public void disableCaseExpiration(UUID caseUuid) { - CaseMetadataEntity caseMetadataEntity = caseMetadataRepository.findById(caseUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "case " + caseUuid + " not found")); + CaseMetadataEntity caseMetadataEntity = getCaseMetaDataEntity(caseUuid); caseMetadataEntity.setExpirationDate(null); } From 0f911aef2fef79ccd343ec4a63c77028c6243fc9 Mon Sep 17 00:00:00 2001 From: jamal-khey Date: Fri, 16 Aug 2024 13:04:47 +0200 Subject: [PATCH 22/22] Review Signed-off-by: Slimane AMAR --- src/main/java/com/powsybl/caseserver/CaseService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/powsybl/caseserver/CaseService.java b/src/main/java/com/powsybl/caseserver/CaseService.java index 7d1c92c..29c8892 100644 --- a/src/main/java/com/powsybl/caseserver/CaseService.java +++ b/src/main/java/com/powsybl/caseserver/CaseService.java @@ -244,7 +244,7 @@ UUID duplicateCase(UUID sourceCaseUuid, boolean withExpiration) { } } - CaseMetadataEntity getCaseMetaDataEntity(UUID caseUuid) { + private CaseMetadataEntity getCaseMetaDataEntity(UUID caseUuid) { return caseMetadataRepository.findById(caseUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "case " + caseUuid + " not found")); }