Skip to content

Commit b216754

Browse files
authored
Swallow exceptions in getCases() when some cases do not have case_metadata (#67)
Signed-off-by: Etienne Homer <etiennehomer@gmail.com>
1 parent c1a7c6c commit b216754

File tree

6 files changed

+72
-21
lines changed

6 files changed

+72
-21
lines changed

src/main/java/com/powsybl/caseserver/service/CaseService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ default void validateCaseName(String caseName) {
4949
}
5050

5151
default CaseMetadataEntity getCaseMetaDataEntity(UUID caseUuid) {
52-
return getCaseMetadataRepository().findById(caseUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "case " + caseUuid + NOT_FOUND));
52+
return getCaseMetadataRepository().findById(caseUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Metadata of case " + caseUuid + NOT_FOUND));
5353
}
5454

5555
default Boolean isUploadedAsPlainFile(UUID caseUuid) {

src/main/java/com/powsybl/caseserver/service/FsCaseService.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,20 +100,25 @@ String getFormat(Path caseFile) {
100100
public List<CaseInfos> getCases() {
101101
try (Stream<Path> walk = Files.walk(getStorageRootDir())) {
102102
return walk.filter(Files::isRegularFile)
103-
.map(this::getCaseInfos)
103+
.map(this::getCaseInfoSafely)
104104
.filter(Objects::nonNull)
105-
.map(this::removeGzipExtensionFromPlainFile)
106105
.toList();
107106
} catch (IOException e) {
108107
throw new UncheckedIOException(e);
109108
}
110109
}
111110

112111
private CaseInfos getCaseInfos(Path file) {
112+
CaseInfos caseInfos = createInfos(file, UUID.fromString(file.getParent().getFileName().toString()));
113+
return removeGzipExtensionFromPlainFile(caseInfos);
114+
}
115+
116+
private CaseInfos getCaseInfoSafely(Path file) {
113117
Objects.requireNonNull(file);
114118
try {
115-
return createInfos(file, UUID.fromString(file.getParent().getFileName().toString()));
119+
return getCaseInfos(file);
116120
} catch (Exception e) {
121+
// This method is called by getCases() that is a method for supervision and administration. We do not want the request to stop and fail on error cases.
117122
LOGGER.error("Error processing file {}: {}", file.getFileName(), e.getMessage(), e);
118123
return null;
119124
}
@@ -129,9 +134,6 @@ public String getCaseName(UUID caseUuid) {
129134
if (caseInfos == null) {
130135
throw CaseException.createFileNameNotFound(caseUuid);
131136
}
132-
if (Boolean.TRUE.equals(isUploadedAsPlainFile(caseUuid))) {
133-
return removeExtension(caseInfos.getName(), GZIP_EXTENSION);
134-
}
135137
return caseInfos.getName();
136138
}
137139

@@ -142,8 +144,7 @@ public CaseInfos getCaseInfos(UUID caseUuid) {
142144
LOGGER.error("The directory with the following uuid doesn't exist: {}", caseUuid);
143145
return null;
144146
}
145-
CaseInfos caseInfos = getCaseInfos(file);
146-
return this.removeGzipExtensionFromPlainFile(caseInfos);
147+
return getCaseInfos(file);
147148
}
148149

149150
public Path getCaseFile(UUID caseUuid) {

src/main/java/com/powsybl/caseserver/service/MetadataService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public MetadataService(CaseMetadataRepository caseMetadataRepository) {
3131

3232
@Transactional
3333
public void disableCaseExpiration(UUID caseUuid) {
34-
CaseMetadataEntity caseMetadataEntity = caseMetadataRepository.findById(caseUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "case " + caseUuid + NOT_FOUND));
34+
CaseMetadataEntity caseMetadataEntity = caseMetadataRepository.findById(caseUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Metadata of case " + caseUuid + NOT_FOUND));
3535
caseMetadataEntity.setExpirationDate(null);
3636
}
3737
}

src/main/java/com/powsybl/caseserver/service/S3CaseService.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,14 +270,25 @@ public List<CaseInfos> getCases() {
270270
List<CaseInfos> caseInfosList = new ArrayList<>();
271271
CaseInfos caseInfos;
272272
for (S3Object o : getCaseS3Objects(rootDirectory + DELIMITER)) {
273-
caseInfos = getCaseInfos(parseUuidFromKey(o.key()));
273+
caseInfos = getCaseInfoSafely(parseUuidFromKey(o.key()));
274274
if (Objects.nonNull(caseInfos)) {
275275
caseInfosList.add(caseInfos);
276276
}
277277
}
278278
return caseInfosList;
279279
}
280280

281+
private CaseInfos getCaseInfoSafely(UUID uuid) {
282+
Objects.requireNonNull(uuid);
283+
try {
284+
return getCaseInfos(uuid);
285+
} catch (Exception e) {
286+
// This method is called by getCases() that is a method for supervision and administration. We do not want the request to stop and fail on error cases.
287+
LOGGER.error("Error processing case with uuid {}: {}", uuid, e.getMessage(), e);
288+
return null;
289+
}
290+
}
291+
281292
@Override
282293
public boolean caseExists(UUID uuid) {
283294
return !getCaseS3Objects(uuid).isEmpty();

src/test/java/com/powsybl/caseserver/service/AbstractCaseControllerTest.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
5858
@ContextConfigurationWithTestChannel
5959
abstract class AbstractCaseControllerTest {
60-
private static final String TEST_CASE = "testCase.xiidm";
60+
static final String TEST_CASE = "testCase.xiidm";
6161
private static final String TEST_TAR_CASE = "tarCase.tar";
6262
private static final String TEST_CASE_FORMAT = "XIIDM";
6363
private static final String NOT_A_NETWORK = "notANetwork.txt";
@@ -80,11 +80,11 @@ abstract class AbstractCaseControllerTest {
8080
OutputDestination outputDestination;
8181

8282
@Autowired
83-
private ObjectMapper mapper;
83+
ObjectMapper mapper;
8484

8585
FileSystem fileSystem;
8686

87-
private final String caseImportDestination = "case.import.destination";
87+
final String caseImportDestination = "case.import.destination";
8888

8989
@AfterEach
9090
public void tearDown() throws Exception {
@@ -93,7 +93,7 @@ public void tearDown() throws Exception {
9393
TestUtils.assertQueuesEmptyThenClear(destinations, outputDestination);
9494
}
9595

96-
private void createStorageDir() throws IOException {
96+
void createStorageDir() throws IOException {
9797
Path path = fileSystem.getPath(caseService.getRootDirectory());
9898
if (!Files.exists(path)) {
9999
Files.createDirectories(path);
@@ -467,7 +467,7 @@ void testDuplicateNonIndexedCase() throws Exception {
467467
assertFalse(caseMetadataRepository.findById(duplicateCaseUuid).get().isIndexed());
468468
}
469469

470-
private UUID importCase(String testCase, Boolean withExpiration) throws Exception {
470+
UUID importCase(String testCase, Boolean withExpiration) throws Exception {
471471
String importedCase;
472472
if (withExpiration) {
473473
importedCase = mvc.perform(multipart("/v1/cases")
@@ -722,11 +722,17 @@ private static String getDateSearchTerm(String entsoeFormatDate) {
722722
}
723723

724724
@Test
725-
void invalidFileInCaseDirectoryShouldBeIgnored() throws Exception {
725+
void casesWithoutMetadataShouldBeIgnored() throws Exception {
726726
createStorageDir();
727-
Path filePath = fileSystem.getPath(caseService.getRootDirectory()).resolve("randomFile.txt");
728-
Files.createFile(filePath);
727+
728+
// add a case file in a UUID named directory but no metadata in the database
729+
UUID caseUuid = importCase(TEST_CASE, false);
730+
assertNotNull(outputDestination.receive(1000, caseImportDestination));
731+
caseMetadataRepository.deleteById(caseUuid);
732+
733+
// import a case properly
729734
importCase(TEST_CASE, false);
735+
assertNotNull(outputDestination.receive(1000, caseImportDestination));
730736

731737
MvcResult mvcResult = mvc.perform(get("/v1/cases"))
732738
.andExpect(status().isOk())
@@ -736,10 +742,9 @@ void invalidFileInCaseDirectoryShouldBeIgnored() throws Exception {
736742
assertEquals(1, caseInfos.size());
737743
assertEquals(TEST_CASE, caseInfos.get(0).getName());
738744

739-
Files.delete(filePath);
745+
caseService.deleteCase(caseUuid);
740746
mvc.perform(delete("/v1/cases"))
741747
.andExpect(status().isOk());
742-
assertNotNull(outputDestination.receive(1000, caseImportDestination));
743748
}
744749

745750
@Test

src/test/java/com/powsybl/caseserver/service/FsCaseControllerTest.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,28 @@
66
*/
77
package com.powsybl.caseserver.service;
88

9+
import com.fasterxml.jackson.core.type.TypeReference;
910
import com.google.common.jimfs.Configuration;
1011
import com.google.common.jimfs.Jimfs;
1112

13+
import static org.junit.jupiter.api.Assertions.assertEquals;
14+
import static org.junit.jupiter.api.Assertions.assertNotNull;
1215
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
16+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
1317
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
1418

19+
import com.powsybl.caseserver.dto.CaseInfos;
1520
import com.powsybl.computation.ComputationManager;
1621
import org.junit.jupiter.api.BeforeEach;
1722
import org.junit.jupiter.api.Test;
1823
import org.mockito.Mockito;
1924
import org.springframework.beans.factory.annotation.Autowired;
2025
import org.springframework.test.context.TestPropertySource;
26+
import org.springframework.test.web.servlet.MvcResult;
27+
28+
import java.nio.file.Files;
29+
import java.nio.file.Path;
30+
import java.util.List;
2131

2232
/**
2333
* @author Ghazwa Rehili <ghazwa.rehili at rte-france.com>
@@ -44,4 +54,28 @@ void testStorageNotCreated() throws Exception {
4454
mvc.perform(delete("/v1/cases")).andExpect(status().isUnprocessableEntity());
4555
}
4656

57+
@Test
58+
void invalidFileInCaseDirectoryShouldBeIgnored() throws Exception {
59+
createStorageDir();
60+
61+
// add a random file in the storage, not stored in a UUID named directory
62+
Path filePath = fileSystem.getPath(caseService.getRootDirectory()).resolve("randomFile.txt");
63+
Files.createFile(filePath);
64+
65+
// import a case properly
66+
importCase(TEST_CASE, false);
67+
68+
MvcResult mvcResult = mvc.perform(get("/v1/cases"))
69+
.andExpect(status().isOk())
70+
.andReturn();
71+
String resultAsString = mvcResult.getResponse().getContentAsString();
72+
List<CaseInfos> caseInfos = mapper.readValue(resultAsString, new TypeReference<>() { });
73+
assertEquals(1, caseInfos.size());
74+
assertEquals(TEST_CASE, caseInfos.get(0).getName());
75+
76+
Files.delete(filePath);
77+
mvc.perform(delete("/v1/cases"))
78+
.andExpect(status().isOk());
79+
assertNotNull(outputDestination.receive(1000, caseImportDestination));
80+
}
4781
}

0 commit comments

Comments
 (0)