package com.constellio.model.services.schemas;
import static com.constellio.model.entities.schemas.Schemas.PATH;
import static com.constellio.model.services.schemas.builders.CommonMetadataBuilder.ALL_REMOVED_AUTHS;
import static com.constellio.model.services.schemas.builders.CommonMetadataBuilder.ATTACHED_ANCESTORS;
import static com.constellio.model.services.schemas.builders.CommonMetadataBuilder.INHERITED_AUTHORIZATIONS;
import static java.util.Arrays.asList;
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.spy;
import java.util.Collections;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import com.constellio.model.entities.Taxonomy;
import com.constellio.model.entities.calculators.CalculatorParameters;
import com.constellio.model.entities.calculators.MetadataValueCalculator;
import com.constellio.model.entities.calculators.dependencies.Dependency;
import com.constellio.model.entities.calculators.dependencies.HierarchyDependencyValue;
import com.constellio.model.entities.calculators.dependencies.SpecialDependencies;
import com.constellio.model.entities.calculators.dependencies.SpecialDependency;
import com.constellio.model.entities.records.Record;
import com.constellio.model.entities.records.Transaction;
import com.constellio.model.entities.schemas.Metadata;
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.services.records.RecordServices;
import com.constellio.model.services.schemas.builders.MetadataSchemaTypesBuilder;
import com.constellio.model.services.search.SearchServices;
import com.constellio.model.services.search.query.logical.LogicalSearchQueryOperators;
import com.constellio.model.services.search.query.logical.condition.LogicalSearchCondition;
import com.constellio.model.services.taxonomies.TaxonomiesManager;
import com.constellio.sdk.tests.ConstellioTest;
import com.constellio.sdk.tests.TestRecord;
import com.constellio.sdk.tests.setups.TwoTaxonomiesContainingFolderAndDocumentsSetup;
import com.constellio.sdk.tests.setups.TwoTaxonomiesContainingFolderAndDocumentsSetup.CollectionSchema;
import com.constellio.sdk.tests.setups.TwoTaxonomiesContainingFolderAndDocumentsSetup.DocumentSchema;
import com.constellio.sdk.tests.setups.TwoTaxonomiesContainingFolderAndDocumentsSetup.FolderSchema;
import com.constellio.sdk.tests.setups.TwoTaxonomiesContainingFolderAndDocumentsSetup.Taxonomy1FirstSchemaType;
import com.constellio.sdk.tests.setups.TwoTaxonomiesContainingFolderAndDocumentsSetup.Taxonomy1SecondSchemaType;
import com.constellio.sdk.tests.setups.TwoTaxonomiesContainingFolderAndDocumentsSetup.Taxonomy2CustomSchema;
import com.constellio.sdk.tests.setups.TwoTaxonomiesContainingFolderAndDocumentsSetup.Taxonomy2DefaultSchema;
import com.constellio.sdk.tests.setups.TwoTaxonomiesContainingFolderAndDocumentsSetup.TaxonomyRecords;
public class ModificationImpactCalculator_HierarchiesAcceptanceTest extends ConstellioTest {
List<Metadata> noAlreadyReindexedMetadata = Collections.emptyList();
RecordServices recordServices;
MetadataSchemasManager schemasManager;
ModificationImpactCalculator impactCalculator;
TwoTaxonomiesContainingFolderAndDocumentsSetup schemas =
new TwoTaxonomiesContainingFolderAndDocumentsSetup(zeCollection);
Taxonomy1FirstSchemaType taxonomy1FirstSchema = schemas.new Taxonomy1FirstSchemaType();
Taxonomy1SecondSchemaType taxonomy1SecondSchema = schemas.new Taxonomy1SecondSchemaType();
Taxonomy2DefaultSchema taxonomy2DefaultSchema = schemas.new Taxonomy2DefaultSchema();
Taxonomy2CustomSchema taxonomy2CustomSchema = schemas.new Taxonomy2CustomSchema();
CollectionSchema collectionSchema = schemas.new CollectionSchema();
FolderSchema folderSchema = schemas.new FolderSchema();
DocumentSchema documentSchema = schemas.new DocumentSchema();
TaxonomyRecords records;
Record aFolderWithTaxonomy;
Record aFolderWithoutTaxonomy;
SearchServices searchServices;
@Before
public void setUp()
throws Exception {
TaxonomiesManager taxonomiesManager = getModelLayerFactory().getTaxonomiesManager();
searchServices = spy(getModelLayerFactory().newSearchServices());
doReturn(1L).when(searchServices).getResultsCount(any(LogicalSearchCondition.class));
schemasManager = getModelLayerFactory().getMetadataSchemasManager();
recordServices = getModelLayerFactory().newRecordServices();
defineSchemasManager().using(schemas);
for (Taxonomy taxonomy : schemas.getTaxonomies()) {
taxonomiesManager.addTaxonomy(taxonomy, schemasManager);
}
records = schemas.givenTaxonomyRecords(recordServices);
MetadataSchemaTypesBuilder typesBuilder = schemasManager.modify("zeCollection");
typesBuilder.getSchema(taxonomy1FirstSchema.code()).create("taxo1FirstSchemaMetaWithTaxoDependency")
.setType(MetadataValueType.STRING).defineDataEntry().asCalculated(DummyCalculatorWithTaxonomyDependency.class);
typesBuilder.getSchema(taxonomy1SecondSchema.code()).create("taxo1SecondSchemaMetaWithTaxoDependency")
.setType(MetadataValueType.STRING).defineDataEntry().asCalculated(DummyCalculatorWithTaxonomyDependency.class);
typesBuilder.getSchema(folderSchema.code()).create("folderMetaWithTaxoDependency")
.setType(MetadataValueType.STRING).defineDataEntry().asCalculated(DummyCalculatorWithTaxonomyDependency.class);
typesBuilder.getSchema(documentSchema.code()).create("documentMetaWithTaxoDependency")
.setType(MetadataValueType.STRING).defineDataEntry().asCalculated(DummyCalculatorWithTaxonomyDependency.class);
schemas.onSchemaBuilt(schemasManager.saveUpdateSchemaTypes(typesBuilder));
aFolderWithTaxonomy = recordServices.newRecordWithSchema(folderSchema.instance());
aFolderWithTaxonomy.set(folderSchema.taxonomy1(), records.taxo1_firstTypeItem2_firstTypeItem2_secondTypeItem1);
aFolderWithoutTaxonomy = recordServices.newRecordWithSchema(folderSchema.instance());
Transaction transaction = new Transaction();
transaction.addUpdate(aFolderWithTaxonomy);
transaction.addUpdate(aFolderWithoutTaxonomy);
recordServices.execute(transaction);
List<Taxonomy> taxonomies = getModelLayerFactory().getTaxonomiesManager().getEnabledTaxonomies(zeCollection);
MetadataSchemaTypes types = schemasManager.getSchemaTypes(zeCollection);
impactCalculator = new ModificationImpactCalculator(types, taxonomies, searchServices, recordServices);
}
@Test
public void givenPathModifiedOfTaxonomyConceptThenHasImpactOnTaxonomyChildren()
throws Exception {
TestRecord record = (TestRecord) records.taxo1_firstTypeItem2_firstTypeItem1;
record.markAsModified(taxonomy1FirstSchema.path());
List<ModificationImpact> impacts = impactCalculator
.findTransactionImpact(new Transaction(record), true);
assertPathAndAuthorizationsImpactInFirstAndSecondSchema(record, impacts);
}
@Test
public void givenTrivialMetadataModifiedOfTaxonomyConceptThenNoImpactOnTaxonomyChildren()
throws Exception {
TestRecord record = records.taxo1_firstTypeItem2_firstTypeItem1;
record.set(taxonomy1FirstSchema.title(), "newTitle");
List<ModificationImpact> impacts = impactCalculator
.findTransactionImpact(new Transaction(record), true);
assertThat(impacts).isEmpty();
}
@Test
public void givenPathMetadataModifiedOfTaxonomyConceptUsedByFoldersThenHasImpactOnTaxonomyChildrenAndRecordsUsingIt()
throws Exception {
TestRecord record = records.taxo1_firstTypeItem2_secondTypeItem1;
record.markAsModified(folderSchema.path());
List<ModificationImpact> impacts = impactCalculator
.findTransactionImpact(new Transaction(record), true);
assertPathAndAuthorizationsImpactInSecondSchemaAndFolderSchema(record, impacts);
}
@Test
public void givenAllRemovedAuthsMetadataModifiedOfTaxonomyConceptUsedByFoldersThenHasImpactOnTaxonomyChildrenAndRecordsUsingIt()
throws Exception {
TestRecord record = records.taxo1_firstTypeItem2_secondTypeItem1;
record.markAsModified(folderSchema.allRemovedAuths());
List<ModificationImpact> impacts = impactCalculator
.findTransactionImpact(new Transaction(record), true);
assertAllRemovedAuthImpactInSecondSchemaAndFolderSchema(record, impacts);
}
@Test
public void givenTrivialMetadataModifiedOfTaxonomyConceptUsedByFoldersThenHasNoImpactOnTaxonomyChildrenAndRecordsUsingIt()
throws Exception {
TestRecord record = records.taxo1_firstTypeItem2_secondTypeItem1;
record.set(taxonomy1SecondSchema.title(), "newTitle");
List<ModificationImpact> impacts = impactCalculator
.findTransactionImpact(new Transaction(record), true);
assertThat(impacts).isEmpty();
}
@Test
public void givenARecordPathModifiedThenHasImpactOnChildren()
throws Exception {
TestRecord record = new TestRecord(folderSchema, "zeFolder");
recordServices.add(record);
record.markAsModified(folderSchema.path());
List<ModificationImpact> impacts = impactCalculator
.findTransactionImpact(new Transaction(record), true);
assertPathAndAuthorizationsImpactInFolderAndDocumentSchema(record, impacts);
}
@Test
public void givenARecordAttachedAncestorsModifiedThenHasImpactOnChildren()
throws Exception {
TestRecord record = new TestRecord(folderSchema, "zeFolder");
recordServices.add(record);
record.markAsModified(folderSchema.attachedAncestors());
List<ModificationImpact> impacts = impactCalculator
.findTransactionImpact(new Transaction(record), true);
assertAttachedAncestorsImpactInFolderAndDocumentSchema(record, impacts);
}
@Test
public void givenTrivialMetadataOfRecordsModifiedThenHasNoImpactOnChildren()
throws Exception {
TestRecord record = new TestRecord(folderSchema, "zeFolder");
recordServices.add(record);
record.set(folderSchema.title(), "newTitle");
List<ModificationImpact> impacts = impactCalculator
.findTransactionImpact(new Transaction(record), true);
assertThat(impacts).isEmpty();
}
// ------------------------------------------------------------------------------------------------------------
private void assertAuthorizationsImpactInFirstAndSecondSchema(TestRecord record, List<ModificationImpact> impacts) {
Metadata taxo1FirstSchemaAuthorizations = taxonomy1FirstSchema.inheritedAuthorizations();
Metadata taxo1SecondSchemaAuthorizations = taxonomy1SecondSchema.inheritedAuthorizations();
assertThat(impacts).hasSize(2);
assertThat(impacts.get(0).getMetadataToReindex())
.containsOnly(taxo1FirstSchemaAuthorizations);
assertThat(impacts.get(1).getMetadataToReindex())
.containsOnly(taxo1SecondSchemaAuthorizations);
assertThat(impacts.get(0).getLogicalSearchCondition())
.isEqualTo(LogicalSearchQueryOperators.from(taxonomy1FirstSchema.type()).whereAny(
asList(taxonomy1FirstSchema.parent())).isIn(asList(record)));
assertThat(impacts.get(1).getLogicalSearchCondition())
.isEqualTo(LogicalSearchQueryOperators.from(taxonomy1SecondSchema.type())
.whereAny(asList(taxonomy1SecondSchema.parentOfType1())).isIn(asList(record)));
}
private void assertAllRemovedAuthImpactInSecondSchemaAndFolderSchema(TestRecord record,
List<ModificationImpact> impacts) {
Metadata folderAllRemovedAuths = folderSchema.allRemovedAuths();
Metadata taxo1SecondSchemaAllRemovedAuths = taxonomy1SecondSchema.allRemovedAuths();
assertThat(impacts).extracting("metadataToReindex")
.containsExactly(asList(folderAllRemovedAuths), asList(taxo1SecondSchemaAllRemovedAuths));
assertThat(impacts.get(1).getLogicalSearchCondition())
.isEqualTo(LogicalSearchQueryOperators.from(taxonomy1SecondSchema.type()).whereAny(
asList(taxonomy1SecondSchema.parentOfType2())).isIn(asList(record)));
assertThat(impacts.get(0).getLogicalSearchCondition())
.isEqualTo(LogicalSearchQueryOperators.from(folderSchema.type())
.whereAny(asList(folderSchema.taxonomy1())).isIn(asList(record)));
}
private void assertAttachedAncestorsImpactInFolderAndDocumentSchema(TestRecord record,
List<ModificationImpact> impacts) {
Metadata folderAuthorizations = folderSchema.attachedAncestors();
Metadata documentAuthorizations = documentSchema.attachedAncestors();
assertThat(impacts).hasSize(2);
assertThat(impacts.get(1).getMetadataToReindex())
.containsOnly(folderAuthorizations);
assertThat(impacts.get(0).getMetadataToReindex())
.containsOnly(documentAuthorizations);
assertThat(impacts.get(1).getLogicalSearchCondition())
.isEqualTo(LogicalSearchQueryOperators.from(folderSchema.type()).whereAny(
asList(folderSchema.parent())).isIn(asList(record)));
assertThat(impacts.get(0).getLogicalSearchCondition())
.isEqualTo(LogicalSearchQueryOperators.from(documentSchema.type())
.whereAny(asList(documentSchema.parent())).isIn(asList(record)));
}
private void assertPathAndAuthorizationsImpactInFirstAndSecondSchema(TestRecord record, List<ModificationImpact> impacts) {
assertThat(impacts).hasSize(2);
assertThat(impacts.get(0).getMetadataToReindex()).extracting("localCode")
.containsOnly("allRemovedAuths", "attachedAncestors", "path", "taxo1FirstSchemaMetaWithTaxoDependency",
"inheritedauthorizations");
assertThat(impacts.get(1).getMetadataToReindex()).extracting("localCode")
.containsOnly("allRemovedAuths", "taxo1SecondSchemaMetaWithTaxoDependency", "attachedAncestors", "path",
"inheritedauthorizations");
assertThat(impacts.get(0).getLogicalSearchCondition())
.isEqualTo(LogicalSearchQueryOperators.from(taxonomy1FirstSchema.type()).whereAny(
asList(taxonomy1FirstSchema.parent())).isIn(asList(record)));
assertThat(impacts.get(1).getLogicalSearchCondition())
.isEqualTo(LogicalSearchQueryOperators.from(taxonomy1SecondSchema.type())
.whereAny(asList(taxonomy1SecondSchema.parentOfType1())).isIn(asList(record)));
}
private void assertPathAndAuthorizationsImpactInSecondSchemaAndFolderSchema(TestRecord record,
List<ModificationImpact> impacts) {
assertThat(impacts).hasSize(2);
assertThat(impacts.get(1).getMetadataToReindex()).extracting("localCode")
.containsOnly("allRemovedAuths", "taxo1SecondSchemaMetaWithTaxoDependency", "attachedAncestors", "path",
"inheritedauthorizations");
assertThat(impacts.get(0).getMetadataToReindex()).extracting("localCode")
.containsOnly("allRemovedAuths", "folderMetaWithTaxoDependency", "attachedAncestors", "path",
"inheritedauthorizations");
assertThat(impacts.get(1).getLogicalSearchCondition())
.isEqualTo(LogicalSearchQueryOperators.from(taxonomy1SecondSchema.type()).whereAny(
asList(taxonomy1SecondSchema.parentOfType2())).isIn(asList(record)));
assertThat(impacts.get(0).getLogicalSearchCondition())
.isEqualTo(LogicalSearchQueryOperators.from(folderSchema.type())
.whereAny(asList(folderSchema.taxonomy1())).isIn(asList(record)));
}
private void assertPathAndAuthorizationsImpactInFolderAndDocumentSchema(TestRecord record,
List<ModificationImpact> impacts) {
assertThat(impacts).hasSize(2);
assertThat(impacts.get(1).getMetadataToReindex()).extracting("localCode")
.containsOnly("folderMetaWithTaxoDependency", ALL_REMOVED_AUTHS, INHERITED_AUTHORIZATIONS,
ATTACHED_ANCESTORS, "path");
assertThat(impacts.get(0).getMetadataToReindex()).extracting("localCode")
.containsOnly("documentMetaWithTaxoDependency", ALL_REMOVED_AUTHS, INHERITED_AUTHORIZATIONS,
ATTACHED_ANCESTORS, "path");
assertThat(impacts.get(1).getLogicalSearchCondition())
.isEqualTo(LogicalSearchQueryOperators.from(folderSchema.type()).whereAny(
asList(folderSchema.parent())).isIn(asList(record)));
assertThat(impacts.get(0).getLogicalSearchCondition())
.isEqualTo(LogicalSearchQueryOperators.from(documentSchema.type())
.whereAny(asList(documentSchema.parent())).isIn(asList(record)));
}
private Record newFolder(String title, Record parentFolder, Record taxonomy1, Record... taxonomy2s) {
Record record = recordServices.newRecordWithSchema(folderSchema.instance());
record.set(folderSchema.title(), title);
record.set(folderSchema.parent(), parentFolder);
record.set(folderSchema.taxonomy1(), taxonomy1);
record.set(folderSchema.taxonomy2(), asList(taxonomy2s));
return record;
}
private Record newDocument(String title, Record folder) {
Record record = recordServices.newRecordWithSchema(documentSchema.instance());
record.set(documentSchema.title(), title);
record.set(documentSchema.parent(), folder);
return record;
}
public static class DummyCalculatorWithTaxonomyDependency implements MetadataValueCalculator<String> {
SpecialDependency<HierarchyDependencyValue> taxonomies = SpecialDependencies.HIERARCHY;
@Override
public String calculate(CalculatorParameters parameters) {
return null;
}
@Override
public String getDefaultValue() {
return null;
}
@Override
public MetadataValueType getReturnType() {
return MetadataValueType.STRING;
}
@Override
public boolean isMultiValue() {
return false;
}
@Override
public List<? extends Dependency> getDependencies() {
return asList(taxonomies);
}
}
}