Skip to content

Commit 77a26ce

Browse files
FACT-1688 Get Rejected Zip By Name Endpoint (#3302)
* - adds missing event to enum * - adds endpoint for getting rejected zip files by name * - adds tests for getting rejected zip files by name * - adds swagger, tidies up * - order by date desc * Adding get rejected zip by name endpoint test * removing some checkstyle errors * trying to check just the response code * trying with event 'DOC_FAILURE' * taking response print screen * removing checkstyle error * validating body event value * - changes semi colon to dot * - changes equalTo to hasItem --------- Co-authored-by: Ayisha-Sharjeel <[email protected]>
1 parent 1a4ed08 commit 77a26ce

File tree

8 files changed

+343
-1
lines changed

8 files changed

+343
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package uk.gov.hmcts.reform.bulkscanprocessor.controllers;
2+
3+
import com.azure.core.util.Context;
4+
import com.azure.storage.blob.BlobContainerClient;
5+
import com.azure.storage.blob.models.BlobItem;
6+
import com.azure.storage.blob.models.DeleteSnapshotsOptionType;
7+
import com.azure.storage.blob.models.ListBlobsOptions;
8+
import io.restassured.RestAssured;
9+
import org.junit.jupiter.api.AfterEach;
10+
import org.junit.jupiter.api.BeforeEach;
11+
import org.junit.jupiter.api.Test;
12+
13+
import java.util.ArrayList;
14+
import java.util.Arrays;
15+
import java.util.List;
16+
import java.util.concurrent.TimeUnit;
17+
18+
import static com.jayway.awaitility.Awaitility.await;
19+
import static io.restassured.RestAssured.given;
20+
import static java.util.stream.Collectors.toList;
21+
import static org.assertj.core.api.Assertions.assertThat;
22+
import static org.hamcrest.Matchers.equalTo;
23+
import static org.hamcrest.Matchers.hasItem;
24+
import static org.hamcrest.Matchers.is;
25+
import static uk.gov.hmcts.reform.bulkscanprocessor.config.TestConfiguration.SCAN_DELAY;
26+
import static uk.gov.hmcts.reform.bulkscanprocessor.config.TestConfiguration.TEST_URL;
27+
28+
public class RejectedZipByNameEndpointTest extends BaseFunctionalTest {
29+
30+
private List<String> filesToDeleteAfterTest = new ArrayList<>();
31+
32+
@BeforeEach
33+
public void setUp() throws Exception {
34+
super.setUp();
35+
}
36+
37+
@AfterEach
38+
public void tearDown() {
39+
for (String filename : filesToDeleteAfterTest) {
40+
var inBlobClient = inputContainer.getBlobClient(filename);
41+
if (inBlobClient.exists()) {
42+
inBlobClient.deleteWithResponse(DeleteSnapshotsOptionType.INCLUDE, null, null, Context.NONE);
43+
}
44+
45+
var rejBlobClient = rejectedContainer.getBlobClient(filename);
46+
47+
if (rejBlobClient.exists()) {
48+
rejBlobClient.deleteWithResponse(DeleteSnapshotsOptionType.INCLUDE, null, null, Context.NONE);
49+
}
50+
}
51+
}
52+
53+
@Test
54+
public void should_return_rejected_zip_files_by_name() {
55+
String destZipFilename = testHelper.getRandomFilename();
56+
57+
testHelper.uploadZipFile(
58+
inputContainer,
59+
Arrays.asList("1111006.pdf"),
60+
null, // missing metadata file
61+
destZipFilename
62+
);
63+
64+
filesToDeleteAfterTest.add(destZipFilename);
65+
66+
await(destZipFilename + " file should be deleted")
67+
.atMost(SCAN_DELAY + 60_000, TimeUnit.MILLISECONDS)
68+
.pollInterval(2, TimeUnit.SECONDS)
69+
.until(() -> testHelper.storageHasFile(inputContainer, destZipFilename), is(false));
70+
71+
assertThat(testHelper.storageHasFile(rejectedContainer, destZipFilename)).isTrue();
72+
assertThat(searchByName(rejectedContainer, destZipFilename)).hasSize(1);
73+
74+
given()
75+
.baseUri(TEST_URL)
76+
.relaxedHTTPSValidation()
77+
.get("/reports/rejected-zip-files/name/" + destZipFilename)
78+
.then().statusCode(200)
79+
.body("rejected_zip_files.event", hasItem("FILE_VALIDATION_FAILURE"));
80+
81+
}
82+
83+
@Test
84+
public void should_return_empty_list_if_there_is_no_rejected_zip_files() {
85+
86+
String destZipFilename = testHelper.getRandomFilename();
87+
RestAssured
88+
.given()
89+
.baseUri(TEST_URL)
90+
.relaxedHTTPSValidation()
91+
.get("/reports/rejected-zip-files/name/" + destZipFilename)
92+
.then().statusCode(200)
93+
.assertThat()
94+
.body("count", equalTo(0));
95+
96+
}
97+
98+
private List<BlobItem> searchByName(BlobContainerClient container, String fileName) {
99+
ListBlobsOptions listOptions = new ListBlobsOptions();
100+
listOptions.getDetails().setRetrieveSnapshots(true);
101+
listOptions.setPrefix(fileName);
102+
return container.listBlobs(listOptions, null, null)
103+
.stream()
104+
.collect(toList());
105+
}
106+
107+
}

src/integrationTest/java/uk/gov/hmcts/reform/bulkscanprocessor/controllers/ReportsControllerTest.java

+59
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,65 @@ void should_return_rejected_zip_files() throws Exception {
630630
));
631631
}
632632

