diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/audio/controller/AudioControllerGetAdminMediaVersionsByIdIntTest.java b/src/integrationTest/java/uk/gov/hmcts/darts/audio/controller/AudioControllerGetAdminMediaVersionsByIdIntTest.java new file mode 100644 index 0000000000..6d698996c5 --- /dev/null +++ b/src/integrationTest/java/uk/gov/hmcts/darts/audio/controller/AudioControllerGetAdminMediaVersionsByIdIntTest.java @@ -0,0 +1,220 @@ +package uk.gov.hmcts.darts.audio.controller; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.skyscreamer.jsonassert.JSONAssert; +import org.skyscreamer.jsonassert.JSONCompareMode; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import uk.gov.hmcts.darts.common.entity.MediaEntity; +import uk.gov.hmcts.darts.common.enums.SecurityRoleEnum; +import uk.gov.hmcts.darts.testutils.GivenBuilder; +import uk.gov.hmcts.darts.testutils.IntegrationBase; +import uk.gov.hmcts.darts.testutils.stubs.DartsDatabaseStub; + +import java.time.Duration; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; + +import static org.junit.jupiter.params.provider.EnumSource.Mode.EXCLUDE; +import static org.junit.jupiter.params.provider.EnumSource.Mode.INCLUDE; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static uk.gov.hmcts.darts.test.common.TestUtils.getContentsFromFile; + +@AutoConfigureMockMvc +class AudioControllerGetAdminMediaVersionsByIdIntTest extends IntegrationBase { + @Autowired + private GivenBuilder given; + + @Autowired + private MockMvc mockMvc; + + @Autowired + private DartsDatabaseStub databaseStub; + + private static final String ENDPOINT_URL = "/admin/medias/{id}/versions"; + private static final String COURTHOUSE_NAME = "TESTCOURTHOUSE"; + private static final String COURTROOM_NAME = "TESTCOURTROOM"; + private static final OffsetDateTime HEARING_START_AT = OffsetDateTime.parse("2024-01-01T12:10:10Z"); + private static final OffsetDateTime MEDIA_START_AT = HEARING_START_AT; + private static final OffsetDateTime MEDIA_END_AT = MEDIA_START_AT.plusHours(1); + private static final String RETAIN_UNTIL = "2200-02-01T00:00:00Z"; + + + @ParameterizedTest + @EnumSource(value = SecurityRoleEnum.class, names = {"SUPER_USER", "SUPER_ADMIN"}, mode = INCLUDE) + void shouldReturn200_whenChronicleIdHasBothCurrentAndNonCurrentVersions(SecurityRoleEnum role) throws Exception { + final String chronicleId = "chronicleId"; + MediaEntity currentMediaEntity = createAndSaveMediaEntity(true, chronicleId, Duration.ofDays(3)); + MediaEntity versionedMediaEntity1 = createAndSaveMediaEntity(false, chronicleId, Duration.ofDays(2)); + MediaEntity versionedMediaEntity2 = createAndSaveMediaEntity(false, chronicleId, Duration.ofDays(1)); + //Craeted unrelated media to ensure not returned + createAndSaveMediaEntity(true, "unrealted"); + + given.anAuthenticatedUserWithGlobalAccessAndRole(role); + + // When + MvcResult mvcResult = mockMvc.perform(get(ENDPOINT_URL, currentMediaEntity.getId())) + .andExpect(status().isOk()) + .andReturn(); + + String expectedResponse = getContentsFromFile( + "tests/audio/AudioControllerGetAdminMediaVersionsByIdIntTest/expectedResponseTypical.json") + .replace("", currentMediaEntity.getCreatedDateTime().format(DateTimeFormatter.ISO_DATE_TIME)) + .replace("", versionedMediaEntity2.getCreatedDateTime().format(DateTimeFormatter.ISO_DATE_TIME)) + .replace("", versionedMediaEntity1.getCreatedDateTime().format(DateTimeFormatter.ISO_DATE_TIME)); + JSONAssert.assertEquals(expectedResponse, mvcResult.getResponse().getContentAsString(), JSONCompareMode.STRICT); + } + + @Test + void shouldReturn200_whenMediaIdPassedIsNotCurrent_shouldReturnTheCorrectCorrentVersion() throws Exception { + final String chronicleId = "chronicleId"; + MediaEntity currentMediaEntity = createAndSaveMediaEntity(true, chronicleId, Duration.ofDays(3)); + MediaEntity versionedMediaEntity1 = createAndSaveMediaEntity(false, chronicleId, Duration.ofDays(2)); + MediaEntity versionedMediaEntity2 = createAndSaveMediaEntity(false, chronicleId, Duration.ofDays(1)); + //Craeted unrelated media to ensure not returned + createAndSaveMediaEntity(true, "unrealted"); + + given.anAuthenticatedUserWithGlobalAccessAndRole(SecurityRoleEnum.SUPER_ADMIN); + + // When + MvcResult mvcResult = mockMvc.perform(get(ENDPOINT_URL, versionedMediaEntity1.getId())) + .andExpect(status().isOk()) + .andReturn(); + + String expectedResponse = getContentsFromFile( + "tests/audio/AudioControllerGetAdminMediaVersionsByIdIntTest/expectedResponseTypical.json") + .replace("", currentMediaEntity.getCreatedDateTime().format(DateTimeFormatter.ISO_DATE_TIME)) + .replace("", versionedMediaEntity2.getCreatedDateTime().format(DateTimeFormatter.ISO_DATE_TIME)) + .replace("", versionedMediaEntity1.getCreatedDateTime().format(DateTimeFormatter.ISO_DATE_TIME)); + JSONAssert.assertEquals(expectedResponse, mvcResult.getResponse().getContentAsString(), JSONCompareMode.STRICT); + } + + @Test + void shouldReturn200_whenChronicleIdHasOnlyCurrentAndNoVersions() throws Exception { + final String chronicleId = "chronicleId"; + MediaEntity currentMediaEntity = createAndSaveMediaEntity(true, chronicleId, Duration.ofDays(3)); + //Craeted unrelated media to ensure not returned + createAndSaveMediaEntity(true, "unrealted"); + + given.anAuthenticatedUserWithGlobalAccessAndRole(SecurityRoleEnum.SUPER_ADMIN); + + // When + MvcResult mvcResult = mockMvc.perform(get(ENDPOINT_URL, currentMediaEntity.getId())) + .andExpect(status().isOk()) + .andReturn(); + + String expectedResponse = getContentsFromFile( + "tests/audio/AudioControllerGetAdminMediaVersionsByIdIntTest/expectedResponseNoVersions.json") + .replace("", currentMediaEntity.getCreatedDateTime().format(DateTimeFormatter.ISO_DATE_TIME)); + JSONAssert.assertEquals(expectedResponse, mvcResult.getResponse().getContentAsString(), JSONCompareMode.STRICT); + } + + @ParameterizedTest + @EnumSource(value = SecurityRoleEnum.class, names = {"SUPER_USER", "SUPER_ADMIN"}, mode = INCLUDE) + void shouldReturn404_WhenMediaRecordDoesNotExist(SecurityRoleEnum role) throws Exception { + // Given + given.anAuthenticatedUserWithGlobalAccessAndRole(role); + + // When + MvcResult mvcResult = mockMvc.perform(get(ENDPOINT_URL, "123456789")) + .andExpect(status().isNotFound()) + .andReturn(); + + // Then + var jsonString = mvcResult.getResponse().getContentAsString(); + JSONAssert.assertEquals(""" + { + "type": "AUDIO_102", + "title": "The requested media cannot be found", + "status": 404 + } + """, jsonString, JSONCompareMode.STRICT); + } + + @ParameterizedTest + @EnumSource(value = SecurityRoleEnum.class, names = {"SUPER_USER", "SUPER_ADMIN"}, mode = INCLUDE) + void shouldReturn404_WhenMediaRecordIsDeleted(SecurityRoleEnum role) throws Exception { + // Given + given.anAuthenticatedUserWithGlobalAccessAndRole(role); + + + var mediaEntity = createAndSaveMediaEntity(true, true, "chronicleId", Duration.ofMillis(0)); + // When + MvcResult mvcResult = mockMvc.perform(get(ENDPOINT_URL, String.valueOf(mediaEntity.getId()))) + .andExpect(status().isNotFound()) + .andReturn(); + + // Then + var jsonString = mvcResult.getResponse().getContentAsString(); + JSONAssert.assertEquals(""" + { + "type": "AUDIO_102", + "title": "The requested media cannot be found", + "status": 404 + } + """, jsonString, JSONCompareMode.STRICT); + + } + + @ParameterizedTest + @EnumSource(value = SecurityRoleEnum.class, names = {"SUPER_USER", "SUPER_ADMIN"}, mode = EXCLUDE) + void shouldDenyAccess_whenNotAuthorised(SecurityRoleEnum role) throws Exception { + // Given + given.anAuthenticatedUserWithGlobalAccessAndRole(role); + + // When + MvcResult mvcResult = mockMvc.perform(get(ENDPOINT_URL, "123456789")) + .andExpect(status().isForbidden()) + .andReturn(); + + // Then + var jsonString = mvcResult.getResponse().getContentAsString(); + JSONAssert.assertEquals(""" + { + "type": "AUTHORISATION_109", + "title": "User is not authorised for this endpoint", + "status": 403 + } + """, jsonString, JSONCompareMode.STRICT); + } + + private MediaEntity createAndSaveMediaEntity(boolean isCurrent, String chronicleId) { + return createAndSaveMediaEntity(false, isCurrent, chronicleId, Duration.ofMillis(0)); + } + + private MediaEntity createAndSaveMediaEntity(boolean isCurrent, String chronicleId, Duration timeOffset) { + return createAndSaveMediaEntity(false, isCurrent, chronicleId, timeOffset); + } + + private MediaEntity createAndSaveMediaEntity(boolean isDeleted, boolean isCurrent, String chronicleId, Duration timeOffset) { + MediaEntity mediaEntity = databaseStub.createMediaEntity(COURTHOUSE_NAME, + COURTROOM_NAME, + MEDIA_START_AT.plus(timeOffset), + MEDIA_END_AT.plus(timeOffset), + 2); + var userAccountEntity = databaseStub.getUserAccountRepository().findAll().stream() + .findFirst() + .orElseThrow(); + mediaEntity.setLegacyObjectId("object-id-value"); + mediaEntity.setContentObjectId("content-id-value"); + mediaEntity.setClipId("clip-id-value"); + mediaEntity.setMediaStatus("media-status-value"); + mediaEntity.setHidden(true); + mediaEntity.setDeleted(isDeleted); + mediaEntity.setLegacyVersionLabel("version-label-value"); + mediaEntity.setChronicleId(chronicleId); + mediaEntity.setAntecedentId("antecedent-value"); + mediaEntity.setRetainUntilTs(OffsetDateTime.parse(RETAIN_UNTIL)); + mediaEntity.setCreatedBy(userAccountEntity); + mediaEntity.setLastModifiedBy(userAccountEntity); + mediaEntity.setIsCurrent(isCurrent); + + return databaseStub.getMediaRepository() + .saveAndFlush(mediaEntity); + } +} diff --git a/src/integrationTest/resources/tests/audio/AudioControllerGetAdminMediaVersionsByIdIntTest/expectedResponseNoVersions.json b/src/integrationTest/resources/tests/audio/AudioControllerGetAdminMediaVersionsByIdIntTest/expectedResponseNoVersions.json new file mode 100644 index 0000000000..ca45beb8ad --- /dev/null +++ b/src/integrationTest/resources/tests/audio/AudioControllerGetAdminMediaVersionsByIdIntTest/expectedResponseNoVersions.json @@ -0,0 +1,22 @@ +{ + "media_object_id": "object-id-value", + "current_version": { + "id": 1, + "courthouse": { + "id": 1, + "display_name": "TESTCOURTHOUSE" + }, + "courtroom": { + "id": 1, + "name": "TESTCOURTROOM" + }, + "start_at": "2024-01-04T12:10:10Z", + "end_at": "2024-01-04T13:10:10Z", + "channel": 2, + "chronicle_id": "chronicleId", + "antecedent_id": "antecedent-value", + "is_current": true, + "created_at": "" + }, + "previous_versions": [] +} \ No newline at end of file diff --git a/src/integrationTest/resources/tests/audio/AudioControllerGetAdminMediaVersionsByIdIntTest/expectedResponseTypical.json b/src/integrationTest/resources/tests/audio/AudioControllerGetAdminMediaVersionsByIdIntTest/expectedResponseTypical.json new file mode 100644 index 0000000000..7883035ef8 --- /dev/null +++ b/src/integrationTest/resources/tests/audio/AudioControllerGetAdminMediaVersionsByIdIntTest/expectedResponseTypical.json @@ -0,0 +1,59 @@ +{ + "media_object_id": "object-id-value", + "current_version": { + "id": 1, + "courthouse": { + "id": 1, + "display_name": "TESTCOURTHOUSE" + }, + "courtroom": { + "id": 1, + "name": "TESTCOURTROOM" + }, + "start_at": "2024-01-04T12:10:10Z", + "end_at": "2024-01-04T13:10:10Z", + "channel": 2, + "chronicle_id": "chronicleId", + "antecedent_id": "antecedent-value", + "is_current": true, + "created_at": "" + }, + "previous_versions": [ + { + "id": 3, + "courthouse": { + "id": 1, + "display_name": "TESTCOURTHOUSE" + }, + "courtroom": { + "id": 1, + "name": "TESTCOURTROOM" + }, + "start_at": "2024-01-02T12:10:10Z", + "end_at": "2024-01-02T13:10:10Z", + "channel": 2, + "chronicle_id": "chronicleId", + "antecedent_id": "antecedent-value", + "is_current": false, + "created_at": "" + }, + { + "id": 2, + "courthouse": { + "id": 1, + "display_name": "TESTCOURTHOUSE" + }, + "courtroom": { + "id": 1, + "name": "TESTCOURTROOM" + }, + "start_at": "2024-01-03T12:10:10Z", + "end_at": "2024-01-03T13:10:10Z", + "channel": 2, + "chronicle_id": "chronicleId", + "antecedent_id": "antecedent-value", + "is_current": false, + "created_at": "" + } + ] +} \ No newline at end of file diff --git a/src/main/java/uk/gov/hmcts/darts/audio/mapper/GetAdminMediaResponseMapper.java b/src/main/java/uk/gov/hmcts/darts/audio/mapper/GetAdminMediaResponseMapper.java index a786de30c9..95c9fe96e2 100644 --- a/src/main/java/uk/gov/hmcts/darts/audio/mapper/GetAdminMediaResponseMapper.java +++ b/src/main/java/uk/gov/hmcts/darts/audio/mapper/GetAdminMediaResponseMapper.java @@ -1,6 +1,8 @@ package uk.gov.hmcts.darts.audio.mapper; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import uk.gov.hmcts.darts.audio.model.AdminActionResponse; import uk.gov.hmcts.darts.audio.model.AdminMediaVersionResponse; @@ -26,10 +28,11 @@ @Slf4j @Component +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) public class GetAdminMediaResponseMapper { - private CourtroomMapper courtroomMapper; - private CourthouseMapper courthouseMapper; + private final CourtroomMapper courtroomMapper; + private final CourthouseMapper courthouseMapper; public static List createResponseItemList(List mediaEntities, HearingEntity hearing) { List responseList = new ArrayList<>(); diff --git a/src/main/java/uk/gov/hmcts/darts/audio/service/impl/AdminMediaServiceImpl.java b/src/main/java/uk/gov/hmcts/darts/audio/service/impl/AdminMediaServiceImpl.java index b8ffd7c5af..5847cd54fa 100644 --- a/src/main/java/uk/gov/hmcts/darts/audio/service/impl/AdminMediaServiceImpl.java +++ b/src/main/java/uk/gov/hmcts/darts/audio/service/impl/AdminMediaServiceImpl.java @@ -3,6 +3,7 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -63,6 +64,7 @@ @Service @RequiredArgsConstructor +@Slf4j public class AdminMediaServiceImpl implements AdminMediaService { private final SearchMediaValidator searchMediaValidator; @@ -273,13 +275,43 @@ public MediaApproveMarkedForDeletionResponse adminApproveMediaMarkedForDeletion( @Override public AdminVersionedMediaResponse getMediaVersionsById(Integer id) { - MediaEntity mediaEntity = getMediaEntityById(id); - List mediaVersions = new ArrayList<>(); - //Only fetch versions if the media is part of a chronicle - if (mediaEntity.getChronicleId() != null) { - mediaVersions.addAll(mediaRepository.findAllByChronicleId(mediaEntity.getChronicleId())); + MediaEntity mediaEntityFromRequest = getMediaEntityById(id); + + if (mediaEntityFromRequest.getChronicleId() == null) { + throw new DartsApiException(CommonApiError.INTERNAL_SERVER_ERROR, + "Media " + id + " has a Chronicle Id that is null. As such we can not ensure accurate results are returned"); + } + List mediaVersions = mediaRepository.findAllByChronicleId(mediaEntityFromRequest.getChronicleId()); + + + List currentMediaVersions = mediaVersions.stream() + .filter(mediaEntity -> mediaEntity.getIsCurrent() != null) + .filter(media -> media.getIsCurrent()) + .sorted((o1, o2) -> o1.getCreatedDateTime().compareTo(o2.getCreatedDateTime())) + .collect(Collectors.toCollection(ArrayList::new)); + + List versionedMedia = mediaVersions.stream() + .filter(media -> media.getIsCurrent() == null || !media.getIsCurrent()) + .sorted((o1, o2) -> o2.getCreatedDateTime().compareTo(o1.getCreatedDateTime())) + .collect(Collectors.toCollection(ArrayList::new)); + + MediaEntity currentVersion; + if (currentMediaVersions.size() == 1) { + currentVersion = currentMediaVersions.getLast(); + } else if (currentMediaVersions.size() == 0) { + currentVersion = null; + log.info("Media with id {} has {} current versions", id, currentMediaVersions.size()); + } else { + log.warn("Media with id {} has {} current versions we only expect one", id, currentMediaVersions.size()); + currentVersion = currentMediaVersions.getLast(); + //Add any extra current events to top of versionedMedia so they still get displayed + currentMediaVersions.removeLast(); + currentMediaVersions + .forEach(mediaEntity -> { + versionedMedia.addFirst(mediaEntity); + }); } - return getAdminMediaResponseMapper.mapAdminVersionedMediaResponse(mediaEntity, mediaVersions); + return getAdminMediaResponseMapper.mapAdminVersionedMediaResponse(currentVersion, versionedMedia); } private ApplyAdminActionComponent.AdminActionProperties mapToAdminActionProperties(AdminActionRequest adminActionRequest) { diff --git a/src/main/java/uk/gov/hmcts/darts/common/exception/CommonApiError.java b/src/main/java/uk/gov/hmcts/darts/common/exception/CommonApiError.java index f7fa6e330f..4bdc1fa823 100644 --- a/src/main/java/uk/gov/hmcts/darts/common/exception/CommonApiError.java +++ b/src/main/java/uk/gov/hmcts/darts/common/exception/CommonApiError.java @@ -24,6 +24,11 @@ public enum CommonApiError implements DartsApiError { CommonErrorCode.NOT_FOUND.getValue(), HttpStatus.NOT_FOUND, CommonTitleErrors.NOT_FOUND.getValue() + ), + INTERNAL_SERVER_ERROR( + CommonErrorCode.INTERNAL_SERVER_ERROR.getValue(), + HttpStatus.INTERNAL_SERVER_ERROR, + CommonTitleErrors.INTERNAL_SERVER_ERROR.getValue() ); private static final String ERROR_TYPE_PREFIX = "COMMON"; diff --git a/src/main/resources/openapi/common.yaml b/src/main/resources/openapi/common.yaml index 99e3ac1ad4..6de458c48d 100644 --- a/src/main/resources/openapi/common.yaml +++ b/src/main/resources/openapi/common.yaml @@ -174,9 +174,10 @@ components: - "COMMON_100" - "COMMON_101" - "COMMON_102" + - "COMMON_103" x-enum-varnames: [ COURTHOUSE_PROVIDED_DOES_NOT_EXIST, FEATURE_FLAG_NOT_ENABLED, - NOT_FOUND ] + NOT_FOUND, INTERNAL_SERVER_ERROR ] CommonTitleErrors: type: string @@ -184,7 +185,8 @@ components: - "Provided courthouse does not exist" - "Feature flag not enabled" - "Resource not found" + - "Internal server error" x-enum-varnames: [ COURTHOUSE_PROVIDED_DOES_NOT_EXIST , FEATURE_FLAG_NOT_ENABLED, - NOT_FOUND + NOT_FOUND, INTERNAL_SERVER_ERROR ] \ No newline at end of file diff --git a/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AdminMediaServiceImplTest.java b/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AdminMediaServiceImplTest.java index fc455f2c87..841cfb4b47 100644 --- a/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AdminMediaServiceImplTest.java +++ b/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AdminMediaServiceImplTest.java @@ -76,10 +76,10 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; @SuppressWarnings("PMD.CouplingBetweenObjects") @@ -597,45 +597,129 @@ void getMediaEntityById_shouldThrowException_ifNoMediaEntityExists() { @DisplayName("AdminVersionedMediaResponse getMediaVersionsById(Integer id)") class GetMediaVersionsById { @Test - void getMediaVersionsById_shouldFetchMediaVersions_whenChronicleIdIsNotNull() { + void getMediaVersionsById_shouldThrowException_whenChronicleIdIsNull() { MediaEntity mediaEntity = mock(MediaEntity.class); + mediaEntity.setChronicleId(null); doReturn(mediaEntity).when(mediaRequestService).getMediaEntityById(123); - when(mediaEntity.getChronicleId()).thenReturn("chronicleId1"); - List versionedMedias = List.of(mock(MediaEntity.class), mock(MediaEntity.class)); - when(mediaRepository.findAllByChronicleId("chronicleId1")).thenReturn(versionedMedias); + DartsApiException exception = assertThrows(DartsApiException.class, () -> mediaRequestService.getMediaVersionsById(123)); + assertThat(exception.getError()).isEqualTo(CommonApiError.INTERNAL_SERVER_ERROR); + assertThat(exception.getMessage()) + .isEqualTo("Internal server error. Media 123 has a Chronicle Id that is null. As such we can not ensure accurate results are returned"); + } + + @Test + void getMediaVersionsById_shouldReturnEmptyVersionList_whenNoMediaVersionsExist() { + final String chronicleId = "someChronicleId"; + MediaEntity mediaEntity = mockMediaEntity(true, chronicleId, OffsetDateTime.now()); + doReturn(mediaEntity).when(mediaRequestService).getMediaEntityById(123); + when(mediaRepository.findAllByChronicleId(chronicleId)).thenReturn(List.of(mediaEntity)); + + AdminVersionedMediaResponse response = mock(AdminVersionedMediaResponse.class); + when(getAdminMediaResponseMapper.mapAdminVersionedMediaResponse(mediaEntity, List.of())).thenReturn(response); + + assertThat(mediaRequestService.getMediaVersionsById(123)) + .isEqualTo(response); + + verify(mediaRepository).findAllByChronicleId(chronicleId); + verify(getAdminMediaResponseMapper).mapAdminVersionedMediaResponse(mediaEntity, List.of()); + verify(mediaRequestService).getMediaEntityById(123); + } + + @Test + void getMediaVersionsById_shouldReturnVersionsAndCurrentMedia_whenVersionsExist() { + final String chronicleId = "someChronicleId"; + OffsetDateTime now = OffsetDateTime.now(); + MediaEntity currentMediaEntity = mockMediaEntity(true, chronicleId, now); + MediaEntity versionedMediaEntity1 = mockMediaEntity(null, chronicleId, now.plusMinutes(2)); + MediaEntity versionedMediaEntity2 = mockMediaEntity(false, chronicleId, now.plusMinutes(1)); + + doReturn(currentMediaEntity).when(mediaRequestService).getMediaEntityById(123); + when(mediaRepository.findAllByChronicleId(chronicleId)) + .thenReturn(List.of(currentMediaEntity, versionedMediaEntity2, versionedMediaEntity1)); AdminVersionedMediaResponse response = mock(AdminVersionedMediaResponse.class); - when(getAdminMediaResponseMapper.mapAdminVersionedMediaResponse(mediaEntity, versionedMedias)) + + List expectedVersioendMedia = List.of(versionedMediaEntity1, versionedMediaEntity2); + when(getAdminMediaResponseMapper.mapAdminVersionedMediaResponse(currentMediaEntity, expectedVersioendMedia)) .thenReturn(response); assertThat(mediaRequestService.getMediaVersionsById(123)) .isEqualTo(response); - verify(getAdminMediaResponseMapper).mapAdminVersionedMediaResponse(mediaEntity, versionedMedias); + verify(mediaRepository).findAllByChronicleId(chronicleId); + verify(getAdminMediaResponseMapper).mapAdminVersionedMediaResponse(currentMediaEntity, expectedVersioendMedia); verify(mediaRequestService).getMediaEntityById(123); - verify(mediaRepository).findAllByChronicleId("chronicleId1"); } + @Test - void getMediaVersionsById_shouldNotFetchMediaVersions_whenChronicleIdIsNull() { - MediaEntity mediaEntity = mock(MediaEntity.class); - doReturn(mediaEntity).when(mediaRequestService).getMediaEntityById(123); - when(mediaEntity.getChronicleId()).thenReturn(null); + void getMediaVersionsById_shouldReturnNullCurrentVersion_ifAllMediaIsCurrentFlase() { + final String chronicleId = "someChronicleId"; + OffsetDateTime now = OffsetDateTime.now(); + MediaEntity versionedMediaEntity1 = mockMediaEntity(null, chronicleId, now.plusMinutes(2)); + MediaEntity versionedMediaEntity2 = mockMediaEntity(false, chronicleId, now.plusMinutes(1)); + + doReturn(versionedMediaEntity1).when(mediaRequestService).getMediaEntityById(123); + + + when(mediaRepository.findAllByChronicleId(chronicleId)) + .thenReturn(List.of(versionedMediaEntity2, versionedMediaEntity1)); AdminVersionedMediaResponse response = mock(AdminVersionedMediaResponse.class); - when(getAdminMediaResponseMapper.mapAdminVersionedMediaResponse(mediaEntity, new ArrayList<>())) + + List expectedVersioendMedia = List.of(versionedMediaEntity1, versionedMediaEntity2); + when(getAdminMediaResponseMapper.mapAdminVersionedMediaResponse(null, expectedVersioendMedia)) .thenReturn(response); assertThat(mediaRequestService.getMediaVersionsById(123)) .isEqualTo(response); - verify(getAdminMediaResponseMapper).mapAdminVersionedMediaResponse(mediaEntity, new ArrayList<>()); + + verify(mediaRepository).findAllByChronicleId(chronicleId); + verify(getAdminMediaResponseMapper).mapAdminVersionedMediaResponse(null, expectedVersioendMedia); + verify(mediaRequestService).getMediaEntityById(123); + + } + + @Test + void getMediaVersionsById_shouldReturnLastCreatedMedia_ifMultipleIsCurrentTrueExist() { + final String chronicleId = "someChronicleId"; + OffsetDateTime now = OffsetDateTime.now(); + MediaEntity currentMediaEntity1 = mockMediaEntity(true, chronicleId, now.plusMinutes(2)); + MediaEntity currentMediaEntity2 = mockMediaEntity(true, chronicleId, now); + MediaEntity currentMediaEntity3 = mockMediaEntity(true, chronicleId, now.plusMinutes(1)); + + MediaEntity versionedMediaEntity1 = mockMediaEntity(null, chronicleId, now.plusMinutes(2)); + MediaEntity versionedMediaEntity2 = mockMediaEntity(false, chronicleId, now.plusMinutes(1)); + + doReturn(currentMediaEntity1).when(mediaRequestService).getMediaEntityById(123); + when(mediaRepository.findAllByChronicleId(chronicleId)) + .thenReturn(List.of(currentMediaEntity1, currentMediaEntity2, currentMediaEntity3, versionedMediaEntity2, versionedMediaEntity1)); + AdminVersionedMediaResponse response = mock(AdminVersionedMediaResponse.class); + List expectedVersioendMedia = List.of(currentMediaEntity3, currentMediaEntity2, versionedMediaEntity1, versionedMediaEntity2); + when(getAdminMediaResponseMapper.mapAdminVersionedMediaResponse(currentMediaEntity1, expectedVersioendMedia)) + .thenReturn(response); + + assertThat(mediaRequestService.getMediaVersionsById(123)) + .isEqualTo(response); + + verify(mediaRepository).findAllByChronicleId(chronicleId); + verify(getAdminMediaResponseMapper).mapAdminVersionedMediaResponse(currentMediaEntity1, expectedVersioendMedia); verify(mediaRequestService).getMediaEntityById(123); - verifyNoInteractions(mediaRepository); + } + private MediaEntity mockMediaEntity(Boolean isCurrent, String chronicleId, OffsetDateTime offsetDateTime) { + MediaEntity mediaEntity = mock(MediaEntity.class); + lenient().when(mediaEntity.getChronicleId()).thenReturn(chronicleId); + lenient().when(mediaEntity.getIsCurrent()).thenReturn(isCurrent); + lenient().when(mediaEntity.getCreatedDateTime()).thenReturn(offsetDateTime); + return mediaEntity; + } + + }