Skip to content

Commit bb8dbb8

Browse files
authored
Recreate index instead of deleting all its documents (#80)
Signed-off-by: BOUHOURS Antoine <antoine.bouhours@rte-france.com>
1 parent 216333b commit bb8dbb8

File tree

4 files changed

+127
-23
lines changed

4 files changed

+127
-23
lines changed

src/main/java/com/powsybl/caseserver/SupervisionController.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,15 @@ public ResponseEntity<Void> reindexAllCases() {
6868
return ResponseEntity.ok().build();
6969
}
7070

71-
@DeleteMapping(value = "/cases/indexation")
72-
@Operation(summary = "delete indexed cases")
73-
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "all indexed cases have been deleted")})
74-
public ResponseEntity<String> deleteIndexedCases() {
75-
return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(Long.toString(supervisionService.deleteIndexedCases()));
71+
@PostMapping(value = "/cases/index")
72+
@Operation(summary = "Recreate Elasticsearch index")
73+
@ApiResponses(value = {
74+
@ApiResponse(responseCode = "200", description = "Elasticsearch index recreated successfully"),
75+
@ApiResponse(responseCode = "500", description = "Failed to recreate Elasticsearch index")
76+
})
77+
public ResponseEntity<Void> recreateESIndex() {
78+
supervisionService.recreateIndex();
79+
return ResponseEntity.ok().build();
7680
}
7781

7882
@GetMapping(value = "/cases/indexation-count")

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

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,38 +6,44 @@
66
*/
77
package com.powsybl.caseserver.service;
88

9+
import com.powsybl.caseserver.dto.CaseInfos;
910
import com.powsybl.caseserver.elasticsearch.CaseInfosRepository;
10-
import org.slf4j.Logger;
11-
import org.slf4j.LoggerFactory;
11+
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
12+
import org.springframework.data.elasticsearch.core.IndexOperations;
13+
import org.springframework.http.HttpStatus;
1214
import org.springframework.stereotype.Service;
13-
14-
import java.util.concurrent.TimeUnit;
15-
import java.util.concurrent.atomic.AtomicReference;
15+
import org.springframework.web.server.ResponseStatusException;
1616

1717
/**
1818
* @author Jamal KHEYYAD <jamal.kheyyad at rte-international.com>
1919
*/
2020
@Service
2121
public class SupervisionService {
22-
private static final Logger LOGGER = LoggerFactory.getLogger(SupervisionService.class);
2322

2423
private final CaseInfosRepository caseInfosRepository;
24+
private final ElasticsearchOperations elasticsearchOperations;
2525

26-
public SupervisionService(CaseInfosRepository caseInfosRepository) {
26+
public SupervisionService(CaseInfosRepository caseInfosRepository, ElasticsearchOperations elasticsearchOperations) {
2727
this.caseInfosRepository = caseInfosRepository;
28-
}
29-
30-
public long deleteIndexedCases() {
31-
AtomicReference<Long> startTime = new AtomicReference<>();
32-
startTime.set(System.nanoTime());
33-
34-
long nbIndexesToDelete = getIndexedCasesCount();
35-
caseInfosRepository.deleteAll();
36-
LOGGER.trace("Indexed cases deletion : {} seconds", TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime.get()));
37-
return nbIndexesToDelete;
28+
this.elasticsearchOperations = elasticsearchOperations;
3829
}
3930

4031
public long getIndexedCasesCount() {
4132
return caseInfosRepository.count();
4233
}
34+
35+
public void recreateIndex() {
36+
IndexOperations indexOperations = elasticsearchOperations.indexOps(CaseInfos.class);
37+
boolean isDeleted = indexOperations.delete();
38+
if (!isDeleted) {
39+
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,
40+
"Failed to delete cases ElasticSearch index");
41+
}
42+
43+
boolean isCreated = indexOperations.createWithMapping();
44+
if (!isCreated) {
45+
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,
46+
"Failed to create cases ElasticSearch index");
47+
}
48+
}
4349
}

