Skip to content

Commit

Permalink
FACT-1688 Get Rejected Zip By Name Endpoint (#3302)
Browse files Browse the repository at this point in the history
* - 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]>
  • Loading branch information
RuthKirby and Ayisha-Sharjeel authored Jul 17, 2024
1 parent 1a4ed08 commit 77a26ce
Show file tree
Hide file tree
Showing 8 changed files with 343 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package uk.gov.hmcts.reform.bulkscanprocessor.controllers;

import com.azure.core.util.Context;
import com.azure.storage.blob.BlobContainerClient;
import com.azure.storage.blob.models.BlobItem;
import com.azure.storage.blob.models.DeleteSnapshotsOptionType;
import com.azure.storage.blob.models.ListBlobsOptions;
import io.restassured.RestAssured;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.jayway.awaitility.Awaitility.await;
import static io.restassured.RestAssured.given;
import static java.util.stream.Collectors.toList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.is;
import static uk.gov.hmcts.reform.bulkscanprocessor.config.TestConfiguration.SCAN_DELAY;
import static uk.gov.hmcts.reform.bulkscanprocessor.config.TestConfiguration.TEST_URL;

public class RejectedZipByNameEndpointTest extends BaseFunctionalTest {

private List<String> filesToDeleteAfterTest = new ArrayList<>();

@BeforeEach
public void setUp() throws Exception {
super.setUp();
}

@AfterEach
public void tearDown() {
for (String filename : filesToDeleteAfterTest) {
var inBlobClient = inputContainer.getBlobClient(filename);
if (inBlobClient.exists()) {
inBlobClient.deleteWithResponse(DeleteSnapshotsOptionType.INCLUDE, null, null, Context.NONE);
}

var rejBlobClient = rejectedContainer.getBlobClient(filename);

if (rejBlobClient.exists()) {
rejBlobClient.deleteWithResponse(DeleteSnapshotsOptionType.INCLUDE, null, null, Context.NONE);
}
}
}

@Test
public void should_return_rejected_zip_files_by_name() {
String destZipFilename = testHelper.getRandomFilename();

testHelper.uploadZipFile(
inputContainer,
Arrays.asList("1111006.pdf"),
null, // missing metadata file
destZipFilename
);

filesToDeleteAfterTest.add(destZipFilename);

await(destZipFilename + " file should be deleted")
.atMost(SCAN_DELAY + 60_000, TimeUnit.MILLISECONDS)
.pollInterval(2, TimeUnit.SECONDS)
.until(() -> testHelper.storageHasFile(inputContainer, destZipFilename), is(false));

assertThat(testHelper.storageHasFile(rejectedContainer, destZipFilename)).isTrue();
assertThat(searchByName(rejectedContainer, destZipFilename)).hasSize(1);

given()
.baseUri(TEST_URL)
.relaxedHTTPSValidation()
.get("/reports/rejected-zip-files/name/" + destZipFilename)
.then().statusCode(200)
.body("rejected_zip_files.event", hasItem("FILE_VALIDATION_FAILURE"));

}

@Test
public void should_return_empty_list_if_there_is_no_rejected_zip_files() {

String destZipFilename = testHelper.getRandomFilename();
RestAssured
.given()
.baseUri(TEST_URL)
.relaxedHTTPSValidation()
.get("/reports/rejected-zip-files/name/" + destZipFilename)
.then().statusCode(200)
.assertThat()
.body("count", equalTo(0));

}

private List<BlobItem> searchByName(BlobContainerClient container, String fileName) {
ListBlobsOptions listOptions = new ListBlobsOptions();
listOptions.getDetails().setRetrieveSnapshots(true);
listOptions.setPrefix(fileName);
return container.listBlobs(listOptions, null, null)
.stream()
.collect(toList());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,65 @@ void should_return_rejected_zip_files() throws Exception {
));
}

@Test
void should_return_rejected_zip_files_by_name() throws Exception {
UUID uuid1 = randomUUID();
UUID uuid2 = randomUUID();

given(rejectedZipFilesService.getRejectedZipFiles("a.zip"))
.willReturn(asList(
new RejectedZipFileItem(
"a.zip",
"A",
LocalDateTime.parse("2021-04-16T09:01:43.029000").toInstant(ZoneOffset.UTC),
uuid1,
"FILE_VALIDATION_FAILURE"
),
new RejectedZipFileItem(
"a.zip",
"A",
LocalDateTime.parse("2021-04-16T09:01:44.029000").toInstant(ZoneOffset.UTC),
uuid2,
"DOC_SIGNATURE_FAILURE"
)
));

mockMvc
.perform(get("/reports/rejected-zip-files/name/a.zip"))
.andExpect(status().isOk())
.andExpect(content().json(
"{"
+ "'count': 2,"
+ "'rejected_zip_files': ["
+ " {"
+ " 'zip_file_name': 'a.zip',"
+ " 'container': 'A',"
+ " 'processing_started_date_time': '2021-04-16T09:01:43.029',"
+ " 'envelope_id': '" + uuid1 + "',"
+ " 'event': 'FILE_VALIDATION_FAILURE'"
+ " },"
+ " {"
+ " 'zip_file_name': 'a.zip',"
+ " 'container': 'A',"
+ " 'processing_started_date_time': '2021-04-16T09:01:44.029',"
+ " 'envelope_id': '" + uuid2 + "',"
+ " 'event': 'DOC_SIGNATURE_FAILURE'"
+ " }"
+ "]"
+ "}"
));
}