633+
@Test
634+
void should_return_rejected_zip_files_by_name() throws Exception {
635+
UUID uuid1 = randomUUID();
636+
UUID uuid2 = randomUUID();
637+
638+
given(rejectedZipFilesService.getRejectedZipFiles("a.zip"))
639+
.willReturn(asList(
640+
new RejectedZipFileItem(
641+
"a.zip",
642+
"A",
643+
LocalDateTime.parse("2021-04-16T09:01:43.029000").toInstant(ZoneOffset.UTC),
644+
uuid1,
645+
"FILE_VALIDATION_FAILURE"
646+
),
647+
new RejectedZipFileItem(
648+
"a.zip",
649+
"A",
650+
LocalDateTime.parse("2021-04-16T09:01:44.029000").toInstant(ZoneOffset.UTC),
651+
uuid2,
652+
"DOC_SIGNATURE_FAILURE"
653+
)
654+
));
655+
656+
mockMvc
657+
.perform(get("/reports/rejected-zip-files/name/a.zip"))
658+
.andExpect(status().isOk())
659+
.andExpect(content().json(
660+
"{"
661+
+ "'count': 2,"
662+
+ "'rejected_zip_files': ["
663+
+ " {"
664+
+ " 'zip_file_name': 'a.zip',"
665+
+ " 'container': 'A',"
666+
+ " 'processing_started_date_time': '2021-04-16T09:01:43.029',"
667+
+ " 'envelope_id': '" + uuid1 + "',"
668+
+ " 'event': 'FILE_VALIDATION_FAILURE'"
669+
+ " },"
670+
+ " {"
671+
+ " 'zip_file_name': 'a.zip',"
672+
+ " 'container': 'A',"
673+
+ " 'processing_started_date_time': '2021-04-16T09:01:44.029',"
674+
+ " 'envelope_id': '" + uuid2 + "',"
675+
+ " 'event': 'DOC_SIGNATURE_FAILURE'"
676+
+ " }"
677+
+ "]"
678+
+ "}"
679+
));
680+
}
681+
682+
@Test
683+
void should_return_empty_list_if_no_rejected_zip_files_match_name() throws Exception {
684+
mockMvc
685+
.perform(get("/reports/rejected-zip-files/name/a.zip"))
686+
.andExpect(status().isOk())
687+
.andExpect(content().json(
688+
"{}"
689+
));
690+
}
691+
633692
@Test
634693
void should_return_received_scannable_items() throws Exception {
635694
given(receivedScannableItemsService.getReceivedScannableItems(LocalDate.parse("2021-04-16")))

src/integrationTest/java/uk/gov/hmcts/reform/bulkscanprocessor/entity/RejectedZipFileRepositoryTest.java

+83
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@
2222
import static java.util.Collections.emptyList;
2323
import static java.util.Collections.singletonList;
2424
import static org.assertj.core.api.Assertions.assertThat;
25+
import static org.assertj.core.api.AssertionsForClassTypes.tuple;
2526
import static uk.gov.hmcts.reform.bulkscanprocessor.model.common.Classification.EXCEPTION;
2627
import static uk.gov.hmcts.reform.bulkscanprocessor.model.common.Event.DOC_FAILURE;
28+
import static uk.gov.hmcts.reform.bulkscanprocessor.model.common.Event.DOC_SIGNATURE_FAILURE;
2729
import static uk.gov.hmcts.reform.bulkscanprocessor.model.common.Event.FILE_VALIDATION_FAILURE;
2830
import static uk.gov.hmcts.reform.bulkscanprocessor.model.common.Event.ZIPFILE_PROCESSING_STARTED;
2931

@@ -160,6 +162,87 @@ void should_return_single_result_by_date_if_envelope_exists_with_multiple_failur
160162
);
161163
}
162164