src/test/java/com/powsybl/caseserver/AbstractSupervisionControllerTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ void testReindexAll() throws Exception {
6363
importCase(true);
6464
importCase(false);
6565

66-
mockMvc.perform(delete("/v1/supervision/cases/indexation"))
66+
// recreate the index
67+
mockMvc.perform(post("/v1/supervision/cases/index"))
6768
.andExpect(status().isOk());
6869

6970
assertEquals(0, supervisionService.getIndexedCasesCount());
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/**
2+
* Copyright (c) 2025, RTE (http://www.rte-france.com)
3+
* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
*/
7+
package com.powsybl.caseserver.service;
8+
9+
import com.powsybl.caseserver.dto.CaseInfos;
10+
import com.powsybl.caseserver.elasticsearch.DisableElasticsearch;
11+
import org.junit.jupiter.api.AfterEach;
12+
import org.junit.jupiter.api.Test;
13+
import org.junit.runner.RunWith;
14+
15+
import org.springframework.beans.factory.annotation.Autowired;
16+
import org.springframework.boot.test.context.SpringBootTest;
17+
import org.springframework.boot.test.mock.mockito.MockBean;
18+
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
19+
import org.springframework.data.elasticsearch.core.IndexOperations;
20+
import org.springframework.http.HttpStatus;
21+
import org.springframework.test.context.junit4.SpringRunner;
22+
import org.springframework.web.server.ResponseStatusException;
23+
24+
import static org.junit.jupiter.api.Assertions.assertEquals;
25+
import static org.junit.jupiter.api.Assertions.assertThrows;
26+
import static org.mockito.Mockito.*;
27+
import static org.mockito.Mockito.times;
28+
29+
/**
30+
* @author Antoine Bouhours <antoine.bouhours at rte-france.com>
31+
*/
32+
@RunWith(SpringRunner.class)
33+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
34+
@DisableElasticsearch
35+
class SupervisionServiceTest {
36+
37+
@MockBean
38+
ElasticsearchOperations elasticsearchOperations;
39+
40+
@MockBean
41+
IndexOperations indexOperations;
42+
43+
@Autowired
44+
SupervisionService supervisionService;
45+
46+
@Test
47+
void recreateIndexThrowsExceptionWhenDeleteFails() {
48+
when(elasticsearchOperations.indexOps(CaseInfos.class)).thenReturn(indexOperations);
49+
when(indexOperations.delete()).thenReturn(false);
50+
51+
ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> supervisionService.recreateIndex());
52+
53+
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, exception.getStatusCode());
54+
assertEquals("Failed to delete cases ElasticSearch index", exception.getReason());
55+
verify(elasticsearchOperations, times(1)).indexOps(CaseInfos.class);
56+
verify(indexOperations, times(1)).delete();
57+
verify(indexOperations, never()).createWithMapping();
58+
}
59+
60+
@Test
61+
void recreateIndexThrowsExceptionWhenCreateFails() {
62+
when(elasticsearchOperations.indexOps(CaseInfos.class)).thenReturn(indexOperations);
63+
when(indexOperations.delete()).thenReturn(true);
64+
when(indexOperations.createWithMapping()).thenReturn(false);
65+
66+
ResponseStatusException exception = assertThrows(ResponseStatusException.class, () -> supervisionService.recreateIndex());
67+
68+
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, exception.getStatusCode());
69+
assertEquals("Failed to create cases ElasticSearch index", exception.getReason());
70+
verify(elasticsearchOperations, times(1)).indexOps(CaseInfos.class);
71+
verify(indexOperations, times(1)).delete();
72+
verify(indexOperations, times(1)).createWithMapping();
73+
}
74+
75+
@Test
76+
void recreateIndexSuccess() {
77+
when(elasticsearchOperations.indexOps(CaseInfos.class)).thenReturn(indexOperations);
78+
when(indexOperations.delete()).thenReturn(true);
79+
when(indexOperations.createWithMapping()).thenReturn(true);
80+
81+
supervisionService.recreateIndex();
82+
83+
verify(elasticsearchOperations, times(1)).indexOps(CaseInfos.class);
84+
verify(indexOperations, times(1)).delete();
85+
verify(indexOperations, times(1)).createWithMapping();
86+
}
87+
88+
@AfterEach
89+
void verifyNoMoreInteractionsMocks() {
90+
verifyNoMoreInteractions(elasticsearchOperations);
91+
verifyNoMoreInteractions(indexOperations);
92+
}
93+
}

0 commit comments

Comments
 (0)