@Test
void should_return_empty_list_if_no_rejected_zip_files_match_name() throws Exception {
mockMvc
.perform(get("/reports/rejected-zip-files/name/a.zip"))
.andExpect(status().isOk())
.andExpect(content().json(
"{}"
));
}

@Test
void should_return_received_scannable_items() throws Exception {
given(receivedScannableItemsService.getReceivedScannableItems(LocalDate.parse("2021-04-16")))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.AssertionsForClassTypes.tuple;
import static uk.gov.hmcts.reform.bulkscanprocessor.model.common.Classification.EXCEPTION;
import static uk.gov.hmcts.reform.bulkscanprocessor.model.common.Event.DOC_FAILURE;
import static uk.gov.hmcts.reform.bulkscanprocessor.model.common.Event.DOC_SIGNATURE_FAILURE;
import static uk.gov.hmcts.reform.bulkscanprocessor.model.common.Event.FILE_VALIDATION_FAILURE;
import static uk.gov.hmcts.reform.bulkscanprocessor.model.common.Event.ZIPFILE_PROCESSING_STARTED;

Expand Down Expand Up @@ -160,6 +162,87 @@ void should_return_single_result_by_date_if_envelope_exists_with_multiple_failur
);
}

@Test
public void should_return_rejected_zip_files_with_matching_name() {
Instant eventDate = Instant.parse("2019-02-15T14:15:23.456Z");

dbHasEvents(
event("c2", "test2.zip", eventDate, DOC_FAILURE),
event("c2", "test2.zip", eventDate, FILE_VALIDATION_FAILURE),
event("c2", "test2.zip", eventDate, DOC_SIGNATURE_FAILURE),
event("c2", "test3.zip", eventDate, FILE_VALIDATION_FAILURE)
);

Envelope existingEnvelope
= envelope("c2", "test2.zip", Status.COMPLETED, EXCEPTION, "ccd-id-1", "ccd-action-1", "test5");
dbHasEnvelope(existingEnvelope);
dbHasEnvelope(envelope("c3", "test3.zip", Status.COMPLETED, EXCEPTION, "ccd-id-1", "ccd-action-1", null));

List<RejectedZipFile> result = reportRepo.getRejectedZipFilesReportFor("test2.zip");

assertThat(result)
.hasSize(3)
.extracting("zipFileName", "event")
.contains(tuple("test2.zip", "DOC_FAILURE"),
tuple("test2.zip", "FILE_VALIDATION_FAILURE"),
tuple("test2.zip", "DOC_SIGNATURE_FAILURE"))
.doesNotContain(tuple("test3.zip", "FILE_VALIDATION_FAILURE"));
}

@Test
public void should_group_rejected_zip_files_with_matching_name_if_same_event_same_day() {
Instant eventDate = Instant.parse("2019-02-15T14:15:23.456Z");
Instant eventDate2 = Instant.parse("2019-02-16T14:15:23.456Z");
dbHasEvents(
event("c2", "test2.zip", eventDate, FILE_VALIDATION_FAILURE),
event("c2", "test2.zip", eventDate, FILE_VALIDATION_FAILURE),
event("c2", "test2.zip", eventDate2, FILE_VALIDATION_FAILURE),
event("c2", "test2.zip", eventDate2, FILE_VALIDATION_FAILURE)
);

Envelope existingEnvelope
= envelope("c2", "test2.zip", Status.COMPLETED, EXCEPTION, "ccd-id-1", "ccd-action-1", "test5");
dbHasEnvelope(existingEnvelope);
dbHasEnvelope(envelope("c3", "test3.zip", Status.COMPLETED, EXCEPTION, "ccd-id-1", "ccd-action-1", null));

List<RejectedZipFile> result = reportRepo.getRejectedZipFilesReportFor("test2.zip");

assertThat(result)
.hasSize(2)
.extracting("zipFileName", "event")
.contains(tuple("test2.zip", "FILE_VALIDATION_FAILURE"), tuple("test2.zip", "FILE_VALIDATION_FAILURE"));
}

