diff --git a/provider/storage-azure/pom.xml b/provider/storage-azure/pom.xml index a316ddc9a7bec77acd375ea4cd42389b5ad965a0..28c971c6790569c15d5f75079ef9c7fb2df1ca47 100644 --- a/provider/storage-azure/pom.xml +++ b/provider/storage-azure/pom.xml @@ -313,10 +313,28 @@ </deployment> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.22.2</version> + <configuration> + <argLine>@{argLine} --add-opens java.base/java.lang=ALL_UNNAMED</argLine> + </configuration> + </plugin> <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>0.8.10</version> + <configuration> + <excludes> + <exclude>org/opengroup/osdu/storage/provider/azure/di/**</exclude> + <exclude>org/opengroup/osdu/storage/provider/azure/*Doc.class</exclude> + <exclude>org/opengroup/osdu/storage/provider/azure/StorageApplication.class</exclude> + <exclude>org/opengroup/osdu/storage/provider/azure/SomeBasicInterfaceImpl.class</exclude> + <exclude>org/opengroup/osdu/storage/provider/azure/model/**</exclude> + <exclude>org/opengroup/osdu/storage/provider/azure/exception/**</exclude> + </excludes> + </configuration> <executions> <execution> <goals> diff --git a/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/CloudStorageImplTest.java b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/CloudStorageImplTest.java index 69b207660b475f179282dfc4be7767703d713805..db74722eb87a1546d86df25682ebc31eab67ffc0 100644 --- a/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/CloudStorageImplTest.java +++ b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/CloudStorageImplTest.java @@ -1,101 +1,514 @@ package org.opengroup.osdu.storage.provider.azure; import com.google.common.collect.Sets; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import org.apache.http.HttpStatus; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; import org.opengroup.osdu.azure.blobstorage.BlobStore; import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; import org.opengroup.osdu.core.common.model.entitlements.Acl; import org.opengroup.osdu.core.common.model.http.AppException; +import org.opengroup.osdu.core.common.model.http.CollaborationContext; import org.opengroup.osdu.core.common.model.http.DpsHeaders; import org.opengroup.osdu.core.common.model.legal.Legal; import org.opengroup.osdu.core.common.model.legal.LegalCompliance; import org.opengroup.osdu.core.common.model.storage.Record; -import org.opengroup.osdu.core.common.model.storage.RecordMetadata; +import org.opengroup.osdu.core.common.model.storage.*; import org.opengroup.osdu.storage.provider.azure.repository.RecordMetadataRepository; import org.opengroup.osdu.storage.provider.azure.util.EntitlementsHelper; +import org.opengroup.osdu.storage.provider.azure.util.RecordUtil; +import org.opengroup.osdu.storage.util.CrcHashGenerator; import org.springframework.test.util.ReflectionTestUtils; -import java.util.Arrays; +import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; -@RunWith(MockitoJUnitRunner.class) -public class CloudStorageImplTest { +@ExtendWith(MockitoExtension.class) +class CloudStorageImplTest { + private static final String DATA_PARTITION = "dp"; + private static final String CONTAINER = "opendes"; + private static final CrcHashGenerator crcHashGenerator = new CrcHashGenerator(); @Mock private JaxRsDpsLog logger; - @Mock private DpsHeaders headers; - @Mock private BlobStore blobStore; - @Mock private RecordMetadataRepository recordRepository; - @Mock private EntitlementsHelper entitlementsHelper; - + @Mock + private RecordProcessing recordProcessing; + @Mock + private RecordUtil recordUtil; + @Mock + private RecordData data; + @Mock + private TransferInfo transfer; @InjectMocks private CloudStorageImpl cloudStorage; - private static final String DATA_PARTITION = "dp"; - private static final String CONTAINER = "opendes"; - - @Before - public void setup() { + @BeforeEach + void setup() { ReflectionTestUtils.setField(cloudStorage, "containerName", CONTAINER); - Mockito.when(headers.getPartitionId()).thenReturn(DATA_PARTITION); } @Test - public void shouldNotInvokeDeleteOnBlobStoreWhenNoVersion() { - RecordMetadata recordMetadata = setUpRecordMetadata(); + void shouldNotInvokeDeleteOnBlobStoreWhenNoVersion() { + RecordMetadata recordMetadata = setUpRecordMetadata("id1"); cloudStorage.delete(recordMetadata); - Mockito.verify(blobStore, Mockito.never()).deleteFromStorageContainer(any(String.class), any(String.class), any(String.class)); + verify(blobStore, Mockito.never()).deleteFromStorageContainer(any(String.class), any(String.class), any(String.class)); } @Test - public void shouldNotInvokeDeleteOnBlobStoreWhenReferencedFromOtherDocuments() { - RecordMetadata recordMetadata = setUpRecordMetadata(); - recordMetadata.setGcsVersionPaths(Arrays.asList("path1")); - Mockito.when(entitlementsHelper.hasOwnerAccessToRecord(recordMetadata)).thenReturn(true); - Mockito.when(recordRepository.getMetadataDocumentCountForBlob("path1")).thenReturn(1); + void shouldNotInvokeDeleteOnBlobStoreWhenReferencedFromOtherDocuments() { + RecordMetadata recordMetadata = setUpRecordMetadata("id1"); + recordMetadata.setGcsVersionPaths(List.of("path1")); + when(entitlementsHelper.hasOwnerAccessToRecord(recordMetadata)).thenReturn(true); + when(recordRepository.getMetadataDocumentCountForBlob("path1")).thenReturn(1); cloudStorage.delete(recordMetadata); - Mockito.verify(blobStore, Mockito.never()).deleteFromStorageContainer(any(String.class), any(String.class), any(String.class)); + verify(blobStore, Mockito.never()).deleteFromStorageContainer(any(String.class), any(String.class), any(String.class)); } - @Test(expected = AppException.class) - public void shouldThrowAppExceptionWhenDeleteWithNoOwnerAccess() { - RecordMetadata recordMetadata = setUpRecordMetadata(); + @Test + void shouldThrowAppExceptionWhenDeleteWithNoOwnerAccess() { + RecordMetadata recordMetadata = setUpRecordMetadata("id1"); recordMetadata.setGcsVersionPaths(Arrays.asList("path1", "path2")); - Mockito.when(entitlementsHelper.hasOwnerAccessToRecord(recordMetadata)).thenReturn(false); - cloudStorage.delete(recordMetadata); + when(entitlementsHelper.hasOwnerAccessToRecord(recordMetadata)).thenReturn(false); + + AppException exception = assertThrows(AppException.class, () -> cloudStorage.delete(recordMetadata)); + + validateAccessDeniedException(exception); } @Test - public void shouldDeleteAllVersionsFromBlobStoreUponDeleteAction() { - RecordMetadata recordMetadata = setUpRecordMetadata(); + void shouldDeleteAllVersionsFromBlobStoreUponDeleteAction() { + RecordMetadata recordMetadata = setUpRecordMetadata("id1"); recordMetadata.setGcsVersionPaths(Arrays.asList("path1", "path2")); - Mockito.when(entitlementsHelper.hasOwnerAccessToRecord(recordMetadata)).thenReturn(true); - Mockito.when(recordRepository.getMetadataDocumentCountForBlob("path1")).thenReturn(0); - Mockito.when(recordRepository.getMetadataDocumentCountForBlob("path2")).thenReturn(0); + + when(entitlementsHelper.hasOwnerAccessToRecord(recordMetadata)).thenReturn(true); + when(recordRepository.getMetadataDocumentCountForBlob("path1")).thenReturn(0); + when(recordRepository.getMetadataDocumentCountForBlob("path2")).thenReturn(0); + when(headers.getPartitionId()).thenReturn(DATA_PARTITION); + cloudStorage.delete(recordMetadata); - Mockito.verify(blobStore, Mockito.times(1)).deleteFromStorageContainer(DATA_PARTITION, "path1", CONTAINER); - Mockito.verify(blobStore, Mockito.times(1)).deleteFromStorageContainer(DATA_PARTITION, "path2", CONTAINER); + verify(blobStore, Mockito.times(1)).deleteFromStorageContainer(DATA_PARTITION, "path1", CONTAINER); + verify(blobStore, Mockito.times(1)).deleteFromStorageContainer(DATA_PARTITION, "path2", CONTAINER); + } + + @Test + void shouldWriteToBlob_when_writeIsCalled() { + ExecutorService executorService = Executors.newFixedThreadPool(3); + ReflectionTestUtils.setField(cloudStorage, "threadPool", executorService); + + RecordMetadata recordMetadata = setUpRecordMetadata("id1"); + recordMetadata.setGcsVersionPaths(Collections.singletonList("path/1")); + RecordData recordData = createAndGetRandomRecordData(); + + when(headers.getPartitionId()).thenReturn(DATA_PARTITION); + when(recordProcessing.getRecordData()).thenReturn(recordData); + when(recordProcessing.getRecordMetadata()).thenReturn(recordMetadata); + + cloudStorage.write(recordProcessing); + + Gson gson = new GsonBuilder().serializeNulls().create(); + verify(blobStore, Mockito.times(1)).writeToStorageContainer(DATA_PARTITION, "kind/id1/1", gson.toJson(recordData), CONTAINER); + } + + @Test + void updateObjectMetadata_updatesWhenIdsMatch() { + RecordMetadata recordMetadata = setUpRecordMetadata("id1"); + List<RecordMetadata> recordMetadataList = Collections.singletonList(recordMetadata); + + List<String> recordsId = Collections.singletonList("data-partition:record1:version:1"); + Map<String, String> recordsIdMap = new HashMap<>(); + recordsIdMap.put("id1", "data-partition:record1:version:1"); + + Map<String, RecordMetadata> currentRecords = new HashMap<>(); + currentRecords.put("id1", recordMetadata); + + when(recordRepository.get(recordsId, Optional.empty())).thenReturn(currentRecords); + recordMetadata.setGcsVersionPaths(Arrays.asList("path/0", "path/1")); + List<RecordMetadata> validMetaData = new ArrayList<>(); + // Execution + Map<String, Acl> originalAcls = cloudStorage.updateObjectMetadata(recordMetadataList, recordsId, validMetaData, new ArrayList<>(), recordsIdMap, Optional.empty()); + + // Verification + assertEquals(1, originalAcls.size()); + assertEquals(1, validMetaData.size()); + } + + @Test + void updateObjectMetadata_updatesWhenIdsDontMatch() { + RecordMetadata recordMetadata = setUpRecordMetadata("id1"); + List<RecordMetadata> recordMetadataList = Collections.singletonList(recordMetadata); + + List<String> recordsId = Collections.singletonList("data-partition:record1:version:1"); + Map<String, String> recordsIdMap = new HashMap<>(); + recordsIdMap.put("id1", "data-partition:record1:version:1"); + + Map<String, RecordMetadata> currentRecords = new HashMap<>(); + currentRecords.put("id1", recordMetadata); + + when(recordRepository.get(recordsId, Optional.empty())).thenReturn(currentRecords); + recordMetadata.setGcsVersionPaths(Arrays.asList("path/1", "path/2")); + List<String> lockedRecords = new ArrayList<>(); + List<RecordMetadata> validMetaData = new ArrayList<>(); + // Execution + Map<String, Acl> originalAcls = cloudStorage.updateObjectMetadata(recordMetadataList, recordsId, validMetaData, lockedRecords, recordsIdMap, Optional.empty()); + + // Verification + assertEquals(0, originalAcls.size()); + assertEquals(0, validMetaData.size()); + assertEquals(1, lockedRecords.size()); + } + + @Test + void readWithVersion_isSuccessful() { + RecordMetadata recordMetadata = setUpRecordMetadata("id1"); + recordMetadata.setGcsVersionPaths(List.of("path1")); + when(entitlementsHelper.hasViewerAccessToRecord(recordMetadata)).thenReturn(true); + when(headers.getPartitionId()).thenReturn(DATA_PARTITION); + when(recordUtil.getKindForVersion(recordMetadata, "1")).thenReturn("kind"); + + cloudStorage.read(recordMetadata, 1L, true); + + verify(blobStore, Mockito.times(1)).readFromStorageContainer(DATA_PARTITION, "kind/id1/1", CONTAINER); + } + + @Test + void testReadWithVersion_recoversObject_whenDataInconsistencyIsFound() { + RecordMetadata recordMetadata = setUpRecordMetadata("id1"); + recordMetadata.setGcsVersionPaths(List.of("path1")); + + when(entitlementsHelper.hasViewerAccessToRecord(recordMetadata)).thenReturn(true); + when(headers.getPartitionId()).thenReturn(DATA_PARTITION); + when(recordUtil.getKindForVersion(recordMetadata, "1")).thenReturn("kind"); + + when(blobStore.readFromStorageContainer(DATA_PARTITION, "kind/id1/1", CONTAINER)).thenThrow(new AppException(HttpStatus.SC_NOT_FOUND, "NotFound", "NotFound")).thenReturn("some content"); + + long version = 1; + cloudStorage.read(recordMetadata, version, true); + + verify(blobStore, Mockito.times(1)).undeleteFromStorageContainer(DATA_PARTITION, "kind/id1/1", CONTAINER); + verify(blobStore, Mockito.times(2)).readFromStorageContainer(DATA_PARTITION, "kind/id1/1", CONTAINER); + } + + @Test + void testReadWithVersion_fails_whenOwnerAndViewerPrivilegesNotPresent() { + RecordMetadata recordMetadata = setUpRecordMetadata("id1"); + recordMetadata.setGcsVersionPaths(List.of("path1")); + + when(entitlementsHelper.hasOwnerAccessToRecord(recordMetadata)).thenReturn(false); + when(entitlementsHelper.hasViewerAccessToRecord(recordMetadata)).thenReturn(false); + + long version = 1; + AppException exception = assertThrows(AppException.class, () -> + cloudStorage.read(recordMetadata, version, true)); + + validateAccessDeniedException(exception); + } + + @Test + void revertObjectMetadata_isSuccessful_whenAllRequirementsAreMet() { + RecordMetadata recordMetadata = setUpRecordMetadata("id1"); + Map<String, org.opengroup.osdu.core.common.model.entitlements.Acl> originalAcls = new HashMap<>(); + Acl acl = Acl.builder() + .viewers(new String[]{"original viewers"}) + .owners(new String[]{"original owners"}) + .build(); + originalAcls.put("id1", acl); + + List<RecordMetadata> recordMetadataList = Collections.singletonList(recordMetadata); + cloudStorage.revertObjectMetadata(recordMetadataList, originalAcls, Optional.empty()); + + assertEquals(originalAcls.get("id1"), recordMetadataList.get(0).getAcl()); + recordMetadata.setAcl(acl); + List<RecordMetadata> originalRecordMetadata = Collections.singletonList(recordMetadata); + + verify(recordRepository, times(1)).createOrUpdate(originalRecordMetadata, Optional.empty()); + } + + @Test + void revertObjectMetadataThrowsInternalServerException_when_recordRepositoryUpdateFails() { + RecordMetadata recordMetadata = setUpRecordMetadata("id1"); + Map<String, org.opengroup.osdu.core.common.model.entitlements.Acl> originalAcls = new HashMap<>(); + Acl acl = Acl.builder() + .viewers(new String[]{"original viewers"}) + .owners(new String[]{"original owners"}) + .build(); + originalAcls.put("id1", acl); + + List<RecordMetadata> recordMetadataList = Collections.singletonList(recordMetadata); + when(recordRepository.createOrUpdate(any(), any())). + thenThrow(RuntimeException.class); + + Optional<CollaborationContext> context = Optional.empty(); + AppException exception = assertThrows(AppException.class, () -> + cloudStorage.revertObjectMetadata(recordMetadataList, originalAcls, context)); + + assertEquals(originalAcls.get("id1"), recordMetadataList.get(0).getAcl()); + assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, exception.getError().getCode()); + } + + @Test + void shouldReadSuccessfullyFromBlobstore_when_readRecords() { + Map<String, String> objects = new HashMap<>(); + objects.put("id1", "path1"); + objects.put("id2", "path2"); + Map<String, RecordMetadata> recordMetadatarecordMetadataMap = new HashMap<>(); + recordMetadatarecordMetadataMap.put("id1", setUpRecordMetadata("id1")); + recordMetadatarecordMetadataMap.put("id2", setUpRecordMetadata("id2")); + when(recordRepository.get(objects.keySet().stream().toList(), Optional.empty())) + .thenReturn(recordMetadatarecordMetadataMap); + when(headers.getPartitionId()).thenReturn(DATA_PARTITION); + when(entitlementsHelper.hasViewerAccessToRecord(any())).thenReturn(Boolean.TRUE); + when(blobStore.readFromStorageContainer(DATA_PARTITION, "path1", CONTAINER)).thenReturn("content1"); + when(blobStore.readFromStorageContainer(DATA_PARTITION, "path2", CONTAINER)).thenReturn("content2"); + ExecutorService executorService = Executors.newFixedThreadPool(3); + ReflectionTestUtils.setField(cloudStorage, "threadPool", executorService); + + Map<String, String> recordIdContentMap = cloudStorage.read(objects, Optional.empty()); + + verify(blobStore, times(1)) + .readFromStorageContainer(DATA_PARTITION, "path1", CONTAINER); + verify(blobStore, times(1)) + .readFromStorageContainer(DATA_PARTITION, "path2", CONTAINER); + + assertEquals(2, recordIdContentMap.size()); + } + + @Test + void shouldAttemptRestoreBlob_when_blobStoreReadThrowsException() { + Map<String, String> objectsToRead = new HashMap<>(); + objectsToRead.put("id1", "path1"); + objectsToRead.put("id2", "path2"); + Map<String, RecordMetadata> recordMetadatarecordMetadataMap = new HashMap<>(); + recordMetadatarecordMetadataMap.put("id1", setUpRecordMetadata("id1")); + recordMetadatarecordMetadataMap.put("id2", setUpRecordMetadata("id2")); + when(recordRepository.get(objectsToRead.keySet().stream().toList(), Optional.empty())) + .thenReturn(recordMetadatarecordMetadataMap); + when(headers.getPartitionId()).thenReturn(DATA_PARTITION); + when(entitlementsHelper.hasViewerAccessToRecord(any())).thenReturn(Boolean.TRUE); + + when(blobStore.readFromStorageContainer(DATA_PARTITION, "path1", CONTAINER)).thenReturn("content1"); + when(blobStore.readFromStorageContainer(DATA_PARTITION, "path2", CONTAINER)).thenThrow(new AppException(HttpStatus.SC_NOT_FOUND, "NotFound", "NotFound")).thenReturn("content2"); + + ExecutorService executorService = Executors.newFixedThreadPool(3); + ReflectionTestUtils.setField(cloudStorage, "threadPool", executorService); + + Map<String, String> recordIdContentMap = cloudStorage.read(objectsToRead, Optional.empty()); + + verify(blobStore, times(1)) + .readFromStorageContainer(DATA_PARTITION, "path1", CONTAINER); + verify(blobStore, times(2)) + .readFromStorageContainer(DATA_PARTITION, "path2", CONTAINER); + verify(blobStore).undeleteFromStorageContainer(DATA_PARTITION, "path2", CONTAINER); + assertEquals(2, recordIdContentMap.size()); + } + + @Test + void hasAccessReturnsTrue_when_accessToAllRecordsIsPresent() { + RecordMetadata recordMetadata = setUpRecordMetadata("id1"); + RecordMetadata recordMetadata2 = setUpRecordMetadata("id2"); + recordMetadata.setStatus(RecordState.active); + recordMetadata2.setStatus(RecordState.active); + + recordMetadata.setGcsVersionPaths(List.of("1")); + recordMetadata2.setGcsVersionPaths(List.of("2")); + + when(entitlementsHelper.hasViewerAccessToRecord(recordMetadata)).thenReturn(true); + + boolean access = cloudStorage.hasAccess(recordMetadata, recordMetadata2); + + assertTrue(access); + } + + @Test + void hasAccessReturnsTrue_when_accessToOneActiveRecordIsPresent() { + RecordMetadata recordMetadata = setUpRecordMetadata("id1"); + RecordMetadata recordMetadata2 = setUpRecordMetadata("id2"); + recordMetadata.setStatus(RecordState.active); + recordMetadata2.setStatus(RecordState.deleted); + + recordMetadata.setGcsVersionPaths(List.of("1")); + recordMetadata2.setGcsVersionPaths(List.of("2")); + + when(entitlementsHelper.hasViewerAccessToRecord(recordMetadata)).thenReturn(true); + + boolean access = cloudStorage.hasAccess(recordMetadata, recordMetadata2); + + assertTrue(access); + } + + @Test + void hasAccessReturnsFalse_when_accessToAnyRecordIsNotPresent() { + RecordMetadata recordMetadata = setUpRecordMetadata("id1"); + RecordMetadata recordMetadata2 = setUpRecordMetadata("id2"); + recordMetadata.setStatus(RecordState.active); + recordMetadata2.setStatus(RecordState.active); + + recordMetadata.setGcsVersionPaths(List.of("1")); + recordMetadata2.setGcsVersionPaths(List.of("2")); + + when(entitlementsHelper.hasViewerAccessToRecord(recordMetadata)).thenReturn(false); + when(entitlementsHelper.hasViewerAccessToRecord(recordMetadata2)).thenReturn(false); + + boolean access = cloudStorage.hasAccess(recordMetadata, recordMetadata2); + + assertFalse(access); + } + + @Test + void hasAccess_returnsTrue_whenNoRecordsPresent() { + boolean access = cloudStorage.hasAccess(); + + assertTrue(access); + } + + @Test + void hasAccess_returnsTrue_whenRecordsAreDeleted() { + RecordMetadata recordMetadata = setUpRecordMetadata("id1"); + recordMetadata.setStatus(RecordState.deleted); + + boolean access = cloudStorage.hasAccess(recordMetadata); + + assertTrue(access); + } + + @Test + void hasAccess_returnsTrue_whenRecordsHaveNoVersion() { + RecordMetadata recordMetadata = setUpRecordMetadata("id1"); + recordMetadata.setStatus(RecordState.active); + + boolean access = cloudStorage.hasAccess(recordMetadata); + + assertTrue(access); } - private RecordMetadata setUpRecordMetadata() { + @Test + void deleteVersionIsSuccess_when_ownerAccessIsPresent() { + RecordMetadata recordMeta = setUpRecordMetadata("recordId"); + recordMeta.setGcsVersionPaths(List.of("1")); + when(entitlementsHelper.hasOwnerAccessToRecord(recordMeta)).thenReturn(true); + when(headers.getPartitionId()).thenReturn(DATA_PARTITION); + when(recordUtil.getKindForVersion(recordMeta, "1")).thenReturn("kind"); + + cloudStorage.deleteVersion(recordMeta, 1L); + + verify(blobStore, times(1)).deleteFromStorageContainer(DATA_PARTITION, "kind/recordId/1", CONTAINER); + } + + + @Test + void getHash_returnsHashForACollection() { + String recordId = "recordId"; + RecordData recordData = createAndGetRandomRecordData(); + RecordMetadata recordMetadata = setUpRecordMetadata(recordId); + recordMetadata.setGcsVersionPaths(List.of("1")); + when(entitlementsHelper.hasViewerAccessToRecord(recordMetadata)).thenReturn(true); + when(headers.getPartitionId()).thenReturn(DATA_PARTITION); + when(recordUtil.getKindForVersion(recordMetadata, "1")).thenReturn("kind"); + + + Gson gson = new GsonBuilder().serializeNulls().create(); + when(blobStore.readFromStorageContainer(DATA_PARTITION, "kind/recordId/1", CONTAINER)).thenReturn(gson.toJson(recordData)); + + Map<String, String> expectedHashes = new HashMap<>(); + expectedHashes.put(recordId, crcHashGenerator.getHash(recordData)); + ReflectionTestUtils.setField(cloudStorage, "crcHashGenerator", crcHashGenerator); + + assertEquals(expectedHashes, cloudStorage.getHash(List.of(recordMetadata))); + } + + @Test + void getHash_skipsRecord_whenExceptionOccursForOneItemInList() { + String recordId = "recordId"; + RecordData recordData = createAndGetRandomRecordData(); + RecordMetadata recordMetadata = setUpRecordMetadata(recordId); + recordMetadata.setGcsVersionPaths(List.of("1")); + + RecordMetadata recordMetadata2 = setUpRecordMetadata("recordId2"); + recordMetadata2.setGcsVersionPaths(List.of("1")); + when(entitlementsHelper.hasViewerAccessToRecord(recordMetadata)).thenReturn(true); + when(entitlementsHelper.hasViewerAccessToRecord(recordMetadata2)).thenReturn(true); + + when(headers.getPartitionId()).thenReturn(DATA_PARTITION); + when(recordUtil.getKindForVersion(recordMetadata, "1")).thenReturn("kind"); + when(recordUtil.getKindForVersion(recordMetadata2, "1")).thenReturn("kind"); + + + Gson gson = new GsonBuilder().serializeNulls().create(); + when(blobStore.readFromStorageContainer(DATA_PARTITION, "kind/recordId/1", CONTAINER)).thenReturn(gson.toJson(recordData)); + + //return non-compliant data for another record + when(blobStore.readFromStorageContainer(DATA_PARTITION, "kind/recordId2/1", CONTAINER)).thenReturn(recordData.toString()); + + Map<String, String> expectedHashes = new HashMap<>(); + //only one hash in expected output + expectedHashes.put(recordId, crcHashGenerator.getHash(recordData)); + ReflectionTestUtils.setField(cloudStorage, "crcHashGenerator", crcHashGenerator); + + assertEquals(expectedHashes, cloudStorage.getHash(Arrays.asList(recordMetadata, recordMetadata2))); + } + + @Test + void isDuplicated_returnsTrue_whenDuplicatedRecordsFound() { + Map<String, String> hashMap = new HashMap<>(); + RecordData recordData = createAndGetRandomRecordData(); + RecordMetadata recordMetadata = setUpRecordMetadata("recordId"); + + Map.Entry<RecordMetadata, RecordData> kv = new AbstractMap.SimpleEntry<>(recordMetadata, recordData); + + List<String> skippedRecords = new ArrayList<>(); + when(transfer.getSkippedRecords()).thenReturn(skippedRecords); + ReflectionTestUtils.setField(cloudStorage, "crcHashGenerator", crcHashGenerator); + hashMap.put("recordId", crcHashGenerator.getHash(recordData)); + + boolean result = cloudStorage.isDuplicateRecord(transfer, hashMap, kv); + + assertTrue(result); + assertEquals(1, transfer.getSkippedRecords().size()); + } + + @Test + void isDuplicated_returnsFalse_whenDuplicatedRecordsNotFound() { + Map<String, String> hashMap = new HashMap<>(); + RecordData recordData = createAndGetRandomRecordData(); + RecordMetadata recordMetadata = setUpRecordMetadata("recordId"); + + Map.Entry<RecordMetadata, RecordData> kv = new AbstractMap.SimpleEntry<>(recordMetadata, recordData); + + List<String> skippedRecords = new ArrayList<>(); + when(transfer.getSkippedRecords()).thenReturn(skippedRecords); + ReflectionTestUtils.setField(cloudStorage, "crcHashGenerator", crcHashGenerator); + //different record hash + hashMap.put("recordId", crcHashGenerator.getHash(recordData.toString())); + + boolean result = cloudStorage.isDuplicateRecord(transfer, hashMap, kv); + + assertFalse(result); + assertEquals(0, transfer.getSkippedRecords().size()); + } + + private RecordMetadata setUpRecordMetadata(String id) { Record record = new Record(); - record.setId("id1"); + record.setId(id); Acl acl = Acl.builder() .viewers(new String[]{"viewers"}) .owners(new String[]{"owners"}) @@ -111,4 +524,21 @@ public class CloudStorageImplTest { RecordMetadata recordMetadata = new RecordMetadata(record); return recordMetadata; } + + private RecordData createAndGetRandomRecordData() { + RecordData recordData = new RecordData(); + Map<String, Object> data = new HashMap<>(); + data.put("key", "value"); + recordData.setData(data); + recordData.setMeta(new Map[]{data}); + recordData.setModifyTime(123L); + recordData.setModifyUser("user"); + return recordData; + } + + private void validateAccessDeniedException(AppException exception) { + assertNotNull(exception); + assertEquals(403, exception.getError().getCode()); + assertEquals("The user is not authorized to perform this action", exception.getError().getMessage()); + } } diff --git a/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/EntitlementsAndCacheServiceAzureTest.java b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/EntitlementsAndCacheServiceAzureTest.java new file mode 100644 index 0000000000000000000000000000000000000000..89f9efb624b33fd944173eaee04dcde2f1ce2886 --- /dev/null +++ b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/EntitlementsAndCacheServiceAzureTest.java @@ -0,0 +1,132 @@ +package org.opengroup.osdu.storage.provider.azure; + +import org.apache.http.HttpStatus; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.opengroup.osdu.core.common.cache.ICache; +import org.opengroup.osdu.core.common.entitlements.IEntitlementsFactory; +import org.opengroup.osdu.core.common.entitlements.IEntitlementsService; +import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; +import org.opengroup.osdu.core.common.model.entitlements.EntitlementsException; +import org.opengroup.osdu.core.common.model.entitlements.GroupInfo; +import org.opengroup.osdu.core.common.model.entitlements.Groups; +import org.opengroup.osdu.core.common.model.http.AppException; +import org.opengroup.osdu.core.common.model.http.DpsHeaders; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class EntitlementsAndCacheServiceAzureTest { + + private static final String expectedErrorMessage = "Unknown error happened when validating ACL"; + @InjectMocks + EntitlementsAndCacheServiceAzure entitlementsAndCacheServiceAzure; + @Mock + private ICache<String, Groups> cache; + @Mock + private DpsHeaders headers; + @Mock + private IEntitlementsFactory entitlementsFactory; + @Mock + private IEntitlementsService entitlementsService; + @Mock + private JaxRsDpsLog logger; + + @Test + void hasAccessToDataReturnsTrue_when_RequiredGroupsArePresent() { + when(cache.get(Mockito.any())).thenReturn(createRandomGroup()); + Set<String> acls = new HashSet<>(); + acls.add("service.service_name2.user@blabla.com"); + + boolean result = entitlementsAndCacheServiceAzure.hasAccessToData(headers, acls); + + assertTrue(result); + } + + @Test + void hasAccessToDataThrowsAppException_when_noRequiredGroupsArePresent() { + when(cache.get(Mockito.any())).thenReturn(new Groups()); + Set<String> acls = new HashSet<>(); + + AppException appException = assertThrows(AppException.class, () -> entitlementsAndCacheServiceAzure.hasAccessToData(headers, acls)); + + assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, appException.getError().getCode()); + assertEquals(expectedErrorMessage, appException.getError().getMessage()); + } + + @Test + void hasAccessToDataThrowsAppException_when_emailIdValidationFails() { + Groups groups = createRandomGroup(); + groups.getGroups().get(0).setEmail("invalid_email_without_any_dot_coms"); + when(cache.get(Mockito.any())).thenReturn(groups); + Set<String> acls = new HashSet<>(); + + AppException appException = assertThrows(AppException.class, () -> entitlementsAndCacheServiceAzure.hasAccessToData(headers, acls)); + + assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, appException.getError().getCode()); + assertEquals(expectedErrorMessage, appException.getError().getMessage()); + } + + @Test + void hasAccessToDataReturnsFalse_when_noAclsPresent() { + Groups groups = createRandomGroup(); + when(cache.get(Mockito.any())).thenReturn(groups); + Set<String> acls = new HashSet<>(); + + boolean bAccessPresent = entitlementsAndCacheServiceAzure.hasAccessToData(headers, acls); + + assertFalse(bAccessPresent); + } + + @Test + void hasAccessToDataReturnsFalse_when_noAclTenantsDontMatch() { + Groups groups = createRandomGroup(); + when(cache.get(Mockito.any())).thenReturn(groups); + Set<String> acls = new HashSet<>(); + acls.add("group_not_present_in_groups@different_domain.com"); + + boolean bAccessPresent = entitlementsAndCacheServiceAzure.hasAccessToData(headers, acls); + + assertFalse(bAccessPresent); + } + + @Test + void hasAccessToDataReturnsFalse_when_noAclRolesDontMatch() { + Groups groups = createRandomGroup(); + when(cache.get(Mockito.any())).thenReturn(groups); + Set<String> acls = new HashSet<>(); + acls.add("group_not_present_in_groups@blabla.com"); + + boolean bAccessPresent = entitlementsAndCacheServiceAzure.hasAccessToData(headers, acls); + + assertFalse(bAccessPresent); + } + + private Groups createRandomGroup() { + Groups groups = new Groups(); + + GroupInfo groupInfo = new GroupInfo(); + groupInfo.setEmail("service.service_name.user@blabla.com"); + groupInfo.setName("service.service_name.user"); + groupInfo.setDescription("description"); + + GroupInfo groupInfo2 = new GroupInfo(); + groupInfo2.setEmail("service.service_name2.user@blabla.com"); + groupInfo2.setName("service.service_name2.user"); + groupInfo2.setDescription("description"); + + groups.setDesId("username@blabla.com"); + groups.setMemberEmail("username@blabla.com"); + groups.setGroups(Arrays.asList(groupInfo, groupInfo2)); + return groups; + } +} diff --git a/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/MessageBusImplTest.java b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/MessageBusImplTest.java index 3b0e4bc5b0b2fefa06839c7b49d369af87fdd8d1..cfefe361d5c22d1229905fa72f0ae95fccdaeadd 100644 --- a/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/MessageBusImplTest.java +++ b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/MessageBusImplTest.java @@ -15,41 +15,36 @@ package org.opengroup.osdu.storage.provider.azure; import com.microsoft.azure.servicebus.primitives.ServiceBusException; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; import org.opengroup.osdu.azure.publisherFacade.MessagePublisher; -import org.opengroup.osdu.azure.publisherFacade.PubsubConfiguration; -import org.opengroup.osdu.core.common.feature.IFeatureFlag; import org.opengroup.osdu.core.common.model.http.CollaborationContext; import org.opengroup.osdu.core.common.model.http.DpsHeaders; import org.opengroup.osdu.core.common.model.storage.PubSubInfo; import org.opengroup.osdu.storage.model.RecordChangedV2; import org.opengroup.osdu.storage.provider.azure.di.EventGridConfig; -import org.opengroup.osdu.storage.provider.azure.di.ServiceBusConfig; import org.opengroup.osdu.storage.provider.azure.di.PublisherConfig; +import org.opengroup.osdu.storage.provider.azure.di.ServiceBusConfig; import java.util.Optional; import java.util.UUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; -import static org.mockito.MockitoAnnotations.initMocks; -@RunWith(MockitoJUnitRunner.class) -public class MessageBusImplTest { +@ExtendWith(MockitoExtension.class) +class MessageBusImplTest { private static final String TOPIC_NAME = "recordstopic"; private final static String RECORDS_CHANGED_EVENT_SUBJECT = "RecordsChanged"; private final static String RECORDS_CHANGED_EVENT_TYPE = "RecordsChanged"; private final static String RECORDS_CHANGED_EVENT_DATA_VERSION = "1.0"; - + private static final String PUBSUB_BATCH_SIZE = "10"; private final Optional<CollaborationContext> COLLABORATION_CONTEXT = Optional.ofNullable(CollaborationContext.builder().id(UUID.fromString("9e1c4e74-3b9b-4b17-a0d5-67766558ec65")).application("TestApp").build()); - private final static String FEATURE_NAME = "collaborations-enabled"; - private final static String PARTITION_ID = "partitionId"; - @Mock private MessagePublisher messagePublisher; @Mock @@ -59,18 +54,13 @@ public class MessageBusImplTest { @Mock private PublisherConfig publisherConfig; @Mock - public IFeatureFlag iCollaborationFeatureFlag; - @Mock - private PubsubConfiguration pubsubConfiguration; - @Mock private DpsHeaders dpsHeaders; @InjectMocks - private MessageBusImpl sut; + private MessageBusImpl messageBus; - @Before - public void init() throws ServiceBusException, InterruptedException { - initMocks(this); - doReturn("10").when(publisherConfig).getPubSubBatchSize(); + @BeforeEach + void init(){ + doReturn(PUBSUB_BATCH_SIZE).when(publisherConfig).getPubSubBatchSize(); doReturn(TOPIC_NAME).when(eventGridConfig).getEventGridTopic(); doReturn(RECORDS_CHANGED_EVENT_SUBJECT).when(eventGridConfig).getEventSubject(); doReturn(RECORDS_CHANGED_EVENT_DATA_VERSION).when(eventGridConfig).getEventDataVersion(); @@ -78,30 +68,36 @@ public class MessageBusImplTest { } @Test - public void should_publishToMessagePublisher() { + void publishMessage_should_publishesInBatches_when_messageSizeGreaterThanBatchSize() { // Set Up String[] ids = {"id1", "id2", "id3", "id4", "id5", "id6", "id7", "id8", "id9", "id10", "id11"}; String[] kinds = {"kind1", "kind2", "kind3", "kind4", "kind5", "kind6", "kind7", "kind8", "kind9", "kind10", "kind11"}; - doNothing().when(messagePublisher).publishMessage(eq(dpsHeaders), any(), any()); - PubSubInfo[] pubSubInfo = new PubSubInfo[11]; for (int i = 0; i < ids.length; ++i) { pubSubInfo[i] = getPubsInfo(ids[i], kinds[i]); } - sut.publishMessage(dpsHeaders, pubSubInfo); + + messageBus.publishMessage(dpsHeaders, pubSubInfo); + + int batch_size = Integer.parseInt(PUBSUB_BATCH_SIZE); + Mockito.verify(messagePublisher, times(ids.length % batch_size + 1)).publishMessage(eq(dpsHeaders), any(), any()); } @Test - public void should_publishToOnlyRecordsEventTopic_WhenCollaborationContextIsProvided() { + void should_publishToOnlyRecordsEventTopic_WhenCollaborationContextIsProvided() { RecordChangedV2[] recordChangedV2s = setUpRecordsChangedV2(); - sut.publishMessage(COLLABORATION_CONTEXT, dpsHeaders, recordChangedV2s); + + messageBus.publishMessage(COLLABORATION_CONTEXT, dpsHeaders, recordChangedV2s); + verify(messagePublisher, times(1)).publishMessage(any(), any(), eq(COLLABORATION_CONTEXT)); } @Test - public void should_publishToBothTopics_WhenCollaborationContextIsNotProvided() { + void should_publishToBothTopics_WhenCollaborationContextIsNotProvided() { PubSubInfo[] pubSubInfo = setupPubSubInfo(); - sut.publishMessage(dpsHeaders, pubSubInfo); + + messageBus.publishMessage(dpsHeaders, pubSubInfo); + verify(messagePublisher, times(1)).publishMessage(any(), any(), eq(Optional.empty())); } diff --git a/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/QueryRepositoryTest.java b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/QueryRepositoryTest.java deleted file mode 100644 index 8175e5642f3be56fc544c6b9aeff2f560e7c0ad1..0000000000000000000000000000000000000000 --- a/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/QueryRepositoryTest.java +++ /dev/null @@ -1,85 +0,0 @@ -package org.opengroup.osdu.storage.provider.azure; - -import com.azure.cosmos.models.CosmosQueryRequestOptions; -import com.azure.cosmos.models.SqlQuerySpec; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; -import org.opengroup.osdu.azure.cosmosdb.CosmosStore; -import org.opengroup.osdu.core.common.model.http.DpsHeaders; -import org.opengroup.osdu.core.common.model.storage.DatastoreQueryResult; -import org.opengroup.osdu.core.common.model.storage.SchemaItem; -import org.opengroup.osdu.storage.provider.azure.repository.QueryRepository; -import org.opengroup.osdu.storage.provider.azure.repository.SchemaRepository; -import org.springframework.data.domain.Sort; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.MockitoAnnotations.initMocks; - -@RunWith(MockitoJUnitRunner.class) -public class QueryRepositoryTest { - - private final String cosmosDBName = "osdu-db"; - private final String dataPartitionID = "opendes"; - private final String storageContainer = "StorageRecord"; - - @InjectMocks - private QueryRepository repo = new QueryRepository(); - - @Mock(lenient = true) - private CosmosStore cosmosStore; - - @Mock(lenient = true) - private DpsHeaders dpsHeaders; - - @Before - public void setUp() { - initMocks(this); - Mockito.when(dpsHeaders.getPartitionId()).thenReturn(dataPartitionID); - } - - private static final String KIND1 = "ztenant:source:type:1.0.0"; - private static final String KIND2 = "atenant:source:type:1.0.0"; - - - @Test - public void testGetAllKindsNoRecords() { - // No records found - List<String> result = new ArrayList<>(); - Mockito.when(cosmosStore.queryItems(eq(dataPartitionID), eq(cosmosDBName), eq(storageContainer), any(), any(), any())).thenReturn(Collections.singletonList(result)); //th - DatastoreQueryResult datastoreQueryResult = repo.getAllKinds(null, null); - Assert.assertEquals(datastoreQueryResult.getResults(), Collections.singletonList(result)); - } - - @Test - public void testGetAllKindsOneRecord() { - List<String> result = new ArrayList<>(); - result.add(KIND1); - Mockito.when(cosmosStore.queryItems(eq(dataPartitionID), eq(cosmosDBName), eq(storageContainer), any(), any(), any())).thenReturn(Collections.singletonList(result)); //th - DatastoreQueryResult datastoreQueryResult = repo.getAllKinds(null, null); - // Expected one kind - Assert.assertEquals(datastoreQueryResult.getResults().size(), result.size()); - } - - @Test - public void testGetAllKindsMultipleRecord() { - List<String> result = new ArrayList<>(); - result.add(KIND1); - result.add(KIND2); - Mockito.when(cosmosStore.queryItems(eq(dataPartitionID), eq(cosmosDBName), eq(storageContainer), any(), any(), any())).thenReturn(Collections.singletonList(result)); //th - DatastoreQueryResult datastoreQueryResult = repo.getAllKinds(null, null); - List<String> results = datastoreQueryResult.getResults(); - Assert.assertEquals(results, Collections.singletonList(result)); - } -} diff --git a/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/generator/FindQuerySpecGeneratorTest.java b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/generator/FindQuerySpecGeneratorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1e55f407c6a516a030318f161c737c14bef349cb --- /dev/null +++ b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/generator/FindQuerySpecGeneratorTest.java @@ -0,0 +1,85 @@ +package org.opengroup.osdu.storage.provider.azure.generator; + +import com.azure.cosmos.models.SqlQuerySpec; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.junit.jupiter.MockitoExtension; +import org.opengroup.osdu.storage.provider.azure.query.CosmosStoreQuery; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class FindQuerySpecGeneratorTest { + + @InjectMocks + FindQuerySpecGenerator findQuerySpecGenerator; + + @Test + void generateWithQueryTextShouldCreateQueryWithOrdering_whenOrderingIsPresent() { + CosmosStoreQuery query = new CosmosStoreQuery(); + query.with(mock(Pageable.class)); + query.with(Sort.by("id")).with(Sort.by("field2")); + + String queryText = "Select id, f1, f2, f3 from c"; + String expectedQuery = "Select id, f1, f2, f3 from c ORDER BY c.field2 ASC,c.id ASC"; + + SqlQuerySpec querySpec = findQuerySpecGenerator.generateWithQueryText(query, queryText); + + assertEquals(expectedQuery, querySpec.getQueryText()); + } + + @Test + void generateWithQueryTextShouldCreateQueryWithoutOrdering_whenOrderingIsNotPresent() { + CosmosStoreQuery query = mock(CosmosStoreQuery.class); + when(query.getSort()).thenReturn(Sort.unsorted()); + + String queryText = "Select id, f1, f2, f3"; + String expectedQuery = "Select id, f1, f2, f3 "; + + SqlQuerySpec querySpec = findQuerySpecGenerator.generateWithQueryText(query, queryText); + + assertEquals(expectedQuery, querySpec.getQueryText()); + } + + @Test + void generateWithQueryTextShouldThrowIllegalArgumentsException_whenIgnoreCaseIsPresentOnSort() { + //arrange + CosmosStoreQuery query = mock(CosmosStoreQuery.class); + when(query.getSort()).thenReturn(Sort.by(Sort.Order.by("id").ignoreCase())); + + //act + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, + () -> findQuerySpecGenerator.generateWithQueryText(query, "queryText")); + + assertTrue(exception.getMessage().contains("Ignore case is not supported")); + } + + @Test + void generateShouldGenerateQuery_whenCosmosQueryIsProvided() { + CosmosStoreQuery query = mock(CosmosStoreQuery.class); + when(query.getSort()).thenReturn(Sort.by("id")); + String expectedQuery = "SELECT * FROM c ORDER BY c.id ASC"; + + SqlQuerySpec sqlQuerySpec = findQuerySpecGenerator.generate(query); + + assertEquals(expectedQuery, sqlQuerySpec.getQueryText()); + } + + @Test + void generateWithQueryTextShouldIgnoreOrder_whenOrderingIsNotPresent() { + CosmosStoreQuery query = new CosmosStoreQuery(); + query.with(mock(Pageable.class)); + query.with(Sort.by("id")).with(Sort.unsorted()); + + String queryText = "Select id, f1, f2, f3 from c"; + String expectedQuery = "Select id, f1, f2, f3 from c ORDER BY c.id ASC"; + + SqlQuerySpec querySpec = findQuerySpecGenerator.generateWithQueryText(query, queryText); + assertEquals(expectedQuery, querySpec.getQueryText()); + } +} diff --git a/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/pubsub/LegalComplianceChangeUpdateTest.java b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/pubsub/LegalComplianceChangeUpdateTest.java index cab1ffe72512228203ec5eab9a75c2674afc57f7..51e3b6d89aca275717673b51ce4d246e9513eb33 100644 --- a/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/pubsub/LegalComplianceChangeUpdateTest.java +++ b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/pubsub/LegalComplianceChangeUpdateTest.java @@ -7,23 +7,24 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; +import org.opengroup.osdu.core.common.model.http.AppException; +import org.opengroup.osdu.storage.provider.azure.config.ThreadDpsHeaders; import org.opengroup.osdu.storage.provider.azure.service.LegalComplianceChangeServiceAzureImpl; import org.opengroup.osdu.storage.provider.azure.util.MDCContextMap; -import static org.junit.jupiter.api.Assertions.*; - import java.util.Collections; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) -public class LegalComplianceChangeUpdateTest { +class LegalComplianceChangeUpdateTest { private static final String emptyMessage = "{}"; private static final String messageId = "40cc96f5-85b9-4923-9a5b-c27f67a3e815"; - private static Exception exception = null; private static final String validIMessage = "{\"id\":\"40cc96f5-85b9-4923-9a5b-c27f67a3e815\",\"subject\":\"legaltagschanged\",\"data\":{\"deliveryCount\":0,\"messageId\":\"9aa0cb2c-baf6-4dcb-ae5a-c29aecca59cd\",\"messageBody\":{\"bodyType\":\"BINARY\",\"binaryData\":[\"eyJtZXNzYWdlIjp7ImRhdGEiOnsic3RhdHVzQ2hhbmdlZFRhZ3MiOlt7ImNoYW5nZWRUYWdOYW1lIjoib3BlbmRlcy1wdWJsaWMtdXNhLWRhdGFzZXQtMSIsImNoYW5nZWRUYWdTdGF0dXMiOiJpbmNvbXBsaWFudCJ9LHsiY2hhbmdlZFRhZ05hbWUiOiJvcGVuZGVzLXN0b3JhZ2UtMTYwMTk5MTMwNzkzMCIsImNoYW5nZWRUYWdTdGF0dXMiOiJpbmNvbXBsaWFudCJ9XX0sImFjY291bnQtaWQiOiJvcGVuZGVzIiwiZGF0YS1wYXJ0aXRpb24taWQiOiJvcGVuZGVzIiwiY29ycmVsYXRpb24taWQiOiI5NWFiMTVkZC00NjYzLTRjMmYtYjZmZS1kNjdiNjI1ODU4ZWEiLCJ1c2VyIjoiYTM4ZmRkN2ItZjIwOS00NTUyLTk2Y2QtMTI2ZWMyNDk0NjA1In19\"]},\"contentType\":\"application/json\",\"sequenceNumber\":0,\"properties\":{\"account-id\":\"opendes\",\"correlation-id\":\"95ab15dd-4663-4c2f-b6fe-d67b625858ea\",\"user\":\"a38fdd7b-f209-4552-96cd-126ec2494605\",\"data-partition-id\":\"opendes\"}},\"eventType\":\"legaltagschanged\",\"dataVersion\":\"1.0\",\"metadataVersion\":\"1\",\"eventTime\":\"2021-06-18T20:33:50.038Z\",\"topic\":\"/subscriptions/7c052588-ead2-45c9-9346-5b156a157bd1/resourceGroups/osdu-mvp-dp1dev-qs29-rg/providers/Microsoft.EventGrid/topics/osdu-mvp-dp1dev-qs29-grid-legaltagschangedtopic\"}"; - + private static Exception exception = null; @InjectMocks private LegalComplianceChangeUpdate legalComplianceChangeUpdate; @@ -36,14 +37,19 @@ public class LegalComplianceChangeUpdateTest { @Mock private Message message; + @Mock + private ThreadDpsHeaders headers; + + @Mock + private ComplianceMessagePullReceiver complianceMessagePullReceiver; @BeforeEach - public void init() { + void init() { lenient().when(message.getMessageId()).thenReturn(messageId); } @Test - public void shouldRaiseInRetrieveDataFromMessage() throws Exception { + void shouldRaiseInRetrieveDataFromMessage() { when(message.getMessageBody()).thenReturn(getMessageBody(emptyMessage)); try { legalComplianceChangeUpdate.updateCompliance(message); @@ -54,21 +60,53 @@ public class LegalComplianceChangeUpdateTest { } @Test - public void shouldRaiseNullPointerException() throws Exception { + void shouldRaiseNullPointerException() throws Exception { when(message.getMessageBody()).thenReturn(getMessageBody(validIMessage)); try { legalComplianceChangeUpdate.updateCompliance(message); verify(message, times(1)).getMessageBody(); verify(message, times(1)).setMessageId(messageId); - } - catch (NullPointerException ex){ + } catch (NullPointerException ex) { exception = ex; } assertNotNull(exception); } + private MessageBody getMessageBody(String messageValue) { byte[] binaryData = messageValue.getBytes(); return MessageBody.fromBinaryData(Collections.singletonList(binaryData)); } -} \ No newline at end of file + + @Test + void updateComplianceShouldUpdateThePullReceiver_whenMessageIsValid() throws Exception { + when(message.getMessageBody()).thenReturn(getMessageBody(validIMessage)); + + legalComplianceChangeUpdate.updateCompliance(message); + + verify(complianceMessagePullReceiver).receiveMessage(any(), any()); + } + + @Test + void updateComplianceShouldThrowAppException_whenComplianceMessagePullReceiverThrowsAppException() throws Exception { + when(message.getMessageBody()).thenReturn(getMessageBody(validIMessage)); + AppException exception = new AppException(403, "some error", "some error"); + Mockito.doThrow(exception).when(complianceMessagePullReceiver).receiveMessage(any(), any()); + + AppException actualException = assertThrows(AppException.class, () -> legalComplianceChangeUpdate.updateCompliance(message)); + + verify(complianceMessagePullReceiver).receiveMessage(any(), any()); + assertEquals(exception.getMessage(), actualException.getError().getMessage()); + } + + @Test + void updateComplianceShouldThrowException_whenComplianceMessagePullReceiverThrowsException() throws Exception { + when(message.getMessageBody()).thenReturn(getMessageBody(validIMessage)); + Exception exception = new RuntimeException("some error"); + + doThrow(exception).when(complianceMessagePullReceiver).receiveMessage(any(), any()); + + assertThrows(Exception.class, () -> legalComplianceChangeUpdate.updateCompliance(message)); + verify(complianceMessagePullReceiver).receiveMessage(any(), any()); + } +} diff --git a/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/repository/QueryRepositoryTest.java b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/repository/QueryRepositoryTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f33ab5e4ad3e2b618020d80153652ba602c4621d --- /dev/null +++ b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/repository/QueryRepositoryTest.java @@ -0,0 +1,285 @@ +package org.opengroup.osdu.storage.provider.azure.repository; + +import com.azure.cosmos.CosmosException; +import org.apache.http.HttpStatus; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.opengroup.osdu.azure.cosmosdb.CosmosStore; +import org.opengroup.osdu.azure.query.CosmosStorePageRequest; +import org.opengroup.osdu.core.common.cache.ICache; +import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; +import org.opengroup.osdu.core.common.model.entitlements.Acl; +import org.opengroup.osdu.core.common.model.http.AppException; +import org.opengroup.osdu.core.common.model.http.CollaborationContext; +import org.opengroup.osdu.core.common.model.http.DpsHeaders; +import org.opengroup.osdu.core.common.model.storage.DatastoreQueryResult; +import org.opengroup.osdu.core.common.model.storage.RecordMetadata; +import org.opengroup.osdu.storage.provider.azure.RecordMetadataDoc; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.test.util.ReflectionTestUtils; + +import java.util.*; + +import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class QueryRepositoryTest { + + private static final String KIND1 = "ztenant:source:type:1.0.0"; + private static final String KIND2 = "atenant:source:type:1.0.0"; + private final String cosmosDBName = "osdu-db"; + private final String dataPartitionID = "opendes"; + private final String storageContainer = "StorageRecord"; + @Mock + Page<RecordMetadataDoc> page; + @Mock + private RecordMetadataRepository recordMetadataRepository; + @InjectMocks + private QueryRepository queryRepository = new QueryRepository(); + @Mock(lenient = true) + private CosmosStore cosmosStore; + @Mock(lenient = true) + private DpsHeaders dpsHeaders; + @Mock + private JaxRsDpsLog logger; + + @Mock(name = "CursorCache") + private ICache<String, String> cursorCache; + + @BeforeEach + public void setUp() { + when(dpsHeaders.getPartitionId()).thenReturn(dataPartitionID); + ReflectionTestUtils.setField(queryRepository, "record", recordMetadataRepository); + } + + @Test + void testGetAllKindsNoRecords() { + // No records found + List<String> result = new ArrayList<>(); + when(cosmosStore.queryItems(eq(dataPartitionID), eq(cosmosDBName), eq(storageContainer), any(), any(), any())).thenReturn(Collections.singletonList(result)); //th + + DatastoreQueryResult datastoreQueryResult = queryRepository.getAllKinds(null, null); + + assertEquals(datastoreQueryResult.getResults(), Collections.singletonList(result)); + } + + @Test + void testGetAllKindsOneRecord() { + List<String> result = new ArrayList<>(); + result.add(KIND1); + when(cosmosStore.queryItems(eq(dataPartitionID), eq(cosmosDBName), eq(storageContainer), any(), any(), any())).thenReturn(Collections.singletonList(result)); //th + + DatastoreQueryResult datastoreQueryResult = queryRepository.getAllKinds(null, null); + + // Expected one kind + assertEquals(datastoreQueryResult.getResults().size(), result.size()); + } + + @Test + void testGetAllKindsMultipleRecord() { + List<String> result = new ArrayList<>(); + result.add(KIND1); + result.add(KIND2); + + when(cosmosStore.queryItems(eq(dataPartitionID), eq(cosmosDBName), eq(storageContainer), any(), any(), any())).thenReturn(Collections.singletonList(result)); + + DatastoreQueryResult datastoreQueryResult = queryRepository.getAllKinds(null, null); + + List<String> results = datastoreQueryResult.getResults(); + assertEquals(results, Collections.singletonList(result)); + } + + @Test + void getAllRecordIdsFromKindShouldThrowIllegalArgumentsException_whenKindIsNull() { + Optional<CollaborationContext> context = Optional.empty(); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> queryRepository.getAllRecordIdsFromKind(null, 10, "cursor", context)); + + verify(recordMetadataRepository, never()).findIdsByMetadata_kindAndMetadata_status(any(), any(), any(), any()); + + assertTrue(exception.getMessage().contains("kind must not be null")); + } + + @Test + void getAllRecordIdsFromKindShouldReturnAllRecords_whenKindIsNotNull() { + //Arrange + when(recordMetadataRepository.findIdsByMetadata_kindAndMetadata_status(eq("kind"), eq("active"), any(), eq(Optional.empty()))).thenReturn(page); + RecordMetadataDoc doc1 = new RecordMetadataDoc("id1", createRecord("id1")); + RecordMetadataDoc doc2 = new RecordMetadataDoc("id2", createRecord("id2")); + when(page.getContent()).thenReturn(Arrays.asList(doc1, doc2)); + + //Act + DatastoreQueryResult datastoreQueryResult = queryRepository.getAllRecordIdsFromKind("kind", 10, "cursor", Optional.empty()); + + //Assertions + verify(recordMetadataRepository).findIdsByMetadata_kindAndMetadata_status(any(), any(), any(), any()); + assertEquals(2, datastoreQueryResult.getResults().size()); + List<String> expectedResponse = Arrays.asList("id1", "id2"); + assertEquals(expectedResponse, datastoreQueryResult.getResults()); + } + + @Test + void getAllRecordIdsFromKindShouldCallCosmosAgain_whenContinuationTokenIsPresent() { + Pageable pageable = CosmosStorePageRequest.of(0, 3, "continue"); + RecordMetadataDoc doc1 = new RecordMetadataDoc("id1", createRecord("id1")); + RecordMetadataDoc doc2 = new RecordMetadataDoc("id2", createRecord("id2")); + + when(recordMetadataRepository.findIdsByMetadata_kindAndMetadata_status(eq("kind"), eq("active"), any(), eq(Optional.empty()))).thenReturn(page); + when(page.getContent()).thenReturn(Arrays.asList(doc1, doc2)); + when(page.getPageable()).thenReturn(pageable); + + + DatastoreQueryResult datastoreQueryResult = queryRepository.getAllRecordIdsFromKind("kind", 10, "cursor", Optional.empty()); + + + verify(recordMetadataRepository, times(5)).findIdsByMetadata_kindAndMetadata_status(any(), any(), any(), any()); + assertEquals(10, datastoreQueryResult.getResults().size()); + } + + @Test + void getAllRecordIdsByKindShouldThrowBadRequestException_whenCursorIsInvalid() { + CosmosException cosmosException = mock(CosmosException.class); + doReturn(HttpStatus.SC_BAD_REQUEST).when(cosmosException).getStatusCode(); + doReturn("INVALID JSON in continuation token").when(cosmosException).getMessage(); + + when(recordMetadataRepository.findIdsByMetadata_kindAndMetadata_status(eq("kind"), eq("active"), any(), eq(Optional.empty()))).thenThrow(cosmosException); + Optional<CollaborationContext> context = Optional.empty(); + + AppException exception = assertThrows(AppException.class, () -> queryRepository.getAllRecordIdsFromKind("kind", 10, "cursor", context)); + + verify(recordMetadataRepository).findIdsByMetadata_kindAndMetadata_status(any(), any(), any(), any()); + assertEquals(HttpStatus.SC_BAD_REQUEST, exception.getError().getCode()); + } + + @Test + void getAllRecordIdsByKindShouldRethrowException_whenCosmosExceptionIsEncounteredFromRecordRepository() { + CosmosException cosmosException = mock(CosmosException.class); + doReturn(HttpStatus.SC_BAD_REQUEST).when(cosmosException).getStatusCode(); + doReturn("Some other bad request").when(cosmosException).getMessage(); + + when(recordMetadataRepository.findIdsByMetadata_kindAndMetadata_status(eq("kind"), eq("active"), any(), eq(Optional.empty()))).thenThrow(cosmosException); + Optional<CollaborationContext> context = Optional.empty(); + + CosmosException exception = assertThrows(CosmosException.class, () -> queryRepository.getAllRecordIdsFromKind("kind", 10, "cursor", context)); + + verify(recordMetadataRepository).findIdsByMetadata_kindAndMetadata_status(any(), any(), any(), any()); + assertEquals(HttpStatus.SC_BAD_REQUEST, exception.getStatusCode()); + } + + @Test + void getAllRecordIdsByKindShouldRethrowException_whenExceptionIsEncounteredFromRecordRepository() { + Exception exception = new RuntimeException("some exception"); + when(recordMetadataRepository.findIdsByMetadata_kindAndMetadata_status(eq("kind"), eq("active"), any(), eq(Optional.empty()))).thenThrow(exception); + + Exception actualException = assertThrows(Exception.class, () -> queryRepository.getAllRecordIdsFromKind("kind", 10, "cursor", Optional.empty())); + + verify(recordMetadataRepository).findIdsByMetadata_kindAndMetadata_status(any(), any(), any(), any()); + assertEquals(exception, actualException); + } + + @Test + void getAllRecordIdsFromKindShouldReturnAllRecords_whenPaginationIsNotPresent() { + List<RecordMetadataDoc> recordMetadataDocs = new ArrayList<>(); + recordMetadataDocs.add(new RecordMetadataDoc("id1", createRecord("id1"))); + recordMetadataDocs.add(new RecordMetadataDoc("id2", createRecord("id2"))); + List<String> expectedResponse = Arrays.asList("id1", "id2"); + + when(recordMetadataRepository.findIdsByMetadata_kindAndMetadata_status("kind", "active", Optional.empty())).thenReturn(recordMetadataDocs); + + DatastoreQueryResult datastoreQueryResult = queryRepository.getAllRecordIdsFromKind("kind", null, null, Optional.empty()); + + verify(recordMetadataRepository).findIdsByMetadata_kindAndMetadata_status(any(), any(), any()); + assertEquals(2, datastoreQueryResult.getResults().size()); + assertEquals(expectedResponse, datastoreQueryResult.getResults()); + } + + @Test + void getAllKindsShouldReturnAllKinds_whenRecordsArePresent() { + List<Object> docs = new ArrayList<>(); + docs.add("Kind1"); + docs.add("Kind2"); + + when(cosmosStore.queryItems(any(), any(), any(), any(), any(), any())).thenReturn(docs); + when(cursorCache.get("cursor")).thenReturn("0"); + + DatastoreQueryResult datastoreQueryResult = queryRepository.getAllKinds(1, "cursor"); + + verify(cosmosStore).queryItems(any(), any(), any(), any(), any(), any()); + assertEquals(1, datastoreQueryResult.getResults().size()); + } + + @Test + void getAllKindsShouldUseLimitAndIgnoreCursor_whenCursorIsNull() { + List<Object> docs = new ArrayList<>(); + docs.add("Kind1"); + docs.add("Kind2"); + + when(cosmosStore.queryItems(any(), any(), any(), any(), any(), any())).thenReturn(docs); + + DatastoreQueryResult datastoreQueryResult = queryRepository.getAllKinds(1, null); + + verify(cosmosStore).queryItems(any(), any(), any(), any(), any(), any()); + assertEquals(1, datastoreQueryResult.getResults().size()); + } + + @Test + void getAllKindsShouldIgnoreCursorAndLimit_whenBothAreNullAndFetchAllKinds() { + List<Object> docs = new ArrayList<>(); + docs.add("Kind1"); + docs.add("Kind2"); + + when(cosmosStore.queryItems(any(), any(), any(), any(), any(), any())).thenReturn(docs); + + DatastoreQueryResult datastoreQueryResult = queryRepository.getAllKinds(null, null); + + verify(cosmosStore).queryItems(any(), any(), any(), any(), any(), any()); + assertEquals(2, datastoreQueryResult.getResults().size()); + } + + + @Test + void getAllKindsShouldRethrowException_whenCosmosExceptionIsThrown() { + CosmosException expectedException = mock(CosmosException.class); + when(cosmosStore.queryItems(any(), any(), any(), any(), any(), any())).thenThrow(expectedException); + + CosmosException exception = assertThrows(CosmosException.class, () -> queryRepository.getAllKinds(1, "cursor")); + + verify(cosmosStore, times(1)).queryItems(any(), any(), any(), any(), any(), any()); + assertEquals(expectedException, exception); + } + + @Test + void getAllKindsShouldRethrowException_whenGenericExceptionIsThrown() { + RuntimeException expectedException = mock(RuntimeException.class); + when(cosmosStore.queryItems(any(), any(), any(), any(), any(), any())).thenThrow(expectedException); + + RuntimeException exception = assertThrows(RuntimeException.class, () -> queryRepository.getAllKinds(1, "cursor")); + + verify(cosmosStore, times(1)).queryItems(any(), any(), any(), any(), any(), any()); + assertEquals(expectedException, exception); + } + + private RecordMetadata createRecord(String recordId) { + RecordMetadata recordMetadata = new RecordMetadata(); + recordMetadata.setId(recordId); + Acl recordAcl = new Acl(); + String[] owners = {"owner1@devint.osdu.com"}; + String[] viewers = {"viewer1@devint.osdu.com"}; + recordAcl.setOwners(owners); + recordAcl.setViewers(viewers); + recordMetadata.setAcl(recordAcl); + recordMetadata.setModifyUser("user1"); + recordMetadata.setModifyTime(123L); + return recordMetadata; + } + +} diff --git a/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/repository/RecordMetadataRepositoryTest.java b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/repository/RecordMetadataRepositoryTest.java index a292f3beff6e59feaacff440854274c7b4dc4e9a..aff72fd09789a0d8f112e5a94aeaa3937f856d55 100644 --- a/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/repository/RecordMetadataRepositoryTest.java +++ b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/repository/RecordMetadataRepositoryTest.java @@ -1,9 +1,11 @@ package org.opengroup.osdu.storage.provider.azure.repository; +import com.azure.cosmos.CosmosException; import com.azure.cosmos.models.CosmosQueryRequestOptions; import com.azure.cosmos.models.SqlQuerySpec; import com.fasterxml.jackson.databind.ObjectMapper; import com.github.fge.jsonpatch.JsonPatch; +import org.apache.http.HttpStatus; import org.junit.Rule; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -12,9 +14,11 @@ import org.junit.rules.ExpectedException; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.opengroup.osdu.azure.cosmosdb.CosmosStore; import org.opengroup.osdu.azure.cosmosdb.CosmosStoreBulkOperations; +import org.opengroup.osdu.azure.query.CosmosStorePageRequest; import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; import org.opengroup.osdu.core.common.model.entitlements.Acl; import org.opengroup.osdu.core.common.model.http.AppError; @@ -23,6 +27,7 @@ import org.opengroup.osdu.core.common.model.http.CollaborationContext; import org.opengroup.osdu.core.common.model.http.DpsHeaders; import org.opengroup.osdu.core.common.model.storage.RecordMetadata; import org.opengroup.osdu.storage.provider.azure.RecordMetadataDoc; +import org.opengroup.osdu.storage.provider.azure.model.DocumentCount; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -35,41 +40,34 @@ import java.util.*; import static java.util.Collections.singletonList; import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) -public class RecordMetadataRepositoryTest { +class RecordMetadataRepositoryTest { private final static String RECORD_ID1 = "opendes:id1:15706318658560"; private final static String RECORD_ID2 = "opendes:id2:15706318658560"; private final static String KIND = "opendes:source:type:1.0.0"; private final static String STATUS = "active"; - + private final ObjectMapper mapper = new ObjectMapper(); + @Rule + ExpectedException exceptionRule = ExpectedException.none(); @Mock private JaxRsDpsLog logger; - @Mock private CosmosStoreBulkOperations cosmosBulkStore; - @Mock private DpsHeaders headers; - @Mock private Page<RecordMetadataDoc> page; - @Mock - private CosmosStore operation; - + private CosmosStore cosmosStore; @InjectMocks private RecordMetadataRepository recordMetadataRepository; - @Rule - public ExpectedException exceptionRule = ExpectedException.none(); - - private final ObjectMapper mapper = new ObjectMapper(); - @BeforeEach - public void setup() { + void setup() { lenient().when(headers.getPartitionId()).thenReturn("opendes"); ReflectionTestUtils.setField(recordMetadataRepository, "cosmosDBName", "osdu-db"); ReflectionTestUtils.setField(recordMetadataRepository, "recordMetadataCollection", "collection"); @@ -78,7 +76,7 @@ public class RecordMetadataRepositoryTest { @Test - public void shouldFailOnCreateOrUpdate_IfAclIsNull() { + void shouldFailOnCreateOrUpdate_IfAclIsNull() { try { recordMetadataRepository.createOrUpdate(singletonList(new RecordMetadata()), Optional.empty()); } catch (IllegalArgumentException e) { @@ -88,7 +86,7 @@ public class RecordMetadataRepositoryTest { } @Test - public void shouldSetCorrectDocId_IfCollaborationContextIsProvided_InParallel() { + void shouldSetCorrectDocId_IfCollaborationContextIsProvided_InParallel() { UUID CollaborationId = UUID.randomUUID(); CollaborationContext collaborationContext = CollaborationContext.builder().id(CollaborationId).build(); RecordMetadata recordMetadata1 = createRecord(RECORD_ID1); @@ -103,13 +101,13 @@ public class RecordMetadataRepositoryTest { verify(cosmosBulkStore).bulkInsertWithCosmosClient(any(), any(), any(), docCaptor.capture(), any(), eq(1)); List capturedDocs = docCaptor.getValue(); RecordMetadataDoc capturedDoc1 = (RecordMetadataDoc) capturedDocs.get(0); - assertEquals(capturedDoc1.getId(), CollaborationId.toString() + RECORD_ID1); + assertEquals(capturedDoc1.getId(), CollaborationId + RECORD_ID1); RecordMetadataDoc capturedDoc2 = (RecordMetadataDoc) capturedDocs.get(1); - assertEquals(capturedDoc2.getId(), CollaborationId.toString() + RECORD_ID2); + assertEquals(capturedDoc2.getId(), CollaborationId + RECORD_ID2); } @Test - public void shouldSetCorrectDocId_IfCollaborationContextIsProvided_InSerial() { + void shouldSetCorrectDocId_IfCollaborationContextIsProvided_InSerial() { UUID CollaborationId = UUID.randomUUID(); CollaborationContext collaborationContext = CollaborationContext.builder().id(CollaborationId).build(); @@ -118,10 +116,10 @@ public class RecordMetadataRepositoryTest { recordMetadataRepository.createOrUpdate(singletonList(recordMetadata), Optional.of(collaborationContext)); ArgumentCaptor<RecordMetadataDoc> itemCaptor = ArgumentCaptor.forClass(RecordMetadataDoc.class); - verify(operation).upsertItem(any(), + verify(cosmosStore).upsertItem(any(), any(), eq("collection"), - eq(CollaborationId.toString() + RECORD_ID1), + eq(CollaborationId + RECORD_ID1), itemCaptor.capture()); RecordMetadataDoc capturedItem = itemCaptor.getValue(); @@ -130,7 +128,7 @@ public class RecordMetadataRepositoryTest { } @Test - public void shouldPatchRecordsWithCorrectDocId_whenCollaborationContextIsProvided() throws IOException { + void shouldPatchRecordsWithCorrectDocId_whenCollaborationContextIsProvided() throws IOException { UUID CollaborationId = UUID.randomUUID(); CollaborationContext collaborationContext = CollaborationContext.builder().id(CollaborationId).build(); String expectedDocId = CollaborationId + RECORD_ID1; @@ -145,7 +143,7 @@ public class RecordMetadataRepositoryTest { } @Test - public void shouldPatchRecordsWithCorrectDocId_whenCollaborationContextIsNotProvided() throws IOException { + void shouldPatchRecordsWithCorrectDocId_whenCollaborationContextIsNotProvided() throws IOException { RecordMetadata recordMetadata = createRecord(RECORD_ID1); Map<RecordMetadata, JsonPatch> jsonPatchPerRecord = new HashMap<>(); jsonPatchPerRecord.put(recordMetadata, getJsonPatchFromJsonString(getValidInputJsonForPatch())); @@ -157,7 +155,7 @@ public class RecordMetadataRepositoryTest { } @Test - public void shouldPatchRecordsWithCorrectDocId_whenCollaborationContextIsNotProvided_withDuplicateOpAndPath() throws IOException { + void shouldPatchRecordsWithCorrectDocId_whenCollaborationContextIsNotProvided_withDuplicateOpAndPath() throws IOException { RecordMetadata recordMetadata = createRecord(RECORD_ID1); Map<RecordMetadata, JsonPatch> jsonPatchPerRecord = new HashMap<>(); jsonPatchPerRecord.put(recordMetadata, getJsonPatchFromJsonString(getValidInputJsonForPatchWithSameOpAndPath())); @@ -169,7 +167,7 @@ public class RecordMetadataRepositoryTest { } @Test - public void shouldReturnErrors_whenPatchFailsWithAppExceptionWithoutCollaborationContext() throws IOException { + void shouldReturnErrors_whenPatchFailsWithAppExceptionWithoutCollaborationContext() throws IOException { RecordMetadata recordMetadata = createRecord(RECORD_ID1); Map<RecordMetadata, JsonPatch> jsonPatchPerRecord = new HashMap<>(); jsonPatchPerRecord.put(recordMetadata, getJsonPatchFromJsonString(getValidInputJsonForPatch())); @@ -194,7 +192,7 @@ public class RecordMetadataRepositoryTest { } @Test - public void shouldReturnErrors_whenPatchFailsWithAppExceptionWithCollaborationContext() throws IOException { + void shouldReturnErrors_whenPatchFailsWithAppExceptionWithCollaborationContext() throws IOException { UUID CollaborationId = UUID.randomUUID(); CollaborationContext collaborationContext = CollaborationContext.builder().id(CollaborationId).build(); String expectedDocId = CollaborationId + RECORD_ID1; @@ -222,7 +220,7 @@ public class RecordMetadataRepositoryTest { } @Test - public void shouldThrowException_whenPatchFailsWithOtherException() throws IOException { + void shouldThrowException_whenPatchFailsWithOtherException() throws IOException { RecordMetadata recordMetadata = createRecord(RECORD_ID1); Map<RecordMetadata, JsonPatch> jsonPatchPerRecord = new HashMap<>(); jsonPatchPerRecord.put(recordMetadata, getJsonPatchFromJsonString(getValidInputJsonForPatch())); @@ -231,8 +229,9 @@ public class RecordMetadataRepositoryTest { AppException appException = mock(AppException.class); doThrow(appException).when(cosmosBulkStore).bulkPatchWithCosmosClient(eq("opendes"), eq("osdu-db"), eq("collection"), anyMap(), eq(partitionKeyForDoc), eq(1)); + Optional<CollaborationContext> context = Optional.empty(); try { - recordMetadataRepository.patch(jsonPatchPerRecord, Optional.empty()); + recordMetadataRepository.patch(jsonPatchPerRecord, context); fail("expected exception"); } catch (AppException e) { @@ -240,19 +239,19 @@ public class RecordMetadataRepositoryTest { } @Test - public void shouldQueryByDocIdWithCollaborationId_IfCollaborationContextIsProvided() { + void shouldQueryByDocIdWithCollaborationId_IfCollaborationContextIsProvided() { UUID CollaborationId = UUID.randomUUID(); CollaborationContext collaborationContext = CollaborationContext.builder().id(CollaborationId).build(); - String expectedQuery = "SELECT c.metadata.id FROM c WHERE c.metadata.kind = '" + KIND + "' AND c.metadata.status = 'active' and STARTSWITH(c.id, '" + CollaborationId.toString() + "') "; + String expectedQuery = "SELECT c.metadata.id FROM c WHERE c.metadata.kind = '" + KIND + "' AND c.metadata.status = 'active' and STARTSWITH(c.id, '" + CollaborationId + "') "; Pageable pageable = PageRequest.of(0, 8); - doReturn(page).when(operation).queryItemsPage(eq("opendes"), eq("osdu-db"), eq("collection"), any(SqlQuerySpec.class), any(Class.class), eq(8), any(), any(CosmosQueryRequestOptions.class)); + doReturn(page).when(cosmosStore).queryItemsPage(eq("opendes"), eq("osdu-db"), eq("collection"), any(SqlQuerySpec.class), any(Class.class), eq(8), any(), any(CosmosQueryRequestOptions.class)); this.recordMetadataRepository.findIdsByMetadata_kindAndMetadata_status(KIND, STATUS, pageable, Optional.of(collaborationContext)); ArgumentCaptor<SqlQuerySpec> queryCaptor = ArgumentCaptor.forClass(SqlQuerySpec.class); - verify(operation).queryItemsPage(eq("opendes"), + verify(cosmosStore).queryItemsPage(eq("opendes"), eq("osdu-db"), eq("collection"), queryCaptor.capture(), @@ -264,6 +263,260 @@ public class RecordMetadataRepositoryTest { assertEquals(expectedQuery, capturedQuery.getQueryText()); } + @Test + void findIdsByMetadata_kindAndMetadata_status_shouldQueryByDocIdWithCollaborationId_IfCollaborationContextIsProvided() { + UUID CollaborationId = UUID.randomUUID(); + CollaborationContext collaborationContext = CollaborationContext.builder().id(CollaborationId).build(); + + String expectedQuery = "SELECT c.metadata.id FROM c WHERE c.metadata.kind = '" + KIND + "' AND c.metadata.status = 'active' and STARTSWITH(c.id, '" + CollaborationId + "')"; + + List<RecordMetadataDoc> returnList = new ArrayList<>(); + returnList.add(Mockito.mock(RecordMetadataDoc.class)); + + doReturn(returnList).when(cosmosStore).queryItems(eq("opendes"), + eq("osdu-db"), + eq("collection"), + any(SqlQuerySpec.class), + any(CosmosQueryRequestOptions.class), + eq(RecordMetadataDoc.class)); + + this.recordMetadataRepository.findIdsByMetadata_kindAndMetadata_status(KIND, STATUS, Optional.of(collaborationContext)); + + ArgumentCaptor<SqlQuerySpec> queryCaptor = ArgumentCaptor.forClass(SqlQuerySpec.class); + verify(cosmosStore).queryItems(eq("opendes"), + eq("osdu-db"), + eq("collection"), + queryCaptor.capture(), + any(CosmosQueryRequestOptions.class), + eq(RecordMetadataDoc.class)); + SqlQuerySpec capturedQuery = queryCaptor.getValue(); + assertEquals(expectedQuery, capturedQuery.getQueryText()); + } + + @Test + void shouldQueryByDocIdWithCollaborationId_IfCollaborationContextIsNotProvided() { + String expectedQuery = "SELECT c.metadata.id FROM c WHERE c.metadata.kind = 'opendes:source:type:1.0.0' AND c.metadata.status = 'active' AND c.id = c.metadata.id "; + + Pageable pageable = PageRequest.of(0, 8); + + doReturn(page).when(cosmosStore).queryItemsPage(eq("opendes"), eq("osdu-db"), eq("collection"), any(SqlQuerySpec.class), any(Class.class), eq(8), any(), any(CosmosQueryRequestOptions.class)); + + this.recordMetadataRepository.findIdsByMetadata_kindAndMetadata_status(KIND, STATUS, pageable, Optional.empty()); + + ArgumentCaptor<SqlQuerySpec> queryCaptor = ArgumentCaptor.forClass(SqlQuerySpec.class); + verify(cosmosStore).queryItemsPage(eq("opendes"), + eq("osdu-db"), + eq("collection"), + queryCaptor.capture(), + any(Class.class), + eq(8), + any(), + any(CosmosQueryRequestOptions.class)); + + SqlQuerySpec capturedQuery = queryCaptor.getValue(); + assertEquals(expectedQuery, capturedQuery.getQueryText()); + } + + @Test + void shouldPatchRecordsWithRemovePatch_whenCollaborationContextIsNotProvided_withDuplicateOpAndPath() throws IOException { + RecordMetadata recordMetadata = createRecord(RECORD_ID1); + + Map<RecordMetadata, JsonPatch> jsonPatchPerRecord = new HashMap<>(); + jsonPatchPerRecord.put(recordMetadata, getJsonPatchFromJsonString(getValidInputJsonForPatchRemove())); + + Map<String, String> partitionKeyForDoc = new HashMap<>(); + partitionKeyForDoc.put(RECORD_ID1, RECORD_ID1); + + Map<String, String> recordErrors = recordMetadataRepository.patch(jsonPatchPerRecord, Optional.empty()); + + + verify(cosmosBulkStore, times(1)).bulkPatchWithCosmosClient(eq("opendes"), eq("osdu-db"), eq("collection"), anyMap(), eq(partitionKeyForDoc), eq(1)); + assertTrue((recordErrors.isEmpty())); + } + + @Test + void shouldReturnCorrectRecords_when_queryByLegalTagName() { + String legalTagName = "legal_tag_name"; + int limit = 200; + String cursor = "cursor"; + + String expectedQueryWithTrailingSpace = "SELECT * FROM c WHERE ARRAY_CONTAINS(c.metadata.legal.legaltags, '" + legalTagName + "') "; + + doReturn(page).when(cosmosStore).queryItemsPage(eq("opendes"), eq("osdu-db"), eq("collection"), any(SqlQuerySpec.class), any(Class.class), eq(limit), any(), any(CosmosQueryRequestOptions.class)); + + CosmosStorePageRequest pageable = Mockito.mock(CosmosStorePageRequest.class); + doReturn(pageable).when(page).getPageable(); + doReturn("continuation").when(pageable).getRequestContinuation(); + + recordMetadataRepository.queryByLegalTagName(legalTagName, limit, cursor); + + ArgumentCaptor<SqlQuerySpec> queryCaptor = ArgumentCaptor.forClass(SqlQuerySpec.class); + verify(cosmosStore).queryItemsPage(eq("opendes"), + eq("osdu-db"), + eq("collection"), + queryCaptor.capture(), + any(Class.class), + eq(limit), + any(), + any(CosmosQueryRequestOptions.class)); + SqlQuerySpec capturedQuery = queryCaptor.getValue(); + assertEquals(expectedQueryWithTrailingSpace, capturedQuery.getQueryText()); + } + + @Test + void queryByLegalTagName_shouldThrowAppException_when_cosmosStore_throwsInvalidCursorException() { + String legalTagName = "legal_tag_name"; + int limit = 200; + String cursor = "invalid%cursor"; + + CosmosException cosmosException = mock(CosmosException.class); + doReturn(HttpStatus.SC_BAD_REQUEST).when(cosmosException).getStatusCode(); + doReturn("INVALID JSON in continuation token").when(cosmosException).getMessage(); + + doThrow(cosmosException).when(cosmosStore).queryItemsPage(eq("opendes"), eq("osdu-db"), eq("collection"), any(SqlQuerySpec.class), any(Class.class), eq(limit), any(), any(CosmosQueryRequestOptions.class)); + + AppException appException = assertThrows(AppException.class, () -> recordMetadataRepository.queryByLegalTagName( + legalTagName, limit, cursor)); + + assertEquals(HttpStatus.SC_BAD_REQUEST, appException.getError().getCode()); + assertEquals("Cursor invalid", appException.getError().getReason()); + } + + @Test + void queryByLegalTagName_shouldThrowCosmosException_when_cosmosStore_throwsGenericCosmosException() { + String legalTagName = "legal_tag_name"; + int limit = 200; + String cursor = "invalid%cursor"; + + CosmosException cosmosException = mock(CosmosException.class); + doReturn(HttpStatus.SC_BAD_REQUEST).when(cosmosException).getStatusCode(); + + String badRequestMessage = "Some other bad request exception"; + doReturn(badRequestMessage).when(cosmosException).getMessage(); + + doThrow(cosmosException).when(cosmosStore).queryItemsPage(eq("opendes"), eq("osdu-db"), eq("collection"), any(SqlQuerySpec.class), any(Class.class), eq(limit), any(), any(CosmosQueryRequestOptions.class)); + + CosmosException actualCosmosException = assertThrows(CosmosException.class, () -> recordMetadataRepository.queryByLegalTagName( + legalTagName, limit, cursor)); + + assertEquals(HttpStatus.SC_BAD_REQUEST, actualCosmosException.getStatusCode()); + assertEquals(badRequestMessage, actualCosmosException.getMessage()); + } + + @Test + void queryByLegalTagName_shouldThrowException_when_cosmosStore_throwsGenericException() { + String legalTagName = "legal_tag_name"; + int limit = 200; + String cursor = "invalid%cursor"; + + doThrow(RuntimeException.class).when(cosmosStore).queryItemsPage(eq("opendes"), eq("osdu-db"), eq("collection"), any(SqlQuerySpec.class), any(Class.class), eq(limit), any(), any(CosmosQueryRequestOptions.class)); + + assertThrows(RuntimeException.class, () -> recordMetadataRepository.queryByLegalTagName( + legalTagName, limit, cursor)); + } + + @Test + void getById_shouldReturnRecordMetadata_when_called() { + RecordMetadataDoc doc = Mockito.mock(RecordMetadataDoc.class); + + doReturn(Optional.of(doc)).when(cosmosStore).findItem("opendes", "osdu-db", "collection", "id", "id", RecordMetadataDoc.class); + + recordMetadataRepository.get("id", Optional.empty()); + + verify(cosmosStore).findItem("opendes", "osdu-db", "collection", "id", "id", RecordMetadataDoc.class); + } + + @Test + void getById_shouldReturnNull_when_blobStoreFindItemReturnsNull() { + doReturn(Optional.empty()).when(cosmosStore).findItem("opendes", "osdu-db", "collection", "id", "id", RecordMetadataDoc.class); + + recordMetadataRepository.get("id", Optional.empty()); + + verify(cosmosStore).findItem("opendes", "osdu-db", "collection", "id", "id", RecordMetadataDoc.class); + } + + @Test + void getByList_shouldReturnValidResultSet_whenCosmosStoreReturnsValidRecords() { + RecordMetadataDoc doc1 = new RecordMetadataDoc(RECORD_ID1, createRecord(RECORD_ID1)); + RecordMetadataDoc doc2 = new RecordMetadataDoc(RECORD_ID2, createRecord(RECORD_ID2)); + + doReturn(Arrays.asList(doc1, doc2)).when(cosmosStore).queryItems(eq("opendes"), eq("osdu-db"), eq("collection"), any(SqlQuerySpec.class), any(CosmosQueryRequestOptions.class), eq(RecordMetadataDoc.class)); + + String expectedQuery = String.format("SELECT * FROM c WHERE c.id IN (\"%s\",\"%s\")", RECORD_ID1, RECORD_ID2); + + Map<String, RecordMetadata> resultSet = recordMetadataRepository.get(Arrays.asList(RECORD_ID1, RECORD_ID2), Optional.empty()); + + ArgumentCaptor<SqlQuerySpec> queryCaptor = ArgumentCaptor.forClass(SqlQuerySpec.class); + + verify(cosmosStore).queryItems(eq("opendes"), eq("osdu-db"), eq("collection"), queryCaptor.capture(), any(CosmosQueryRequestOptions.class), eq(RecordMetadataDoc.class)); + + SqlQuerySpec capturedQuery = queryCaptor.getValue(); + assertEquals(expectedQuery, capturedQuery.getQueryText()); + assertEquals(2, resultSet.size()); + } + + @Test + void getByList_shouldReturnEmptyResultSet_whenCosmosStoreReturnsEmptyRecords() { + RecordMetadataDoc doc1 = mock(RecordMetadataDoc.class); + RecordMetadataDoc doc2 = mock(RecordMetadataDoc.class); + + doReturn(Arrays.asList(doc1, doc2)).when(cosmosStore).queryItems(eq("opendes"), eq("osdu-db"), eq("collection"), any(SqlQuerySpec.class), any(CosmosQueryRequestOptions.class), eq(RecordMetadataDoc.class)); + + String expectedQuery = String.format("SELECT * FROM c WHERE c.id IN (\"%s\",\"%s\")", RECORD_ID1, RECORD_ID2); + + Map<String, RecordMetadata> resultSet = recordMetadataRepository.get(Arrays.asList(RECORD_ID1, RECORD_ID2), Optional.empty()); + + ArgumentCaptor<SqlQuerySpec> queryCaptor = ArgumentCaptor.forClass(SqlQuerySpec.class); + + verify(cosmosStore).queryItems(eq("opendes"), eq("osdu-db"), eq("collection"), queryCaptor.capture(), any(CosmosQueryRequestOptions.class), eq(RecordMetadataDoc.class)); + + SqlQuerySpec capturedQuery = queryCaptor.getValue(); + assertEquals(expectedQuery, capturedQuery.getQueryText()); + assertEquals(0, resultSet.size()); + } + + @Test + void getMetadataDocumentCountForBlob_shouldReturnZero_whenEmptyResultSetReturnedFromCosmos() { + DocumentCount documentCount = Mockito.mock(DocumentCount.class); + doReturn(Collections.singletonList(documentCount)).when(cosmosStore).queryItems(eq("opendes"), eq("osdu-db"), eq("collection"), any(SqlQuerySpec.class), any(CosmosQueryRequestOptions.class), eq(DocumentCount.class)); + + int actualRecordSize = recordMetadataRepository.getMetadataDocumentCountForBlob("path"); + + String requiredQuery = "SELECT COUNT(1) AS documentCount from c WHERE ARRAY_CONTAINS (c.metadata.gcsVersionPaths, 'path')"; + ArgumentCaptor<SqlQuerySpec> argumentCaptor = ArgumentCaptor.forClass(SqlQuerySpec.class); + + verify(cosmosStore).queryItems(eq("opendes"), eq("osdu-db"), eq("collection"), argumentCaptor.capture(), any(CosmosQueryRequestOptions.class), eq(DocumentCount.class)); + + SqlQuerySpec capturedQuery = argumentCaptor.getValue(); + assertEquals(requiredQuery, capturedQuery.getQueryText()); + assertEquals(0, actualRecordSize); + } + + @Test + void getMetadataDocumentCountForBlob_shouldReturnValidRecordSize_whenValidResultSetReturnedFromCosmos() { + DocumentCount documentCount = new DocumentCount(1); + doReturn(Collections.singletonList(documentCount)).when(cosmosStore).queryItems(eq("opendes"), eq("osdu-db"), eq("collection"), any(SqlQuerySpec.class), any(CosmosQueryRequestOptions.class), eq(DocumentCount.class)); + + int actualRecordSize = recordMetadataRepository.getMetadataDocumentCountForBlob("path"); + + String requiredQuery = "SELECT COUNT(1) AS documentCount from c WHERE ARRAY_CONTAINS (c.metadata.gcsVersionPaths, 'path')"; + + ArgumentCaptor<SqlQuerySpec> argumentCaptor = ArgumentCaptor.forClass(SqlQuerySpec.class); + + verify(cosmosStore).queryItems(eq("opendes"), eq("osdu-db"), eq("collection"), argumentCaptor.capture(), any(CosmosQueryRequestOptions.class), eq(DocumentCount.class)); + + SqlQuerySpec capturedQuery = argumentCaptor.getValue(); + assertEquals(requiredQuery, capturedQuery.getQueryText()); + assertEquals(1, actualRecordSize); + } + + @Test + void deleteShould_deleteItemFromCosmos_whenIdIsNotNull() { + recordMetadataRepository.delete(RECORD_ID1, Optional.empty()); + + verify(cosmosStore, times(1)).deleteItem("opendes", "osdu-db", "collection", RECORD_ID1, RECORD_ID1); + } + private RecordMetadata createRecord(String recordId) { RecordMetadata recordMetadata = new RecordMetadata(); recordMetadata.setId(recordId); @@ -308,4 +561,14 @@ public class RecordMetadataRepositoryTest { " ]"; } + private String getValidInputJsonForPatchRemove() { + return "[\n" + + " {\n" + + " \"op\": \"remove\",\n" + + " \"path\": \"/kind\",\n" + + " \"value\": \"/newKind\"\n" + + " }\n" + + "]"; + } + } diff --git a/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/repository/SchemaRepositoryTest.java b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/repository/SchemaRepositoryTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e4ea92d03c1f42664e8cfc71eb6d4d27f402c6b5 --- /dev/null +++ b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/repository/SchemaRepositoryTest.java @@ -0,0 +1,149 @@ +package org.opengroup.osdu.storage.provider.azure.repository; + +import com.azure.cosmos.models.CosmosQueryRequestOptions; +import com.azure.cosmos.models.SqlQuerySpec; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.opengroup.osdu.azure.cosmosdb.CosmosStore; +import org.opengroup.osdu.core.common.model.http.DpsHeaders; +import org.opengroup.osdu.core.common.model.storage.Schema; +import org.opengroup.osdu.core.common.model.storage.SchemaItem; +import org.opengroup.osdu.storage.provider.azure.SchemaDoc; +import org.opengroup.osdu.storage.provider.azure.di.CosmosContainerConfig; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.test.util.ReflectionTestUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class SchemaRepositoryTest { + + private final Schema schema = mock(Schema.class); + private final String DATA_PARTITION_ID = "opendes"; + private final String COSMOS_DB_NAME = "osdu-db"; + private final String COLLECTION = "collection"; + private final String KIND = "opendes:wks:work-product-component--wellLog:1.0.0"; + @Mock + CosmosStore cosmosStore; + @InjectMocks + SchemaRepository schemaRepository; + @Mock + private DpsHeaders dpsHeaders; + @Mock + private CosmosContainerConfig cosmosContainerConfig; + + @BeforeEach + void setup() { + lenient().when(dpsHeaders.getPartitionId()).thenReturn(DATA_PARTITION_ID); + lenient().when(schema.getKind()).thenReturn(KIND); + ReflectionTestUtils.setField(schemaRepository, "operation", cosmosStore); + ReflectionTestUtils.setField(schemaRepository, "cosmosDBName", COSMOS_DB_NAME); + ReflectionTestUtils.setField(schemaRepository, "schemaCollection", COLLECTION); + } + + @Test + void AddShouldThrowIllegalArgumentException_whenSchemaIsNull() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> schemaRepository.add(null, "user")); + + assertTrue(exception.getMessage().contains("schema must not be null")); + } + + + @Test + void AddShouldThrowIllegalArgumentException_whenUserIsNull() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> schemaRepository.add(mock(Schema.class), null)); + + assertTrue(exception.getMessage().contains("user must not be null")); + } + + + @Test + void AddShouldThrowIllegalArgumentException_whenKindAlreadyExists() { + Optional<SchemaDoc> schemaDoc = Optional.of(mock(SchemaDoc.class)); + when(cosmosStore.findItem(DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION, KIND, KIND, SchemaDoc.class)).thenReturn(schemaDoc); + + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> schemaRepository.add(schema, "user")); + + assertTrue(exception.getMessage().contains(String.format("Schema %s already exists. Can't create again.", KIND))); + } + + @Test + void AddShouldUpsertSchemaInCosmos_whenNoneExists() { + when(cosmosStore.findItem(DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION, KIND, KIND, SchemaDoc.class)).thenReturn(Optional.empty()); + + schemaRepository.add(schema, "user"); + + verify(cosmosStore).upsertItem(eq(DATA_PARTITION_ID), eq(COSMOS_DB_NAME), eq(COLLECTION), eq(KIND), any()); + } + + @Test + void GetShouldReturnNull_whenNoRecordsAreReturnedFromCosmos() { + when(cosmosStore.findItem(DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION, KIND, KIND, SchemaDoc.class)).thenReturn(Optional.empty()); + + Schema foundItem = schemaRepository.get(KIND); + + assertNull(foundItem); + } + + @Test + void GetShouldReturnSchema_whenRecordsAreReturnedFromCosmos() { + when(cosmosStore.findItem(DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION, KIND, KIND, SchemaDoc.class)).thenReturn(Optional.of(mock(SchemaDoc.class))); + + Schema foundItem = schemaRepository.get(KIND); + + assertNotNull(foundItem); + } + + @Test + void mapReturnsSchema_whenSchemaDocIsProvided() { + Map<String, Object> extension = new HashMap<>(); + SchemaItem[] items = new SchemaItem[2]; + SchemaDoc schemaDoc = new SchemaDoc("kind", "id", extension, "user", items); + + Schema schemaReturned = schemaRepository.map(schemaDoc); + + assertEquals(schemaReturned.getKind(), schemaDoc.getKind()); + assertEquals(schemaReturned.getSchema(), schemaDoc.getSchemaItems()); + assertEquals(schemaReturned.getExt(), schemaDoc.getExtension()); + } + + @Test + void deleteShouldDeleteFromCosmos_whenIdIsNotNull() { + schemaRepository.delete(KIND); + + verify(cosmosStore).deleteItem(DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION, KIND, KIND); + } + + @Test + void findAllWithPageableShouldFetchRecords_whenPageableIsPresent() { + schemaRepository.findAll(Pageable.ofSize(1)); + + ArgumentCaptor<SqlQuerySpec> argumentCaptor = ArgumentCaptor.forClass(SqlQuerySpec.class); + + verify(cosmosStore).queryItemsPage(eq(DATA_PARTITION_ID), eq(COSMOS_DB_NAME), eq(COLLECTION), argumentCaptor.capture(), eq(SchemaDoc.class), eq(1), any(), any(CosmosQueryRequestOptions.class)); + + assertEquals("SELECT * FROM c ", argumentCaptor.getValue().getQueryText()); + } + + @Test + void findAllWithSortShouldFetchRecords_whenSortIsPresent() { + schemaRepository.findAll(Sort.by("id")); + ArgumentCaptor<SqlQuerySpec> argumentCaptor = ArgumentCaptor.forClass(SqlQuerySpec.class); + String expectedQuery = "SELECT * FROM c ORDER BY c.id ASC"; + + verify(cosmosStore).queryItems(eq(DATA_PARTITION_ID), eq(COSMOS_DB_NAME), eq(COLLECTION), argumentCaptor.capture(), any(CosmosQueryRequestOptions.class), eq(SchemaDoc.class)); + + assertEquals(expectedQuery, argumentCaptor.getValue().getQueryText()); + } +} diff --git a/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/repository/SimpleCosmosStoreRepositoryTest.java b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/repository/SimpleCosmosStoreRepositoryTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c182569c530b9639f4b14d598faf53a59c151f7e --- /dev/null +++ b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/repository/SimpleCosmosStoreRepositoryTest.java @@ -0,0 +1,187 @@ +package org.opengroup.osdu.storage.provider.azure.repository; + +import com.azure.cosmos.models.CosmosQueryRequestOptions; +import com.azure.cosmos.models.SqlQuerySpec; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.opengroup.osdu.azure.cosmosdb.CosmosStore; +import org.opengroup.osdu.core.common.model.http.DpsHeaders; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.test.util.ReflectionTestUtils; + +import java.util.Optional; + +import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class SimpleCosmosStoreRepositoryTest { + private static final String ORDER_ASC_BY_ID = "ORDER BY c.field ASC"; + private static String DATA_PARTITION_ID = "opendes"; + private static String COSMOS_DB_NAME = "osdu-db"; + private static String COLLECTION = "collection"; + @Mock + private DpsHeaders headers; + @Mock + private CosmosStore cosmosStore; + @InjectMocks + private SimpleCosmosStoreRepository simpleCosmosStoreRepository; + + @BeforeEach + void setup() { + lenient().when(headers.getPartitionId()).thenReturn("opendes"); + ReflectionTestUtils.setField(simpleCosmosStoreRepository, "operation", cosmosStore); + } + + @Test + void findAll_shouldCallCosmosStoreAndReturnAllRecords() { + simpleCosmosStoreRepository.findAll(DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION); + + verify(cosmosStore).findAllItems(eq(DATA_PARTITION_ID), eq(COSMOS_DB_NAME), eq(COLLECTION), any()); + } + + @Test + void findAllWithPageable_shouldCallCosmosStoreAndReturnAllRecords() { + Pageable pageable = PageRequest.of(0, 2, Sort.by("field")); + + simpleCosmosStoreRepository.findAll(pageable, DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION); + + ArgumentCaptor<SqlQuerySpec> argumentCaptor = ArgumentCaptor.forClass(SqlQuerySpec.class); + verify(cosmosStore).queryItemsPage(eq(DATA_PARTITION_ID), eq(COSMOS_DB_NAME), eq(COLLECTION), argumentCaptor.capture(), any(), eq(2), any(), any(CosmosQueryRequestOptions.class)); + assertTrue(argumentCaptor.getValue().getQueryText().contains(ORDER_ASC_BY_ID)); + } + + @Test + void findAllWithSort_shouldCallCosmosStoreAndReturnAllRecords() { + simpleCosmosStoreRepository.findAll(Sort.by("field"), DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION); + + ArgumentCaptor<SqlQuerySpec> argumentCaptor = ArgumentCaptor.forClass(SqlQuerySpec.class); + verify(cosmosStore).queryItems(eq(DATA_PARTITION_ID), eq(COSMOS_DB_NAME), eq(COLLECTION), argumentCaptor.capture(), any(CosmosQueryRequestOptions.class), any()); + + assertTrue(argumentCaptor.getValue().getQueryText().contains(ORDER_ASC_BY_ID)); + } + + @Test + void findByIdShouldThrowIllegalArgumentsExceptionAndNotCallCosmosStore_whenIdIsNull() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> simpleCosmosStoreRepository.findById(null, DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION, null)); + + verify(cosmosStore, never()).findItem(eq(DATA_PARTITION_ID), eq(COSMOS_DB_NAME), eq(COLLECTION), any(), any(), any()); + + assertTrue(exception.getMessage().contains("id must not be null")); + } + + @Test + void findByIdShouldReturnEmptyAndNotCallCosmosStore_whenIdIsBlank() { + ReflectionTestUtils.setField(simpleCosmosStoreRepository, "domainClass", String.class); + Optional<String> ret = simpleCosmosStoreRepository.findById("", DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION, ""); + + verify(cosmosStore, never()).findItem(eq(DATA_PARTITION_ID), eq(COSMOS_DB_NAME), eq(COLLECTION), any(), any(), any()); + + assertTrue(ret.isEmpty()); + } + + @Test + void findByIdShouldCallCosmosStoreAndReturnRecord_whenValidIdIsPassed() { + ReflectionTestUtils.setField(simpleCosmosStoreRepository, "domainClass", String.class); + when(cosmosStore.findItem(DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION, "id", "id", String.class)).thenReturn(Optional.of("record")); + + Optional<String> ret = simpleCosmosStoreRepository.findById("id", DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION, "id"); + + verify(cosmosStore).findItem(DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION, "id", "id", String.class); + + assertTrue(ret.isPresent()); + assertEquals("record", ret.get()); + } + + + @Test + void existsShouldThrowIllegalArgumentsExceptionAndNotCallCosmosStore_whenIdIsNull() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> simpleCosmosStoreRepository.exists(DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION, null, null)); + + verify(cosmosStore, never()).findItem(eq(DATA_PARTITION_ID), eq(COSMOS_DB_NAME), eq(COLLECTION), any(), any(), any()); + + assertTrue(exception.getMessage().contains("id must not be null")); + } + + @Test + void existsShouldCallCosmosStoreAndReturnTrue_whenValidIdIsPassedAndRecordIsPresent() { + when(cosmosStore.findItem(eq(DATA_PARTITION_ID), eq(COSMOS_DB_NAME), eq(COLLECTION), eq("id"), eq("id"), any())).thenReturn(Optional.of("record")); + + Boolean ret = simpleCosmosStoreRepository.exists(DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION, "id", "id"); + + verify(cosmosStore).findItem(eq(DATA_PARTITION_ID), eq(COSMOS_DB_NAME), eq(COLLECTION), any(), any(), any()); + assertTrue(ret); + } + + @Test + void existsByIdShouldThrowIllegalArgumentsExceptionAndNotCallCosmosStore_whenPrimaryKeyIsNull() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> simpleCosmosStoreRepository.existsById(null, DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION, null)); + + verify(cosmosStore, never()).findItem(eq(DATA_PARTITION_ID), eq(COSMOS_DB_NAME), eq(COLLECTION), any(), any(), any()); + assertTrue(exception.getMessage().contains("primaryKey should not be null")); + } + + @Test + void existsByIdShouldCallCosmosStoreAndReturnTrue_whenValidIdIsPassedAndRecordIsPresent() { + when(cosmosStore.findItem(any(), any(), any(), any(), any(), any())).thenReturn(Optional.of("record")); + + Boolean ret = simpleCosmosStoreRepository.existsById("primary_key", DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION, "partition_key"); + + verify(cosmosStore).findItem(any(), any(), any(), any(), any(), any()); + assertTrue(ret); + } + + @Test + void paginationQueryThrowsIllegalArgumentsException_whenPageableSizeIsLessThan0() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> simpleCosmosStoreRepository.paginationQuery(Mockito.mock(Pageable.class), Mockito.mock(SqlQuerySpec.class), String.class, "", "", "", Mockito.mock(CosmosQueryRequestOptions.class))); + + verify(cosmosStore, never()).queryItemsPage(eq(DATA_PARTITION_ID), eq(COSMOS_DB_NAME), eq(COLLECTION), any(SqlQuerySpec.class), any(), any(int.class), any(), any(CosmosQueryRequestOptions.class)); + + assertTrue(exception.getMessage().contains("pageable should have page size larger than 0")); + } + + @Test + void findWithPageable_shouldCallCosmosStoreAndReturnAllRecords() { + Pageable pageable = PageRequest.of(0, 10, Sort.by("id")); + + simpleCosmosStoreRepository.find(pageable, DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION, new SqlQuerySpec("queryText"), new CosmosQueryRequestOptions()); + + verify(cosmosStore).queryItemsPage(eq(DATA_PARTITION_ID), eq(COSMOS_DB_NAME), eq(COLLECTION), any(), any(), eq(10), any(), any()); + } + + @Test + void createItem_shouldCallCosmosStoreAndCreateRecordIfItemIsNotNull() { + simpleCosmosStoreRepository.createItem(DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION, "partitionKey", "New Item"); + + verify(cosmosStore).createItem(DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION, "partitionKey", "New Item"); + } + + @Test + void createItem_shouldThrowIllegalArgumentsExceptionsIfItemIsNull() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> simpleCosmosStoreRepository.createItem(DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION, "partitionKey", null)); + + verify(cosmosStore, never()).createItem(DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION, "partitionKey", "New Item"); + + assertTrue(exception.getMessage().contains("entity must not be null")); + } + + @Test + void queryItemsPage_shouldCallCosmosStore() { + SqlQuerySpec querySpec = new SqlQuerySpec("query"); + simpleCosmosStoreRepository.queryItemsPage(DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION, querySpec, String.class, 10, "continuationToken"); + + verify(cosmosStore).queryItemsPage(DATA_PARTITION_ID, COSMOS_DB_NAME, COLLECTION, querySpec, String.class, 10, "continuationToken"); + } + +} diff --git a/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/util/EntitlementsHelperTest.java b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/util/EntitlementsHelperTest.java index d38c3c6defffccc71556492cfd08ebc3cde60f8c..9f2897caa83750100a377a614cc67fd4566da1a0 100644 --- a/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/util/EntitlementsHelperTest.java +++ b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/util/EntitlementsHelperTest.java @@ -1,13 +1,12 @@ package org.opengroup.osdu.storage.provider.azure.util; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatcher; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; import org.opengroup.osdu.core.common.model.entitlements.Acl; import org.opengroup.osdu.core.common.model.http.DpsHeaders; import org.opengroup.osdu.core.common.model.storage.RecordMetadata; @@ -18,42 +17,29 @@ import java.util.Set; import static org.junit.Assert.*; import static org.mockito.Mockito.*; -@RunWith(MockitoJUnitRunner.class) -public class EntitlementsHelperTest { +@ExtendWith(MockitoExtension.class) +class EntitlementsHelperTest { private static final String OWNER_ACL = "owner_acl"; private static final String VIEWER_ACL = "viewer_acl"; private static final String USER = "test_user"; - + private final ArgumentCaptor<Set<String>> captor = ArgumentCaptor.forClass(Set.class); @Mock private DpsHeaders headers; - @Mock private EntitlementsAndCacheServiceAzure dataEntitlementsService; - @InjectMocks private EntitlementsHelper entitlementsHelper; - @Mock private RecordMetadata recordMetadata; - @Mock private Acl acl; - private final ArgumentCaptor<Set<String>> captor = ArgumentCaptor.forClass(Set.class); - - - @Before - public void setup() { + @Test + void hasOwnerAccessToRecord_shouldReturnTrue_ifUserIsOwner() { when(recordMetadata.getAcl()).thenReturn(acl); - when(recordMetadata.getUser()).thenReturn(USER); when(acl.getOwners()).thenReturn(new String[]{OWNER_ACL}); - when(acl.getViewers()).thenReturn(new String[]{VIEWER_ACL}); - } - - @Test - public void hasOwnerAccessToRecord_shouldReturnTrue_ifUserIsOwner() { when(dataEntitlementsService.hasAccessToData(eq(headers), anySet())).thenReturn(true); assertTrue(entitlementsHelper.hasOwnerAccessToRecord(recordMetadata)); @@ -64,7 +50,9 @@ public class EntitlementsHelperTest { } @Test - public void hasOwnerAccessToRecord_shouldReturnFalse_ifUserIsNotOwner() { + void hasOwnerAccessToRecord_shouldReturnFalse_ifUserIsNotOwner() { + when(recordMetadata.getAcl()).thenReturn(acl); + when(acl.getOwners()).thenReturn(new String[]{OWNER_ACL}); when(dataEntitlementsService.hasAccessToData(eq(headers), anySet())).thenReturn(false); assertFalse(entitlementsHelper.hasOwnerAccessToRecord(recordMetadata)); @@ -75,7 +63,7 @@ public class EntitlementsHelperTest { } @Test - public void hasOwnerAccessToRecord_shouldReturnFalse_ifRecordIsNull() { + void hasOwnerAccessToRecord_shouldReturnFalse_ifRecordIsNull() { when(dataEntitlementsService.hasAccessToData(eq(headers), anySet())).thenReturn(false); assertFalse(entitlementsHelper.hasOwnerAccessToRecord(null)); @@ -85,7 +73,7 @@ public class EntitlementsHelperTest { } @Test - public void hasOwnerAccessToRecord_shouldReturnFalse_ifRecordsAclsAreNull() { + void hasOwnerAccessToRecord_shouldReturnFalse_ifRecordsAclsAreNull() { when(recordMetadata.getAcl()).thenReturn(null); when(dataEntitlementsService.hasAccessToData(eq(headers), anySet())).thenReturn(false); @@ -97,7 +85,11 @@ public class EntitlementsHelperTest { //----- @Test - public void hasViewerAccessToRecord_shouldReturnTrue_ifUserIsViewer() { + void hasViewerAccessToRecord_shouldReturnTrue_ifUserIsViewer() { + when(recordMetadata.getAcl()).thenReturn(acl); + when(recordMetadata.getUser()).thenReturn(USER); + when(acl.getViewers()).thenReturn(new String[]{VIEWER_ACL}); + when(dataEntitlementsService.hasAccessToData(eq(headers), anySet())).thenReturn(true); assertTrue(entitlementsHelper.hasViewerAccessToRecord(recordMetadata)); @@ -108,7 +100,11 @@ public class EntitlementsHelperTest { } @Test - public void hasViewerAccessToRecord_shouldReturnTrue_ifUserIsNotViewerButOwner() { + void hasViewerAccessToRecord_shouldReturnTrue_ifUserIsNotViewerButOwner() { + when(recordMetadata.getAcl()).thenReturn(acl); + when(recordMetadata.getUser()).thenReturn(USER); + when(acl.getOwners()).thenReturn(new String[]{OWNER_ACL}); + when(acl.getViewers()).thenReturn(new String[]{VIEWER_ACL}); when(dataEntitlementsService.hasAccessToData(eq(headers), argThat((ArgumentMatcher<Set>) set -> set.contains(VIEWER_ACL)))).thenReturn(false); when(dataEntitlementsService.hasAccessToData(eq(headers), @@ -126,7 +122,10 @@ public class EntitlementsHelperTest { @Test - public void hasViewerAccessToRecord_shouldReturnTrue_ifUserIsNotViewerButCreator() { + void hasViewerAccessToRecord_shouldReturnTrue_ifUserIsNotViewerButCreator() { + when(recordMetadata.getAcl()).thenReturn(acl); + when(recordMetadata.getUser()).thenReturn(USER); + when(acl.getViewers()).thenReturn(new String[]{VIEWER_ACL}); when(dataEntitlementsService.hasAccessToData(eq(headers), argThat((ArgumentMatcher<Set>) set -> set.contains(VIEWER_ACL)))).thenReturn(false); when(headers.getUserEmail()).thenReturn(USER); @@ -138,7 +137,7 @@ public class EntitlementsHelperTest { } @Test - public void hasViewerAccessToRecord_shouldReturnFalse_ifRecordIsNull() { + void hasViewerAccessToRecord_shouldReturnFalse_ifRecordIsNull() { when(dataEntitlementsService.hasAccessToData(eq(headers), anySet())).thenReturn(false); assertFalse(entitlementsHelper.hasViewerAccessToRecord(null)); @@ -150,7 +149,7 @@ public class EntitlementsHelperTest { } @Test - public void hasViewerAccessToRecord_shouldReturnFalse_ifRecordsAclsAreNull() { + void hasViewerAccessToRecord_shouldReturnFalse_ifRecordsAclsAreNull() { when(recordMetadata.getAcl()).thenReturn(null); when(dataEntitlementsService.hasAccessToData(eq(headers), anySet())).thenReturn(false); diff --git a/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/util/RecordUtilTest.java b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/util/RecordUtilTest.java index 8c943f8322920a08921c62f2420515315a70411f..630a30faab02b68feba0fbac464bd9546c95ab52 100644 --- a/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/util/RecordUtilTest.java +++ b/provider/storage-azure/src/test/java/org/opengroup/osdu/storage/provider/azure/util/RecordUtilTest.java @@ -1,28 +1,25 @@ package org.opengroup.osdu.storage.provider.azure.util; import org.apache.http.HttpStatus; -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; -import org.opengroup.osdu.core.common.model.http.AppError; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; import org.opengroup.osdu.core.common.model.http.AppException; import org.opengroup.osdu.core.common.model.storage.RecordMetadata; import org.springframework.util.ReflectionUtils; import java.lang.reflect.Field; import java.util.Arrays; +import java.util.List; import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.springframework.util.ReflectionUtils.findField; -@RunWith(MockitoJUnitRunner.class) -public class RecordUtilTest { +@ExtendWith(MockitoExtension.class) +class RecordUtilTest { private static final String RECORD_ID_WITH_11_SYMBOLS = "onetwothree"; private static final String ERROR_REASON = "Invalid id"; private static final String ERROR_MESSAGE = "RecordId values which are exceeded 100 symbols temporarily not allowed"; @@ -33,35 +30,35 @@ public class RecordUtilTest { private static final int RECORD_ID_MAX_LENGTH = 10; - @Rule - public ExpectedException exceptionRule = ExpectedException.none(); + private final RecordUtil recordUtil = new RecordUtil(); - private RecordUtil recordUtil = new RecordUtil(); - - @Before - public void setup() { + @BeforeEach + void setup() { Field recordIdMaxLength = findField(RecordUtil.class, "recordIdMaxLength"); recordIdMaxLength.setAccessible(true); ReflectionUtils.setField(recordIdMaxLength, recordUtil, RECORD_ID_MAX_LENGTH); } @Test - public void shouldFail_CreateUpdateRecords_ifTooLOngRecordIdPresented() { + void shouldFail_CreateUpdateRecords_ifTooLOngRecordIdPresented() { assertEquals(11, RECORD_ID_WITH_11_SYMBOLS.length()); + List<String> listToBeValidated = Arrays.asList(RECORD_ID_WITH_11_SYMBOLS, RECORD_ID_WITH_11_SYMBOLS); + + AppException appException = assertThrows(AppException.class, () -> recordUtil.validateIds(listToBeValidated)); - exceptionRule.expect(AppException.class); - exceptionRule.expect(buildAppExceptionMatcher(ERROR_MESSAGE, ERROR_REASON, 400)); + assertEquals(HttpStatus.SC_BAD_REQUEST, appException.getError().getCode()); + assertEquals(ERROR_MESSAGE, appException.getError().getMessage()); + assertEquals(ERROR_REASON, appException.getError().getReason()); - recordUtil.validateIds(Arrays.asList(RECORD_ID_WITH_11_SYMBOLS, RECORD_ID_WITH_11_SYMBOLS)); } @Test - public void shouldDoNothing_ifNullRecordId_passed() { + void shouldDoNothing_ifNullRecordId_passed() { recordUtil.validateIds(singletonList(null)); } @Test - public void shouldGetKindForVersion_successFully() { + void shouldGetKindForVersion_successFully() { RecordMetadata record = buildRecordMetadata(); String actualKind = recordUtil.getKindForVersion(record, VERSION.toString()); @@ -70,31 +67,33 @@ public class RecordUtilTest { } @Test - public void shouldFailGetKindForVersion_whenVersionNotFound() { + void shouldFailGetKindForVersion_whenVersionNotFound() { String errorMessage = String.format("The version %s can't be found for record %s", WRONG_VERSION, RECORD_ID_WITH_11_SYMBOLS); String errorReason = "Version not found"; RecordMetadata recordMetadata = buildRecordMetadata(); - exceptionRule.expect(AppException.class); - exceptionRule.expect(buildAppExceptionMatcher(errorMessage, errorReason, HttpStatus.SC_NOT_FOUND)); + AppException appException = assertThrows(AppException.class, () -> recordUtil.getKindForVersion(recordMetadata, WRONG_VERSION)); - recordUtil.getKindForVersion(recordMetadata, WRONG_VERSION); + assertEquals(HttpStatus.SC_NOT_FOUND, appException.getError().getCode()); + assertEquals(errorMessage, appException.getError().getMessage()); + assertEquals(errorReason, appException.getError().getReason()); } @Test - public void shouldFailGetKindForVersion_whenVersionMatches_onlySequence() { + void shouldFailGetKindForVersion_whenVersionMatches_onlySequence() { String errorMessage = String.format("The version %s can't be found for record %s", VERSION_SEQUENCE, RECORD_ID_WITH_11_SYMBOLS); String errorReason = "Version not found"; RecordMetadata recordMetadata = buildRecordMetadata(); - exceptionRule.expect(AppException.class); - exceptionRule.expect(buildAppExceptionMatcher(errorMessage, errorReason, HttpStatus.SC_NOT_FOUND)); + AppException appException = assertThrows(AppException.class, () -> recordUtil.getKindForVersion(recordMetadata, VERSION_SEQUENCE)); - recordUtil.getKindForVersion(recordMetadata, VERSION_SEQUENCE); + assertEquals(HttpStatus.SC_NOT_FOUND, appException.getError().getCode()); + assertEquals(errorMessage, appException.getError().getMessage()); + assertEquals(errorReason, appException.getError().getReason()); } private RecordMetadata buildRecordMetadata() { @@ -103,35 +102,6 @@ public class RecordUtilTest { recordMetadata.setKind(KIND); recordMetadata.addGcsPath(VERSION); recordMetadata.getGcsVersionPaths().add(null); - return recordMetadata; - } - - private Matcher<AppException> buildAppExceptionMatcher(String message, String reason, int errorCode) { - return new Matcher<AppException>() { - @Override - public boolean matches(Object o) { - AppException appException = (AppException) o; - AppError error = appException.getError(); - - return error.getCode() == errorCode && - error.getMessage().equals(message) && - error.getReason().equals(reason); - } - - @Override - public void describeMismatch(Object o, Description description) { - - } - - @Override - public void _dont_implement_Matcher___instead_extend_BaseMatcher_() { - - } - - @Override - public void describeTo(Description description) { - - } - }; + return recordMetadata; } }