diff --git a/backend/src/test/java/ca/bc/gov/app/TestConstants.java b/backend/src/test/java/ca/bc/gov/app/TestConstants.java index 78258e6c5d..6a0f945673 100644 --- a/backend/src/test/java/ca/bc/gov/app/TestConstants.java +++ b/backend/src/test/java/ca/bc/gov/app/TestConstants.java @@ -461,7 +461,7 @@ public class TestConstants { "requestType":"", "name":"Auric Enterprises", "clientType":"A", - "updated":" | 2023-04-19", + "updated":" | %s", "status":"Submitted" } ]"""; diff --git a/backend/src/test/java/ca/bc/gov/app/controller/client/ClientSubmissionControllerIntegrationTest.java b/backend/src/test/java/ca/bc/gov/app/controller/client/ClientSubmissionControllerIntegrationTest.java index 2a527df6b7..b4c3053522 100644 --- a/backend/src/test/java/ca/bc/gov/app/controller/client/ClientSubmissionControllerIntegrationTest.java +++ b/backend/src/test/java/ca/bc/gov/app/controller/client/ClientSubmissionControllerIntegrationTest.java @@ -19,6 +19,8 @@ import ca.bc.gov.app.utils.ClientSubmissionAggregator; import com.github.tomakehurst.wiremock.junit5.WireMockExtension; import java.net.URI; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Map; import java.util.function.Function; @@ -182,7 +184,8 @@ void shouldListAndSearch( .expectStatus().isOk() .expectBody() .json(found ? - TestConstants.SUBMISSION_LIST_CONTENT : + String.format(TestConstants.SUBMISSION_LIST_CONTENT, LocalDate.now().format( + DateTimeFormatter.ISO_DATE)) : TestConstants.SUBMISSION_LIST_CONTENT_EMPTY ); } diff --git a/frontend/.vscode/extensions.json b/frontend/.vscode/extensions.json deleted file mode 100644 index 806eacda61..0000000000 --- a/frontend/.vscode/extensions.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "recommendations": ["johnsoncodehk.volar", "johnsoncodehk.vscode-typescript-vue-plugin"] -} diff --git a/legacy/openshift.deploy.yml b/legacy/openshift.deploy.yml index 641a8bfb1b..1b3c3b6e55 100644 --- a/legacy/openshift.deploy.yml +++ b/legacy/openshift.deploy.yml @@ -70,6 +70,19 @@ objects: requests: storage: ${CERT_PVC_SIZE} storageClassName: netapp-file-standard + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + labels: + app: ${NAME}-${ZONE} + name: ${NAME}-${ZONE}-${COMPONENT}-reports + spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 125Mi + storageClassName: netapp-file-standard - apiVersion: v1 kind: DeploymentConfig metadata: @@ -102,8 +115,9 @@ objects: - name: ${NAME}-${ZONE}-certs persistentVolumeClaim: claimName: ${NAME}-${ZONE}-${COMPONENT} - - name: reports - emptyDir: { } + - name: ${NAME}-${ZONE}-reports + persistentVolumeClaim: + claimName: ${NAME}-${ZONE}-${COMPONENT}-reports initContainers: - name: ${NAME}-init image: ${REGISTRY}/bcgov/${NAME}/common:${ZONE} @@ -127,10 +141,10 @@ objects: resources: limits: cpu: ${CPU_LIMIT} - memory: 75Mi + memory: 125Mi requests: cpu: ${CPU_REQUEST} - memory: 75Mi + memory: 125Mi containers: - image: ${NAME}-${ZONE}-${COMPONENT}:${IMAGE_TAG} imagePullPolicy: Always @@ -220,7 +234,7 @@ objects: - mountPath: /cert name: ${NAME}-${ZONE}-certs - mountPath: /workspace/temp - name: reports + name: ${NAME}-${ZONE}-reports - apiVersion: v1 kind: Service metadata: diff --git a/legacy/src/main/java/ca/bc/gov/app/controller/ReportingClientController.java b/legacy/src/main/java/ca/bc/gov/app/controller/ReportingClientController.java index aeef408bf2..fce4183060 100644 --- a/legacy/src/main/java/ca/bc/gov/app/controller/ReportingClientController.java +++ b/legacy/src/main/java/ca/bc/gov/app/controller/ReportingClientController.java @@ -2,18 +2,28 @@ import ca.bc.gov.app.service.ReportingClientService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; 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 java.io.File; +import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ZeroCopyHttpOutputMessage; import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; @@ -23,42 +33,60 @@ name = "Forest Client Reporting", description = "Generate reports for the forest client" ) -@RequestMapping(value = "/api/reports", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) +@RequestMapping(value = "/api/reports") @RequiredArgsConstructor public class ReportingClientController { private final ReportingClientService service; - @GetMapping("/all") - @Operation(summary = "Get an excel report file for all existing forest clients") + @GetMapping(value = "/{id}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + @Operation(summary = "Get an excel report file") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Excel file generated successfully"), - @ApiResponse(responseCode = "500", description = "Internal server error") + @ApiResponse(responseCode = "404", description = "No report found for ID 00000000") }) - public Mono getAllClientsReport(ServerHttpResponse response) { - return - getReport( - service.generateAllClientsReport(), - response, - "All Clients" - ); + public Mono getReport( + @Parameter(name = "id", in = ParameterIn.PATH, description = "ID of the report to be downloaded") + @PathVariable String id, + ServerHttpResponse response + ) { + return getReport(service.getReportFile(id), response, id); } - @GetMapping("/businessAs") - @Operation(summary = "Get a business as excel report file") + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "List Existing Report Files") @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Excel file generated successfully"), - @ApiResponse(responseCode = "500", description = "Internal server error") + @ApiResponse( + responseCode = "200", + description = "A list of available reports", + content = @Content( + mediaType = MediaType.APPLICATION_JSON_VALUE, + array = @ArraySchema( + schema = @Schema(implementation = String.class) + ) + ) + ) }) - public Mono getBusinessAsReport(ServerHttpResponse response) { - return - getReport( - service.generateDoingBusinessAsReport(), - response, - "Business As" - ); + public Mono> listReports() { + return service.listReports().collectList(); + } + + @DeleteMapping(value = "/{id}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + @Operation(summary = "Delete an excel report file") + @ApiResponses(value = { + @ApiResponse(responseCode = "202", description = "Excel file deleted successfully"), + @ApiResponse(responseCode = "404", description = "No report found for ID 00000000") + }) + @ResponseStatus(HttpStatus.ACCEPTED) + public Mono removeReport( + @Parameter(name = "id", in = ParameterIn.PATH, description = "ID of the report to be removed") + @PathVariable String id, + ServerHttpResponse response + ) { + return service.removeReport(id); } + private Mono getReport(Mono request, ServerHttpResponse response, String fileName) { ZeroCopyHttpOutputMessage zeroCopyResponse = (ZeroCopyHttpOutputMessage) response; zeroCopyResponse.getHeaders() diff --git a/legacy/src/main/java/ca/bc/gov/app/exception/MissingReportFileException.java b/legacy/src/main/java/ca/bc/gov/app/exception/MissingReportFileException.java new file mode 100644 index 0000000000..bc9a48a0e3 --- /dev/null +++ b/legacy/src/main/java/ca/bc/gov/app/exception/MissingReportFileException.java @@ -0,0 +1,12 @@ +package ca.bc.gov.app.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.server.ResponseStatusException; + +@ResponseStatus(HttpStatus.NOT_FOUND) +public class MissingReportFileException extends ResponseStatusException { + public MissingReportFileException(String reportId) { + super(HttpStatus.NOT_FOUND, "No report found for ID " + reportId); + } +} diff --git a/legacy/src/main/java/ca/bc/gov/app/service/ReportingClientService.java b/legacy/src/main/java/ca/bc/gov/app/service/ReportingClientService.java index 5200043f72..d6bae4880e 100644 --- a/legacy/src/main/java/ca/bc/gov/app/service/ReportingClientService.java +++ b/legacy/src/main/java/ca/bc/gov/app/service/ReportingClientService.java @@ -3,14 +3,12 @@ import ca.bc.gov.app.dto.ClientPublicViewDto; import ca.bc.gov.app.dto.OrgBookTopicDto; import ca.bc.gov.app.dto.OrgBookTopicListResponse; -import ca.bc.gov.app.entity.ClientDoingBusinessAsEntity; import ca.bc.gov.app.entity.ForestClientEntity; -import ca.bc.gov.app.repository.ClientDoingBusinessAsRepository; +import ca.bc.gov.app.exception.MissingReportFileException; import ca.bc.gov.app.repository.ForestClientRepository; import ca.bc.gov.app.util.SheetWriter; import java.io.File; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -39,46 +37,92 @@ public class ReportingClientService { private final ForestClientRepository forestClientRepository; - private final ClientDoingBusinessAsRepository clientDoingBusinessAsRepository; private final WebClient orgBookApi; public ReportingClientService(ForestClientRepository forestClientRepository, - ClientDoingBusinessAsRepository clientDoingBusinessAsRepository, - @Qualifier("orgBookApi") WebClient orgBookApi) { + @Qualifier("orgBookApi") WebClient orgBookApi + ) { this.forestClientRepository = forestClientRepository; - this.clientDoingBusinessAsRepository = clientDoingBusinessAsRepository; this.orgBookApi = orgBookApi; } - public Mono generateDoingBusinessAsReport() { + /** + * Returns a {@link Mono} of {@link File} representing the report file for the given report ID. + * + * @param reportId the report ID for which to retrieve the report file + * @return a {@link Mono} of {@link File} representing the report file for the given report ID + * @throws MissingReportFileException if the report file does not exist for the given report ID + */ + public Mono getReportFile(String reportId) { - return - generateReport( - clientDoingBusinessAsRepository - //As we are streaming through the data with Flux, we will not have the entire - //dataset in memory at any given time - .findAll() - //for each entry, we will grab the data from orgbook - .flatMap(this::mapToPublicView) - ); + File sheetFile = getReportPath(reportId) + .normalize() + .toFile(); + + if (!sheetFile.exists()) { + return Mono.error(new MissingReportFileException(reportId)); + } + + return Mono.just(sheetFile); } - public Mono generateAllClientsReport() { - return - generateReport( - forestClientRepository - //As we are streaming through the data with Flux, we will not have the entire - //dataset in memory at any given time - .findAll() - //for each entry, we will grab the data from orgbook - .flatMap(this::mapToPublicView) - ); + /** + * Returns a {@link Flux} of {@link String} containing the names of reports in the report folder, + * with the ".xlsx" extension removed. + * + * @return a {@link Flux} of {@link String} containing the names of reports in the report folder + */ + public Flux listReports() { + try { + return Flux + .fromStream(Files.list(getReportFolder())) + .map(Path::getFileName) + .map(Path::toFile) + .map(File::getName) + .map(name -> name.replace(".xlsx", StringUtils.EMPTY)); + } catch (IOException exception) { + log.error("Error while cleaning temp folder", exception); + return Flux.empty(); + } } - @Scheduled(fixedDelay = 5, timeUnit = TimeUnit.MINUTES) + + public Mono removeReport(String id) { + return getReportFile(id) + .doOnNext(this::deleteReportFile) + .then(); + } + + @Scheduled(cron = "0 0 0 ? * MON-FRI") + public void generateAllClientsReport() { + generateReport( + forestClientRepository + //As we are streaming through the data with Flux, we will not have the entire + //dataset in memory at any given time + .findAll() + //for each entry, we will grab the data from orgbook + .flatMap(this::mapToPublicView) + ) + .blockOptional() + .ifPresent(reportFile -> log.info("Generated report {} now", reportFile)); + } + + @Scheduled(fixedDelay = 1, timeUnit = TimeUnit.HOURS) @SuppressWarnings({"java:S3864", "java:S4042"}) public void cleanOldReports() { + try (Stream paths = Files.list(getReportFolder())) { + paths + .peek(file -> log.info("Found report on folder with name {}", file.getFileName())) + .filter(file -> isFileOlderThan(file.toFile(), 48)) + .peek(file -> log.info("Report {} is older than 48 hours, removing it", file.getFileName())) + .forEach(path -> path.toFile().delete()); + } catch (IOException exception) { + log.error("Error while cleaning temp folder", exception); + } + } + + private Path getReportFolder() { Path sheetFolder = Paths .get("./temp/") .normalize(); @@ -90,44 +134,35 @@ public void cleanOldReports() { sheetFolder.toFile().mkdirs() ); } + return sheetFolder; + } - try (Stream paths = Files.list(sheetFolder)) { - paths - .peek(file -> log.info("Found report on folder with name {}", file.getFileName())) - .filter(file -> isFileOlderThan(file.toFile(), 5)) - .forEach(path -> path.toFile().delete()); - } catch (IOException exception) { - log.error("Error while cleaning temp folder", exception); - } - + private Path getReportPath(String reportId) { + return getReportFolder().resolve(reportId + ".xlsx"); + } + @SuppressWarnings("java:S4042") + private void deleteReportFile(File file){ + if(file.exists()) + log.info("File {} deleted {}",file,file.delete()); } - private boolean isFileOlderThan(File file, int minutesDiff) { + private boolean isFileOlderThan(File file, int hoursDiff) { return Duration .between( Instant.ofEpochMilli(file.lastModified()), Instant.now() ) - .toMinutes() > minutesDiff; + .toHours() > hoursDiff; } private Mono generateReport(Flux values) { - File sheetFile = Paths - .get("./temp/", UUID.randomUUID().toString() + ".xlsx") + File sheetFile = getReportPath(UUID.randomUUID().toString()) .normalize() .toFile(); - if (!sheetFile.getParentFile().exists()) { - log.info( - "Temporary folder for reports {} does not exist, creating {}", - sheetFile.getParentFile().getAbsolutePath(), - sheetFile.getParentFile().mkdirs() - ); - } - SheetWriter writer = new SheetWriter(sheetFile); log.debug("Generating sheet file {}", sheetFile); @@ -151,14 +186,6 @@ private Mono mapToPublicView(ForestClientEntity entity) { ); } - private Mono mapToPublicView(ClientDoingBusinessAsEntity entity) { - return loadValueFromOrgbook( - entity.getDoingBusinessAsName(), - entity.getClientNumber(), - StringUtils.EMPTY - ); - } - private Mono loadValueFromOrgbook( String clientName, String clientNumber, diff --git a/legacy/src/main/java/ca/bc/gov/app/util/HandlerUtil.java b/legacy/src/main/java/ca/bc/gov/app/util/HandlerUtil.java deleted file mode 100644 index b6d69e54ad..0000000000 --- a/legacy/src/main/java/ca/bc/gov/app/util/HandlerUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package ca.bc.gov.app.util; - -import java.util.Optional; -import java.util.function.Consumer; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; -import org.springframework.http.HttpStatus; -import org.springframework.web.reactive.function.BodyInserters; -import org.springframework.web.reactive.function.server.ServerResponse; -import org.springframework.web.server.ResponseStatusException; -import reactor.core.publisher.Mono; - -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class HandlerUtil { - - - public static Consumer handleStatusResponse() { - return t -> ServerResponse.status(t.getStatusCode()) - .body( - BodyInserters - .fromPublisher( - Mono - .justOrEmpty( - Optional - .ofNullable(t.getReason()) - ), - String.class - ) - ); - } - - public static Consumer handleError() { - return throwable -> - ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR) - .body(BodyInserters.fromValue(throwable.getMessage())); - } -} diff --git a/legacy/src/test/java/ca/bc/gov/app/endpoints/ForestClientReportingIntegrationTest.java b/legacy/src/test/java/ca/bc/gov/app/endpoints/ForestClientReportingIntegrationTest.java index fc2b35a3ec..64692f1758 100644 --- a/legacy/src/test/java/ca/bc/gov/app/endpoints/ForestClientReportingIntegrationTest.java +++ b/legacy/src/test/java/ca/bc/gov/app/endpoints/ForestClientReportingIntegrationTest.java @@ -6,15 +6,28 @@ import static com.github.tomakehurst.wiremock.client.WireMock.matching; import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import ca.bc.gov.app.TestConstants; import ca.bc.gov.app.extensions.AbstractTestContainerIntegrationTest; import ca.bc.gov.app.extensions.WiremockLogNotifier; +import ca.bc.gov.app.service.ReportingClientService; import com.github.tomakehurst.wiremock.junit5.WireMockExtension; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Optional; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.extension.RegisterExtension; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; @@ -23,12 +36,18 @@ @Slf4j @DisplayName("Integrated Test | Forest Client Reporting Controller") +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) class ForestClientReportingIntegrationTest extends AbstractTestContainerIntegrationTest { + private String reportId = null; + @Autowired protected WebTestClient client; + @Autowired + private ReportingClientService service; + @RegisterExtension static WireMockExtension wireMockExtension = WireMockExtension .newInstance() @@ -43,68 +62,161 @@ class ForestClientReportingIntegrationTest extends .build(); @BeforeAll - public static void setUp() { + public static void setUp() throws IOException { + Path tempFolder = Paths.get("./temp"); + + if(!tempFolder.toFile().exists()) + tempFolder.toFile().mkdirs(); + + Files + .list(tempFolder) + .forEach(path -> path.toFile().delete()); + + tempFolder.toFile().delete(); + wireMockExtension.resetAll(); } - @Test - @DisplayName("Generate all spreadsheet") - void shouldGenerateAllSheet() { - wireMockExtension - .stubFor( - get(urlPathEqualTo("/v4/search/topic")) - .withQueryParam("format",equalTo("json")) - .withQueryParam("inactive",equalTo("any")) - .withQueryParam("ordering",equalTo("-score")) - .withQueryParam("q",matching("^(.*)$")) - .willReturn( - aResponse() - .withBody(TestConstants.ORGBOOK_TOPIC) - .withStatus(200) - .withHeader("Content-Type",MediaType.APPLICATION_JSON_VALUE) - .withTransformers("response-template") - ) - ); + @DisplayName("List no reports available") + @Order(1) + void shouldGetNoReportsListed() throws IOException { client .get() - .uri("/api/reports/all") + .uri("/api/reports") .exchange() .expectStatus().isOk() + .expectBody() + .json("[]"); + } + + @Test + @DisplayName("Fail when getting a dummy report") + @Order(2) + void shouldFailWhenGettingReportNonExisting() { + client + .get() + .uri("/api/reports/ad8b3785-9c88-4378-aca3-ba93a4c3d3fa") + .exchange() + .expectStatus().isNotFound() .expectHeader() - .contentType(MediaType.APPLICATION_OCTET_STREAM) - .expectHeader().valueEquals(HttpHeaders.CONTENT_DISPOSITION,"attachment; filename=FC Report All Clients.xlsx"); + .contentType(MediaType.APPLICATION_JSON_VALUE) + .expectBody(String.class) + .isEqualTo("No report found for ID ad8b3785-9c88-4378-aca3-ba93a4c3d3fa"); } @Test - @DisplayName("Generate business as spreadsheet") - void shouldGenerateBusinessAsSheet() { + @DisplayName("Generate all spreadsheet") + @Order(3) + void shouldGenerateAllSheet() throws IOException { wireMockExtension .stubFor( get(urlPathEqualTo("/v4/search/topic")) - .withQueryParam("format",equalTo("json")) - .withQueryParam("inactive",equalTo("any")) - .withQueryParam("ordering",equalTo("-score")) - .withQueryParam("q",matching("^(.*)$")) + .withQueryParam("format", equalTo("json")) + .withQueryParam("inactive", equalTo("any")) + .withQueryParam("ordering", equalTo("-score")) + .withQueryParam("q", matching("^(.*)$")) .willReturn( aResponse() .withBody(TestConstants.ORGBOOK_TOPIC) .withStatus(200) - .withHeader("Content-Type",MediaType.APPLICATION_JSON_VALUE) + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) .withTransformers("response-template") ) ); + service.generateAllClientsReport(); + + assertTrue( + Files + .list(Paths.get("./temp")) + .findFirst() + .isPresent() + ); + } + + @Test + @DisplayName("List Reports available") + @Order(4) + void shouldGetListOfReports() { + client + .get() + .uri("/api/reports") + .exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$[0]").isNotEmpty() + .consumeWith(response -> persistIds(response.getResponseBody())); + + } + + + @Test + @DisplayName("Get the report") + @Order(5) + void shouldGetTheReport() throws IOException { + + Optional reportId = + Files + .list(Paths.get("./temp")) + .map(path -> path.toFile().getName()) + .map(name -> name.replace(".xlsx",StringUtils.EMPTY)) + .findFirst(); + + assertTrue(reportId.isPresent()); + client .get() - .uri("/api/reports/businessAs") + .uri("/api/reports/"+reportId.get()) .exchange() .expectStatus().isOk() .expectHeader() .contentType(MediaType.APPLICATION_OCTET_STREAM) - .expectHeader().valueEquals(HttpHeaders.CONTENT_DISPOSITION,"attachment; filename=FC Report Business As.xlsx"); + .expectHeader().valueEquals(HttpHeaders.CONTENT_DISPOSITION,"attachment; filename=FC Report "+reportId.get()+".xlsx"); + } + + @Test + @DisplayName("Remove the report") + @Order(6) + void shouldRemoveReport() throws IOException { + Optional reportId = + Files + .list(Paths.get("./temp")) + .map(path -> path.toFile().getName()) + .map(name -> name.replace(".xlsx",StringUtils.EMPTY)) + .findFirst(); + + assertTrue(reportId.isPresent()); + + client + .delete() + .uri("/api/reports/"+reportId.get()) + .exchange() + .expectStatus().isAccepted() + .expectBody() + .isEmpty(); + } + + @Test + @DisplayName("Remove the report") + @Order(7) + void shouldHaveNoReportAgain() throws IOException { + shouldGetNoReportsListed(); + } + + + private void persistIds(byte[] data) { + this.reportId = + new String(data, Charset.defaultCharset()) + .replace("[", StringUtils.EMPTY) + .replace("]", StringUtils.EMPTY) + .replace("\"", StringUtils.EMPTY); + + System.out.printf("Report Id loaded " + this.reportId); + + assertNotNull(this.reportId); } }