@Test
public void should_not_return_rejected_zip_files_with_matching_name_if_not_failure_event() {
Instant eventDate = Instant.parse("2019-02-15T14:15:23.456Z");
dbHasEvents(
event("c2", "test2.zip", eventDate, ZIPFILE_PROCESSING_STARTED)
);
Envelope existingEnvelope
= envelope("c2", "test2.zip", Status.COMPLETED, EXCEPTION, "ccd-id-1", "ccd-action-1", "test5");
dbHasEnvelope(existingEnvelope);

List<RejectedZipFile> result = reportRepo.getRejectedZipFilesReportFor("test2.zip");

assertThat(result).isEmpty();
}

@Test
public void should_not_return_rejected_zip_files_if_no_event_with_matching_name() {
Instant eventDate = Instant.parse("2019-02-15T14:15:23.456Z");
dbHasEvents(
event("c2", "test2.zip", eventDate, FILE_VALIDATION_FAILURE)
);
Envelope existingEnvelope
= envelope("c2", "test2.zip", Status.COMPLETED, EXCEPTION, "ccd-id-1", "ccd-action-1", "test5");
dbHasEnvelope(existingEnvelope);

List<RejectedZipFile> result = reportRepo.getRejectedZipFilesReportFor("test22.zip");

assertThat(result).isEmpty();
}

private void dbHasEvents(ProcessEvent... events) {
eventRepo.saveAll(asList(events));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package uk.gov.hmcts.reform.bulkscanprocessor.controllers;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.validation.ClockProvider;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
Expand Down Expand Up @@ -243,6 +245,31 @@ public RejectedZipFilesResponse getRejectedZipFiles(
);
}

/**
* Retrieves rejected zip files by name.
* @param name The name of the rejected zip file
* @return RejectedZipFilesResponse list of rejected zip files matching given name
*/
@GetMapping(path = "/rejected-zip-files/name/{name}", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(description = "Retrieves rejected files by name")
@ApiResponse(responseCode = "200", description = "Success")
public RejectedZipFilesResponse getRejectedZipFilesByName(@PathVariable String name) {
List<RejectedZipFile> result = rejectedZipFilesService.getRejectedZipFiles(name);
return new RejectedZipFilesResponse(
result.size(),
result
.stream()
.map(file -> new RejectedZipFileData(
file.getZipFileName(),
file.getContainer(),
LocalDateTime.ofInstant(file.getProcessingStartedEventDate(), ZoneId.of("UTC")),
file.getEnvelopeId(),
file.getEvent()
))
.collect(toList())
);
}

/**
* Retrieves reconciliation report.
* @param statement The reconciliation statement
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,28 @@ public interface RejectedZipFileRepository extends JpaRepository<Envelope, UUID>
+ " envelopeId"
)
List<RejectedZipFile> getRejectedZipFilesReportFor(@Param("date") LocalDate date);

@Query(
nativeQuery = true,
value = "SELECT "
+ " process_events.container, "
+ " process_events.zipfilename, "
+ " process_events.event, "
+ " MIN(process_events.createdat) AS processingStartedEventDate, "
+ " Cast(envelopes.id as varchar) as envelopeId "
+ "FROM process_events "
+ "LEFT OUTER JOIN envelopes "
+ " ON envelopes.container = process_events.container "
+ " AND envelopes.zipfilename = process_events.zipfilename "
+ "WHERE process_events.event "
+ " IN ('DOC_FAILURE', 'FILE_VALIDATION_FAILURE', 'DOC_SIGNATURE_FAILURE') "
+ " AND process_events.zipfilename = :name "
+ "GROUP BY process_events.container, "
+ " process_events.zipfilename, "
+ " process_events.event, "
+ " process_events.createdat, "
+ " envelopeId "
+ "ORDER BY process_events.createdat DESC"
)
List<RejectedZipFile> getRejectedZipFilesReportFor(@Param("name") String name);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ public enum Event {
COMPLETED, // the processing of the envelope completed successfully
// when envelope status needs to be updated for reprocessing (used manually to set the event with reason)
MANUAL_STATUS_CHANGE,
MANUAL_RETRIGGER_PROCESSING
MANUAL_RETRIGGER_PROCESSING,
DOC_SIGNATURE_FAILURE
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,13 @@ public RejectedZipFilesService(RejectedZipFileRepository rejectedZipFileReposito
public List<RejectedZipFile> getRejectedZipFiles(LocalDate date) {
return rejectedZipFileRepository.getRejectedZipFilesReportFor(date);
}

/**
* Get the list of rejected zip files with a specific name.
* @param name the name the rejected zip files should match
* @return The list of rejected zip files
*/
public List<RejectedZipFile> getRejectedZipFiles(String name) {
return rejectedZipFileRepository.getRejectedZipFilesReportFor(name);
}
}
Loading

0 comments on commit 77a26ce

Please sign in to comment.