165+
@Test
166+
public void should_return_rejected_zip_files_with_matching_name() {
167+
Instant eventDate = Instant.parse("2019-02-15T14:15:23.456Z");
168+
169+
dbHasEvents(
170+
event("c2", "test2.zip", eventDate, DOC_FAILURE),
171+
event("c2", "test2.zip", eventDate, FILE_VALIDATION_FAILURE),
172+
event("c2", "test2.zip", eventDate, DOC_SIGNATURE_FAILURE),
173+
event("c2", "test3.zip", eventDate, FILE_VALIDATION_FAILURE)
174+
);
175+
176+
Envelope existingEnvelope
177+
= envelope("c2", "test2.zip", Status.COMPLETED, EXCEPTION, "ccd-id-1", "ccd-action-1", "test5");
178+
dbHasEnvelope(existingEnvelope);
179+
dbHasEnvelope(envelope("c3", "test3.zip", Status.COMPLETED, EXCEPTION, "ccd-id-1", "ccd-action-1", null));
180+
181+
List<RejectedZipFile> result = reportRepo.getRejectedZipFilesReportFor("test2.zip");
182+
183+
assertThat(result)
184+
.hasSize(3)
185+
.extracting("zipFileName", "event")
186+
.contains(tuple("test2.zip", "DOC_FAILURE"),
187+
tuple("test2.zip", "FILE_VALIDATION_FAILURE"),
188+
tuple("test2.zip", "DOC_SIGNATURE_FAILURE"))
189+
.doesNotContain(tuple("test3.zip", "FILE_VALIDATION_FAILURE"));
190+
}
191+
192+
@Test
193+
public void should_group_rejected_zip_files_with_matching_name_if_same_event_same_day() {
194+
Instant eventDate = Instant.parse("2019-02-15T14:15:23.456Z");
195+
Instant eventDate2 = Instant.parse("2019-02-16T14:15:23.456Z");
196+
dbHasEvents(
197+
event("c2", "test2.zip", eventDate, FILE_VALIDATION_FAILURE),
198+
event("c2", "test2.zip", eventDate, FILE_VALIDATION_FAILURE),
199+
event("c2", "test2.zip", eventDate2, FILE_VALIDATION_FAILURE),
200+
event("c2", "test2.zip", eventDate2, FILE_VALIDATION_FAILURE)
201+
);
202+
203+
Envelope existingEnvelope
204+
= envelope("c2", "test2.zip", Status.COMPLETED, EXCEPTION, "ccd-id-1", "ccd-action-1", "test5");
205+
dbHasEnvelope(existingEnvelope);
206+
dbHasEnvelope(envelope("c3", "test3.zip", Status.COMPLETED, EXCEPTION, "ccd-id-1", "ccd-action-1", null));
207+
208+
List<RejectedZipFile> result = reportRepo.getRejectedZipFilesReportFor("test2.zip");
209+
210+
assertThat(result)
211+
.hasSize(2)
212+
.extracting("zipFileName", "event")
213+
.contains(tuple("test2.zip", "FILE_VALIDATION_FAILURE"), tuple("test2.zip", "FILE_VALIDATION_FAILURE"));
214+
}
215+
216+
@Test
217+
public void should_not_return_rejected_zip_files_with_matching_name_if_not_failure_event() {
218+
Instant eventDate = Instant.parse("2019-02-15T14:15:23.456Z");
219+
dbHasEvents(
220+
event("c2", "test2.zip", eventDate, ZIPFILE_PROCESSING_STARTED)
221+
);
222+
Envelope existingEnvelope
223+
= envelope("c2", "test2.zip", Status.COMPLETED, EXCEPTION, "ccd-id-1", "ccd-action-1", "test5");
224+
dbHasEnvelope(existingEnvelope);
225+
226+
List<RejectedZipFile> result = reportRepo.getRejectedZipFilesReportFor("test2.zip");
227+
228+
assertThat(result).isEmpty();
229+
}
230+
231+
@Test
232+
public void should_not_return_rejected_zip_files_if_no_event_with_matching_name() {
233+
Instant eventDate = Instant.parse("2019-02-15T14:15:23.456Z");
234+
dbHasEvents(
235+
event("c2", "test2.zip", eventDate, FILE_VALIDATION_FAILURE)
236+
);
237+
Envelope existingEnvelope
238+
= envelope("c2", "test2.zip", Status.COMPLETED, EXCEPTION, "ccd-id-1", "ccd-action-1", "test5");
239+
dbHasEnvelope(existingEnvelope);
240+
241+
List<RejectedZipFile> result = reportRepo.getRejectedZipFilesReportFor("test22.zip");
242+
243+
assertThat(result).isEmpty();
244+
}
245+
163246
private void dbHasEvents(ProcessEvent... events) {
164247
eventRepo.saveAll(asList(events));
165248
}

