package com.constellio.model.services.schemas; import static com.constellio.model.services.search.query.logical.LogicalSearchQueryOperators.from; import static com.constellio.sdk.tests.TestUtils.asList; import static com.constellio.sdk.tests.TestUtils.asSet; import static com.constellio.sdk.tests.TestUtils.mockMetadata; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import com.constellio.model.entities.Taxonomy; import com.constellio.model.entities.calculators.MetadataValueCalculator; import com.constellio.model.entities.calculators.dependencies.LocalDependency; import com.constellio.model.entities.calculators.dependencies.ReferenceDependency; import com.constellio.model.entities.records.Record; import com.constellio.model.entities.schemas.AllowedReferences; import com.constellio.model.entities.schemas.Metadata; import com.constellio.model.entities.schemas.MetadataSchema; import com.constellio.model.entities.schemas.MetadataSchemaType; import com.constellio.model.entities.schemas.MetadataSchemaTypes; import com.constellio.model.entities.schemas.MetadataValueType; import com.constellio.model.entities.schemas.ModificationImpact; import com.constellio.model.entities.schemas.Schemas; import com.constellio.model.entities.schemas.entries.CalculatedDataEntry; import com.constellio.model.entities.schemas.entries.CopiedDataEntry; import com.constellio.model.services.records.RecordServices; import com.constellio.model.services.search.SearchServices; import com.constellio.model.services.search.query.logical.condition.LogicalSearchCondition; import com.constellio.model.services.taxonomies.TaxonomiesManager; import com.constellio.sdk.tests.ConstellioTest; public class ModificationImpactCalculatorTest extends ConstellioTest { MetadataList modifiedMetadatas; Metadata modifiedMetadata = mockMetadata("zeSchema_default_anotherMetadata"); @Mock Record record; String recordId = aString(); ModificationImpactCalculator impactCalculator; @Mock TaxonomiesManager taxonomiesManager; @Mock List<Taxonomy> taxonomies; @Mock Metadata firstAutomaticMetadata; @Mock Metadata secondAutomaticMetadata; @Mock Metadata thirdAutomaticMetadata; Metadata firstReference = mockMetadata("zeType_default_firstReference"); Metadata secondReference = mockMetadata("zeType_default_secondReference"); Metadata thirdReference = mockMetadata("zeType_default_thirdReference"); @Mock MetadataSchemaTypes schemaTypes; @Mock MetadataSchemaType schemaType; @Mock MetadataSchema defaultSchema; Metadata anotherSchemaCopiedMetadata = mockMetadata("anotherType_default_anotherMetadata"); @Mock List<String> transactionRecordsList; @Mock SearchServices searchServices; @Mock RecordServices recordServices; String zeSchemaMetadataCode = aString(); String anotherSchemaReferenceToZeSchemaMetadataCode = aString(); @Mock RecordsModification recordsModification; List<Metadata> alreadyReindexedMetadata; List<Metadata> returnedMetadatas; @Mock MetadataValueCalculator<?> calculator; Metadata anotherSchemaTitle = mockMetadata("anotherType_default_title"); Metadata anotherSchemaUnmodifiedField = mockMetadata("anotherType_default_unmodifiedField"); Metadata notTheSameTypeSchemaTitle = mockMetadata("notTheSameType_default_title"); Metadata calculatedMetadata = mockMetadata("zeType_default_calculated"); Metadata copiedTitleUsingReferenceToAnotherSchema = mockMetadata("zeType_default_copiedTitle"); Metadata referenceToAnotherSchema = mockMetadata("zeType_default_ref"); Metadata anotherReferenceToAnotherSchema = mockMetadata("zeType_default_ref2"); Metadata referenceToNotSameSchema = mockMetadata("zeType_default_refToDifferentSchema"); @Mock MetadataSchemaTypes types; @Before public void setUp() throws Exception { taxonomies = new ArrayList<>(); alreadyReindexedMetadata = new ArrayList<>(); modifiedMetadatas = new MetadataList(); modifiedMetadatas.add(modifiedMetadata); when(record.getId()).thenReturn(recordId); when(record.isSaved()).thenReturn(true); when(record.getSchemaCode()).thenReturn("zeSchema_default"); when(record.getModifiedMetadatas(schemaTypes)).thenReturn(modifiedMetadatas); when(schemaType.getDefaultSchema()).thenReturn(defaultSchema); when(schemaTypes.getCollection()).thenReturn("zeCollection"); when(firstReference.getType()).thenReturn(MetadataValueType.REFERENCE); when(secondReference.getType()).thenReturn(MetadataValueType.REFERENCE); when(thirdReference.getType()).thenReturn(MetadataValueType.REFERENCE); when(taxonomiesManager.getEnabledTaxonomies("zeCollection")).thenReturn(taxonomies); impactCalculator = spy(new ModificationImpactCalculator(schemaTypes, taxonomies, searchServices, recordServices)); when(schemaTypes.getMetadata("anotherType_default_title")).thenReturn(anotherSchemaTitle); when(schemaTypes.getMetadata("anotherType_default_unmodifiedField")).thenReturn(anotherSchemaUnmodifiedField); when(schemaTypes.getMetadata("notTheSameType_default_title")).thenReturn(notTheSameTypeSchemaTitle); when(referenceToAnotherSchema.getAllowedReferences()).thenReturn(new AllowedReferences("anotherType", null)); when(schemaTypes.getMetadata("zeType_default_ref")).thenReturn(referenceToAnotherSchema); when(anotherReferenceToAnotherSchema.getAllowedReferences()) .thenReturn(new AllowedReferences(null, asSet("anotherType_default"))); when(schemaTypes.getMetadata("zeType_default_ref2")).thenReturn(anotherReferenceToAnotherSchema); when(referenceToNotSameSchema.getAllowedReferences()).thenReturn(new AllowedReferences("differentType", null)); when(schemaTypes.getMetadata("zeType_default_refToDifferentSchema")).thenReturn(referenceToNotSameSchema); when(copiedTitleUsingReferenceToAnotherSchema.getDataEntry()) .thenReturn(new CopiedDataEntry("zeType_default_ref", "anotherType_default_title")); when(schemaTypes.getMetadata("zeType_default_copiedTitle")).thenReturn(copiedTitleUsingReferenceToAnotherSchema); when(calculatedMetadata.getDataEntry()).thenReturn(new CalculatedDataEntry(calculator)); when(schemaTypes.getMetadata("zeType_default_calculated")).thenReturn(calculatedMetadata); } @Test public void whenCalculatingModificationImpactsThenCalculateEachSchemaTypesSeparately() throws Exception { MetadataSchemaType firstTypeWithImpact = mock(MetadataSchemaType.class); MetadataSchemaType secondTypeWithImpact = mock(MetadataSchemaType.class); MetadataSchemaType thirdTypeWithoutImpact = mock(MetadataSchemaType.class); ModificationImpact firstTypeImpact = mock(ModificationImpact.class); ModificationImpact secondTypeImpact = mock(ModificationImpact.class); when(schemaTypes.getSchemaTypes()) .thenReturn(asList(firstTypeWithImpact, secondTypeWithImpact, thirdTypeWithoutImpact)); doReturn(Arrays.asList(firstTypeImpact)).when(impactCalculator) .findImpactsOfARecordsModificationInSchemaType(firstTypeWithImpact, recordsModification, transactionRecordsList, "zeTitle"); doReturn(Arrays.asList(secondTypeImpact)).when(impactCalculator).findImpactsOfARecordsModificationInSchemaType( secondTypeWithImpact, recordsModification, transactionRecordsList, "zeTitle"); doReturn(new ArrayList<>()).when(impactCalculator) .findImpactsOfARecordsModificationInSchemaType(thirdTypeWithoutImpact, recordsModification, transactionRecordsList, "zeTitle"); List<ModificationImpact> impacts = impactCalculator.findImpactOfARecordsModification( recordsModification, transactionRecordsList, "zeTitle"); assertThat(impacts).containsOnly(firstTypeImpact, secondTypeImpact); verify(impactCalculator) .findImpactsOfARecordsModificationInSchemaType(firstTypeWithImpact, recordsModification, transactionRecordsList, "zeTitle"); verify(impactCalculator).findImpactsOfARecordsModificationInSchemaType(secondTypeWithImpact, recordsModification, transactionRecordsList, "zeTitle"); verify(impactCalculator).findImpactsOfARecordsModificationInSchemaType(thirdTypeWithoutImpact, recordsModification, transactionRecordsList, "zeTitle"); } @Test public void whenCalculatingModificationImpactOfSchemaTypeThenReturnModificationImpactBasedOnReferences() throws Exception { when(searchServices.getResultsCount(any(LogicalSearchCondition.class))).thenReturn(1L); List<Metadata> firstMetadataReferences = asList(firstReference, secondReference); List<Metadata> secondMetadataReferences = asList(secondReference, thirdReference); List<Metadata> thirdMetadataReferences = new ArrayList<>(); doReturn(firstMetadataReferences).when(impactCalculator).getReferenceMetadatasLinkingToModifiedMetadatas( firstAutomaticMetadata, modifiedMetadatas); doReturn(secondMetadataReferences).when(impactCalculator).getReferenceMetadatasLinkingToModifiedMetadatas( secondAutomaticMetadata, modifiedMetadatas); doReturn(thirdMetadataReferences).when(impactCalculator).getReferenceMetadatasLinkingToModifiedMetadatas( thirdAutomaticMetadata, modifiedMetadatas); List<Metadata> automaticMetadatas = asList(firstAutomaticMetadata, secondAutomaticMetadata, thirdAutomaticMetadata); when(schemaType.getAutomaticMetadatas()).thenReturn(automaticMetadatas); RecordsModification modification = new RecordsModification(Arrays.asList(record), Arrays.asList(modifiedMetadata), schemaType); List<ModificationImpact> modificationImpacts = impactCalculator.findImpactsOfARecordsModificationInSchemaType( schemaType, modification, Arrays.asList(recordId), "zeTitle"); assertThat(modificationImpacts).hasSize(1); assertThat(modificationImpacts.get(0).getMetadataToReindex()).containsOnly(firstAutomaticMetadata, secondAutomaticMetadata); LogicalSearchCondition expectedCondition = from(schemaType).whereAny( Arrays.asList(firstReference, secondReference, thirdReference)).isIn(Arrays.asList(record)).andWhere( Schemas.IDENTIFIER).isNotIn(Arrays.asList(recordId)); assertThat(modificationImpacts.get(0).getLogicalSearchCondition()).isEqualTo(expectedCondition); } @Test public void givenAMetadataAlreadyReindexedWhenCalculatingModificationImpactOfSchemaTypeThenReturnModificationImpactWithoutTheMetadata() throws Exception { when(searchServices.getResultsCount(any(LogicalSearchCondition.class))).thenReturn(1L); alreadyReindexedMetadata.add(firstAutomaticMetadata); List<Metadata> firstMetadataReferences = asList(firstReference, secondReference); List<Metadata> secondMetadataReferences = asList(secondReference, thirdReference); List<Metadata> thirdMetadataReferences = new ArrayList<>(); doReturn(firstMetadataReferences).when(impactCalculator).getReferenceMetadatasLinkingToModifiedMetadatas( firstAutomaticMetadata, modifiedMetadatas); doReturn(secondMetadataReferences).when(impactCalculator).getReferenceMetadatasLinkingToModifiedMetadatas( secondAutomaticMetadata, modifiedMetadatas); doReturn(thirdMetadataReferences).when(impactCalculator).getReferenceMetadatasLinkingToModifiedMetadatas( thirdAutomaticMetadata, modifiedMetadatas); List<Metadata> automaticMetadatas = asList(firstAutomaticMetadata, secondAutomaticMetadata, thirdAutomaticMetadata); when(schemaType.getAutomaticMetadatas()).thenReturn(automaticMetadatas); RecordsModification modification = new RecordsModification(Arrays.asList(record), Arrays.asList(modifiedMetadata), schemaType); List<ModificationImpact> modificationImpacts = impactCalculator.findImpactsOfARecordsModificationInSchemaType( schemaType, modification, Arrays.asList(recordId), "zeTitle"); assertThat(modificationImpacts).hasSize(1); assertThat(modificationImpacts.get(0).getMetadataToReindex()).containsOnly(firstAutomaticMetadata, secondAutomaticMetadata); LogicalSearchCondition expectedCondition = from(schemaType) .whereAny(Arrays.asList(firstReference, secondReference, thirdReference)) .isIn(Arrays.asList(record)).andWhere(Schemas.IDENTIFIER).isNotIn(Arrays.asList(recordId)); assertThat(modificationImpacts.get(0).getLogicalSearchCondition()).isEqualTo(expectedCondition); } @Test public void givenAllMetadataAlreadyReindexedWhenCalculatingModificationImpactOfSchemaTypeThenReturnNull() throws Exception { transactionRecordsList = new ArrayList<>(); alreadyReindexedMetadata.add(firstAutomaticMetadata); alreadyReindexedMetadata.add(secondAutomaticMetadata); List<Metadata> firstMetadataReferences = asList(firstReference, secondReference); List<Metadata> secondMetadataReferences = asList(secondReference, thirdReference); List<Metadata> thirdMetadataReferences = new ArrayList<>(); doReturn(firstMetadataReferences).when(impactCalculator).getReferenceMetadatasLinkingToModifiedMetadatas( firstAutomaticMetadata, modifiedMetadatas); doReturn(secondMetadataReferences).when(impactCalculator).getReferenceMetadatasLinkingToModifiedMetadatas( secondAutomaticMetadata, modifiedMetadatas); doReturn(thirdMetadataReferences).when(impactCalculator).getReferenceMetadatasLinkingToModifiedMetadatas( thirdAutomaticMetadata, modifiedMetadatas); List<Metadata> automaticMetadatas = asList(firstAutomaticMetadata, secondAutomaticMetadata, thirdAutomaticMetadata); when(schemaType.getAutomaticMetadatas()).thenReturn(automaticMetadatas); RecordsModification modification = new RecordsModification(Arrays.asList(record), Arrays.asList(modifiedMetadata), schemaType); List<ModificationImpact> modificationImpacts = impactCalculator.findImpactsOfARecordsModificationInSchemaType( schemaType, modification, Arrays.asList(recordId), "zeTitle"); assertThat(modificationImpacts).isEmpty(); } @Test public void givenMetadataCopyingAUnmodifiedValueWhenGetReferenceMetadataLinkedToModifiedMetadatasThenEmptyList() { when(anotherSchemaCopiedMetadata.getDataEntry()).thenReturn( new CopiedDataEntry(anotherSchemaReferenceToZeSchemaMetadataCode, zeSchemaMetadataCode)); List<Metadata> references = impactCalculator.getReferenceMetadatasLinkingToModifiedMetadatas( anotherSchemaCopiedMetadata, modifiedMetadatas); assertThat(references).isEmpty(); } @Test public void givenMultipleModifiedMetadatasThenGetReferencesUsingThem() { Metadata reference1 = mockMetadata("zetype_default_reference1"); Metadata reference2 = mockMetadata("zetype_default_reference2"); Metadata modifiedMetadata1 = mockMetadata("zetype_default_modifiedMetadata1"); Metadata modifiedMetadata2 = mockMetadata("zetype_default_modifiedMetadata2"); Metadata automaticMetadata = mockMetadata("zetype_default_automaticMetadata"); doReturn(asList(reference1)).when(impactCalculator) .getReferencesToMetadata(automaticMetadata, modifiedMetadata1); doReturn(asList(reference1, reference2)).when(impactCalculator) .getReferencesToMetadata(automaticMetadata, modifiedMetadata2); List<Metadata> modifiedMetadatas = asList(modifiedMetadata1, modifiedMetadata2); List<Metadata> references = impactCalculator.getReferenceMetadatasLinkingToModifiedMetadatas( automaticMetadata, modifiedMetadatas); assertThat(references).containsOnly(reference1, reference2).hasSize(2); } @Test public void whenGetCopiedMetadataReferencesToOtherMetadataWithSameCodeInAnotherSchemaThenEmptyList() throws Exception { List<Metadata> referenceMetadatas = impactCalculator .getReferencesToMetadata(copiedTitleUsingReferenceToAnotherSchema, notTheSameTypeSchemaTitle); assertThat(referenceMetadatas).isEmpty(); } @Test public void whenGetCopiedMetadataReferencesToOtherMetadataWithSameCodeInSameSchemaThenReturnedInList() throws Exception { List<Metadata> referenceMetadatas = impactCalculator .getReferencesToMetadata(copiedTitleUsingReferenceToAnotherSchema, anotherSchemaTitle); assertThat(referenceMetadatas).containsOnly(referenceToAnotherSchema); } @Test public void givenCalculatorDefinedWithSimpleCodesWhenCalculatedMetadataWithReferencesToOtherMetadataThenReturnThem() throws Exception { List dependencies = new ArrayList<>(); dependencies.add(ReferenceDependency.toAString("ref", "title")); dependencies.add(ReferenceDependency.toAString("ref2", "title")); dependencies.add(ReferenceDependency.toAString("ref1", "unmodifiedField")); dependencies.add(ReferenceDependency.toAString("refToDifferentSchema", "title")); dependencies.add(LocalDependency.toAString("notImportant")); when(calculator.getDependencies()).thenReturn(dependencies); List<Metadata> referenceMetadatas = impactCalculator.getReferencesToMetadata(calculatedMetadata, anotherSchemaTitle); assertThat(referenceMetadatas).containsOnly(referenceToAnotherSchema, anotherReferenceToAnotherSchema); } @Test public void givenCalculatorDefinedWithCompleteCodesWhenCalculatedMetadataWithReferencesToOtherMetadataThenReturnThem() throws Exception { List dependencies = new ArrayList<>(); dependencies.add(ReferenceDependency.toAString("zeType_default_ref", "anotherType_default_title")); dependencies.add(ReferenceDependency.toAString("zeType_default_ref2", "anotherType_default_title")); dependencies.add(ReferenceDependency.toAString("zeType_default_ref1", "anotherType_default_unmodifiedField")); dependencies.add(ReferenceDependency.toAString("zeType_default_refToDifferentSchema", "notTheSameType_default_title")); dependencies.add(LocalDependency.toAString("notImportant")); when(calculator.getDependencies()).thenReturn(dependencies); List<Metadata> referenceMetadatas = impactCalculator.getReferencesToMetadata(calculatedMetadata, anotherSchemaTitle); assertThat(referenceMetadatas).containsOnly(referenceToAnotherSchema, anotherReferenceToAnotherSchema); } @Test public void givenCalculatorDefinedWithCompleteCodesWithoutCollectionWhenCalculatedMetadataWithReferencesToOtherMetadataThenReturnThem() throws Exception { List dependencies = new ArrayList<>(); dependencies.add(ReferenceDependency.toAString("zeType_default_ref", "anotherType_default_title")); dependencies.add(ReferenceDependency.toAString("zeType_default_ref2", "anotherType_default_title")); dependencies.add(ReferenceDependency.toAString("zeType_default_ref1", "anotherType_default_unmodifiedField")); dependencies.add(ReferenceDependency.toAString("zeType_default_refToDifferentSchema", "notTheSameType_default_title")); dependencies.add(LocalDependency.toAString("notImportant")); when(calculator.getDependencies()).thenReturn(dependencies); List<Metadata> referenceMetadatas = impactCalculator.getReferencesToMetadata(calculatedMetadata, anotherSchemaTitle); assertThat(referenceMetadatas).containsOnly(referenceToAnotherSchema, anotherReferenceToAnotherSchema); } }