diff --git a/charts/darts-api/Chart.yaml b/charts/darts-api/Chart.yaml index fd4ea7b9c1b..77a08148e2b 100644 --- a/charts/darts-api/Chart.yaml +++ b/charts/darts-api/Chart.yaml @@ -4,7 +4,7 @@ appVersion: "1.0" description: A Helm chart for darts-api App name: darts-api home: https://github.com/hmcts/darts-api -version: 0.0.114 +version: 0.0.115 maintainers: - name: HMCTS darts team dependencies: diff --git a/charts/darts-api/values.dev.template.yaml b/charts/darts-api/values.dev.template.yaml index 03b27f581c4..501d2c2c01e 100644 --- a/charts/darts-api/values.dev.template.yaml +++ b/charts/darts-api/values.dev.template.yaml @@ -135,6 +135,7 @@ java: SHEDLOCK_LOG_LEVEL: INFO ARM_RPO_TOTAL_CATCHUP_HOURS: 5 ARM_RPO_TOTAL_CATCHUP_MAX_HOURS_ENDING_POINT: 50 + ARM_DOWN_FOR_MAINTENANCE: false secrets: DARTS_API_DB_PASSWORD: secretRef: "postgres" @@ -168,6 +169,7 @@ darts-portal: DARTS_AZUREAD_B2C_ORIGIN_HOST: https://hmctsstgextid.b2clogin.com DARTS_AZUREAD_B2C_HOSTNAME: https://darts.staging.apps.hmcts.net MANUAL_DELETION_ENABLED: true + ARM_DOWN_FOR_MAINTENANCE: false darts-gateway: enabled: ${DEV_ENABLE_DARTS_GATEWAY} @@ -340,6 +342,7 @@ function: ENABLE_ARM_V5_2_UPGRADE: true ARM_RPO_TOTAL_CATCHUP_HOURS: 5 ARM_RPO_TOTAL_CATCHUP_MAX_HOURS_ENDING_POINT: 50 + ARM_DOWN_FOR_MAINTENANCE: false secrets: DARTS_API_DB_PASSWORD: diff --git a/charts/darts-api/values.yaml b/charts/darts-api/values.yaml index d7a597bf0fa..76ad27d5636 100644 --- a/charts/darts-api/values.yaml +++ b/charts/darts-api/values.yaml @@ -131,6 +131,7 @@ java: SHEDLOCK_LOG_LEVEL: INFO ARM_RPO_TOTAL_CATCHUP_HOURS: 5 ARM_RPO_TOTAL_CATCHUP_MAX_HOURS_ENDING_POINT: 50 + ARM_DOWN_FOR_MAINTENANCE: false function: scaleType: Job @@ -256,6 +257,7 @@ function: ARM_RPO_FEATURE_FLAG_LOGS_ENABLED: false DETS_TO_ARM_PUSH_FEATURE_FLAG_LOGS_ENABLED: false ARM_PULL_FEATURE_FLAG_LOGS_ENABLED: false + ARM_DOWN_FOR_MAINTENANCE: false secrets: DARTS_API_DB_CONNECTION_STRING: secretRef: darts-api-function-values diff --git a/src/main/java/uk/gov/hmcts/darts/annotation/service/impl/AnnotationDataManagement.java b/src/main/java/uk/gov/hmcts/darts/annotation/service/impl/AnnotationDataManagement.java index 67ce3d410a0..2ff2a3238e5 100644 --- a/src/main/java/uk/gov/hmcts/darts/annotation/service/impl/AnnotationDataManagement.java +++ b/src/main/java/uk/gov/hmcts/darts/annotation/service/impl/AnnotationDataManagement.java @@ -5,6 +5,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.core.io.Resource; import org.springframework.stereotype.Service; +import uk.gov.hmcts.darts.arm.exception.ArmDownForMaintenanceException; import uk.gov.hmcts.darts.common.datamanagement.api.DataManagementFacade; import uk.gov.hmcts.darts.common.datamanagement.component.impl.DownloadResponseMetaData; import uk.gov.hmcts.darts.common.entity.ExternalObjectDirectoryEntity; @@ -20,6 +21,7 @@ import static uk.gov.hmcts.darts.annotation.errors.AnnotationApiError.FAILED_TO_DOWNLOAD_ANNOTATION_DOCUMENT; import static uk.gov.hmcts.darts.annotation.errors.AnnotationApiError.FAILED_TO_UPLOAD_ANNOTATION_DOCUMENT; +import static uk.gov.hmcts.darts.arm.enums.ArmApiError.ARM_DOWN_FOR_MAINTENANCE; import static uk.gov.hmcts.darts.common.enums.ExternalLocationTypeEnum.INBOUND; import static uk.gov.hmcts.darts.common.enums.ExternalLocationTypeEnum.UNSTRUCTURED; @@ -58,6 +60,10 @@ public Resource download(List externalObjectDirec DownloadResponseMetaData downloadResponseMetaData = dataManagementFacade.retrieveFileFromStorage(externalObjectDirectoryEntities); return downloadResponseMetaData.getResource(); + } catch (ArmDownForMaintenanceException e) { + log.error("ARM is down for maintenance, failed to download annotation document {}", + externalObjectDirectoryEntities.getFirst().getAnnotationDocumentEntity().getId(), e); + throw new DartsApiException(ARM_DOWN_FOR_MAINTENANCE, e); } catch (IOException | FileNotDownloadedException e) { log.error("Failed to download annotation document {}", externalObjectDirectoryEntities.getFirst().getAnnotationDocumentEntity().getId(), e); diff --git a/src/main/java/uk/gov/hmcts/darts/arm/enums/ArmApiError.java b/src/main/java/uk/gov/hmcts/darts/arm/enums/ArmApiError.java new file mode 100644 index 00000000000..9cda743d470 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/darts/arm/enums/ArmApiError.java @@ -0,0 +1,32 @@ +package uk.gov.hmcts.darts.arm.enums; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import uk.gov.hmcts.darts.common.exception.DartsApiError; +import uk.gov.hmcts.darts.common.model.ArmErrorCode; +import uk.gov.hmcts.darts.common.model.ArmTitleErrors; + +@Getter +@RequiredArgsConstructor +@SuppressWarnings("java:S6548") +public enum ArmApiError implements DartsApiError { + + ARM_DOWN_FOR_MAINTENANCE( + ArmErrorCode.ARM_DOWN_FOR_MAINTENTANCE.getValue(), + HttpStatus.SERVICE_UNAVAILABLE, + ArmTitleErrors.ARM_DOWN_FOR_MAINTENTANCE.getValue() + ); + + private static final String ERROR_TYPE_PREFIX = "ARM"; + + private final String errorTypeNumeric; + private final HttpStatus httpStatus; + private final String title; + + @Override + public String getErrorTypePrefix() { + return ERROR_TYPE_PREFIX; + } + +} diff --git a/src/main/java/uk/gov/hmcts/darts/arm/exception/ArmDownForMaintenanceException.java b/src/main/java/uk/gov/hmcts/darts/arm/exception/ArmDownForMaintenanceException.java new file mode 100644 index 00000000000..6b4c5d64339 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/darts/arm/exception/ArmDownForMaintenanceException.java @@ -0,0 +1,9 @@ +package uk.gov.hmcts.darts.arm.exception; + +public class ArmDownForMaintenanceException extends Exception { + + public ArmDownForMaintenanceException(String message) { + super(message); + } + +} \ No newline at end of file diff --git a/src/main/java/uk/gov/hmcts/darts/audio/service/AudioTransformationService.java b/src/main/java/uk/gov/hmcts/darts/audio/service/AudioTransformationService.java index cb9f2bd811c..a7055b7d9b4 100644 --- a/src/main/java/uk/gov/hmcts/darts/audio/service/AudioTransformationService.java +++ b/src/main/java/uk/gov/hmcts/darts/audio/service/AudioTransformationService.java @@ -1,5 +1,6 @@ package uk.gov.hmcts.darts.audio.service; +import uk.gov.hmcts.darts.arm.exception.ArmDownForMaintenanceException; import uk.gov.hmcts.darts.common.entity.MediaEntity; import java.io.IOException; @@ -18,7 +19,7 @@ List filterMediaByMediaRequestTimeframeAndSortByStartTimeAndChannel OffsetDateTime startTime, OffsetDateTime endTime); - Path retrieveFromStorageAndSaveToTempWorkspace(MediaEntity mediaEntity) throws IOException; + Path retrieveFromStorageAndSaveToTempWorkspace(MediaEntity mediaEntity) throws IOException, ArmDownForMaintenanceException; void handleKedaInvocationForMediaRequests(); diff --git a/src/main/java/uk/gov/hmcts/darts/audio/service/impl/AudioServiceImpl.java b/src/main/java/uk/gov/hmcts/darts/audio/service/impl/AudioServiceImpl.java index 506451d36a6..637f68f6080 100644 --- a/src/main/java/uk/gov/hmcts/darts/audio/service/impl/AudioServiceImpl.java +++ b/src/main/java/uk/gov/hmcts/darts/audio/service/impl/AudioServiceImpl.java @@ -4,6 +4,8 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import uk.gov.hmcts.darts.arm.enums.ArmApiError; +import uk.gov.hmcts.darts.arm.exception.ArmDownForMaintenanceException; import uk.gov.hmcts.darts.audio.component.AudioBeingProcessedFromArchiveQuery; import uk.gov.hmcts.darts.audio.exception.AudioApiError; import uk.gov.hmcts.darts.audio.model.AudioBeingProcessedFromArchiveQueryResult; @@ -71,6 +73,9 @@ public BinaryData encode(Long mediaId) { Path encodedAudioPath = encodedAudioFileInfo.getPath(); mediaBinaryData = fileOperationService.convertFileToBinaryData(encodedAudioPath.toFile().getAbsolutePath()); + + } catch (ArmDownForMaintenanceException e) { + throw new DartsApiException(ArmApiError.ARM_DOWN_FOR_MAINTENANCE, e); } catch (InterruptedException exception) { Thread.currentThread().interrupt(); throw new DartsApiException(AudioApiError.FAILED_TO_PROCESS_AUDIO_REQUEST, exception); diff --git a/src/main/java/uk/gov/hmcts/darts/audio/service/impl/AudioTransformationServiceImpl.java b/src/main/java/uk/gov/hmcts/darts/audio/service/impl/AudioTransformationServiceImpl.java index 5fe3afcd8ec..7e0ff9f904b 100644 --- a/src/main/java/uk/gov/hmcts/darts/audio/service/impl/AudioTransformationServiceImpl.java +++ b/src/main/java/uk/gov/hmcts/darts/audio/service/impl/AudioTransformationServiceImpl.java @@ -9,6 +9,7 @@ import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import uk.gov.hmcts.darts.arm.exception.ArmDownForMaintenanceException; import uk.gov.hmcts.darts.arm.service.ExternalObjectDirectoryService; import uk.gov.hmcts.darts.audio.component.OutboundFileProcessor; import uk.gov.hmcts.darts.audio.component.OutboundFileZipGenerator; @@ -17,7 +18,6 @@ import uk.gov.hmcts.darts.audio.enums.AudioRequestOutputFormat; import uk.gov.hmcts.darts.audio.exception.AudioApiError; import uk.gov.hmcts.darts.audio.helper.TransformedMediaHelper; -import uk.gov.hmcts.darts.audio.helper.UnstructuredDataHelper; import uk.gov.hmcts.darts.audio.model.AudioFileInfo; import uk.gov.hmcts.darts.audio.service.AudioTransformationService; import uk.gov.hmcts.darts.audio.service.MediaRequestService; @@ -71,17 +71,12 @@ public class AudioTransformationServiceImpl implements AudioTransformationServic private final OutboundFileZipGenerator outboundFileZipGenerator; private final FileOperationService fileOperationService; private final MediaRepository mediaRepository; - private final ExternalObjectDirectoryService eodService; - private final TransformedMediaHelper transformedMediaHelper; - private final LogApi logApi; private final DataManagementFacade dataManagementFacade; - private final UnstructuredDataHelper unstructuredDataHelper; private final CurrentTimeHelper currentTimeHelper; private final AudioTransformationServiceProperties config; private final ProcessMediaRequestsForKeda processMediaRequestsForKeda; private final MediaRequestService mediaRequestService; - private static final Comparator MEDIA_START_TIME_CHANNEL_COMPARATOR = (media1, media2) -> { if (media1.getStart().equals(media2.getStart())) { return media1.getChannel().compareTo(media2.getChannel()); @@ -134,7 +129,6 @@ public static class ProcessMediaRequestsForKeda { private final LogApi logApi; private AudioTransformationServiceImpl audioTransformationService; - /** * For all audio related to a given AudioRequest, download, transform and upload the processed file to outbound * storage. @@ -238,7 +232,6 @@ public void processAudioRequest(Integer requestId) { } } - @Override public List filterMediaByMediaRequestTimeframeAndSortByStartTimeAndChannel(List mediaEntitiesForRequest, OffsetDateTime startTime, @@ -256,7 +249,7 @@ public List filterMediaByMediaRequestTimeframeAndSortByStartTimeAnd } private Map downloadAndSaveMediaToWorkspace(List mediaEntitiesForRequest) - throws IOException { + throws IOException, ArmDownForMaintenanceException { Map downloadedMedias = new LinkedHashMap<>(); for (MediaEntity mediaEntity : mediaEntitiesForRequest) { Path downloadPath = retrieveFromStorageAndSaveToTempWorkspace(mediaEntity); @@ -268,7 +261,7 @@ private Map downloadAndSaveMediaToWorkspace(List @Override @SuppressWarnings({"PMD.AvoidThrowingRawExceptionTypes"}) - public Path retrieveFromStorageAndSaveToTempWorkspace(MediaEntity mediaEntity) throws IOException { + public Path retrieveFromStorageAndSaveToTempWorkspace(MediaEntity mediaEntity) throws IOException, ArmDownForMaintenanceException { try (DownloadResponseMetaData downloadResponseMetaData = dataManagementFacade.retrieveFileFromStorage(mediaEntity)) { String id = downloadResponseMetaData.getEodEntity().getExternalLocation(); diff --git a/src/main/java/uk/gov/hmcts/darts/common/datamanagement/api/DataManagementFacade.java b/src/main/java/uk/gov/hmcts/darts/common/datamanagement/api/DataManagementFacade.java index 7ede0522c6a..fde5f6dae27 100644 --- a/src/main/java/uk/gov/hmcts/darts/common/datamanagement/api/DataManagementFacade.java +++ b/src/main/java/uk/gov/hmcts/darts/common/datamanagement/api/DataManagementFacade.java @@ -1,5 +1,6 @@ package uk.gov.hmcts.darts.common.datamanagement.api; +import uk.gov.hmcts.darts.arm.exception.ArmDownForMaintenanceException; import uk.gov.hmcts.darts.common.datamanagement.component.impl.DownloadResponseMetaData; import uk.gov.hmcts.darts.common.entity.AnnotationDocumentEntity; import uk.gov.hmcts.darts.common.entity.ExternalObjectDirectoryEntity; @@ -17,11 +18,14 @@ */ public interface DataManagementFacade { - DownloadResponseMetaData retrieveFileFromStorage(MediaEntity mediaEntity) throws FileNotDownloadedException; + DownloadResponseMetaData retrieveFileFromStorage(MediaEntity mediaEntity) throws FileNotDownloadedException, ArmDownForMaintenanceException; - DownloadResponseMetaData retrieveFileFromStorage(TranscriptionDocumentEntity transcriptionDocumentEntity) throws FileNotDownloadedException; + DownloadResponseMetaData retrieveFileFromStorage( + TranscriptionDocumentEntity transcriptionDocumentEntity) throws FileNotDownloadedException, ArmDownForMaintenanceException; - DownloadResponseMetaData retrieveFileFromStorage(AnnotationDocumentEntity annotationDocumentEntity) throws FileNotDownloadedException; + DownloadResponseMetaData retrieveFileFromStorage( + AnnotationDocumentEntity annotationDocumentEntity) throws FileNotDownloadedException, ArmDownForMaintenanceException; - DownloadResponseMetaData retrieveFileFromStorage(List eodEntities) throws FileNotDownloadedException; + DownloadResponseMetaData retrieveFileFromStorage( + List eodEntities) throws FileNotDownloadedException, ArmDownForMaintenanceException; } \ No newline at end of file diff --git a/src/main/java/uk/gov/hmcts/darts/common/datamanagement/api/DataManagementFacadeImpl.java b/src/main/java/uk/gov/hmcts/darts/common/datamanagement/api/DataManagementFacadeImpl.java index 51a1c38f28c..5e1150d3be8 100644 --- a/src/main/java/uk/gov/hmcts/darts/common/datamanagement/api/DataManagementFacadeImpl.java +++ b/src/main/java/uk/gov/hmcts/darts/common/datamanagement/api/DataManagementFacadeImpl.java @@ -6,6 +6,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.io.FileUtils; import org.springframework.stereotype.Service; +import uk.gov.hmcts.darts.arm.exception.ArmDownForMaintenanceException; import uk.gov.hmcts.darts.arm.service.ArmApiService; import uk.gov.hmcts.darts.audio.helper.UnstructuredDataHelper; import uk.gov.hmcts.darts.common.datamanagement.component.impl.DownloadResponseMetaData; @@ -35,8 +36,10 @@ import java.util.Optional; import java.util.UUID; +import static java.lang.Boolean.TRUE; import static java.util.Objects.nonNull; import static uk.gov.hmcts.darts.common.datamanagement.enums.DatastoreContainerType.ARM; +import static uk.gov.hmcts.darts.common.datamanagement.enums.DatastoreContainerType.UNSTRUCTURED; import static uk.gov.hmcts.darts.common.enums.ObjectRecordStatusEnum.STORED; @Slf4j @@ -58,7 +61,8 @@ public class DataManagementFacadeImpl implements DataManagementFacade { private final ObjectRetrievalQueueRepository objectRetrievalQueueRepository; @Override - public DownloadResponseMetaData retrieveFileFromStorage(MediaEntity mediaEntity) throws FileNotDownloadedException { + public DownloadResponseMetaData retrieveFileFromStorage(MediaEntity mediaEntity) + throws FileNotDownloadedException, ArmDownForMaintenanceException { ObjectRecordStatusEntity storedStatus = objectRecordStatusRepository.getReferenceById(STORED.getId()); List storedEodEntities = externalObjectDirectoryRepository.findByEntityAndStatus(mediaEntity, storedStatus); if (CollectionUtils.isEmpty(storedEodEntities)) { @@ -82,7 +86,8 @@ public DownloadResponseMetaData retrieveFileFromStorage(MediaEntity mediaEntity) } @Override - public DownloadResponseMetaData retrieveFileFromStorage(TranscriptionDocumentEntity transcriptionDocumentEntity) throws FileNotDownloadedException { + public DownloadResponseMetaData retrieveFileFromStorage(TranscriptionDocumentEntity transcriptionDocumentEntity) + throws FileNotDownloadedException, ArmDownForMaintenanceException { ObjectRecordStatusEntity storedStatus = objectRecordStatusRepository.getReferenceById(STORED.getId()); List storedEodEntities = externalObjectDirectoryRepository.findByEntityAndStatus(transcriptionDocumentEntity, storedStatus); @@ -108,7 +113,8 @@ public DownloadResponseMetaData retrieveFileFromStorage(TranscriptionDocumentEnt } @Override - public DownloadResponseMetaData retrieveFileFromStorage(AnnotationDocumentEntity annotationDocumentEntity) throws FileNotDownloadedException { + public DownloadResponseMetaData retrieveFileFromStorage( + AnnotationDocumentEntity annotationDocumentEntity) throws FileNotDownloadedException, ArmDownForMaintenanceException { ObjectRecordStatusEntity storedStatus = objectRecordStatusRepository.getReferenceById(STORED.getId()); List storedEodEntities = externalObjectDirectoryRepository.findByEntityAndStatus(annotationDocumentEntity, storedStatus); if (CollectionUtils.isEmpty(storedEodEntities)) { @@ -125,7 +131,8 @@ public DownloadResponseMetaData retrieveFileFromStorage(AnnotationDocumentEntity } @Override - public DownloadResponseMetaData retrieveFileFromStorage(List eodEntities) throws FileNotDownloadedException { + public DownloadResponseMetaData retrieveFileFromStorage( + List eodEntities) throws FileNotDownloadedException, ArmDownForMaintenanceException { if (CollectionUtils.isEmpty(eodEntities)) { log.error("Supplied list of EodEntities is empty"); throw new FileNotDownloadedException("Supplied list of EodEntities is empty"); @@ -160,10 +167,12 @@ private DownloadResponseMetaData retrieveFileFromStorage(DatastoreContainerType } /** - * Loop through each storage type in order to see if it has a matched EodEntity, and if it does, try to download the file from there, if it fails, + * Loop through each storage type in order to see if it has a matched EodEntity, and if it does, try to download the file from there. If it fails, * move to the next one, if they all fail then throw a FileNotDownloadedException. */ - private DownloadResponseMetaData getDataFromStorage(List storedEodEntities) throws FileNotDownloadedException { + @SuppressWarnings("PMD.CyclomaticComplexity") + private DownloadResponseMetaData getDataFromStorage( + List storedEodEntities) throws FileNotDownloadedException, ArmDownForMaintenanceException { List storageOrder = storageOrderHelper.getStorageOrder(); StringBuilder logBuilder = new StringBuilder(134) .append("Starting to search for files with ") @@ -182,7 +191,11 @@ private DownloadResponseMetaData getDataFromStorage(List container = getSupportedContainer(datastoreContainerType); diff --git a/src/main/java/uk/gov/hmcts/darts/datamanagement/config/DataManagementConfiguration.java b/src/main/java/uk/gov/hmcts/darts/datamanagement/config/DataManagementConfiguration.java index ae9bd275654..ce6d26ff9ff 100644 --- a/src/main/java/uk/gov/hmcts/darts/datamanagement/config/DataManagementConfiguration.java +++ b/src/main/java/uk/gov/hmcts/darts/datamanagement/config/DataManagementConfiguration.java @@ -60,6 +60,9 @@ public class DataManagementConfiguration extends StorageConfiguration { @Value("${darts.storage.blob.az-copy-output-level}") private String azCopyOutputLevel; + @Value("${darts.storage.blob.arm-down-for-maintenance}") + private Boolean armDownForMaintenance; + @Override @Value("${darts.storage.blob.temp-blob-workspace}") public void setTempBlobWorkspace(String tempBlobWorkspace) { diff --git a/src/main/java/uk/gov/hmcts/darts/transcriptions/service/impl/TranscriptionDownloader.java b/src/main/java/uk/gov/hmcts/darts/transcriptions/service/impl/TranscriptionDownloader.java index fcea5162ca9..a34ecfc97ad 100644 --- a/src/main/java/uk/gov/hmcts/darts/transcriptions/service/impl/TranscriptionDownloader.java +++ b/src/main/java/uk/gov/hmcts/darts/transcriptions/service/impl/TranscriptionDownloader.java @@ -4,6 +4,8 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.core.io.Resource; import org.springframework.stereotype.Service; +import uk.gov.hmcts.darts.arm.enums.ArmApiError; +import uk.gov.hmcts.darts.arm.exception.ArmDownForMaintenanceException; import uk.gov.hmcts.darts.audit.api.AuditApi; import uk.gov.hmcts.darts.authorisation.component.UserIdentity; import uk.gov.hmcts.darts.common.datamanagement.api.DataManagementFacade; @@ -68,6 +70,8 @@ private Resource getResourceStreamFor(TranscriptionDocumentEntity latestTranscri try { DownloadResponseMetaData downloadResponseMetaData = dataManagementFacade.retrieveFileFromStorage(latestTranscriptionDocument); return downloadResponseMetaData.getResource(); + } catch (ArmDownForMaintenanceException e) { + throw new DartsApiException(ArmApiError.ARM_DOWN_FOR_MAINTENANCE, e); } catch (IOException | FileNotDownloadedException ex) { log.error("Failed to download transcript file using latestTranscriptionDocument ID {}", latestTranscriptionDocument.getId(), diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 8d80369db95..0a64ed94071 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -269,6 +269,7 @@ darts: url: ${ARM_URL} arm-service-entitlement: ${ARM_SERVICE_ENTITLEMENT:} arm-storage-account-name: ${ARM_STORAGE_ACCOUNT_NAME:} + arm-down-for-maintenance: ${ARM_DOWN_FOR_MAINTENANCE:false} authentication-url: token-path: /auth/account/token @@ -350,6 +351,7 @@ darts: az-copy-preserve-access-tier: "--s2s-preserve-access-tier=false" az-copy-log-level: ${AZCOPY_LOG_LEVEL:} az-copy-output-level: ${AZCOPY_OUTPUT_LEVEL:} + arm-down-for-maintenance: ${ARM_DOWN_FOR_MAINTENANCE:false} search: order: "UNSTRUCTURED,DETS,ARM,VODAFONE" case-document: diff --git a/src/main/resources/openapi/common.yaml b/src/main/resources/openapi/common.yaml index 47d5f14f68e..ad1f5121a3b 100644 --- a/src/main/resources/openapi/common.yaml +++ b/src/main/resources/openapi/common.yaml @@ -189,6 +189,18 @@ components: - "Invalid cron expression" x-enum-varnames: [ FAILED_TO_FIND_AUTOMATED_TASK, INVALID_CRON_EXPRESSION ] + ArmErrorCode: + type: string + enum: + - "ARM_DOWN_FOR_MAINTENTANCE_100" + x-enum-varnames: [ ARM_DOWN_FOR_MAINTENTANCE ] + + ArmTitleErrors: + type: string + enum: + - "ARM is down for maintenance" + x-enum-varnames: [ ARM_DOWN_FOR_MAINTENTANCE ] + CommonErrorCode: type: string enum: diff --git a/src/test/java/uk/gov/hmcts/darts/annotation/service/impl/AnnotationDataManagementTest.java b/src/test/java/uk/gov/hmcts/darts/annotation/service/impl/AnnotationDataManagementTest.java index cabab182d26..a2e700ca79c 100644 --- a/src/test/java/uk/gov/hmcts/darts/annotation/service/impl/AnnotationDataManagementTest.java +++ b/src/test/java/uk/gov/hmcts/darts/annotation/service/impl/AnnotationDataManagementTest.java @@ -6,8 +6,8 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import uk.gov.hmcts.darts.arm.exception.ArmDownForMaintenanceException; import uk.gov.hmcts.darts.common.datamanagement.api.DataManagementFacade; -import uk.gov.hmcts.darts.common.datamanagement.component.impl.DownloadResponseMetaData; import uk.gov.hmcts.darts.common.datamanagement.component.impl.FileBasedDownloadResponseMetaData; import uk.gov.hmcts.darts.common.entity.AnnotationDocumentEntity; import uk.gov.hmcts.darts.common.entity.ExternalObjectDirectoryEntity; @@ -35,6 +35,7 @@ import static org.mockito.Mockito.when; import static uk.gov.hmcts.darts.annotation.errors.AnnotationApiError.FAILED_TO_DOWNLOAD_ANNOTATION_DOCUMENT; import static uk.gov.hmcts.darts.annotation.errors.AnnotationApiError.FAILED_TO_UPLOAD_ANNOTATION_DOCUMENT; +import static uk.gov.hmcts.darts.arm.enums.ArmApiError.ARM_DOWN_FOR_MAINTENANCE; import static uk.gov.hmcts.darts.common.enums.ExternalLocationTypeEnum.INBOUND; import static uk.gov.hmcts.darts.common.enums.ExternalLocationTypeEnum.UNSTRUCTURED; @@ -45,8 +46,6 @@ class AnnotationDataManagementTest { private DataManagementApi dataManagementApi; @Mock private DataManagementFacade dataManagementFacade; - @Mock - private DownloadResponseMetaData downloadResponseMetaData; private AnnotationDataManagement annotationDataManagement; @@ -56,7 +55,7 @@ void setUp() { } @Test - void throwsWhenSavingToInboundContainerFails() { + void upload_throwsWhenSavingToInboundContainerFails() { var binaryData = BinaryData.fromBytes("some-binary-data".getBytes()); when(dataManagementApi.saveBlobDataToInboundContainer(binaryData)).thenThrow(new RuntimeException()); @@ -68,7 +67,7 @@ void throwsWhenSavingToInboundContainerFails() { } @Test - void throwsAndAttemptsToDeleteFromInboundContainerWhenSavingToUnstructuredContainerFails() throws AzureDeleteBlobException { + void upload_throwsAndAttemptsToDeleteFromInboundContainerWhenSavingToUnstructuredContainerFails() throws AzureDeleteBlobException { var binaryData = BinaryData.fromBytes("some-binary-data".getBytes()); var inboundLocationUuid = UUID.randomUUID().toString(); when(dataManagementApi.saveBlobDataToInboundContainer(binaryData)).thenReturn(inboundLocationUuid); @@ -83,7 +82,7 @@ void throwsAndAttemptsToDeleteFromInboundContainerWhenSavingToUnstructuredContai } @Test - void returnsContainerLocationsWhenUploadSucceeds() { + void upload_returnsContainerLocationsWhenUploadSucceeds() { var binaryData = BinaryData.fromBytes("some-binary-data".getBytes()); var inboundLocationUuid = UUID.randomUUID().toString(); var unstructuredLocationUuid = UUID.randomUUID().toString(); @@ -97,7 +96,7 @@ void returnsContainerLocationsWhenUploadSucceeds() { } @Test - void deletesFromCorrectContainer() throws AzureDeleteBlobException { + void attemptToDeleteDocuments_deletesFromCorrectContainer() throws AzureDeleteBlobException { var inboundLocation = UUID.randomUUID().toString(); var unstructuredLocation = UUID.randomUUID().toString(); annotationDataManagement.attemptToDeleteDocuments(Map.of( @@ -110,7 +109,7 @@ void deletesFromCorrectContainer() throws AzureDeleteBlobException { } @Test - void throwsWhenDeleteFails() throws AzureDeleteBlobException { + void retrieveFileFromStorage_throwsWhenDeleteFails() throws AzureDeleteBlobException { var externalLocationUuid = UUID.randomUUID().toString(); doThrow(new AzureDeleteBlobException("some-message")).when(dataManagementApi).deleteBlobDataFromInboundContainer(externalLocationUuid); @@ -120,7 +119,7 @@ void throwsWhenDeleteFails() throws AzureDeleteBlobException { } @Test - void throwsIfDownloadAnnotationDocumentResponseFails() throws FileNotDownloadedException { + void retrieveFileFromStorage_throwsIfDownloadAnnotationDocumentResponseFails() throws FileNotDownloadedException, ArmDownForMaintenanceException { when(dataManagementFacade.retrieveFileFromStorage(anyList())).thenThrow(new FileNotDownloadedException()); assertThatThrownBy(() -> annotationDataManagement.download(Arrays.asList(someExternalObjectDirectoryEntity()))) .isInstanceOf(DartsApiException.class) @@ -129,7 +128,8 @@ void throwsIfDownloadAnnotationDocumentResponseFails() throws FileNotDownloadedE @Test @SuppressWarnings("PMD.CloseResource") - void throwsIfDownloadAnnotationDocumentInputStreamFails() throws FileNotDownloadedException, IOException { + void retrieveFileFromStorage_throwsIfDownloadAnnotationDocumentInputStreamFails() + throws FileNotDownloadedException, IOException, ArmDownForMaintenanceException { var mockFileBasedDownloadResponseMetaData = mock(FileBasedDownloadResponseMetaData.class); when(dataManagementFacade.retrieveFileFromStorage(anyList())).thenReturn(mockFileBasedDownloadResponseMetaData); @@ -141,6 +141,19 @@ void throwsIfDownloadAnnotationDocumentInputStreamFails() throws FileNotDownload .hasFieldOrPropertyWithValue("error", FAILED_TO_DOWNLOAD_ANNOTATION_DOCUMENT); } + @Test + void retrieveFileFromStorage_throwsWhenArmDownForMaintenance() throws FileNotDownloadedException, ArmDownForMaintenanceException { + when(dataManagementFacade.retrieveFileFromStorage(anyList())) + .thenThrow(new ArmDownForMaintenanceException("ARM down")); + + ExternalObjectDirectoryEntity externalObjectDirectoryEntity = someExternalObjectDirectoryEntity(); + externalObjectDirectoryEntity.getAnnotationDocumentEntity().setId(12L); + + assertThatThrownBy(() -> annotationDataManagement.download(List.of(externalObjectDirectoryEntity))) + .isInstanceOf(DartsApiException.class) + .hasFieldOrPropertyWithValue("error", ARM_DOWN_FOR_MAINTENANCE); + } + private ExternalObjectDirectoryEntity someExternalObjectDirectoryEntity() { ExternalObjectDirectoryEntity externalObjectDirectoryEntity = new ExternalObjectDirectoryEntity(); externalObjectDirectoryEntity.setId(1L); diff --git a/src/test/java/uk/gov/hmcts/darts/audio/helper/UnstructuredDataHelperTest.java b/src/test/java/uk/gov/hmcts/darts/audio/helper/UnstructuredDataHelperTest.java new file mode 100644 index 00000000000..a9d9e6959e8 --- /dev/null +++ b/src/test/java/uk/gov/hmcts/darts/audio/helper/UnstructuredDataHelperTest.java @@ -0,0 +1,144 @@ +package uk.gov.hmcts.darts.audio.helper; + +import com.azure.core.util.BinaryData; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import uk.gov.hmcts.darts.common.entity.ExternalLocationTypeEntity; +import uk.gov.hmcts.darts.common.entity.ExternalObjectDirectoryEntity; +import uk.gov.hmcts.darts.common.entity.MediaEntity; +import uk.gov.hmcts.darts.common.entity.ObjectRecordStatusEntity; +import uk.gov.hmcts.darts.common.entity.UserAccountEntity; +import uk.gov.hmcts.darts.common.enums.ExternalLocationTypeEnum; +import uk.gov.hmcts.darts.common.enums.ObjectRecordStatusEnum; +import uk.gov.hmcts.darts.common.enums.SystemUsersEnum; +import uk.gov.hmcts.darts.common.repository.ExternalLocationTypeRepository; +import uk.gov.hmcts.darts.common.repository.ExternalObjectDirectoryRepository; +import uk.gov.hmcts.darts.common.repository.ObjectRecordStatusRepository; +import uk.gov.hmcts.darts.common.repository.UserAccountRepository; +import uk.gov.hmcts.darts.datamanagement.config.DataManagementConfiguration; +import uk.gov.hmcts.darts.datamanagement.model.BlobClientUploadResponseImpl; +import uk.gov.hmcts.darts.datamanagement.service.DataManagementService; + +import java.io.InputStream; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class UnstructuredDataHelperTest { + + @Mock + private ExternalObjectDirectoryRepository externalObjectDirectoryRepository; + @Mock + private ObjectRecordStatusRepository objectRecordStatusRepository; + @Mock + private ExternalLocationTypeRepository externalLocationTypeRepository; + @Mock + private UserAccountRepository userAccountRepository; + @Mock + private DataManagementService dataManagementService; + @Mock + private DataManagementConfiguration dataManagementConfiguration; + @Mock + private BlobClientUploadResponseImpl blobClientUploadResponseImpl; + + private UnstructuredDataHelper unstructuredDataHelper; + + @BeforeEach + void setUp() { + unstructuredDataHelper = new UnstructuredDataHelper( + externalObjectDirectoryRepository, + objectRecordStatusRepository, + externalLocationTypeRepository, + userAccountRepository, + dataManagementService, + dataManagementConfiguration + ); + } + + @Test + void createUnstructuredDataFromEod_shouldCreateAndDeleteRecords() { + when(dataManagementConfiguration.getUnstructuredContainerName()).thenReturn("unstructured"); + when(dataManagementService.saveBlobData(anyString(), any(InputStream.class))).thenReturn(blobClientUploadResponseImpl); + when(blobClientUploadResponseImpl.getBlobName()).thenReturn("blob-id"); + + ObjectRecordStatusEntity storedStatus = new ObjectRecordStatusEntity(); + storedStatus.setId(ObjectRecordStatusEnum.STORED.getId()); + when(objectRecordStatusRepository.getReferenceById(ObjectRecordStatusEnum.STORED.getId())).thenReturn(storedStatus); + + ExternalLocationTypeEntity unstructuredType = new ExternalLocationTypeEntity(); + unstructuredType.setId(ExternalLocationTypeEnum.UNSTRUCTURED.getId()); + when(externalLocationTypeRepository.getReferenceById(ExternalLocationTypeEnum.UNSTRUCTURED.getId())).thenReturn(unstructuredType); + + UserAccountEntity systemUser = new UserAccountEntity(); + systemUser.setId(SystemUsersEnum.DEFAULT.getId()); + when(userAccountRepository.getReferenceById(SystemUsersEnum.DEFAULT.getId())).thenReturn(systemUser); + + MediaEntity mediaEntity = new MediaEntity(); + ExternalObjectDirectoryEntity eodEntity = new ExternalObjectDirectoryEntity(); + eodEntity.setMedia(mediaEntity); + ExternalObjectDirectoryEntity eodEntityToDelete = new ExternalObjectDirectoryEntity(); + eodEntityToDelete.setMedia(mediaEntity); + + BinaryData data = BinaryData.fromString("Test String"); + + boolean created = unstructuredDataHelper.createUnstructuredDataFromEod( + eodEntityToDelete, + eodEntity, + data.toStream() + ); + + assertTrue(created); + verify(externalObjectDirectoryRepository).save(any(ExternalObjectDirectoryEntity.class)); + verify(externalObjectDirectoryRepository).delete(eq(eodEntityToDelete)); + } + + @Test + void createUnstructuredDataFromEod_whenUploadThrows_shouldReturnFalseAndSkipDbUpdates() { + when(dataManagementConfiguration.getUnstructuredContainerName()).thenReturn("unstructured"); + when(dataManagementService.saveBlobData(anyString(), any(InputStream.class))) + .thenThrow(new RuntimeException("upload failed")); + + ExternalObjectDirectoryEntity eodEntity = new ExternalObjectDirectoryEntity(); + ExternalObjectDirectoryEntity eodEntityToDelete = new ExternalObjectDirectoryEntity(); + + boolean created = unstructuredDataHelper.createUnstructuredDataFromEod( + eodEntityToDelete, + eodEntity, + BinaryData.fromString("Test String").toStream() + ); + + assertFalse(created); + verify(externalObjectDirectoryRepository, never()).save(any(ExternalObjectDirectoryEntity.class)); + verify(externalObjectDirectoryRepository, never()).delete(any(ExternalObjectDirectoryEntity.class)); + } + + @Test + void createUnstructuredDataFromEod_whenBlobNameMissing_shouldReturnFalse() { + when(dataManagementConfiguration.getUnstructuredContainerName()).thenReturn("unstructured"); + when(dataManagementService.saveBlobData(anyString(), any(InputStream.class))).thenReturn(blobClientUploadResponseImpl); + when(blobClientUploadResponseImpl.getBlobName()).thenReturn(null); + + ExternalObjectDirectoryEntity eodEntity = new ExternalObjectDirectoryEntity(); + ExternalObjectDirectoryEntity eodEntityToDelete = new ExternalObjectDirectoryEntity(); + + boolean created = unstructuredDataHelper.createUnstructuredDataFromEod( + eodEntityToDelete, + eodEntity, + BinaryData.fromString("Test String").toStream() + ); + + assertFalse(created); + verify(externalObjectDirectoryRepository, never()).save(any(ExternalObjectDirectoryEntity.class)); + verify(externalObjectDirectoryRepository, never()).delete(any(ExternalObjectDirectoryEntity.class)); + } +} \ No newline at end of file diff --git a/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AudioServiceImplTest.java b/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AudioServiceImplTest.java index f49222e188c..ba8cbf270d7 100644 --- a/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AudioServiceImplTest.java +++ b/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AudioServiceImplTest.java @@ -7,6 +7,8 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import uk.gov.hmcts.darts.arm.enums.ArmApiError; +import uk.gov.hmcts.darts.arm.exception.ArmDownForMaintenanceException; import uk.gov.hmcts.darts.audio.component.AudioBeingProcessedFromArchiveQuery; import uk.gov.hmcts.darts.audio.model.AudioBeingProcessedFromArchiveQueryResult; import uk.gov.hmcts.darts.audio.model.AudioMetadata; @@ -14,6 +16,7 @@ import uk.gov.hmcts.darts.audio.service.AudioService; import uk.gov.hmcts.darts.audio.service.AudioTransformationService; import uk.gov.hmcts.darts.common.entity.MediaEntity; +import uk.gov.hmcts.darts.common.exception.DartsApiException; import uk.gov.hmcts.darts.common.repository.ExternalObjectDirectoryRepository; import uk.gov.hmcts.darts.common.repository.MediaRepository; import uk.gov.hmcts.darts.common.service.FileOperationService; @@ -21,8 +24,10 @@ import java.util.Collections; import java.util.List; +import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; @@ -192,4 +197,19 @@ void getMediaEntitiesByHearingAndLowestChannel_singleChannelGroupReturn_shouldRe .containsExactlyInAnyOrder(media1, media2); verify(mediaRepository).findAllByHearingIdAndMinimumChannelAndIsCurrentTrue(HEARING_ID); } -} \ No newline at end of file + + @Test + void encode_whenArmDownForMaintenance_shouldThrowDartsApiException() throws Exception { + MediaEntity mediaEntity = new MediaEntity(); + mediaEntity.setId(11L); + when(mediaRepository.findById(mediaEntity.getId())).thenReturn(Optional.of(mediaEntity)); + + when(audioTransformationService.retrieveFromStorageAndSaveToTempWorkspace(mediaEntity)) + .thenThrow(new ArmDownForMaintenanceException("ARM down")); + + assertThatThrownBy(() -> audioService.encode(mediaEntity.getId())) + .isExactlyInstanceOf(DartsApiException.class) + .hasFieldOrPropertyWithValue("error", ArmApiError.ARM_DOWN_FOR_MAINTENANCE); + } +} + diff --git a/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AudioTransformationServiceImplTest.java b/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AudioTransformationServiceImplTest.java index d75ce3867f4..a7c7f5db376 100644 --- a/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AudioTransformationServiceImplTest.java +++ b/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AudioTransformationServiceImplTest.java @@ -164,10 +164,6 @@ void beforeEach() { mock(), mediaRepository, mock(), - transformedMediaHelper, - mock(), - mock(), - mock(), currentTimeHelper, mock(), processMediaRequestsForKeda, diff --git a/src/test/java/uk/gov/hmcts/darts/common/datamanagement/api/DataManagementFacadeImplTest.java b/src/test/java/uk/gov/hmcts/darts/common/datamanagement/api/DataManagementFacadeImplTest.java index 1b948bb8e76..4e12208e457 100644 --- a/src/test/java/uk/gov/hmcts/darts/common/datamanagement/api/DataManagementFacadeImplTest.java +++ b/src/test/java/uk/gov/hmcts/darts/common/datamanagement/api/DataManagementFacadeImplTest.java @@ -15,6 +15,7 @@ import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.core.io.Resource; +import uk.gov.hmcts.darts.arm.exception.ArmDownForMaintenanceException; import uk.gov.hmcts.darts.arm.service.impl.ArmApiServiceImpl; import uk.gov.hmcts.darts.audio.helper.UnstructuredDataHelper; import uk.gov.hmcts.darts.common.datamanagement.component.impl.DownloadResponseMetaData; @@ -39,7 +40,6 @@ import uk.gov.hmcts.darts.common.repository.UserAccountRepository; import uk.gov.hmcts.darts.datamanagement.config.DataManagementConfiguration; import uk.gov.hmcts.darts.datamanagement.exception.FileNotDownloadedException; -import uk.gov.hmcts.darts.datamanagement.model.BlobClientUploadResponseImpl; import uk.gov.hmcts.darts.datamanagement.service.DataManagementService; import uk.gov.hmcts.darts.test.common.FileStore; @@ -54,7 +54,6 @@ import java.util.Arrays; import java.util.List; import java.util.Optional; -import java.util.UUID; import java.util.stream.Stream; import static java.nio.charset.StandardCharsets.UTF_8; @@ -67,9 +66,9 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; @@ -81,9 +80,10 @@ @Slf4j class DataManagementFacadeImplTest { - private static final String SOME_TEMP_WORKSPACE = "some/temp/workspace"; private static final String DOWNLOAD_RESPONSE_META_DATA = "DownloadResponseMetaData: {}"; + private String tempWorkspace; + @Mock private ExternalObjectDirectoryRepository externalObjectDirectoryRepository; @Mock @@ -106,22 +106,22 @@ class DataManagementFacadeImplTest { private ObjectRetrievalQueueRepository objectRetrievalQueueRepository; @Mock private DownloadResponseMetaData downloadResponseMetaDataMock; - @Mock - private BlobClientUploadResponseImpl blobClientUploadResponseImpl; private ExternalLocationTypeEntity inboundLocationEntity; private ExternalLocationTypeEntity unstructuredLocationEntity; private ExternalLocationTypeEntity detsLocationEntity; private ExternalLocationTypeEntity armLocationEntity; - FileBasedDownloadResponseMetaData fileBasedDownloadResponseMetaData = new FileBasedDownloadResponseMetaData(); - DownloadResponseMetaData downloadResponseMetaData = new FileBasedDownloadResponseMetaData(); + private final FileBasedDownloadResponseMetaData fileBasedDownloadResponseMetaData = new FileBasedDownloadResponseMetaData(); + private DownloadResponseMetaData downloadResponseMetaData = new FileBasedDownloadResponseMetaData(); + @TempDir private File tempDirectory; @SneakyThrows @BeforeEach void setup() { - Files.createDirectories(Paths.get(SOME_TEMP_WORKSPACE)); + tempWorkspace = tempDirectory.toPath().resolve("workspace").toString(); + Files.createDirectories(Paths.get(tempWorkspace)); List datastoreOrder = new ArrayList<>(); datastoreOrder.add(DatastoreContainerType.UNSTRUCTURED); datastoreOrder.add(DatastoreContainerType.DETS); @@ -156,7 +156,7 @@ void setup() { lenient().when(objectRecordStatusRepository.getReferenceById(anyInt())).thenReturn(storedStatus); - lenient().when(dataManagementConfiguration.getTempBlobWorkspace()).thenReturn("/tmp"); + lenient().when(dataManagementConfiguration.getTempBlobWorkspace()).thenReturn(tempWorkspace); lenient().when(resource.getInputStream()).thenReturn(toInputStream("testInputStream", UTF_8)); lenient().when(downloadResponseMetaDataMock.getResource()).thenReturn(resource); lenient().when(downloadResponseMetaDataMock.getContainerTypeUsedToDownload()).thenReturn(DatastoreContainerType.ARM); @@ -169,14 +169,14 @@ public void teardown() throws IOException { downloadResponseMetaData.close(); FileStore.getFileStore().remove(); - FileUtils.cleanDirectory(new File(SOME_TEMP_WORKSPACE)); + FileUtils.deleteQuietly(new File(tempWorkspace)); try (Stream files = Files.list(tempDirectory.toPath())) { assertEquals(0, files.count()); } } @Test - void testDownloadOfFacadeWithArm() throws Exception { + void retrieveFileFromStorage_shouldDownloadFacadeWithArm() throws Exception { final List blobContainerDownloadables = new ArrayList<>(); @@ -194,18 +194,20 @@ void testDownloadOfFacadeWithArm() throws Exception { when(armApiService.downloadArmData(arm.getExternalRecordId(), arm.getExternalFileId())).thenReturn(downloadResponseMetaDataMock); // execute the code - final DataManagementFacadeImpl dmFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, - objectRecordStatusRepository, storageOrderHelper, unstructuredDataHelperTest, - dataManagementConfiguration, armApiService, objectRetrievalQueueRepository); + final DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, + unstructuredDataHelperTest, + dataManagementConfiguration, armApiService, + objectRetrievalQueueRepository); // make the assertion on the response - try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dmFacade.retrieveFileFromStorage(entitiesToDownload)) { + try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dataManagementFacade.retrieveFileFromStorage(entitiesToDownload)) { assertEquals(DatastoreContainerType.ARM, downloadResponseMetaDataAutoClose.getContainerTypeUsedToDownload()); } } @Test - void testDownloadOfFacadeWithUnstructured() throws Exception { + void retrieveFileFromStorage_shouldDownloadFacadeWithUnstructured() throws Exception { final List blobContainerDownloadables = new ArrayList<>(); BlobContainerDownloadable downloadable = mock(BlobContainerDownloadable.class); @@ -218,18 +220,20 @@ void testDownloadOfFacadeWithUnstructured() throws Exception { List entitiesToDownload = List.of(dets); // execute the code - final DataManagementFacadeImpl dmFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, - objectRecordStatusRepository, storageOrderHelper, unstructuredDataHelper, - dataManagementConfiguration, armApiService, objectRetrievalQueueRepository); + final DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, + unstructuredDataHelper, + dataManagementConfiguration, armApiService, + objectRetrievalQueueRepository); // make the assertion on the response - try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dmFacade.retrieveFileFromStorage(entitiesToDownload)) { + try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dataManagementFacade.retrieveFileFromStorage(entitiesToDownload)) { assertEquals(DatastoreContainerType.UNSTRUCTURED, downloadResponseMetaDataAutoClose.getContainerTypeUsedToDownload()); } } @Test - void testThrowErrorNoStoredEodEntities() { + void retrieveFileFromStorage_shouldThrowError_WhenNoStoredEodEntities() { final List blobContainerDownloadables = new ArrayList<>(); BlobContainerDownloadable downloadable = mock(BlobContainerDownloadable.class); @@ -241,15 +245,17 @@ void testThrowErrorNoStoredEodEntities() { List entitiesToDownload = List.of(dets); // execute the code - final DataManagementFacadeImpl dmFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, - objectRecordStatusRepository, storageOrderHelper, unstructuredDataHelper, - dataManagementConfiguration, armApiService, objectRetrievalQueueRepository); + final DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, + unstructuredDataHelper, + dataManagementConfiguration, armApiService, + objectRetrievalQueueRepository); // make the assertion on the response var exception = assertThrows( FileNotDownloadedException.class, () -> { - try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dmFacade.retrieveFileFromStorage(entitiesToDownload)) { + try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dataManagementFacade.retrieveFileFromStorage(entitiesToDownload)) { // add for try close with resources log.info(DOWNLOAD_RESPONSE_META_DATA, downloadResponseMetaDataAutoClose); } @@ -260,7 +266,7 @@ void testThrowErrorNoStoredEodEntities() { } @Test - void testDownloadOfFacadeWithDetsEnabled() throws Exception { + void downloadOfFacadeWithDetsEnabled() throws Exception { final List blobContainerDownloadables = new ArrayList<>(); BlobContainerDownloadable downloadable = mock(BlobContainerDownloadable.class); @@ -273,18 +279,20 @@ void testDownloadOfFacadeWithDetsEnabled() throws Exception { List entitiesToDownload = List.of(dets); // execute the code - final DataManagementFacadeImpl dmFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, - objectRecordStatusRepository, storageOrderHelper, unstructuredDataHelper, - dataManagementConfiguration, armApiService, objectRetrievalQueueRepository); + final DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, + unstructuredDataHelper, + dataManagementConfiguration, armApiService, + objectRetrievalQueueRepository); // make the assertion on the response - try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dmFacade.retrieveFileFromStorage(entitiesToDownload)) { + try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dataManagementFacade.retrieveFileFromStorage(entitiesToDownload)) { assertEquals(DatastoreContainerType.DETS, downloadResponseMetaDataAutoClose.getContainerTypeUsedToDownload()); } } @Test - void testDownloadOfFacadeWithNoneProcessed() throws Exception { + void downloadOfFacadeWithNoneProcessed() throws Exception { final List blobContainerDownloadables = new ArrayList<>(); blobContainerDownloadables.add(setupDownloadableContainer(DatastoreContainerType.INBOUND, false)); @@ -298,15 +306,17 @@ void testDownloadOfFacadeWithNoneProcessed() throws Exception { List entitiesToDownload = List.of(inboundEntity); // execute the code - final DataManagementFacadeImpl dmFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, - objectRecordStatusRepository, storageOrderHelper, unstructuredDataHelper, - dataManagementConfiguration, armApiService, objectRetrievalQueueRepository); + final DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, + unstructuredDataHelper, + dataManagementConfiguration, armApiService, + objectRetrievalQueueRepository); // make the assertion on the response var exception = assertThrows( FileNotDownloadedException.class, () -> { - try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dmFacade.retrieveFileFromStorage(entitiesToDownload)) { + try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dataManagementFacade.retrieveFileFromStorage(entitiesToDownload)) { // add for try close with resources log.info(DOWNLOAD_RESPONSE_META_DATA, downloadResponseMetaDataAutoClose); } @@ -317,7 +327,7 @@ void testDownloadOfFacadeWithNoneProcessed() throws Exception { } @Test - void testDownloadOfFacadeWithUnstructuredAndArmProcessedInPriorityOrder() throws Exception { + void downloadOfFacadeWithUnstructuredAndArmProcessedInPriorityOrder() throws Exception { final List blobContainerDownloadables = new ArrayList<>(); blobContainerDownloadables.add(setupDownloadableContainer(DatastoreContainerType.ARM, false)); @@ -331,15 +341,17 @@ void testDownloadOfFacadeWithUnstructuredAndArmProcessedInPriorityOrder() throws when(armApiService.downloadArmData(any(), any())).thenThrow(FileNotDownloadedException.class); // execute the code - final DataManagementFacadeImpl dmFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, - objectRecordStatusRepository, storageOrderHelper, unstructuredDataHelper, - dataManagementConfiguration, armApiService, objectRetrievalQueueRepository); + final DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, + unstructuredDataHelper, + dataManagementConfiguration, armApiService, + objectRetrievalQueueRepository); // make the assertion on the response var exception = assertThrows( FileNotDownloadedException.class, () -> { - try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dmFacade.retrieveFileFromStorage(entitiesToDownload)) { + try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dataManagementFacade.retrieveFileFromStorage(entitiesToDownload)) { // add for try close with resources log.info(DOWNLOAD_RESPONSE_META_DATA, downloadResponseMetaDataAutoClose); } @@ -357,15 +369,17 @@ void retrieveFileFromStorageListEmpty() throws Exception { List entitiesToDownload = new ArrayList<>(); // execute the code - final DataManagementFacadeImpl dmFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, - objectRecordStatusRepository, storageOrderHelper, unstructuredDataHelper, - dataManagementConfiguration, armApiService, objectRetrievalQueueRepository); + final DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, + unstructuredDataHelper, + dataManagementConfiguration, armApiService, + objectRetrievalQueueRepository); // make the assertion on the response var exception = assertThrows( FileNotDownloadedException.class, () -> { - try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dmFacade.retrieveFileFromStorage(entitiesToDownload)) { + try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dataManagementFacade.retrieveFileFromStorage(entitiesToDownload)) { // add for try close with resources log.info(DOWNLOAD_RESPONSE_META_DATA, downloadResponseMetaDataAutoClose); } @@ -385,15 +399,17 @@ void retrieveFileFromStorageMediaEmpty() throws Exception { mediaEntity.setContentObjectId("2"); mediaEntity.setClipId("clip-id"); // execute the code - final DataManagementFacadeImpl dmFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, - objectRecordStatusRepository, storageOrderHelper, unstructuredDataHelper, - dataManagementConfiguration, armApiService, objectRetrievalQueueRepository); + final DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, + unstructuredDataHelper, + dataManagementConfiguration, armApiService, + objectRetrievalQueueRepository); // make the assertion on the response var exception = assertThrows( FileNotDownloadedException.class, () -> { - try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dmFacade.retrieveFileFromStorage(mediaEntity)) { + try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dataManagementFacade.retrieveFileFromStorage(mediaEntity)) { // add for try close with resources log.info(DOWNLOAD_RESPONSE_META_DATA, downloadResponseMetaDataAutoClose); } @@ -417,9 +433,11 @@ void duplicateObjectRetrievalQueueNotAddedWhenRetrieveFileFromStorageMediaEmpty( ObjectRetrievalQueueEntity objectRetrievalQueueEntity = new ObjectRetrievalQueueEntity(); // execute the code - final DataManagementFacadeImpl dmFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, - objectRecordStatusRepository, storageOrderHelper, unstructuredDataHelper, - dataManagementConfiguration, armApiService, objectRetrievalQueueRepository); + final DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, + unstructuredDataHelper, + dataManagementConfiguration, armApiService, + objectRetrievalQueueRepository); when(objectRetrievalQueueRepository.findMatchingObjectRetrievalQueueItem(mediaEntity, null, @@ -431,7 +449,7 @@ void duplicateObjectRetrievalQueueNotAddedWhenRetrieveFileFromStorageMediaEmpty( var exception = assertThrows( FileNotDownloadedException.class, () -> { - try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dmFacade.retrieveFileFromStorage(mediaEntity)) { + try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dataManagementFacade.retrieveFileFromStorage(mediaEntity)) { // add for try close with resources log.info(DOWNLOAD_RESPONSE_META_DATA, downloadResponseMetaDataAutoClose); } @@ -457,15 +475,17 @@ void insertMediaEntityInObjectRetrievalQueueWhenNotFoundIn() { ObjectRetrievalQueueEntity objectRetrievalQueueEntity = createObjectRetrievalQueueEntity(mediaEntity, userAccount); // execute the code - final DataManagementFacadeImpl dmFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, - objectRecordStatusRepository, storageOrderHelper, unstructuredDataHelper, - dataManagementConfiguration, armApiService, objectRetrievalQueueRepository); + final DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, + unstructuredDataHelper, + dataManagementConfiguration, armApiService, + objectRetrievalQueueRepository); // make the assertion on the response assertThrows( FileNotDownloadedException.class, () -> { - try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dmFacade.retrieveFileFromStorage(mediaEntity)) { + try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dataManagementFacade.retrieveFileFromStorage(mediaEntity)) { // add for try close with resources log.info(DOWNLOAD_RESPONSE_META_DATA, downloadResponseMetaDataAutoClose); } @@ -475,17 +495,6 @@ void insertMediaEntityInObjectRetrievalQueueWhenNotFoundIn() { verify(objectRetrievalQueueRepository, times(1)).saveAndFlush(objectRetrievalQueueEntity); } - private static @NotNull ObjectRetrievalQueueEntity createObjectRetrievalQueueEntity(MediaEntity mediaEntity, UserAccountEntity userAccount) { - ObjectRetrievalQueueEntity objectRetrievalQueueEntity = new ObjectRetrievalQueueEntity(); - objectRetrievalQueueEntity.setMedia(mediaEntity); - objectRetrievalQueueEntity.setCreatedBy(userAccount); - objectRetrievalQueueEntity.setLastModifiedBy(userAccount); - objectRetrievalQueueEntity.setParentObjectId(String.valueOf(mediaEntity.getId())); - objectRetrievalQueueEntity.setContentObjectId(mediaEntity.getContentObjectId()); - objectRetrievalQueueEntity.setClipId(mediaEntity.getClipId()); - return objectRetrievalQueueEntity; - } - @Test void insertTranscriptionEntityInObjectRetrievalQueueWhenNotFoundIn() { final List blobContainerDownloadables = new ArrayList<>(); @@ -497,15 +506,17 @@ void insertTranscriptionEntityInObjectRetrievalQueueWhenNotFoundIn() { userAccount); // execute the code - final DataManagementFacadeImpl dmFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, - objectRecordStatusRepository, storageOrderHelper, unstructuredDataHelper, - dataManagementConfiguration, armApiService, objectRetrievalQueueRepository); + final DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, + unstructuredDataHelper, + dataManagementConfiguration, armApiService, + objectRetrievalQueueRepository); // make the assertion on the response assertThrows( FileNotDownloadedException.class, () -> { - try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dmFacade.retrieveFileFromStorage(transcriptionDocumentEntity)) { + try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dataManagementFacade.retrieveFileFromStorage(transcriptionDocumentEntity)) { // add for try close with resources log.info(DOWNLOAD_RESPONSE_META_DATA, downloadResponseMetaDataAutoClose); } @@ -552,14 +563,16 @@ void retrieveFileFromStorageMediaFail() throws Exception { when(externalObjectDirectoryRepository.findByEntityAndStatus(any(MediaEntity.class), any(ObjectRecordStatusEntity.class))) .thenReturn(List.of(inboundEntity)); // execute the code - final DataManagementFacadeImpl dmFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, - objectRecordStatusRepository, storageOrderHelper, unstructuredDataHelper, - dataManagementConfiguration, armApiService, objectRetrievalQueueRepository); + final DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, + unstructuredDataHelper, + dataManagementConfiguration, armApiService, + objectRetrievalQueueRepository); assertThrows( FileNotDownloadedException.class, () -> { - try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dmFacade.retrieveFileFromStorage(mediaEntity)) { + try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dataManagementFacade.retrieveFileFromStorage(mediaEntity)) { // add for try close with resources log.info(DOWNLOAD_RESPONSE_META_DATA, downloadResponseMetaDataAutoClose); } @@ -580,15 +593,17 @@ void retrieveFileFromStorageTranscriptionEmpty() throws Exception { transcriptionDocumentEntity.setClipId("clip-id"); // execute the code - final DataManagementFacadeImpl dmFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, - objectRecordStatusRepository, storageOrderHelper, unstructuredDataHelper, - dataManagementConfiguration, armApiService, objectRetrievalQueueRepository); + final DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, + unstructuredDataHelper, + dataManagementConfiguration, armApiService, + objectRetrievalQueueRepository); // make the assertion on the response var exception = assertThrows( FileNotDownloadedException.class, () -> { - try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dmFacade.retrieveFileFromStorage(transcriptionDocumentEntity)) { + try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dataManagementFacade.retrieveFileFromStorage(transcriptionDocumentEntity)) { // add for try close with resources log.info(DOWNLOAD_RESPONSE_META_DATA, downloadResponseMetaDataAutoClose); } @@ -610,14 +625,16 @@ void retrieveFileFromStorageTranscriptionFail() throws Exception { when(externalObjectDirectoryRepository.findByEntityAndStatus(any(TranscriptionDocumentEntity.class), any(ObjectRecordStatusEntity.class))) .thenReturn(List.of(inboundEntity)); // execute the code - final DataManagementFacadeImpl dmFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, - objectRecordStatusRepository, storageOrderHelper, unstructuredDataHelper, - dataManagementConfiguration, armApiService, objectRetrievalQueueRepository); + final DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, + unstructuredDataHelper, + dataManagementConfiguration, armApiService, + objectRetrievalQueueRepository); assertThrows( FileNotDownloadedException.class, () -> { - try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dmFacade.retrieveFileFromStorage(transcriptionDocumentEntity)) { + try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dataManagementFacade.retrieveFileFromStorage(transcriptionDocumentEntity)) { // add for try close with resources log.info(DOWNLOAD_RESPONSE_META_DATA, downloadResponseMetaDataAutoClose); } @@ -634,15 +651,17 @@ void retrieveFileFromStorageAnnotationDocumentEmpty() throws Exception { AnnotationDocumentEntity annotationDocumentEntity = new AnnotationDocumentEntity(); // execute the code - final DataManagementFacadeImpl dmFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, - objectRecordStatusRepository, storageOrderHelper, unstructuredDataHelper, - dataManagementConfiguration, armApiService, objectRetrievalQueueRepository); + final DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, + unstructuredDataHelper, + dataManagementConfiguration, armApiService, + objectRetrievalQueueRepository); // make the assertion on the response var exception = assertThrows( FileNotDownloadedException.class, () -> { - try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dmFacade.retrieveFileFromStorage(annotationDocumentEntity)) { + try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dataManagementFacade.retrieveFileFromStorage(annotationDocumentEntity)) { // add for try close with resources log.info(DOWNLOAD_RESPONSE_META_DATA, downloadResponseMetaDataAutoClose); } @@ -664,14 +683,16 @@ void retrieveFileFromStorageAnnotationFail() throws Exception { when(externalObjectDirectoryRepository.findByEntityAndStatus(any(AnnotationDocumentEntity.class), any(ObjectRecordStatusEntity.class))) .thenReturn(List.of(inboundEntity)); // execute the code - final DataManagementFacadeImpl dmFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, - objectRecordStatusRepository, storageOrderHelper, unstructuredDataHelper, - dataManagementConfiguration, armApiService, objectRetrievalQueueRepository); + final DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, + unstructuredDataHelper, + dataManagementConfiguration, armApiService, + objectRetrievalQueueRepository); assertThrows( FileNotDownloadedException.class, () -> { - try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dmFacade.retrieveFileFromStorage(annotationDocumentEntity)) { + try (DownloadResponseMetaData downloadResponseMetaDataAutoClose = dataManagementFacade.retrieveFileFromStorage(annotationDocumentEntity)) { // add for try close with resources log.info(DOWNLOAD_RESPONSE_META_DATA, downloadResponseMetaDataAutoClose); } @@ -679,32 +700,9 @@ void retrieveFileFromStorageAnnotationFail() throws Exception { ); } - @Test - void testUnstructuredDataHelperCreate() { - when(blobClientUploadResponseImpl.getBlobName()).thenReturn(UUID.randomUUID().toString()); - - when(dataManagementConfiguration.getUnstructuredContainerName()).thenReturn("unstructured"); - when(dataManagementService.saveBlobData(anyString(), (InputStream) any())).thenReturn(blobClientUploadResponseImpl); - - UnstructuredDataHelper unstructuredDataHelperTest = getUnstructuredDataHelper(); - - MediaEntity mediaEntity = new MediaEntity(); - ExternalObjectDirectoryEntity eodEntity = createEodEntity(unstructuredLocationEntity); - eodEntity.setMedia(mediaEntity); - ExternalObjectDirectoryEntity eodEntityToDelete = createEodEntity(unstructuredLocationEntity); - eodEntityToDelete.setMedia(mediaEntity); - BinaryData data = BinaryData.fromString("Test String"); - - boolean created = unstructuredDataHelperTest.createUnstructuredDataFromEod( - eodEntityToDelete, - eodEntity, - data.toStream()); - - assertTrue(created); - } @Test - void testUnstructuredDataHelperCreateFailed() { + void unstructuredDataHelperCreateFailed() { UnstructuredDataHelper unstructuredDataHelperTest = getUnstructuredDataHelper(); @@ -724,7 +722,7 @@ void testUnstructuredDataHelperCreateFailed() { } @Test - void testDownloadOfFacadeCreatesUnstructuredWhenUnstructuredNotFound() throws Exception { + void downloadOfFacadeCreatesUnstructuredWhenUnstructuredNotFound() throws Exception { ExternalObjectDirectoryEntity inboundEntity = createEodEntity(inboundLocationEntity); ExternalObjectDirectoryEntity unstructuredEntity = createEodEntity(unstructuredLocationEntity); ExternalObjectDirectoryEntity armEntity = createEodEntity(armLocationEntity); @@ -740,11 +738,13 @@ void testDownloadOfFacadeCreatesUnstructuredWhenUnstructuredNotFound() throws Ex when(armApiService.downloadArmData(armEntity.getExternalRecordId(), armEntity.getExternalFileId())).thenReturn(downloadResponseMetaDataMock); // execute the code - final DataManagementFacadeImpl dmFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, - objectRecordStatusRepository, storageOrderHelper, unstructuredDataHelperFacade, - dataManagementConfiguration, armApiService, objectRetrievalQueueRepository); + final DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, + unstructuredDataHelperFacade, + dataManagementConfiguration, armApiService, + objectRetrievalQueueRepository); - downloadResponseMetaData = dmFacade.retrieveFileFromStorage(mediaEntity); + downloadResponseMetaData = dataManagementFacade.retrieveFileFromStorage(mediaEntity); assertEquals(DatastoreContainerType.ARM, downloadResponseMetaData.getContainerTypeUsedToDownload()); } @@ -755,12 +755,12 @@ void createCopyInUnstructuredDatastore_whenDeleteFileOnCompletionIsTrue_shouldDe File targetFile = Files.createTempFile("test", "txt").toFile(); - final DataManagementFacadeImpl dmFacade = new DataManagementFacadeImpl(null, null, - null, null, unstructuredDataHelper, - null, null, null); + final DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(null, null, + null, null, unstructuredDataHelper, + null, null, null); assertThat(targetFile).exists(); - dmFacade.createCopyInUnstructuredDatastore(eodEntityToUpload, eodEntityToDelete, targetFile, true); + dataManagementFacade.createCopyInUnstructuredDatastore(eodEntityToUpload, eodEntityToDelete, targetFile, true); verify(unstructuredDataHelper).createUnstructuredDataFromEod(eq(eodEntityToDelete), eq(eodEntityToUpload), any(InputStream.class)); assertThat(targetFile).doesNotExist(); @@ -773,12 +773,12 @@ void createCopyInUnstructuredDatastore_whenDeleteFileOnCompletionIsFalse_shouldN File targetFile = Files.createTempFile("test", "txt").toFile(); - final DataManagementFacadeImpl dmFacade = new DataManagementFacadeImpl(null, null, - null, null, unstructuredDataHelper, - null, null, null); + final DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(null, null, + null, null, unstructuredDataHelper, + null, null, null); assertThat(targetFile).exists(); - dmFacade.createCopyInUnstructuredDatastore(eodEntityToUpload, eodEntityToDelete, targetFile, false); + dataManagementFacade.createCopyInUnstructuredDatastore(eodEntityToUpload, eodEntityToDelete, targetFile, false); verify(unstructuredDataHelper).createUnstructuredDataFromEod(eq(eodEntityToDelete), eq(eodEntityToUpload), any(InputStream.class)); assertThat(targetFile).exists(); @@ -797,17 +797,17 @@ void processUnstructuredData_downloadResponseMetaDataIsFileBased_shouldNotCreate when(downloadResponseMetaData.getFileToBeDownloadedTo()).thenReturn(targetFile); - final DataManagementFacadeImpl dmFacade = spy(new DataManagementFacadeImpl(null, null, - null, null, null, - null, null, null)); + final DataManagementFacadeImpl dataManagementFacade = spy(new DataManagementFacadeImpl(null, null, + null, null, null, + null, null, null)); - doNothing().when(dmFacade).createCopyInUnstructuredDatastore(any(), any(), any(), anyBoolean()); + doNothing().when(dataManagementFacade).createCopyInUnstructuredDatastore(any(), any(), any(), anyBoolean()); - dmFacade + dataManagementFacade .processUnstructuredData(datastoreContainerType, downloadResponseMetaData, eodEntityToUpload, eodEntityToDelete); verify(downloadResponseMetaData).getFileToBeDownloadedTo(); - verify(dmFacade).createCopyInUnstructuredDatastore(eodEntityToUpload, eodEntityToDelete, targetFile, false); + verify(dataManagementFacade).createCopyInUnstructuredDatastore(eodEntityToUpload, eodEntityToDelete, targetFile, false); } @Test @@ -826,14 +826,14 @@ void processUnstructuredData_downloadResponseMetaDataIsNotFileBased_shouldCreate when(resource.getInputStream()).thenReturn(stream); DataManagementConfiguration dataManagementConfiguration = mock(DataManagementConfiguration.class); - when(dataManagementConfiguration.getTempBlobWorkspace()).thenReturn(SOME_TEMP_WORKSPACE); - final DataManagementFacadeImpl dmFacade = spy(new DataManagementFacadeImpl(null, null, - null, null, null, - dataManagementConfiguration, null, null)); + when(dataManagementConfiguration.getTempBlobWorkspace()).thenReturn(tempWorkspace); + final DataManagementFacadeImpl dataManagementFacade = spy(new DataManagementFacadeImpl(null, null, + null, null, null, + dataManagementConfiguration, null, null)); - doNothing().when(dmFacade).createCopyInUnstructuredDatastore(any(), any(), any(), anyBoolean()); + doNothing().when(dataManagementFacade).createCopyInUnstructuredDatastore(any(), any(), any(), anyBoolean()); - dmFacade + dataManagementFacade .processUnstructuredData(datastoreContainerType, downloadResponseMetaData, eodEntityToUpload, eodEntityToDelete); ArgumentCaptor targetFileArgumentCaptor = ArgumentCaptor.forClass(File.class); @@ -841,10 +841,201 @@ void processUnstructuredData_downloadResponseMetaDataIsNotFileBased_shouldCreate verify(dataManagementConfiguration).getTempBlobWorkspace(); verify(downloadResponseMetaData).getResource(); verify(resource).getInputStream(); - verify(dmFacade).createCopyInUnstructuredDatastore(eq(eodEntityToUpload), eq(eodEntityToDelete), targetFileArgumentCaptor.capture(), eq(true)); + verify(dataManagementFacade).createCopyInUnstructuredDatastore(eq(eodEntityToUpload), eq(eodEntityToDelete), targetFileArgumentCaptor.capture(), + eq(true)); File targetFileActual = targetFileArgumentCaptor.getValue(); - assertThat(targetFileActual.getAbsolutePath()).matches(".*/" + SOME_TEMP_WORKSPACE + "/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"); + assertThat(targetFileActual.getAbsolutePath()).matches(".*/workspace/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"); + } + + @Test + void retrieveFileFromStorage_whenArmDownForMaintenance_shouldThrow() throws Exception { + List datastoreOrder = List.of(DatastoreContainerType.ARM); + when(storageOrderHelper.getStorageOrder()).thenReturn(datastoreOrder); + when(dataManagementConfiguration.getArmDownForMaintenance()).thenReturn(true); + + ExternalObjectDirectoryEntity armEntity = createEodEntity(armLocationEntity); + List entitiesToDownload = List.of(armEntity); + + List blobContainerDownloadables = new ArrayList<>(); + blobContainerDownloadables.add(setupDownloadableContainer(DatastoreContainerType.ARM, true)); + + DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, unstructuredDataHelper, + dataManagementConfiguration, armApiService, + objectRetrievalQueueRepository); + + assertThrows(ArmDownForMaintenanceException.class, () -> dataManagementFacade.retrieveFileFromStorage(entitiesToDownload)); + verify(armApiService, times(0)).downloadArmData(any(), any()); + } + + @Test + void retrieveFileFromStorage_whenSupportedContainerMissing_shouldContinueToNext() throws Exception { + List datastoreOrder = List.of(DatastoreContainerType.DETS, DatastoreContainerType.ARM); + when(storageOrderHelper.getStorageOrder()).thenReturn(datastoreOrder); + + ExternalObjectDirectoryEntity detsEntity = createEodEntity(detsLocationEntity); + ExternalObjectDirectoryEntity armEntity = createEodEntity(armLocationEntity); + + List entitiesToDownload = List.of(detsEntity, armEntity); + + BlobContainerDownloadable detsContainer = mock(BlobContainerDownloadable.class); + when(detsContainer.getContainerName(DatastoreContainerType.DETS)).thenReturn(Optional.empty()); + + BlobContainerDownloadable armContainer = setupDownloadableContainer(DatastoreContainerType.ARM, true); + when(armApiService.downloadArmData(any(), any())).thenReturn(downloadResponseMetaDataMock); + + List blobContainerDownloadables = List.of(detsContainer, armContainer); + + DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, unstructuredDataHelper, + dataManagementConfiguration, armApiService, + objectRetrievalQueueRepository); + + try (DownloadResponseMetaData response = dataManagementFacade.retrieveFileFromStorage(entitiesToDownload)) { + assertEquals(DatastoreContainerType.ARM, response.getContainerTypeUsedToDownload()); + } + } + + @Test + void retrieveFileFromStorage_whenFirstContainerFails_shouldFallbackToNext() throws Exception { + List datastoreOrder = List.of(DatastoreContainerType.UNSTRUCTURED, DatastoreContainerType.DETS); + when(storageOrderHelper.getStorageOrder()).thenReturn(datastoreOrder); + + ExternalObjectDirectoryEntity unstructuredEntity = createEodEntity(unstructuredLocationEntity); + ExternalObjectDirectoryEntity detsEntity = createEodEntity(detsLocationEntity); + List entitiesToDownload = List.of(unstructuredEntity, detsEntity); + + BlobContainerDownloadable unstructuredContainer = setupDownloadableContainer(DatastoreContainerType.UNSTRUCTURED, false); + BlobContainerDownloadable detsContainer = setupDownloadableContainer(DatastoreContainerType.DETS, true); + + List blobContainerDownloadables = List.of(unstructuredContainer, detsContainer); + + DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, unstructuredDataHelper, + dataManagementConfiguration, armApiService, + objectRetrievalQueueRepository); + + try (DownloadResponseMetaData response = dataManagementFacade.retrieveFileFromStorage(entitiesToDownload)) { + assertEquals(DatastoreContainerType.DETS, response.getContainerTypeUsedToDownload()); + } + } + + @Test + void retrieveFileFromStorage_whenMixedStatuses_shouldUseStoredOnly() throws Exception { + List datastoreOrder = List.of(DatastoreContainerType.DETS); + when(storageOrderHelper.getStorageOrder()).thenReturn(datastoreOrder); + + ExternalObjectDirectoryEntity detsEntityStored = createEodEntity(detsLocationEntity); + ExternalObjectDirectoryEntity detsEntityNotStored = createEodEntity(detsLocationEntity); + detsEntityNotStored.getStatus().setId(ObjectRecordStatusEnum.FAILURE.getId()); + + List entitiesToDownload = List.of(detsEntityNotStored, detsEntityStored); + + BlobContainerDownloadable detsContainer = setupDownloadableContainer(DatastoreContainerType.DETS, true); + + List blobContainerDownloadables = List.of(detsContainer); + + DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(blobContainerDownloadables, externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, unstructuredDataHelper, + dataManagementConfiguration, armApiService, + objectRetrievalQueueRepository); + + try (DownloadResponseMetaData response = dataManagementFacade.retrieveFileFromStorage(entitiesToDownload)) { + assertEquals(DatastoreContainerType.DETS, response.getContainerTypeUsedToDownload()); + } + } + + @Test + void createCopyInUnstructuredDatastore_whenHelperThrows_shouldNotDeleteFile() throws IOException { + ExternalObjectDirectoryEntity eodEntityToUpload = mock(ExternalObjectDirectoryEntity.class); + ExternalObjectDirectoryEntity eodEntityToDelete = mock(ExternalObjectDirectoryEntity.class); + when(eodEntityToUpload.getId()).thenReturn(1L); + + File targetFile = Files.createTempFile("test", "txt").toFile(); + + doThrow(new RuntimeException("boom")).when(unstructuredDataHelper) + .createUnstructuredDataFromEod(eq(eodEntityToDelete), eq(eodEntityToUpload), any(InputStream.class)); + + DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(null, null, + null, null, unstructuredDataHelper, + null, null, null); + + assertThat(targetFile).exists(); + dataManagementFacade.createCopyInUnstructuredDatastore(eodEntityToUpload, eodEntityToDelete, targetFile, true); + + assertThat(targetFile).exists(); + } + + @Test + void retrieveFileFromStorageMedia_whenArmDownForMaintenance_shouldThrow() throws Exception { + List datastoreOrder = List.of(DatastoreContainerType.ARM); + when(storageOrderHelper.getStorageOrder()).thenReturn(datastoreOrder); + when(dataManagementConfiguration.getArmDownForMaintenance()).thenReturn(true); + + ExternalObjectDirectoryEntity armEntity = createEodEntity(armLocationEntity); + MediaEntity mediaEntity = new MediaEntity(); + mediaEntity.setId(1L); + + when(externalObjectDirectoryRepository.findByEntityAndStatus(eq(mediaEntity), any(ObjectRecordStatusEntity.class))) + .thenReturn(List.of(armEntity)); + + DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(List.of(), externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, + unstructuredDataHelper, dataManagementConfiguration, + armApiService, objectRetrievalQueueRepository); + + assertThrows(ArmDownForMaintenanceException.class, () -> dataManagementFacade.retrieveFileFromStorage(mediaEntity)); + verify(armApiService, times(0)).downloadArmData(any(), any()); + } + + @Test + void retrieveFileFromStorageTranscription_whenArmDownForMaintenance_shouldThrow() throws Exception { + List datastoreOrder = List.of(DatastoreContainerType.ARM); + when(storageOrderHelper.getStorageOrder()).thenReturn(datastoreOrder); + when(dataManagementConfiguration.getArmDownForMaintenance()).thenReturn(true); + + ExternalObjectDirectoryEntity armEntity = createEodEntity(armLocationEntity); + TranscriptionEntity transcriptionEntity = new TranscriptionEntity(); + transcriptionEntity.setId(11L); + TranscriptionDocumentEntity transcriptionDocumentEntity = new TranscriptionDocumentEntity(); + transcriptionDocumentEntity.setId(21L); + transcriptionDocumentEntity.setTranscription(transcriptionEntity); + + when(externalObjectDirectoryRepository.findByEntityAndStatus(eq(transcriptionDocumentEntity), any(ObjectRecordStatusEntity.class))) + .thenReturn(List.of(armEntity)); + + DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(List.of(), externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, + unstructuredDataHelper, dataManagementConfiguration, + armApiService, objectRetrievalQueueRepository); + + assertThrows(ArmDownForMaintenanceException.class, + () -> dataManagementFacade.retrieveFileFromStorage(transcriptionDocumentEntity)); + verify(armApiService, times(0)).downloadArmData(any(), any()); + } + + @Test + void retrieveFileFromStorageAnnotation_whenArmDownForMaintenance_shouldThrow() throws Exception { + List datastoreOrder = List.of(DatastoreContainerType.ARM); + when(storageOrderHelper.getStorageOrder()).thenReturn(datastoreOrder); + when(dataManagementConfiguration.getArmDownForMaintenance()).thenReturn(true); + + ExternalObjectDirectoryEntity armEntity = createEodEntity(armLocationEntity); + AnnotationDocumentEntity annotationDocumentEntity = new AnnotationDocumentEntity(); + annotationDocumentEntity.setId(31L); + + when(externalObjectDirectoryRepository.findByEntityAndStatus(eq(annotationDocumentEntity), any(ObjectRecordStatusEntity.class))) + .thenReturn(List.of(armEntity)); + + DataManagementFacadeImpl dataManagementFacade = new DataManagementFacadeImpl(List.of(), externalObjectDirectoryRepository, + objectRecordStatusRepository, storageOrderHelper, + unstructuredDataHelper, dataManagementConfiguration, + armApiService, objectRetrievalQueueRepository); + + assertThrows(ArmDownForMaintenanceException.class, + () -> dataManagementFacade.retrieveFileFromStorage(annotationDocumentEntity)); + verify(armApiService, times(0)).downloadArmData(any(), any()); } @NotNull @@ -891,4 +1082,17 @@ private ExternalObjectDirectoryEntity createEodEntity(ExternalLocationTypeEntity return entity; } -} \ No newline at end of file + + private static @NotNull ObjectRetrievalQueueEntity createObjectRetrievalQueueEntity(MediaEntity mediaEntity, UserAccountEntity userAccount) { + ObjectRetrievalQueueEntity objectRetrievalQueueEntity = new ObjectRetrievalQueueEntity(); + objectRetrievalQueueEntity.setMedia(mediaEntity); + objectRetrievalQueueEntity.setCreatedBy(userAccount); + objectRetrievalQueueEntity.setLastModifiedBy(userAccount); + objectRetrievalQueueEntity.setParentObjectId(String.valueOf(mediaEntity.getId())); + objectRetrievalQueueEntity.setContentObjectId(mediaEntity.getContentObjectId()); + objectRetrievalQueueEntity.setClipId(mediaEntity.getClipId()); + return objectRetrievalQueueEntity; + } + + +} diff --git a/src/test/java/uk/gov/hmcts/darts/transcriptions/service/impl/TranscriptionDownloaderTest.java b/src/test/java/uk/gov/hmcts/darts/transcriptions/service/impl/TranscriptionDownloaderTest.java index 792827cb3ee..1b9f4dff0bc 100644 --- a/src/test/java/uk/gov/hmcts/darts/transcriptions/service/impl/TranscriptionDownloaderTest.java +++ b/src/test/java/uk/gov/hmcts/darts/transcriptions/service/impl/TranscriptionDownloaderTest.java @@ -7,10 +7,13 @@ import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.core.io.Resource; +import uk.gov.hmcts.darts.arm.enums.ArmApiError; +import uk.gov.hmcts.darts.arm.exception.ArmDownForMaintenanceException; import uk.gov.hmcts.darts.audit.api.AuditApi; import uk.gov.hmcts.darts.authorisation.component.UserIdentity; import uk.gov.hmcts.darts.common.datamanagement.api.DataManagementFacade; import uk.gov.hmcts.darts.common.datamanagement.component.impl.DownloadResponseMetaData; +import uk.gov.hmcts.darts.common.entity.CourtCaseEntity; import uk.gov.hmcts.darts.common.entity.ExternalLocationTypeEntity; import uk.gov.hmcts.darts.common.entity.ExternalObjectDirectoryEntity; import uk.gov.hmcts.darts.common.entity.TranscriptionDocumentEntity; @@ -43,6 +46,7 @@ import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import static uk.gov.hmcts.darts.audit.api.AuditActivity.DOWNLOAD_TRANSCRIPTION; import static uk.gov.hmcts.darts.common.enums.ExternalLocationTypeEnum.INBOUND; import static uk.gov.hmcts.darts.common.enums.ExternalLocationTypeEnum.UNSTRUCTURED; import static uk.gov.hmcts.darts.common.enums.SecurityRoleEnum.SUPER_ADMIN; @@ -81,7 +85,7 @@ void setUp() { } @Test - void throwsExceptionIfNoTranscriptionFound() { + void downloadTranscript_throwsExceptionIfNoTranscriptionFound() { when(transcriptionRepository.findById(any())).thenReturn(empty()); assertThatThrownBy(() -> transcriptionDownloader.downloadTranscript(random.nextLong())) @@ -92,7 +96,7 @@ void throwsExceptionIfNoTranscriptionFound() { } @Test - void throwsExceptionIfTranscriptionHasNoTranscriptionDocuments() { + void downloadTranscript_throwsExceptionIfTranscriptionHasNoTranscriptionDocuments() { var transcription = someTranscriptionWith(emptyList()); when(transcriptionRepository.findById(transcription.getId())).thenReturn(Optional.of(transcription)); @@ -104,7 +108,8 @@ void throwsExceptionIfTranscriptionHasNoTranscriptionDocuments() { } @Test - void throwsExceptionIfTranscriptionDocumentHasNoExternalObjectDirectories() throws IOException, FileNotDownloadedException { + void downloadTranscript_throwsExceptionIfTranscriptionDocumentHasNoExternalObjectDirectories() + throws FileNotDownloadedException, ArmDownForMaintenanceException { var transcriptionDocument = someTranscriptionDocumentWithUploadDate(now()); transcriptionDocument.setExternalObjectDirectoryEntities(emptyList()); @@ -123,7 +128,8 @@ void throwsExceptionIfTranscriptionDocumentHasNoExternalObjectDirectories() thro @Test - void throwsExceptionIfFailsToGetDownloadResponseInputStream() throws IOException, FileNotDownloadedException { + void downloadTranscript_throwsExceptionIfFailsToGetDownloadResponseInputStream() + throws IOException, FileNotDownloadedException, ArmDownForMaintenanceException { var transcriptionDocument = someTranscriptionDocumentWithUploadDate(now()); transcriptionDocument.setExternalObjectDirectoryEntities(List.of(someExternalObjectDirectoryWithCreationDate(now()))); @@ -143,7 +149,7 @@ void throwsExceptionIfFailsToGetDownloadResponseInputStream() throws IOException } @Test - void retrievesTranscriptionFromUnstructuredContainer() throws IOException, FileNotDownloadedException { + void retrievesTranscriptionFromUnstructuredContainer() throws IOException, FileNotDownloadedException, ArmDownForMaintenanceException { // Given var inboundExternalObjectDirectoryCreatedToday = someExternalObjectDirectoryWithCreationDate(now()); inboundExternalObjectDirectoryCreatedToday.setExternalLocationType(externalLocationTypeFor(INBOUND)); @@ -160,7 +166,6 @@ void retrievesTranscriptionFromUnstructuredContainer() throws IOException, FileN when(transcriptionRepository.findById(transcription.getId())).thenReturn(Optional.of(transcription)); when(dataManagementFacade.retrieveFileFromStorage(any(TranscriptionDocumentEntity.class))).thenReturn(fileBasedDownloadResponseMetaData); - Resource resource = Mockito.mock(Resource.class); when(fileBasedDownloadResponseMetaData.getResource()).thenReturn(resource); @@ -178,7 +183,7 @@ void retrievesTranscriptionFromUnstructuredContainer() throws IOException, FileN } @Test - void throwsNotFoundExceptionIfTranscriptionDocumentHiddenAndUserIsNotSuperAdmin() { + void downloadTranscript_throwsNotFoundExceptionIfTranscriptionDocumentHiddenAndUserIsNotSuperAdmin() { when(transcriptionDocumentRepository.findByTranscriptionIdAndHiddenTrueIncludeDeleted(anyLong())) .thenReturn(List.of(new TranscriptionDocumentEntity())); @@ -197,7 +202,7 @@ void throwsNotFoundExceptionIfTranscriptionDocumentHiddenAndUserIsNotSuperAdmin( } @Test - void downloadsDocumentIfTranscriptionDocumentHiddenAndUserIsSuperAdmin() throws FileNotDownloadedException, IOException { + void downloadsDocumentIfTranscriptionDocumentHiddenAndUserIsSuperAdmin() throws FileNotDownloadedException, IOException, ArmDownForMaintenanceException { when(userIdentity.userHasGlobalAccess(Set.of(SUPER_ADMIN))).thenReturn(true); var transcriptionDocuments = someTranscriptionDocumentsUploadedAtLeast2DaysAgo(1); @@ -219,6 +224,83 @@ void downloadsDocumentIfTranscriptionDocumentHiddenAndUserIsSuperAdmin() throws verifyNoMoreInteractions(dataManagementFacade, fileBasedDownloadResponseMetaData); } + @Test + void downloadTranscript_throwsArmDownForMaintenanceWhenArmUnavailable() throws FileNotDownloadedException, ArmDownForMaintenanceException { + var transcriptionDocument = someTranscriptionDocumentWithUploadDate(now()); + transcriptionDocument.setExternalObjectDirectoryEntities(List.of(someExternalObjectDirectoryWithCreationDate(now()))); + + var transcription = someTranscriptionWith(List.of(transcriptionDocument)); + when(transcriptionRepository.findById(transcription.getId())).thenReturn(Optional.of(transcription)); + + when(dataManagementFacade.retrieveFileFromStorage(any(TranscriptionDocumentEntity.class))) + .thenThrow(new ArmDownForMaintenanceException("ARM down")); + + assertThatThrownBy(() -> transcriptionDownloader.downloadTranscript(transcription.getId())) + .isExactlyInstanceOf(DartsApiException.class) + .hasFieldOrPropertyWithValue("error", ArmApiError.ARM_DOWN_FOR_MAINTENANCE); + + verify(dataManagementFacade).retrieveFileFromStorage(any(TranscriptionDocumentEntity.class)); + } + + @Test + void recordsAuditOnSuccessfulDownload() throws IOException, FileNotDownloadedException, ArmDownForMaintenanceException { + var transcriptionDocument = someTranscriptionDocumentWithUploadDate(now()); + transcriptionDocument.setExternalObjectDirectoryEntities(List.of(someExternalObjectDirectoryWithCreationDate(now()))); + + var transcription = someTranscriptionWith(List.of(transcriptionDocument)); + var courtCase = new CourtCaseEntity(); + transcription.addCase(courtCase); + when(transcriptionRepository.findById(transcription.getId())).thenReturn(Optional.of(transcription)); + when(dataManagementFacade.retrieveFileFromStorage(any(TranscriptionDocumentEntity.class))).thenReturn(fileBasedDownloadResponseMetaData); + + Resource resource = Mockito.mock(Resource.class); + when(fileBasedDownloadResponseMetaData.getResource()).thenReturn(resource); + + transcriptionDownloader.downloadTranscript(transcription.getId()); + + verify(auditApi).record(DOWNLOAD_TRANSCRIPTION, userIdentity.getUserAccount(), courtCase); + } + + @Test + void downloadsDocumentWhenNoHiddenDocumentsExistForNonSuperAdmin() throws IOException, FileNotDownloadedException, ArmDownForMaintenanceException { + when(transcriptionDocumentRepository.findByTranscriptionIdAndHiddenTrueIncludeDeleted(anyLong())) + .thenReturn(emptyList()); + + var transcriptionDocument = someTranscriptionDocumentWithUploadDate(now()); + transcriptionDocument.setExternalObjectDirectoryEntities(List.of(someExternalObjectDirectoryWithCreationDate(now()))); + var transcription = someTranscriptionWith(List.of(transcriptionDocument)); + when(transcriptionRepository.findById(transcription.getId())).thenReturn(Optional.of(transcription)); + when(dataManagementFacade.retrieveFileFromStorage(any(TranscriptionDocumentEntity.class))).thenReturn(fileBasedDownloadResponseMetaData); + + Resource resource = Mockito.mock(Resource.class); + when(fileBasedDownloadResponseMetaData.getResource()).thenReturn(resource); + + var downloadTranscriptResponse = transcriptionDownloader.downloadTranscript(transcription.getId()); + + assertThat(downloadTranscriptResponse.getTranscriptionDocumentId()).isEqualTo(transcriptionDocument.getId()); + verify(transcriptionDocumentRepository).findByTranscriptionIdAndHiddenTrueIncludeDeleted(transcription.getId()); + } + + @Test + void selectsLatestTranscriptionDocumentByUploadedDate() throws IOException, FileNotDownloadedException, ArmDownForMaintenanceException { + var olderDocument = someTranscriptionDocumentWithUploadDate(now().minusDays(1)); + olderDocument.setExternalObjectDirectoryEntities(List.of(someExternalObjectDirectoryWithCreationDate(now().minusDays(1)))); + + var latestDocument = someTranscriptionDocumentWithUploadDate(now()); + latestDocument.setExternalObjectDirectoryEntities(List.of(someExternalObjectDirectoryWithCreationDate(now()))); + + var transcription = someTranscriptionWith(List.of(olderDocument, latestDocument)); + when(transcriptionRepository.findById(transcription.getId())).thenReturn(Optional.of(transcription)); + when(dataManagementFacade.retrieveFileFromStorage(any(TranscriptionDocumentEntity.class))).thenReturn(fileBasedDownloadResponseMetaData); + + Resource resource = Mockito.mock(Resource.class); + when(fileBasedDownloadResponseMetaData.getResource()).thenReturn(resource); + + var downloadTranscriptResponse = transcriptionDownloader.downloadTranscript(transcription.getId()); + + assertThat(downloadTranscriptResponse.getTranscriptionDocumentId()).isEqualTo(latestDocument.getId()); + } + private ExternalLocationTypeEntity externalLocationTypeFor(ExternalLocationTypeEnum externalLocationTypeEnum) { var externalLocationType = new ExternalLocationTypeEntity(); externalLocationType.setId(externalLocationTypeEnum.getId()); @@ -271,4 +353,4 @@ private TranscriptionEntity someTranscriptionWith(List