src/main/java/uk/gov/hmcts/reform/bulkscanprocessor/controllers/ReportsController.java

+27
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package uk.gov.hmcts.reform.bulkscanprocessor.controllers;
22

33
import io.swagger.v3.oas.annotations.Operation;
4+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
45
import jakarta.validation.ClockProvider;
56
import org.springframework.format.annotation.DateTimeFormat;
67
import org.springframework.http.HttpHeaders;
78
import org.springframework.http.MediaType;
89
import org.springframework.http.ResponseEntity;
910
import org.springframework.web.bind.annotation.CrossOrigin;
1011
import org.springframework.web.bind.annotation.GetMapping;
12+
import org.springframework.web.bind.annotation.PathVariable;
1113
import org.springframework.web.bind.annotation.PostMapping;
1214
import org.springframework.web.bind.annotation.RequestBody;
1315
import org.springframework.web.bind.annotation.RequestMapping;
@@ -243,6 +245,31 @@ public RejectedZipFilesResponse getRejectedZipFiles(
243245
);
244246
}
245247

248+
/**
249+
* Retrieves rejected zip files by name.
250+
* @param name The name of the rejected zip file
251+
* @return RejectedZipFilesResponse list of rejected zip files matching given name
252+
*/
253+
@GetMapping(path = "/rejected-zip-files/name/{name}", produces = MediaType.APPLICATION_JSON_VALUE)
254+
@Operation(description = "Retrieves rejected files by name")
255+
@ApiResponse(responseCode = "200", description = "Success")
256+
public RejectedZipFilesResponse getRejectedZipFilesByName(@PathVariable String name) {
257+
List<RejectedZipFile> result = rejectedZipFilesService.getRejectedZipFiles(name);
258+
return new RejectedZipFilesResponse(
259+
result.size(),
260+
result
261+
.stream()
262+
.map(file -> new RejectedZipFileData(
263+
file.getZipFileName(),
264+
file.getContainer(),
265+
LocalDateTime.ofInstant(file.getProcessingStartedEventDate(), ZoneId.of("UTC")),
266+
file.getEnvelopeId(),
267+
file.getEvent()
268+
))
269+
.collect(toList())
270+
);
271+
}
272+
246273
/**
247274
* Retrieves reconciliation report.
248275
* @param statement The reconciliation statement

src/main/java/uk/gov/hmcts/reform/bulkscanprocessor/entity/reports/RejectedZipFileRepository.java

+24
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,28 @@ public interface RejectedZipFileRepository extends JpaRepository<Envelope, UUID>
3434
+ " envelopeId"
3535
)
3636
List<RejectedZipFile> getRejectedZipFilesReportFor(@Param("date") LocalDate date);
37+
38+
@Query(
39+
nativeQuery = true,
40+
value = "SELECT "
41+
+ " process_events.container, "
42+
+ " process_events.zipfilename, "
43+
+ " process_events.event, "
44+
+ " MIN(process_events.createdat) AS processingStartedEventDate, "
45+
+ " Cast(envelopes.id as varchar) as envelopeId "
46+
+ "FROM process_events "
47+
+ "LEFT OUTER JOIN envelopes "
48+
+ " ON envelopes.container = process_events.container "
49+
+ " AND envelopes.zipfilename = process_events.zipfilename "
50+
+ "WHERE process_events.event "
51+
+ " IN ('DOC_FAILURE', 'FILE_VALIDATION_FAILURE', 'DOC_SIGNATURE_FAILURE') "
52+
+ " AND process_events.zipfilename = :name "
53+
+ "GROUP BY process_events.container, "
54+
+ " process_events.zipfilename, "
55+
+ " process_events.event, "
56+
+ " process_events.createdat, "
57+
+ " envelopeId "
58+
+ "ORDER BY process_events.createdat DESC"
59+
)
60+
List<RejectedZipFile> getRejectedZipFilesReportFor(@Param("name") String name);
3761
}

src/main/java/uk/gov/hmcts/reform/bulkscanprocessor/model/common/Event.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@ public enum Event {
1919
COMPLETED, // the processing of the envelope completed successfully
2020
// when envelope status needs to be updated for reprocessing (used manually to set the event with reason)
2121
MANUAL_STATUS_CHANGE,
22-
MANUAL_RETRIGGER_PROCESSING
22+
MANUAL_RETRIGGER_PROCESSING,
23+
DOC_SIGNATURE_FAILURE
2324
}

src/main/java/uk/gov/hmcts/reform/bulkscanprocessor/services/reports/RejectedZipFilesService.java

+9
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,13 @@ public RejectedZipFilesService(RejectedZipFileRepository rejectedZipFileReposito
3131
public List<RejectedZipFile> getRejectedZipFiles(LocalDate date) {
3232
return rejectedZipFileRepository.getRejectedZipFilesReportFor(date);
3333
}
34+
35+
/**
36+
* Get the list of rejected zip files with a specific name.
37+
* @param name the name the rejected zip files should match
38+
* @return The list of rejected zip files
39+
*/
40+
public List<RejectedZipFile> getRejectedZipFiles(String name) {
41+
return rejectedZipFileRepository.getRejectedZipFilesReportFor(name);
42+
}
3443
}

0 commit comments

Comments
 (0)