package com.constellio.model.services.records;
import static com.constellio.model.entities.schemas.MetadataTransiency.TRANSIENT_EAGER;
import static com.constellio.model.entities.schemas.MetadataTransiency.TRANSIENT_LAZY;
import static com.constellio.model.entities.schemas.Schemas.MARKED_FOR_REINDEXING;
import static com.constellio.model.entities.schemas.Schemas.TITLE;
import static com.constellio.model.frameworks.validation.Validator.METADATA_CODE;
import static com.constellio.model.services.records.RecordServicesAcceptanceTestUtils.calculatedReferenceFromDummyCalculatorUsingOtherMetadata;
import static com.constellio.model.services.records.RecordServicesAcceptanceTestUtils.calculatedTextFromDummyCalculator;
import static com.constellio.model.services.records.RecordServicesAcceptanceTestUtils.calculatedTextListFromDummyCalculator;
import static com.constellio.model.services.records.RecordServicesAcceptanceTestUtils.calculatedTextListFromDummyCalculatorReturningInvalidType;
import static com.constellio.model.services.records.cache.CacheConfig.permanentCache;
import static com.constellio.model.services.schemas.validators.MetadataUnmodifiableValidator.UNMODIFIABLE_METADATA;
import static com.constellio.model.services.search.query.logical.LogicalSearchQuery.query;
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.assertThatRecord;
import static com.constellio.sdk.tests.TestUtils.assertThatRecords;
import static com.constellio.sdk.tests.schemas.TestsSchemasSetup.limitedTo50Characters;
import static com.constellio.sdk.tests.schemas.TestsSchemasSetup.whichAllowsAnotherDefaultSchema;
import static com.constellio.sdk.tests.schemas.TestsSchemasSetup.whichHasDefaultRequirement;
import static com.constellio.sdk.tests.schemas.TestsSchemasSetup.whichHasInputMask;
import static com.constellio.sdk.tests.schemas.TestsSchemasSetup.whichHasTransiency;
import static com.constellio.sdk.tests.schemas.TestsSchemasSetup.whichIsCalculatedUsing;
import static com.constellio.sdk.tests.schemas.TestsSchemasSetup.whichIsEncrypted;
import static com.constellio.sdk.tests.schemas.TestsSchemasSetup.whichIsMultivalue;
import static com.constellio.sdk.tests.schemas.TestsSchemasSetup.whichIsScripted;
import static com.constellio.sdk.tests.schemas.TestsSchemasSetup.whichIsUnmodifiable;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.io.IOException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import org.mockito.ArgumentCaptor;
import com.constellio.data.dao.dto.records.OptimisticLockingResolution;
import com.constellio.data.dao.dto.records.RecordDTO;
import com.constellio.data.dao.services.records.RecordDao;
import com.constellio.data.dao.services.sequence.SequencesManager;
import com.constellio.data.utils.Factory;
import com.constellio.model.conf.PropertiesModelLayerConfiguration.InMemoryModelLayerConfiguration;
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.LocalDependency;
import com.constellio.model.entities.records.Record;
import com.constellio.model.entities.records.Transaction;
import com.constellio.model.entities.records.TransactionRecordsReindexation;
import com.constellio.model.entities.schemas.Metadata;
import com.constellio.model.entities.schemas.MetadataValueType;
import com.constellio.model.entities.schemas.Schemas;
import com.constellio.model.extensions.behaviors.RecordExtension;
import com.constellio.model.extensions.events.records.RecordCreationEvent;
import com.constellio.model.extensions.events.records.RecordInCreationBeforeSaveEvent;
import com.constellio.model.extensions.events.records.RecordInCreationBeforeValidationAndAutomaticValuesCalculationEvent;
import com.constellio.model.extensions.events.records.RecordInModificationBeforeSaveEvent;
import com.constellio.model.extensions.events.records.RecordInModificationBeforeValidationAndAutomaticValuesCalculationEvent;
import com.constellio.model.extensions.events.records.RecordModificationEvent;
import com.constellio.model.extensions.events.records.TransactionExecutionBeforeSaveEvent;
import com.constellio.model.frameworks.validation.ValidationError;
import com.constellio.model.frameworks.validation.Validator;
import com.constellio.model.services.batch.manager.BatchProcessesManager;
import com.constellio.model.services.encrypt.EncryptionKeyFactory;
import com.constellio.model.services.encrypt.EncryptionServices;
import com.constellio.model.services.records.RecordServicesException.ValidationException;
import com.constellio.model.services.records.RecordServicesRuntimeException.CannotSetIdsToReindexInEmptyTransaction;
import com.constellio.model.services.records.RecordServicesRuntimeException.RecordServicesRuntimeException_TransactionHasMoreThan100000Records;
import com.constellio.model.services.records.RecordServicesRuntimeException.RecordServicesRuntimeException_TransactionWithMoreThan1000RecordsCannotHaveTryMergeOptimisticLockingResolution;
import com.constellio.model.services.records.RecordServicesRuntimeException.SchemaTypeOfARecordHasReadOnlyLock;
import com.constellio.model.services.schemas.MetadataSchemaTypesAlteration;
import com.constellio.model.services.schemas.builders.MetadataBuilder;
import com.constellio.model.services.schemas.builders.MetadataBuilder_EnumClassTest.AValidEnum;
import com.constellio.model.services.schemas.builders.MetadataSchemaBuilder;
import com.constellio.model.services.schemas.builders.MetadataSchemaTypeBuilder;
import com.constellio.model.services.schemas.builders.MetadataSchemaTypesBuilder;
import com.constellio.model.services.schemas.validators.MetadataUnmodifiableValidator;
import com.constellio.model.services.search.SearchServices;
import com.constellio.sdk.FakeEncryptionServices;
import com.constellio.sdk.tests.ConstellioTest;
import com.constellio.sdk.tests.ModelLayerConfigurationAlteration;
import com.constellio.sdk.tests.TestRecord;
import com.constellio.sdk.tests.annotations.SlowTest;
import com.constellio.sdk.tests.schemas.MetadataSchemaTypesConfigurator;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class RecordServicesAcceptanceTest extends ConstellioTest {
LocalDate shishDay = new LocalDate().minusDays(42);
LocalDate tockDay = new LocalDate().minusDays(666);
private final String valueTooLong = "this title is too lonnnnnnnnnnnnnnnnnnnnnnnnnnnnnng";
String idReferencedRecordWithAStringAndADateValue, idReferencedRecordWithAnotherDateValue, idReferencedRecordWithoutValue;
RecordServicesTestSchemaSetup schemas;
RecordServicesTestSchemaSetup.ZeSchemaMetadatas zeSchema;
RecordServicesTestSchemaSetup.AnotherSchemaMetadatas anotherSchema;
RecordServicesTestSchemaSetup.ThirdSchemaMetadatas thirdSchema;
LocalDateTime january1 = new LocalDateTime(2014, 1, 1, 0, 0, 0);
LocalDateTime january2 = new LocalDateTime(2014, 1, 2, 0, 0, 0);
Record record;
List<Metadata> allFields;
BatchProcessesManager batchProcessesManager;
LocalDateTime now = new LocalDateTime();
LocalDateTime shishOClock = new LocalDateTime();
LocalDateTime tockOClock = new LocalDateTime();
private RecordServicesImpl recordServices;
RecordDao recordDao;
@Before
public void setup()
throws Exception {
System.out.println("\n\n--RecordServicesAcceptanceTest.setup--\n\n");
configure(new ModelLayerConfigurationAlteration() {
@Override
public void alter(InMemoryModelLayerConfiguration configuration) {
Factory<EncryptionServices> encryptionServicesFactory = new Factory<EncryptionServices>() {
@Override
public EncryptionServices get() {
Key key = EncryptionKeyFactory.newApplicationKey("zePassword", "zeUltimateSalt");
try {
return new EncryptionServices(false).withKey(key);
} catch (NoSuchAlgorithmException | InvalidKeySpecException | IOException e) {
throw new RuntimeException(e);
}
}
};
configuration.setEncryptionServicesFactory(encryptionServicesFactory);
}
});
recordServices = spy((RecordServicesImpl) getModelLayerFactory().newCachelessRecordServices());
batchProcessesManager = getModelLayerFactory().getBatchProcessesManager();
schemas = new RecordServicesTestSchemaSetup();
zeSchema = schemas.new ZeSchemaMetadatas();
anotherSchema = schemas.new AnotherSchemaMetadatas();
thirdSchema = schemas.new ThirdSchemaMetadatas();
record = new TestRecord(zeSchema, "zeUltimateRecord");
recordDao = getDataLayerFactory().newRecordDao();
}
@Test(expected = RecordServicesException.ValidationException.class)
public void givenRequiredAutomaticMetadataWhenSavingWithNullValueThenValidationException()
throws Exception {
System.out.println("\n\n--ze test--\n\n");
defineSchemasManager().using(
schemas.withAStringMetadata(whichHasDefaultRequirement, calculatedTextFromDummyCalculator()));
record.set(zeSchema.metadata("other"), null);
recordServices.add(record);
}
@Test(expected = RecordServicesException.ValidationException.class)
public void givenAutomaticMetadataWhenSavingWithValueWhichIsInvalidValueThenValidationException()
throws Exception {
defineSchemasManager().using(schemas.withAStringMetadata(limitedTo50Characters, calculatedTextFromDummyCalculator()));
record.set(zeSchema.metadata("other"), valueTooLong);
recordServices.add(record);
}
@Test(expected = RecordServicesException.ValidationException.class)
public void givenAutomaticReferenceMetadataWhenSavingWithValueOfUnallowedSchemaThenValidationException()
throws Exception {
defineSchemasManager().using(
schemas.withAReferenceMetadata(whichAllowsAnotherDefaultSchema,
calculatedReferenceFromDummyCalculatorUsingOtherMetadata()));
Record recordUnallowed = saveThirdSchemaRecord();
record.set(zeSchema.metadata("other"), recordUnallowed.getId());
recordServices.add(record);
}
@Test
public void givenAutomaticReferenceMetadataWhenSavingWithValueOfAllowedSchemaThenOK()
throws Exception {
defineSchemasManager().using(
schemas.withAReferenceMetadata(whichAllowsAnotherDefaultSchema,
calculatedReferenceFromDummyCalculatorUsingOtherMetadata()));
Record recordUnallowed = saveAnotherSchemaRecord();
record.set(zeSchema.metadata("other"), recordUnallowed.getId());
recordServices.add(record);
}
@Test
public void givenRequiredAutomaticMetadataWhenSavingWithValueThenOK()
throws Exception {
defineSchemasManager().using(
schemas.withAStringMetadata(whichHasDefaultRequirement, calculatedTextFromDummyCalculator()));
record.set(zeSchema.metadata("other"), "aValue");
recordServices.add(record);
}
@Test(expected = RecordServicesException.ValidationException.class)
public void givenRequiredAutomaticMultivalueMetadataWhenSavingWithNullListThenValidationException()
throws Exception {
defineSchemasManager().using(
schemas.withAStringMetadata(whichHasDefaultRequirement, calculatedTextListFromDummyCalculator()));
record.set(zeSchema.metadata("other"), null);
recordServices.add(record);
}
@Test(expected = RecordServicesException.ValidationException.class)
public void givenRequiredAutomaticMultivalueMetadataWhenSavingWithEmptyListThenValidationException()
throws Exception {
defineSchemasManager().using(
schemas.withAStringMetadata(whichHasDefaultRequirement, calculatedTextListFromDummyCalculator()));
record.set(zeSchema.metadata("other"), new ArrayList<>());
recordServices.add(record);
}
@Test
public void givenRequiredAutomaticMultivalueMetadataWhenSavingWithValueThenOK()
throws Exception {
defineSchemasManager().using(
schemas.withAStringMetadata(whichHasDefaultRequirement, calculatedTextListFromDummyCalculator()));
record.set(zeSchema.metadata("other"), asList("aValue"));
recordServices.add(record);
}
@Test(expected = RecordServicesException.ValidationException.class)
public void givenRequiredAutomaticMetadataWhenSavingWithInvalidTypeThenValidationException()
throws Exception {
defineSchemasManager().using(
schemas.withAStringMetadata(whichHasDefaultRequirement,
calculatedTextListFromDummyCalculatorReturningInvalidType()));
record.set(zeSchema.metadata("other"), 1);
recordServices.add(record);
}
@Test
public void whenAddingSomeRecordsThenDocumentsCountIsCorrect()
throws Exception {
defineSchemasManager().using(schemas.withAStringMetadata().withAnotherStringMetadata());
long initialDocumentsCount = recordServices.documentsCount();
for (int i = 0; i < 11; i++) {
record = new TestRecord(zeSchema);
recordServices.add(record.set(zeSchema.stringMetadata(), "value " + i));
}
assertThat(recordServices.documentsCount() - initialDocumentsCount).isEqualTo(11);
}
@Test
public void whenGettingRecordsTitlesThenTitlesReturned()
throws Exception {
defineSchemasManager().using(schemas);
Record record1 = new TestRecord(zeSchema);
recordServices.add(record1.set(TITLE, "zeTitle1"));
Record record2 = new TestRecord(zeSchema);
recordServices.add(record2.set(TITLE, "zeTitle2"));
assertThat(recordServices.getRecordTitles(zeCollection, Arrays.asList(record1.getId(), record2.getId()))).contains(
"zeTitle1", "zeTitle2");
}
@Test
public void givenSchemaWithEnumListWhenAddingRecordThenValuesPersisted()
throws Exception {
defineSchemasManager().using(schemas.withAnEnumMetadata(AValidEnum.class, whichIsMultivalue));
record.set(zeSchema.enumMetadata(), asList(AValidEnum.SECOND_VALUE, AValidEnum.FIRST_VALUE));
recordServices.add(record);
record = recordServices.getDocumentById(record.getId());
assertThat(record.get(zeSchema.enumMetadata())).isEqualTo(asList(AValidEnum.SECOND_VALUE, AValidEnum.FIRST_VALUE));
}
@Test(expected = RecordServicesException.ValidationException.class)
public void givenSchemaWithValidatorsWhenAddingRecordFailingValidationThenThrowValidationException()
throws Exception {
defineSchemasManager().using(schemas.withAStringMetadata(limitedTo50Characters));
record.set(zeSchema.stringMetadata(), valueTooLong);
recordServices.add(record);
}
@Test(expected = RecordServicesException.ValidationException.class)
public void givenSchemaWithValidatorsWhenUpdatingRecordFailingValidationThenThrowValidationException()
throws Exception {
defineSchemasManager().using(schemas.withAStringMetadata(limitedTo50Characters));
recordServices.add(record.set(zeSchema.stringMetadata(), "Banana"));
record.set(zeSchema.stringMetadata(), valueTooLong);
recordServices.update(record);
}
@Test(expected = SchemaTypeOfARecordHasReadOnlyLock.class)
public void whenAddUpdatingRecordWithReadOnlyLockThenException()
throws Exception {
defineSchemasManager().using(schemas.withAStringMetadata());
schemas.modify(new MetadataSchemaTypesAlteration() {
@Override
public void alter(MetadataSchemaTypesBuilder types) {
types.getSchemaType("zeSchemaType").setReadOnlyLocked(true);
}
});
recordServices.add(record.set(zeSchema.stringMetadata(), "Banana"));
}
@Test
public void whenAddUpdatingRecordWithReadOnlyLockWithFlagAllowingItThenNoException()
throws Exception {
defineSchemasManager().using(schemas.withAStringMetadata());
schemas.modify(new MetadataSchemaTypesAlteration() {
@Override
public void alter(MetadataSchemaTypesBuilder types) {
types.getSchemaType("zeSchemaType").setReadOnlyLocked(true);
}
});
Transaction transaction = new Transaction();
transaction.getRecordUpdateOptions().setAllowSchemaTypeLockedRecordsModification(true);
transaction.add(record.set(zeSchema.stringMetadata(), "Banana"));
recordServices.execute(transaction);
}
@Test()
public void givenSchemaWithFixedSequenceMetadataWhenAddingValidRecordThenSetNewSequenceValue()
throws Exception {
//TODO AFTER-TEST-VALIDATION-SEQ
givenDisabledAfterTestValidations();
defineSchemasManager().using(schemas.withAFixedSequence());
schemas.modify(new MetadataSchemaTypesAlteration() {
@Override
public void alter(MetadataSchemaTypesBuilder types) {
types.getSchema(zeSchema.code()).get("title").setDefaultRequirement(true);
types.getSchema(zeSchema.code()).create("calculatedOnFixedSequence").setType(MetadataValueType.STRING)
.defineDataEntry().asJexlScript("'F'+ fixedSequenceMetadata + '.00'");
}
});
record = recordServices.newRecordWithSchema(zeSchema.instance());
try {
recordServices.add(record);
} catch (RecordServicesException.ValidationException e) {
//OK
}
assertThat(record.get(zeSchema.fixedSequenceMetadata())).isNull();
assertThat(record.get(zeSchema.metadata("calculatedOnFixedSequence"))).isNull();
record.set(TITLE, "Ze title");
try {
recordServices.add(record);
} catch (RecordServicesException.ValidationException e) {
//OK
}
assertThat(record.get(zeSchema.fixedSequenceMetadata())).isEqualTo("1");
assertThat(record.get(zeSchema.metadata("calculatedOnFixedSequence"))).isEqualTo("F1.00");
record = recordServices.newRecordWithSchema(zeSchema.instance());
record.set(TITLE, "Ze title");
try {
recordServices.add(record);
} catch (RecordServicesException.ValidationException e) {
//OK
}
assertThat(record.get(zeSchema.fixedSequenceMetadata())).isEqualTo("2");
assertThat(record.get(zeSchema.metadata("calculatedOnFixedSequence"))).isEqualTo("F2.00");
}
@Test()
public void givenSchemaWithFixedSequenceMetadataWithPatternWhenAddingValidRecordThenSetNewSequenceValue()
throws Exception {
//TODO AFTER-TEST-VALIDATION-SEQ
givenDisabledAfterTestValidations();
defineSchemasManager().using(schemas.withAFixedSequence(whichHasInputMask("99999")));
schemas.modify(new MetadataSchemaTypesAlteration() {
@Override
public void alter(MetadataSchemaTypesBuilder types) {
types.getSchema(zeSchema.code()).get("title").setDefaultRequirement(true);
types.getSchema(zeSchema.code()).create("calculatedOnFixedSequence").setType(MetadataValueType.STRING)
.defineDataEntry().asJexlScript("'F'+ fixedSequenceMetadata + '.00'");
}
});
record = recordServices.newRecordWithSchema(zeSchema.instance());
try {
recordServices.add(record);
} catch (RecordServicesException.ValidationException e) {
//OK
}
assertThat(record.get(zeSchema.fixedSequenceMetadata())).isNull();
assertThat(record.get(zeSchema.metadata("calculatedOnFixedSequence"))).isNull();
record.set(TITLE, "Ze title");
try {
recordServices.add(record);
} catch (RecordServicesException.ValidationException e) {
//OK
}
assertThat(record.get(zeSchema.fixedSequenceMetadata())).isEqualTo("00001");
assertThat(record.get(zeSchema.metadata("calculatedOnFixedSequence"))).isEqualTo("F00001.00");
record = recordServices.newRecordWithSchema(zeSchema.instance());
record.set(TITLE, "Ze title");
try {
recordServices.add(record);
} catch (RecordServicesException.ValidationException e) {
//OK
}
assertThat(record.get(zeSchema.fixedSequenceMetadata())).isEqualTo("00002");
assertThat(record.get(zeSchema.metadata("calculatedOnFixedSequence"))).isEqualTo("F00002.00");
}
@Test()
public void givenSchemaWithDynamicSequenceMetadataWhenChangeSequenceSourceThenGetNewSequenceUsingNewSource()
throws Exception {
//TODO AFTER-TEST-VALIDATION-SEQ
givenDisabledAfterTestValidations();
SequencesManager sequencesManager = getDataLayerFactory().getSequencesManager();
sequencesManager.set("sequence1", 42);
sequencesManager.set("sequence2", 666);
defineSchemasManager().using(schemas.withADynamicSequence());
record = recordServices.newRecordWithSchema(zeSchema.instance());
recordServices.add(record);
assertThat(record.get(zeSchema.dynamicSequenceMetadata())).isNull();
recordServices.update(record.set(zeSchema.metadataDefiningSequenceNumber(), "sequence1"));
assertThat(record.get(zeSchema.dynamicSequenceMetadata())).isEqualTo("43");
recordServices.update(record.set(zeSchema.metadataDefiningSequenceNumber(), "sequence2"));
assertThat(record.get(zeSchema.dynamicSequenceMetadata())).isEqualTo("667");
recordServices.update(record.set(zeSchema.metadataDefiningSequenceNumber(), "sequence1"));
assertThat(record.get(zeSchema.dynamicSequenceMetadata())).isEqualTo("44");
recordServices.update(record.set(TITLE, "zeTitle"));
assertThat(record.get(zeSchema.dynamicSequenceMetadata())).isEqualTo("44");
}
@Test()
public void givenSchemaWithCopiedMetadataWhenAddingRecordThenCopyValues()
throws Exception {
defineSchemasManager().using(
schemas.withTwoMetadatasCopyingAnotherSchemaValuesUsingTwoDifferentReferenceMetadata(false, false, false));
String referencedRecordId = addRecordInAnotherSchemaWithStringMetadataValue(false);
record = recordServices.newRecordWithSchema(zeSchema.instance());
record.set(zeSchema.firstReferenceToAnotherSchema(), referencedRecordId);
recordServices.add(record);
assertThat(record.get(zeSchema.stringCopiedFromFirstReferenceStringMeta())).isEqualTo("Banana");
}
@Test()
public void givenSchemaWithCopiedMultivalueMetadataWhenAddingRecordThenCopyValues()
throws Exception {
defineSchemasManager().using(
schemas.withTwoMetadatasCopyingAnotherSchemaValuesUsingTwoDifferentReferenceMetadata(true, false, false));
String referencedRecordId = addRecordInAnotherSchemaWithStringMetadataValue(true);
record = recordServices.newRecordWithSchema(zeSchema.instance());
record.set(zeSchema.firstReferenceToAnotherSchema(), referencedRecordId);
recordServices.add(record);
assertThat(record.get(zeSchema.stringCopiedFromFirstReferenceStringMeta())).isEqualTo(Arrays.asList("Banana", "Apple"));
}
@Test()
public void givenSchemaWithCopiedMetadataWhenUpdatingRecordThenCopyValues()
throws Exception {
defineSchemasManager().using(
schemas.withTwoMetadatasCopyingAnotherSchemaValuesUsingTwoDifferentReferenceMetadata(false, false, false));
String referencedRecordId = addRecordInAnotherSchemaWithStringMetadataValue(false);
record = recordServices.newRecordWithSchema(zeSchema.instance());
record.set(zeSchema.firstReferenceToAnotherSchema(), referencedRecordId);
recordServices.add(record);
record.set(zeSchema.firstReferenceToAnotherSchema(), null);
recordServices.update(record);
assertThat(record.get(zeSchema.stringCopiedFromFirstReferenceStringMeta())).isNull();
}
@Test()
public void givenSchemaWithCopiedMultivalueMetadataWhenUpdatingRecordThenCopyValues()
throws Exception {
defineSchemasManager().using(
schemas.withTwoMetadatasCopyingAnotherSchemaValuesUsingTwoDifferentReferenceMetadata(true, false, false));
String referencedRecordId = addRecordInAnotherSchemaWithStringMetadataValue(true);
record = recordServices.newRecordWithSchema(zeSchema.instance());
record.set(zeSchema.firstReferenceToAnotherSchema(), referencedRecordId);
recordServices.add(record);
record.set(zeSchema.firstReferenceToAnotherSchema(), null);
recordServices.update(record);
assertThat(record.get(zeSchema.stringCopiedFromFirstReferenceStringMeta())).isEqualTo(new ArrayList<>());
}
@Test()
public void givenSchemaWithCalculatedMetadataWhenAddingRecordThenCalculateValues()
throws Exception {
defineSchemasManager().using(schemas.withCalculatedDaysBetweenLocalDateAndAnotherSchemaRequiredDate(false));
Record anotherRecord = saveAnotherSchemaRecordWithDateMetadataToJanuary1();
Record record = recordServices.newRecordWithSchema(zeSchema.instance());
record.set(zeSchema.dateTimeMetadata(), january2);
record.set(zeSchema.secondReferenceToAnotherSchema(), anotherRecord.getId());
recordServices.add(record);
assertThat(record.get(zeSchema.calculatedDaysBetween())).isEqualTo(1.0);
}
@Test()
public void givenSchemaWithCalculatedMetadataWhenUpdatingRecordWithModifiedDependenciesThenCalculateValues()
throws Exception {
defineSchemasManager().using(schemas.withCalculatedDaysBetweenLocalDateAndAnotherSchemaRequiredDate(false));
Record anotherRecord = saveAnotherSchemaRecordWithDateMetadataToJanuary1();
Record record = recordServices.newRecordWithSchema(zeSchema.instance());
record.set(zeSchema.dateTimeMetadata(), january2);
record.set(zeSchema.secondReferenceToAnotherSchema(), anotherRecord.getId());
recordServices.add(record);
assertThat(record.get(zeSchema.calculatedDaysBetween())).isEqualTo(1.0);
record.set(zeSchema.dateTimeMetadata(), january1);
recordServices.update(record);
assertThat(record.get(zeSchema.calculatedDaysBetween())).isEqualTo(0.0);
}
@Test()
public void givenSchemaWithCalculatedMetadataWhenUpdatingRecordWithRemovedCalculatorDependencyThenSetCalculatedValueToNull()
throws Exception {
defineSchemasManager().using(schemas.withCalculatedDaysBetweenLocalDateAndAnotherSchemaRequiredDate(false));
Record anotherRecord = saveAnotherSchemaRecordWithDateMetadataToJanuary1();
Record record = recordServices.newRecordWithSchema(zeSchema.instance());
record.set(zeSchema.dateTimeMetadata(), january2);
record.set(zeSchema.secondReferenceToAnotherSchema(), anotherRecord.getId());
recordServices.add(record);
assertThat(record.get(zeSchema.calculatedDaysBetween())).isEqualTo(1.0);
record.set(zeSchema.dateTimeMetadata(), null);
recordServices.update(record);
assertThat(record.get(zeSchema.calculatedDaysBetween())).isEqualTo(-1.0);
}
private Record reloadRecord() {
return recordServices.getDocumentById(record.getId());
}
@Test
public void whenAddingOrUpdatingLargeTextMetadataThenValueIsSet()
throws Exception {
defineSchemasManager().using(schemas.withATitle().withALargeTextMetadata());
recordServices.add(record.set(zeSchema.title(), "title").set(zeSchema.largeTextMetadata(), "firstValue"));
Record record = reloadRecord();
assertThat(reloadRecord().get(zeSchema.largeTextMetadata())).isEqualTo("firstValue");
recordServices.update(reloadRecord().set(zeSchema.largeTextMetadata(), "secondValue"));
assertThat(reloadRecord().get(zeSchema.largeTextMetadata())).isEqualTo("secondValue");
recordServices.update(reloadRecord().set(zeSchema.largeTextMetadata(), null));
assertThat(reloadRecord().get(zeSchema.largeTextMetadata())).isEqualTo(null);
}
@Test
public void whenAddingOrUpdatingMultivalueLargeTextMetadataThenValueIsSet()
throws Exception {
defineSchemasManager().using(schemas.withATitle().withALargeTextMetadata(whichIsMultivalue));
recordServices.add(record.set(zeSchema.title(), "title")
.set(zeSchema.largeTextMetadata(), asList("firstValue", "secondValue")));
assertThat(reloadRecord().get(zeSchema.largeTextMetadata())).isEqualTo(asList("firstValue", "secondValue"));
recordServices.update(reloadRecord().set(zeSchema.largeTextMetadata(), asList("secondValue", "thirdValue")));
assertThat(reloadRecord().get(zeSchema.largeTextMetadata())).isEqualTo(asList("secondValue", "thirdValue"));
recordServices.update(reloadRecord().set(zeSchema.largeTextMetadata(), null));
assertThat(reloadRecord().getList(zeSchema.largeTextMetadata())).isEqualTo(new ArrayList<>());
recordServices.update(reloadRecord().set(zeSchema.largeTextMetadata(), new ArrayList<>()));
assertThat(reloadRecord().getList(zeSchema.largeTextMetadata())).isEqualTo(new ArrayList<>());
recordServices.update(reloadRecord().set(zeSchema.largeTextMetadata(), asList("zeValue")));
assertThat(reloadRecord().get(zeSchema.largeTextMetadata())).isEqualTo(asList("zeValue"));
}
@Test
public void givenAddedRecordWhenModifyingSingleValueAndUpdatingThenModificationsSavedAndVersionChanged()
throws Exception {
defineSchemasManager().using(schemas.withATitle().withABooleanMetadata(whichIsMultivalue));
record.set(zeSchema.title(), "aValue");
record.set(zeSchema.booleanMetadata(), Arrays.asList(true, false, true));
recordServices.add(record);
long initialVersion = record.getVersion();
record.set(zeSchema.title(), "anOtherValue");
recordServices.update(record);
assertThat(record.get(zeSchema.title())).isEqualTo("anOtherValue");
assertThat(record.get(zeSchema.booleanMetadata())).isEqualTo(Arrays.asList(true, false, true));
assertThat(record.getVersion()).isNotEqualTo(initialVersion);
}
@Test
public void givenRecordWithDateFieldWhenAddUpdateThenOk()
throws Exception {
defineSchemasManager().using(schemas.withADateMetadata());
record.set(zeSchema.dateMetadata(), shishDay);
recordServices.add(record);
assertThat(recordServices.getDocumentById(record.getId()).get(zeSchema.dateMetadata())).isEqualTo(shishDay);
record.set(zeSchema.dateMetadata(), tockDay);
recordServices.update(record);
assertThat(recordServices.getDocumentById(record.getId()).get(zeSchema.dateMetadata())).isEqualTo(tockDay);
}
@Test
public void givenAddedRecordWhenModifyingMultivalueAndUpdatingThenModificationsSavedAndVersionChanged()
throws Exception {
defineSchemasManager().using(schemas.withATitle().withABooleanMetadata(whichIsMultivalue));
record.set(zeSchema.title(), "aValue");
record.set(zeSchema.booleanMetadata(), Arrays.asList(true, false, true));
recordServices.add(record);
long initialVersion = record.getVersion();
record.set(zeSchema.booleanMetadata(), Arrays.asList(false, true, false));
recordServices.update(record);
assertThat(record.get(zeSchema.title())).isEqualTo("aValue");
assertThat(record.get(zeSchema.booleanMetadata())).isEqualTo(Arrays.asList(false, true, false));
assertThat(record.getVersion()).isNotEqualTo(initialVersion);
}
@Test
public void givenAddedRecordWhenUpdatingNonModifiedRecordThenVersionUnchanged()
throws Exception {
defineSchemasManager().using(schemas.withATitle().withABooleanMetadata(whichIsMultivalue));
record.set(zeSchema.title(), "aValue");
record.set(zeSchema.booleanMetadata(), Arrays.asList(true, false, true));
recordServices.add(record);
long initialVersion = record.getVersion();
recordServices.update(record);
assertThat(record.get(zeSchema.title())).isEqualTo("aValue");
assertThat(record.get(zeSchema.booleanMetadata())).isEqualTo(Arrays.asList(true, false, true));
assertThat(record.getVersion()).isEqualTo(initialVersion);
}
@Test
public void givenEncryptedMetadataThenDecryptedInRecordAndEncryptedInSolr()
throws Exception {
defineSchemasManager()
.using(schemas.withATitle().withAStringMetadata(whichIsEncrypted)
.withAnotherStringMetadata(whichIsEncrypted, whichIsMultivalue));
assertThat(getModelLayerFactory().newEncryptionServices()).isNotNull();
assertThat(getModelLayerFactory().newEncryptionServices()).isNotInstanceOf(FakeEncryptionServices.class);
recordServices.add(record
.set(zeSchema.title(), "neverEncryptedValue")
.set(zeSchema.stringMetadata(), "decryptedValue1")
.set(zeSchema.anotherStringMetadata(), asList("decryptedValue2", "decryptedValue3")));
assertThat(record.get(zeSchema.title())).isEqualTo("neverEncryptedValue");
assertThat(record.get(zeSchema.stringMetadata())).isEqualTo("decryptedValue1");
assertThat(record.get(zeSchema.anotherStringMetadata())).isEqualTo(asList("decryptedValue2", "decryptedValue3"));
record = recordServices.getDocumentById(record.getId());
assertThat(record.get(zeSchema.title())).isEqualTo("neverEncryptedValue");
assertThat(record.get(zeSchema.stringMetadata())).isEqualTo("decryptedValue1");
assertThat(record.get(zeSchema.anotherStringMetadata())).isEqualTo(asList("decryptedValue2", "decryptedValue3"));
RecordDTO recordDTO = recordDao.get(record.getId());
assertThat(recordDTO.getFields().get(zeSchema.title().getDataStoreCode())).isEqualTo("neverEncryptedValue");
assertThat(recordDTO.getFields().get(zeSchema.stringMetadata().getDataStoreCode())).isEqualTo("AN1Qletvk4b6cysfpDjWUg==");
assertThat(recordDTO.getFields().get(zeSchema.anotherStringMetadata().getDataStoreCode()))
.isEqualTo(asList("2xz/K3dNfajma8DJQVMBnQ==", "0d6Amw6w/rOUYwTrjNK4LQ=="));
record.set(zeSchema.stringMetadata(), "decryptedValue2")
.set(zeSchema.anotherStringMetadata(), asList("decryptedValue3", "decryptedValue4"));
assertThat(record.get(zeSchema.title())).isEqualTo("neverEncryptedValue");
assertThat(record.get(zeSchema.stringMetadata())).isEqualTo("decryptedValue2");
assertThat(record.get(zeSchema.anotherStringMetadata())).isEqualTo(asList("decryptedValue3", "decryptedValue4"));
recordServices.update(record);
assertThat(record.get(zeSchema.title())).isEqualTo("neverEncryptedValue");
assertThat(record.get(zeSchema.stringMetadata())).isEqualTo("decryptedValue2");
assertThat(record.get(zeSchema.anotherStringMetadata())).isEqualTo(asList("decryptedValue3", "decryptedValue4"));
record = recordServices.getDocumentById(record.getId());
assertThat(record.get(zeSchema.title())).isEqualTo("neverEncryptedValue");
assertThat(record.get(zeSchema.stringMetadata())).isEqualTo("decryptedValue2");
assertThat(record.get(zeSchema.anotherStringMetadata())).isEqualTo(asList("decryptedValue3", "decryptedValue4"));
recordDTO = recordDao.get(record.getId());
assertThat(recordDTO.getFields().get(zeSchema.title().getDataStoreCode())).isEqualTo("neverEncryptedValue");
assertThat(recordDTO.getFields().get(zeSchema.stringMetadata().getDataStoreCode())).isEqualTo("2xz/K3dNfajma8DJQVMBnQ==");
assertThat(recordDTO.getFields().get(zeSchema.anotherStringMetadata().getDataStoreCode()))
.isEqualTo(asList("0d6Amw6w/rOUYwTrjNK4LQ==", "bLMsWh344pykcDFxbBvrvg=="));
}
@Test
public void givenModificationImpactWhenUpdatingRecordThenHandledInSameTransaction()
throws Exception {
defineSchemasManager().using(schemas.withAMetadataCopiedInAnotherSchema());
Record zeSchemaRecord = zeSchemaRecordWithCopiedMeta("a");
recordServices.add(zeSchemaRecord);
Record anotherSchemaRecord = anotherSchemaRecordLinkedTo(zeSchemaRecord);
recordServices.add(anotherSchemaRecord);
Record thirdSchemaRecord = thirdSchemaRecordLinkedTo(anotherSchemaRecord);
recordServices.add(thirdSchemaRecord);
reset(recordServices);
zeSchemaRecord.set(zeSchema.getCopiedMeta(), "b");
recordServices.update(zeSchemaRecord);
verify(recordServices, times(1)).saveContentsAndRecords(any(Transaction.class),
any(RecordModificationImpactHandler.class), anyInt());
assertThat(anotherSchemaRecord.get(anotherSchema.metadataWithCopiedEntry())).isEqualTo("a");
assertThat(thirdSchemaRecord.get(thirdSchema.metadataWithCopiedEntry())).isEqualTo("a");
recordServices.refresh(asList(anotherSchemaRecord, thirdSchemaRecord));
assertThat(anotherSchemaRecord.get(anotherSchema.metadataWithCopiedEntry())).isEqualTo("b");
assertThat(thirdSchemaRecord.get(thirdSchema.metadataWithCopiedEntry())).isEqualTo("b");
}
@Test
public void givenModificationImpactWhenExecutingTransactionThenHandledInSameTransaction()
throws Exception {
defineSchemasManager().using(schemas.withAMetadataCopiedInAnotherSchema());
ArgumentCaptor<Transaction> savedTransaction = ArgumentCaptor.forClass(Transaction.class);
Record zeSchemaRecord = zeSchemaRecordWithCopiedMeta("a");
recordServices.add(zeSchemaRecord);
Record anotherSchemaRecord = anotherSchemaRecordLinkedTo(zeSchemaRecord);
recordServices.add(anotherSchemaRecord);
Record thirdSchemaRecord = thirdSchemaRecordLinkedTo(anotherSchemaRecord);
recordServices.add(thirdSchemaRecord);
reset(recordServices);
zeSchemaRecord.set(zeSchema.getCopiedMeta(), "b");
Transaction transaction = new Transaction();
transaction.update(zeSchemaRecord);
recordServices.execute(transaction);
zeSchemaRecord.set(zeSchema.getCopiedMeta(), "b");
verify(recordServices, times(3)).execute(savedTransaction.capture());
Transaction firstNestedTransaction = savedTransaction.getAllValues().get(1);
Transaction secondNestedTransaction = savedTransaction.getAllValues().get(2);
assertThat(firstNestedTransaction).isNotSameAs(transaction);
assertThat(firstNestedTransaction.getRecords()).hasSize(2);
assertThat(firstNestedTransaction.getRecords().get(0)).isEqualTo(zeSchemaRecord);
assertThat(firstNestedTransaction.getRecords().get(1).getId()).isEqualTo(anotherSchemaRecord.getId());
assertThat(firstNestedTransaction.getRecords().get(1).get(anotherSchema.metadataWithCopiedEntry())).isEqualTo("b");
assertThat(secondNestedTransaction).isNotSameAs(transaction);
assertThat(secondNestedTransaction.getRecords()).hasSize(3);
assertThat(secondNestedTransaction.getRecords().get(0)).isEqualTo(zeSchemaRecord);
assertThat(secondNestedTransaction.getRecords().get(1).getId()).isEqualTo(anotherSchemaRecord.getId());
assertThat(secondNestedTransaction.getRecords().get(1).get(anotherSchema.metadataWithCopiedEntry())).isEqualTo("b");
assertThat(secondNestedTransaction.getRecords().get(2).getId()).isEqualTo(thirdSchemaRecord.getId());
assertThat(secondNestedTransaction.getRecords().get(2).get(anotherSchema.metadataWithCopiedEntry())).isEqualTo("b");
recordServices.refresh(asList(anotherSchemaRecord, thirdSchemaRecord));
assertThat(anotherSchemaRecord.get(anotherSchema.metadataWithCopiedEntry())).isEqualTo("b");
assertThat(thirdSchemaRecord.get(thirdSchema.metadataWithCopiedEntry())).isEqualTo("b");
}
@Test
public void givenUpdatingMultipleRecordsInTransactionThenHandleThemInCorrectOrderReducingChancesOfModificationImpact()
throws Exception {
defineSchemasManager().using(schemas.withAMetadataCopiedInAnotherSchema());
ArgumentCaptor<Transaction> savedTransaction = ArgumentCaptor.forClass(Transaction.class);
Record zeSchemaRecord = zeSchemaRecordWithCopiedMeta("a");
recordServices.add(zeSchemaRecord);
Record anotherSchemaRecord = anotherSchemaRecordLinkedTo(zeSchemaRecord);
recordServices.add(anotherSchemaRecord);
Record thirdSchemaRecord = thirdSchemaRecordLinkedTo(anotherSchemaRecord);
recordServices.add(thirdSchemaRecord);
reset(recordServices);
zeSchemaRecord.set(zeSchema.getCopiedMeta(), "b");
anotherSchemaRecord.set(anotherSchema.manualMeta(), "z");
thirdSchemaRecord.set(thirdSchema.manualMeta(), "z");
Record anotherThirdSchemaRecord = thirdSchemaRecordLinkedTo(anotherSchemaRecord);
Transaction transaction = new Transaction();
transaction.addUpdate(anotherThirdSchemaRecord);
transaction.update(thirdSchemaRecord);
transaction.update(anotherSchemaRecord);
transaction.update(zeSchemaRecord);
recordServices.execute(transaction);
assertThat(anotherSchemaRecord.get(anotherSchema.metadataWithCopiedEntry())).isEqualTo("b");
assertThat(thirdSchemaRecord.get(thirdSchema.metadataWithCopiedEntry())).isEqualTo("b");
assertThat(anotherThirdSchemaRecord.get(thirdSchema.metadataWithCopiedEntry())).isEqualTo("b");
verify(recordServices, times(1)).saveContentsAndRecords(savedTransaction.capture(),
(RecordModificationImpactHandler) isNull(), anyInt());
}
@Test
public void given2RecordsIn2DifferentSchemaWithTheSecondCalculatedFromTheFirstWhenExecutingTransactionThenAddedInCorrectOrder()
throws Exception {
defineSchemasManager().using(schemas.withAMetadataCopiedInAnotherSchema());
Record zeSchemaRecord1 = recordServices.newRecordWithSchema(zeSchema.instance());
zeSchemaRecord1.set(zeSchema.getCopiedMeta(), "1.1");
recordServices.add(zeSchemaRecord1);
Record zeSchemaRecord2 = recordServices.newRecordWithSchema(zeSchema.instance());
zeSchemaRecord2.set(zeSchema.getCopiedMeta(), "2.1");
recordServices.add(zeSchemaRecord2);
Record anotherSchemaRecord = new TestRecord(anotherSchema);
anotherSchemaRecord.set(anotherSchema.referenceToZeSchema(), zeSchemaRecord1.getId());
recordServices.add(anotherSchemaRecord);
assertThat(anotherSchemaRecord.get(anotherSchema.metadataWithCopiedEntry())).isEqualTo("1.1");
Transaction initialTransaction = new Transaction();
initialTransaction.addUpdate(anotherSchemaRecord.set(anotherSchema.referenceToZeSchema(), zeSchemaRecord2.getId()));
initialTransaction.addUpdate(zeSchemaRecord1.set(zeSchema.getCopiedMeta(), "1.2"));
initialTransaction.addUpdate(zeSchemaRecord2.set(zeSchema.getCopiedMeta(), "2.2"));
recordServices.execute(initialTransaction);
assertThat(anotherSchemaRecord.get(anotherSchema.metadataWithCopiedEntry())).isEqualTo("2.2");
}
@Test
public void given2RecordsIn2DifferentSchemaWithTheSecondCalculatedFromTheFirstAddedInCorrectOrderWhenExecutingTransactionThenKeptInCorrectOrder()
throws Exception {
defineSchemasManager().using(schemas.withAMetadataCopiedInAnotherSchema());
Record zeSchemaRecord1 = recordServices.newRecordWithSchema(zeSchema.instance());
zeSchemaRecord1.set(zeSchema.getCopiedMeta(), "1.1");
recordServices.add(zeSchemaRecord1);
Record zeSchemaRecord2 = recordServices.newRecordWithSchema(zeSchema.instance());
zeSchemaRecord2.set(zeSchema.getCopiedMeta(), "2.1");
recordServices.add(zeSchemaRecord2);
Record anotherSchemaRecord = recordServices.newRecordWithSchema(anotherSchema.instance());
anotherSchemaRecord.set(anotherSchema.referenceToZeSchema(), zeSchemaRecord1.getId());
recordServices.add(anotherSchemaRecord);
assertThat(anotherSchemaRecord.get(anotherSchema.metadataWithCopiedEntry())).isEqualTo("1.1");
Transaction initialTransaction = new Transaction();
initialTransaction.addUpdate(zeSchemaRecord1.set(zeSchema.getCopiedMeta(), "1.2"));
initialTransaction.addUpdate(zeSchemaRecord2.set(zeSchema.getCopiedMeta(), "2.2"));
initialTransaction.addUpdate(anotherSchemaRecord.set(anotherSchema.referenceToZeSchema(), zeSchemaRecord2.getId()));
recordServices.execute(initialTransaction);
assertThat(anotherSchemaRecord.get(anotherSchema.metadataWithCopiedEntry())).isEqualTo("2.2");
}
@Test
public void given2RecordsIn2DifferentSchemaWithTheSecondCalculatedFromTheFirstWhenExecutingAsyncTransactionThenAddedInCorrectOrder()
throws Exception {
defineSchemasManager().using(schemas.withAMetadataCopiedInAnotherSchema());
Record zeSchemaRecord1 = recordServices.newRecordWithSchema(zeSchema.instance());
zeSchemaRecord1.set(zeSchema.getCopiedMeta(), "1.1");
recordServices.add(zeSchemaRecord1);
Record zeSchemaRecord2 = recordServices.newRecordWithSchema(zeSchema.instance());
zeSchemaRecord2.set(zeSchema.getCopiedMeta(), "2.1");
recordServices.add(zeSchemaRecord2);
Record anotherSchemaRecord = new TestRecord(anotherSchema);
anotherSchemaRecord.set(anotherSchema.referenceToZeSchema(), zeSchemaRecord1.getId());
recordServices.add(anotherSchemaRecord);
assertThat(anotherSchemaRecord.get(anotherSchema.metadataWithCopiedEntry())).isEqualTo("1.1");
Transaction initialTransaction = new Transaction();
initialTransaction.addUpdate(anotherSchemaRecord.set(anotherSchema.referenceToZeSchema(), zeSchemaRecord2.getId()));
initialTransaction.addUpdate(zeSchemaRecord1.set(zeSchema.getCopiedMeta(), "1.2"));
initialTransaction.addUpdate(zeSchemaRecord2.set(zeSchema.getCopiedMeta(), "2.2"));
recordServices.executeHandlingImpactsAsync(initialTransaction);
assertThat(anotherSchemaRecord.get(anotherSchema.metadataWithCopiedEntry())).isEqualTo("2.2");
}
@Test
public void givenUnmodifiableMetadataThenCanSetValueButCannotUpdateIt()
throws Exception {
defineSchemasManager().using(schemas.withAStringMetadata(whichIsUnmodifiable));
RecordImpl record = saveZeSchemaRecordAndReload();
assertThat(record.get(zeSchema.stringMetadata())).isNull();
record = updateAndReload(record.set(zeSchema.stringMetadata(), "ze value"));
assertThat(record.get(zeSchema.stringMetadata())).isEqualTo("ze value");
record = updateAndReload(record.set(zeSchema.stringMetadata(), "ze value"));
assertThat(record.get(zeSchema.stringMetadata())).isEqualTo("ze value");
try {
recordServices.update(record.set(zeSchema.stringMetadata(), "another value"));
fail("ValidationException expected");
} catch (ValidationException e) {
Map<String, Object> parameters = asMap(METADATA_CODE, "zeSchemaType_default_stringMetadata");
parameters.put(Validator.METADATA_LABEL, asMap("fr", "A toAString metadata"));
assertThat(e.getErrors().getValidationErrors()).containsOnly(new ValidationError(
MetadataUnmodifiableValidator.class, UNMODIFIABLE_METADATA,
parameters)
);
}
try {
recordServices.update(record.set(zeSchema.stringMetadata(), null));
fail("ValidationException expected");
} catch (ValidationException e) {
Map<String, Object> parameters = asMap(METADATA_CODE, "zeSchemaType_default_stringMetadata");
parameters.put(Validator.METADATA_LABEL, asMap("fr", "A toAString metadata"));
assertThat(e.getErrors().getValidationErrors()).containsOnly(new ValidationError(
MetadataUnmodifiableValidator.class, UNMODIFIABLE_METADATA,
parameters)
);
}
}
@SlowTest
@Test
public void whenExecutingWithMoreThan1000RecordsAndMergeOptimisticLockingResolutionThenOk()
throws Exception {
defineSchemasManager().using(schemas.withATitle().withAStringMetadata());
doNothing().when(recordServices)
.saveContentsAndRecords(any(Transaction.class), any(RecordModificationImpactHandler.class), anyInt());
recordServices.execute(
newTransactionWithNRecords(1000).setOptimisticLockingResolution(OptimisticLockingResolution.TRY_MERGE));
}
@Test(expected = RecordServicesRuntimeException_TransactionWithMoreThan1000RecordsCannotHaveTryMergeOptimisticLockingResolution.class)
public void whenExecutingWithMoreThan1001RecordsAndMergeOptimisticLockingResolutionThenException()
throws Exception {
defineSchemasManager().using(schemas.withATitle().withAStringMetadata());
recordServices.execute(
newTransactionWithNRecords(1001).setOptimisticLockingResolution(OptimisticLockingResolution.TRY_MERGE));
}
@SlowTest
@Test
public void whenExecutingWithMoreThan1001RecordsAndThrowExceptionOptimisticLockingResolutionThenOk()
throws Exception {
defineSchemasManager().using(schemas.withATitle().withAStringMetadata());
recordServices.execute(
newTransactionWithNRecords(1001).setOptimisticLockingResolution(OptimisticLockingResolution.EXCEPTION));
}
@SlowTest
@Test
public void whenExecutingWithMoreThan10000RecordsAndThrowExceptionOptimisticLockingResolutionThenOk()
throws Exception {
defineSchemasManager().using(schemas.withATitle().withAStringMetadata());
recordServices.execute(
newTransactionWithNRecords(100000).setOptimisticLockingResolution(OptimisticLockingResolution.EXCEPTION));
}
@Test(expected = RecordServicesRuntimeException_TransactionHasMoreThan100000Records.class)
public void whenExecutingWithMoreThan10001RecordsAndThrowExceptionOptimisticLockingResolutionThenException()
throws Exception {
defineSchemasManager().using(schemas.withATitle().withAStringMetadata());
recordServices.execute(
newTransactionWithNRecords(100001).setOptimisticLockingResolution(OptimisticLockingResolution.EXCEPTION));
}
@SlowTest
@Test
public void whenExecutingASyncWithMoreThan1000RecordsAndMergeOptimisticLockingResolutionThenOk()
throws Exception {
defineSchemasManager().using(schemas.withATitle().withAStringMetadata());
doNothing().when(recordServices)
.executeWithImpactHandler(any(Transaction.class), any(RecordModificationImpactHandler.class));
recordServices.executeHandlingImpactsAsync(
newTransactionWithNRecords(1000).setOptimisticLockingResolution(
OptimisticLockingResolution.TRY_MERGE));
}
@Test(expected = RecordServicesRuntimeException_TransactionWithMoreThan1000RecordsCannotHaveTryMergeOptimisticLockingResolution.class)
public void whenExecutingASyncWithMoreThan1001RecordsAndMergeOptimisticLockingResolutionThenException()
throws Exception {
defineSchemasManager().using(schemas.withATitle().withAStringMetadata());
recordServices.executeHandlingImpactsAsync(
newTransactionWithNRecords(1001).setOptimisticLockingResolution(OptimisticLockingResolution.TRY_MERGE));
}
@SlowTest
@Test
public void whenExecutingASyncWithMoreThan1001RecordsAndThrowExceptionOptimisticLockingResolutionThenOk()
throws Exception {
defineSchemasManager().using(schemas.withATitle().withAStringMetadata());
recordServices.executeHandlingImpactsAsync(
newTransactionWithNRecords(1001).setOptimisticLockingResolution(OptimisticLockingResolution.EXCEPTION));
}
@SlowTest
@Test
public void whenExecutingASyncWithMoreThan10000RecordsAndThrowExceptionOptimisticLockingResolutionThenOk()
throws Exception {
defineSchemasManager().using(schemas.withATitle().withAStringMetadata());
recordServices.executeHandlingImpactsAsync(
newTransactionWithNRecords(100000).setOptimisticLockingResolution(OptimisticLockingResolution.EXCEPTION));
}
@Test(expected = RecordServicesRuntimeException_TransactionHasMoreThan100000Records.class)
public void whenExecutingASyncWithMoreThan10001RecordsAndThrowExceptionOptimisticLockingResolutionThenException()
throws Exception {
defineSchemasManager().using(schemas.withATitle().withAStringMetadata());
recordServices.executeHandlingImpactsAsync(
newTransactionWithNRecords(100001).setOptimisticLockingResolution(OptimisticLockingResolution.EXCEPTION));
}
@Test
public void whenUpdateARecordAReferenceToANewRecord()
throws Exception {
defineSchemasManager().using(schemas.withAParentReferenceFromAnotherSchemaToZeSchema());
Record anotherSchemaRecord = new TestRecord(anotherSchema).set(TITLE, "New record saved in transaction 1");
recordServices.add(anotherSchemaRecord);
Record zeSchemaRecord = new TestRecord(zeSchema).set(TITLE, "New record saved in transaction 2");
anotherSchemaRecord.set(anotherSchema.metadata("referenceFromAnotherSchemaToZeSchema"), zeSchemaRecord.getId());
recordServices.execute(new Transaction(anotherSchemaRecord, zeSchemaRecord));
}
@Test
public void whenUpdateARecordAReferenceListToANewRecord()
throws Exception {
defineSchemasManager().using(schemas.with(metadataFromAnotherSchemaToZeSchema()));
Record anotherSchemaRecord = new TestRecord(anotherSchema).set(TITLE, "New record saved in transaction 1");
recordServices.add(anotherSchemaRecord);
Record zeSchemaRecord = new TestRecord(zeSchema).set(TITLE, "New record saved in transaction 2");
anotherSchemaRecord.set(anotherSchema.metadata("referenceFromAnotherSchemaToZeSchema"), asList(zeSchemaRecord.getId()));
recordServices.execute(new Transaction(anotherSchemaRecord, zeSchemaRecord));
}
private MetadataSchemaTypesConfigurator metadataFromAnotherSchemaToZeSchema() {
return new MetadataSchemaTypesConfigurator() {
@Override
public void configure(MetadataSchemaTypesBuilder schemaTypes) {
MetadataSchemaTypeBuilder zeSchemaTypeBuilder = schemaTypes.getSchemaType(zeSchema.typeCode());
schemaTypes.getSchema(anotherSchema.code()).create("referenceFromAnotherSchemaToZeSchema")
.defineReferencesTo(zeSchemaTypeBuilder).setMultivalue(true);
}
};
}
@Test
public void whenUpdateARecordWithAnAutomaticReferenceListToANewRecord()
throws Exception {
defineSchemasManager().using(schemas.with(
aMetadataInAnotherSchemaContainingAReferenceToZeSchemaAndACalculatorRetreivingIt()));
Record anotherSchemaRecord = new TestRecord(anotherSchema).set(TITLE, "New record saved in transaction 1");
recordServices.add(anotherSchemaRecord);
Record zeSchemaRecord = new TestRecord(zeSchema).set(TITLE, "New record saved in transaction 2");
anotherSchemaRecord.set(anotherSchema.metadata("aStringMetadata"), zeSchemaRecord.getId());
recordServices.execute(new Transaction(anotherSchemaRecord, zeSchemaRecord));
}
@Test
public void whenExecutingTransactionWithRecordsMarkedForReindexingThenMarkedForReindexing()
throws Exception {
defineSchemasManager().using(schemas);
Record record1 = new TestRecord(zeSchema).set(TITLE, "record1");
Record record2 = new TestRecord(zeSchema).set(TITLE, "record2");
Record record3 = new TestRecord(zeSchema).set(TITLE, "record3");
Record record4 = new TestRecord(zeSchema).set(TITLE, "record4");
Record record5 = new TestRecord(zeSchema).set(TITLE, "record5");
recordServices.execute(new Transaction(record1, record2, record3, record4, record5));
Record record6 = new TestRecord(zeSchema).set(TITLE, "record6");
Transaction transaction = new Transaction();
transaction.add(record1.set(TITLE, "newTitleOfRecord1"));
transaction.add(record2.set(TITLE, "newTitleOfRecord2"));
transaction.add(record6);
transaction.addRecordToReindex(record2);
transaction.addRecordToReindex(record5);
transaction.addRecordToReindex(record4);
transaction.addRecordToReindex(record6);
recordServices.execute(transaction);
SearchServices searchServices = getModelLayerFactory().newSearchServices();
assertThatRecords(searchServices.search(query(from(zeSchema.instance()).returnAll())))
.extractingMetadatas(TITLE, MARKED_FOR_REINDEXING).containsOnly(
tuple("newTitleOfRecord1", null),
tuple("newTitleOfRecord2", true),
tuple("record3", null),
tuple("record4", true),
tuple("record5", true),
tuple("record6", true)
);
}
@Test
public void givenRecordsMarkedForReindexingWhenUpdateThemInTransactionThenUnflaggedEvenIfNoChange()
throws Exception {
defineSchemasManager().using(schemas);
SearchServices searchServices = getModelLayerFactory().newSearchServices();
Record record1 = new TestRecord(zeSchema, "r1").set(TITLE, "record1");
Record record2 = new TestRecord(zeSchema, "r2").set(TITLE, "record2");
Record record3 = new TestRecord(zeSchema, "r3").set(TITLE, "record3");
Record record4 = new TestRecord(zeSchema, "r4").set(TITLE, "record4");
Record record5 = new TestRecord(zeSchema, "r5").set(TITLE, "record5");
recordServices.execute(new Transaction(record1, record2, record3, record4, record5));
assertThatRecords(searchServices.search(query(from(zeSchema.instance()).returnAll())))
.extractingMetadatas(TITLE, MARKED_FOR_REINDEXING).containsOnly(
tuple("record1", null),
tuple("record2", null),
tuple("record3", null),
tuple("record4", null),
tuple("record5", null)
);
Transaction transaction = new Transaction();
transaction.add(record1.set(TITLE, "newTitleOfRecord1"));
transaction.addRecordToReindex(record2);
transaction.addRecordToReindex(record3);
transaction.addRecordToReindex(record4);
transaction.addRecordToReindex(record5);
recordServices.execute(transaction);
assertThatRecords(searchServices.search(query(from(zeSchema.instance()).returnAll())))
.extractingMetadatas(TITLE, MARKED_FOR_REINDEXING).containsOnly(
tuple("newTitleOfRecord1", null),
tuple("record2", true),
tuple("record3", true),
tuple("record4", true),
tuple("record5", true)
);
recordServices.refresh(record2, record3, record4);
transaction = new Transaction();
transaction.add(record2);
transaction.add(record3);
transaction.update(record4);
recordServices.execute(transaction);
assertThatRecords(searchServices.search(query(from(zeSchema.instance()).returnAll())))
.extractingMetadatas(TITLE, MARKED_FOR_REINDEXING).containsOnly(
tuple("newTitleOfRecord1", null),
tuple("record2", true),
tuple("record3", true),
tuple("record4", true),
tuple("record5", true)
);
transaction = new Transaction();
transaction.getRecordUpdateOptions().setForcedReindexationOfMetadatas(TransactionRecordsReindexation.ALL());
transaction.add(record2);
transaction.add(record3);
transaction.update(record4);
recordServices.execute(transaction);
assertThatRecords(searchServices.search(query(from(zeSchema.instance()).returnAll())))
.extractingMetadatas(TITLE, MARKED_FOR_REINDEXING).containsOnly(
tuple("newTitleOfRecord1", null),
tuple("record2", null),
tuple("record3", null),
tuple("record4", null),
tuple("record5", true)
);
}
@Test
public void whenMarkAnInexistentRecordForReindexingThenException()
throws Exception {
defineSchemasManager().using(schemas);
Record record1 = new TestRecord(zeSchema).set(TITLE, "record1");
Record record2 = new TestRecord(zeSchema).set(TITLE, "record2");
Record record3 = new TestRecord(zeSchema).set(TITLE, "record3");
Record record4 = new TestRecord(zeSchema).set(TITLE, "record4");
Record record5 = new TestRecord(zeSchema).set(TITLE, "record5");
recordServices.execute(new Transaction(record1, record2, record3, record4, record5));
Record record6 = new TestRecord(zeSchema).set(TITLE, "record6");
Transaction transaction = new Transaction();
transaction.addRecordToReindex(record2);
transaction.addRecordToReindex(record3);
transaction.addRecordToReindex(record4);
transaction.add(record6);
transaction.addRecordToReindex("record7");
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (RecordServicesException.UnresolvableOptimisticLockingConflict e) {
//OK
}
SearchServices searchServices = getModelLayerFactory().newSearchServices();
assertThatRecords(searchServices.search(query(from(zeSchema.instance()).returnAll())))
.extractingMetadatas(TITLE, MARKED_FOR_REINDEXING).containsOnly(
tuple("record1", null),
tuple("record2", null),
tuple("record3", null),
tuple("record4", null),
tuple("record5", null)
);
}
@Test(expected = CannotSetIdsToReindexInEmptyTransaction.class)
public void givenEmptyTransactionWithOnlyMarkedToReindexThenException()
throws Exception {
defineSchemasManager().using(schemas);
Record record1 = new TestRecord(zeSchema).set(TITLE, "record1");
Record record2 = new TestRecord(zeSchema).set(TITLE, "record2");
Record record3 = new TestRecord(zeSchema).set(TITLE, "record3");
Record record4 = new TestRecord(zeSchema).set(TITLE, "record4");
Record record5 = new TestRecord(zeSchema).set(TITLE, "record5");
recordServices.execute(new Transaction(record1, record2, record3, record4, record5));
Record record6 = new TestRecord(zeSchema).set(TITLE, "record6");
Transaction transaction = new Transaction();
transaction.addRecordToReindex(record2);
transaction.addRecordToReindex(record3);
transaction.addRecordToReindex(record4);
recordServices.execute(transaction);
}
@Test
public void givenTransientLazyMetadataThenNotSavedAndRetrievedOnRecordRecalculate()
throws Exception {
defineSchemasManager().using(schemas.withANumberMetadata(
whichIsCalculatedUsing(TitleLengthCalculator.class),
whichHasTransiency(TRANSIENT_LAZY)));
//TODO records in cache should lost transient metadatas
//Save a record, it keeps the transient metadatas
Record record = new TestRecord(zeSchema).set(TITLE, "Vodka Framboise");
recordServices.add(record);
assertThat(record.get(zeSchema.numberMetadata())).isEqualTo(15.0);
//The record is obtained from the datastore, there is no value
record = recordServices.getDocumentById(record.getId());
assertThat(record.get(zeSchema.numberMetadata())).isNull();
//The record is recalculated, the value is loaded
recordServices.recalculate(record);
assertThat(record.get(zeSchema.numberMetadata())).isEqualTo(15.0);
record = new TestRecord(zeSchema).set(TITLE, "Vodka Canneberge");
recordServices.add(record);
assertThat(record.get(zeSchema.numberMetadata())).isEqualTo(16.0);
record = recordServices.getDocumentById(record.getId());
assertThat(record.get(zeSchema.numberMetadata())).isNull();
//The record is recalculated, the value is loaded
recordServices.recalculate(record);
assertThat(record.get(zeSchema.numberMetadata())).isEqualTo(16.0);
getModelLayerFactory().getRecordsCaches().getCache(zeCollection).configureCache(permanentCache(zeSchema.type()));
Record recordInCache = getModelLayerFactory().getRecordsCaches().getCache(zeCollection).get(record.getId());
assertThat(recordInCache.get(zeSchema.numberMetadata())).isNull();
}
@Test
public void givenTransientEagerMetadataThenNotSavedAndRetrievedOnRecordRetrieval()
throws Exception {
defineSchemasManager().using(schemas.withANumberMetadata(
whichIsCalculatedUsing(TitleLengthCalculator.class),
whichHasTransiency(TRANSIENT_EAGER)));
//TODO records in cache should lost transient metadatas
//Save a record, it keeps the transient metadatas
Record record = new TestRecord(zeSchema).set(TITLE, "Vodka Framboise");
recordServices.add(record);
assertThat(record.get(zeSchema.numberMetadata())).isEqualTo(15.0);
//The record is obtained from the datastore, there is no value
record = recordServices.getDocumentById(record.getId());
assertThat(record.get(zeSchema.numberMetadata())).isEqualTo(15.0);
record = new TestRecord(zeSchema).set(TITLE, "Vodka Canneberge");
recordServices.add(record);
assertThat(record.get(zeSchema.numberMetadata())).isEqualTo(16.0);
record = recordServices.getDocumentById(record.getId());
assertThat(record.get(zeSchema.numberMetadata())).isEqualTo(16.0);
getModelLayerFactory().getRecordsCaches().getCache(zeCollection).configureCache(permanentCache(zeSchema.type()));
Record recordInCache = getModelLayerFactory().getRecordsCaches().getCache(zeCollection).get(record.getId());
assertThat(recordInCache.get(zeSchema.numberMetadata())).isEqualTo(16.0);
}
@Test
public void givenExceptionThrownByRecordInCreationBeforeValidationAndAutomaticValuesCalculationExtensionThenCatchedDependingOnTransactionOption()
throws Exception {
defineSchemasManager().using(schemas);
getModelLayerFactory().getExtensions().forCollection(zeCollection).recordExtensions.add(new RecordExtension() {
@Override
public void recordInCreationBeforeValidationAndAutomaticValuesCalculation(
RecordInCreationBeforeValidationAndAutomaticValuesCalculationEvent event) {
throw new RuntimeException("oh bobo!");
}
});
Record record = new TestRecord(zeSchema).set(TITLE, "Vodka Framboise");
Transaction transaction = new Transaction(record);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (Exception e) {
//OK
}
transaction.getRecordUpdateOptions().setCatchExtensionsValidationsErrors(true);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (Exception e) {
//OK
}
transaction.getRecordUpdateOptions().setCatchExtensionsValidationsErrors(false).setCatchExtensionsExceptions(true);
transaction.getRecordUpdateOptions().setCatchExtensionsExceptions(true);
recordServices.execute(transaction);
assertThatRecord(record).exists();
}
@Test
public void givenExceptionThrownByRecordInCreationBeforeSaveExtensionThenCatchedDependingOnTransactionOption()
throws Exception {
defineSchemasManager().using(schemas);
getModelLayerFactory().getExtensions().forCollection(zeCollection).recordExtensions.add(new RecordExtension() {
@Override
public void recordInCreationBeforeSave(RecordInCreationBeforeSaveEvent event) {
throw new RuntimeException("oh bobo!");
}
});
Record record = new TestRecord(zeSchema).set(TITLE, "Vodka Framboise");
Transaction transaction = new Transaction(record);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (Exception e) {
//OK
}
transaction.getRecordUpdateOptions().setCatchExtensionsValidationsErrors(true);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (Exception e) {
//OK
}
transaction.getRecordUpdateOptions().setCatchExtensionsValidationsErrors(false).setCatchExtensionsExceptions(true);
transaction.getRecordUpdateOptions().setCatchExtensionsExceptions(true);
recordServices.execute(transaction);
assertThatRecord(record).exists();
}
@Test
public void givenExceptionThrownByRecordCreatedExtensionThenCatchedDependingOnTransactionOption()
throws Exception {
defineSchemasManager().using(schemas);
getModelLayerFactory().getExtensions().forCollection(zeCollection).recordExtensions.add(new RecordExtension() {
@Override
public void recordCreated(RecordCreationEvent event) {
throw new RuntimeException("oh bobo!");
}
});
Record record = new TestRecord(zeSchema).set(TITLE, "Vodka Framboise");
Transaction transaction = new Transaction(record);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (Exception e) {
//OK
}
record = new TestRecord(zeSchema).set(TITLE, "Édouard Lechat");
transaction = new Transaction(record);
transaction.getRecordUpdateOptions().setCatchExtensionsValidationsErrors(true);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (Exception e) {
//OK
}
record = new TestRecord(zeSchema).set(TITLE, "Félix");
transaction = new Transaction(record);
transaction.getRecordUpdateOptions().setCatchExtensionsValidationsErrors(false).setCatchExtensionsExceptions(true);
transaction.getRecordUpdateOptions().setCatchExtensionsExceptions(true);
recordServices.execute(transaction);
assertThatRecord(record).exists();
}
@Test
public void givenValidationExceptionThrownByRecordInCreationBeforeSaveExtensionThenCatchedDependingOnTransactionOption()
throws Exception {
defineSchemasManager().using(schemas);
getModelLayerFactory().getExtensions().forCollection(zeCollection).recordExtensions.add(new RecordExtension() {
@Override
public void recordInCreationBeforeSave(RecordInCreationBeforeSaveEvent event) {
event.getValidationErrors().add(RecordServicesAcceptanceTest.class, "Ze validation error");
}
});
Record record = new TestRecord(zeSchema).set(TITLE, "Vodka Framboise");
Transaction transaction = new Transaction(record);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (Exception e) {
//OK
}
transaction.getRecordUpdateOptions().setCatchExtensionsExceptions(true);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (Exception e) {
//OK
}
transaction.getRecordUpdateOptions().setCatchExtensionsValidationsErrors(true).setCatchExtensionsExceptions(false);
recordServices.execute(transaction);
assertThatRecord(record).exists();
}
@Test
public void givenExceptionThrownByRecordInModificationBeforeValidationAndAutomaticValuesCalculationExtensionThenCatchedDependingOnTransactionOption()
throws Exception {
defineSchemasManager().using(schemas);
getModelLayerFactory().getExtensions().forCollection(zeCollection).recordExtensions.add(new RecordExtension() {
@Override
public void recordInModificationBeforeValidationAndAutomaticValuesCalculation(
RecordInModificationBeforeValidationAndAutomaticValuesCalculationEvent event) {
throw new RuntimeException("oh bobo!");
}
});
Record record = new TestRecord(zeSchema).set(TITLE, "Vodka Framboise");
recordServices.add(record);
record.set(Schemas.TITLE, "Édouard Lechat");
Transaction transaction = new Transaction(record);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (Exception e) {
//OK
}
transaction.getRecordUpdateOptions().setCatchExtensionsValidationsErrors(true);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (Exception e) {
//OK
}
transaction.getRecordUpdateOptions().setCatchExtensionsValidationsErrors(false).setCatchExtensionsExceptions(true);
transaction.getRecordUpdateOptions().setCatchExtensionsExceptions(true);
recordServices.execute(transaction);
assertThatRecord(record).exists();
}
@Test
public void givenExceptionThrownByRecordInModificationBeforeSaveExtensionThenCatchedDependingOnTransactionOption()
throws Exception {
defineSchemasManager().using(schemas);
getModelLayerFactory().getExtensions().forCollection(zeCollection).recordExtensions.add(new RecordExtension() {
@Override
public void recordInModificationBeforeSave(RecordInModificationBeforeSaveEvent event) {
throw new RuntimeException("oh bobo!");
}
});
Record record = new TestRecord(zeSchema).set(TITLE, "Vodka Framboise");
recordServices.add(record);
record.set(Schemas.TITLE, "Édouard Lechat");
Transaction transaction = new Transaction(record);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (Exception e) {
//OK
}
transaction.getRecordUpdateOptions().setCatchExtensionsValidationsErrors(true);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (Exception e) {
//OK
}
transaction.getRecordUpdateOptions().setCatchExtensionsValidationsErrors(false).setCatchExtensionsExceptions(true);
transaction.getRecordUpdateOptions().setCatchExtensionsExceptions(true);
recordServices.execute(transaction);
assertThatRecord(record).exists();
}
@Test
public void givenExceptionThrownByRecordModifiedExtensionThenCatchedDependingOnTransactionOption()
throws Exception {
defineSchemasManager().using(schemas);
getModelLayerFactory().getExtensions().forCollection(zeCollection).recordExtensions.add(new RecordExtension() {
@Override
public void recordModified(RecordModificationEvent event) {
throw new RuntimeException("oh bobo!");
}
});
Record record = new TestRecord(zeSchema).set(TITLE, "Un chat");
recordServices.add(record);
record.set(Schemas.TITLE, "Vodka Framboise");
Transaction transaction = new Transaction(record);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (Exception e) {
//OK
}
record = new TestRecord(zeSchema).set(TITLE, "Un chat");
recordServices.add(record);
record.set(Schemas.TITLE, "Édouard Lechat");
transaction = new Transaction(record);
transaction.getRecordUpdateOptions().setCatchExtensionsValidationsErrors(true);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (Exception e) {
//OK
}
record = new TestRecord(zeSchema).set(TITLE, "Un chat");
recordServices.add(record);
record.set(Schemas.TITLE, "Félix");
transaction = new Transaction(record);
transaction.getRecordUpdateOptions().setCatchExtensionsValidationsErrors(false).setCatchExtensionsExceptions(true);
transaction.getRecordUpdateOptions().setCatchExtensionsExceptions(true);
recordServices.execute(transaction);
assertThatRecord(record).exists();
}
@Test
public void givenExceptionThrownByTransactionExecutionBeforeSaveExtensionThenCatchedDependingOnTransactionOption()
throws Exception {
defineSchemasManager().using(schemas);
getModelLayerFactory().getExtensions().forCollection(zeCollection).recordExtensions.add(new RecordExtension() {
@Override
public void transactionExecutionBeforeSave(TransactionExecutionBeforeSaveEvent event) {
throw new RuntimeException("oh bobo!");
}
});
Record record = new TestRecord(zeSchema).set(TITLE, "Vodka Framboise");
Transaction transaction = new Transaction(record);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (Exception e) {
//OK
}
transaction.getRecordUpdateOptions().setCatchExtensionsValidationsErrors(true);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (Exception e) {
//OK
}
transaction.getRecordUpdateOptions().setCatchExtensionsValidationsErrors(false).setCatchExtensionsExceptions(true);
recordServices.execute(transaction);
assertThatRecord(record).exists();
}
@Test
public void givenValidationExceptionThrownByRecordInModificationBeforeSaveExtensionThenCatchedDependingOnTransactionOption()
throws Exception {
defineSchemasManager().using(schemas);
getModelLayerFactory().getExtensions().forCollection(zeCollection).recordExtensions.add(new RecordExtension() {
@Override
public void recordInModificationBeforeSave(RecordInModificationBeforeSaveEvent event) {
event.getValidationErrors().add(RecordServicesAcceptanceTest.class, "Ze validation error");
}
});
Record record = new TestRecord(zeSchema).set(TITLE, "Vodka Framboise");
recordServices.add(record);
record.set(Schemas.TITLE, "Édouard Lechat");
Transaction transaction = new Transaction(record);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (Exception e) {
//OK
}
transaction.getRecordUpdateOptions().setCatchExtensionsExceptions(true);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (Exception e) {
//OK
}
transaction.getRecordUpdateOptions().setCatchExtensionsValidationsErrors(true).setCatchExtensionsExceptions(false);
recordServices.execute(transaction);
assertThatRecord(record).exists();
}
@Test
public void givenValidationExceptionThrownByTransactionExecutionBeforeSafeExtensionThenCatchedDependingOnTransactionOption()
throws Exception {
defineSchemasManager().using(schemas);
getModelLayerFactory().getExtensions().forCollection(zeCollection).recordExtensions.add(new RecordExtension() {
@Override
public void transactionExecutionBeforeSave(TransactionExecutionBeforeSaveEvent event) {
event.getValidationErrors().add(RecordServicesAcceptanceTest.class, "Ze validation error");
}
});
Record record = new TestRecord(zeSchema).set(TITLE, "Vodka Framboise");
Transaction transaction = new Transaction(record);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (Exception e) {
//OK
}
transaction.getRecordUpdateOptions().setCatchExtensionsExceptions(true);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (Exception e) {
//OK
}
transaction.getRecordUpdateOptions().setCatchExtensionsValidationsErrors(true).setCatchExtensionsExceptions(false);
recordServices.execute(transaction);
assertThatRecord(record).exists();
}
@Test
public void givenBrokenReferencesThenCatchedDependingOnTransactionOption()
throws Exception {
defineSchemasManager().using(schemas.withAReferenceFromAnotherSchemaToZeSchema()
.withAnotherSchemaStringMetadata(whichIsScripted("title + referenceFromAnotherSchemaToZeSchema.title")));
Transaction transaction = new Transaction();
transaction.add(new TestRecord(zeSchema, "ours").set(TITLE, "L'ours"));
Record pointeur = transaction.add(new TestRecord(anotherSchema, "pointeur").set(TITLE, "Pointeur d'")
.set(anotherSchema.referenceFromAnotherSchemaToZeSchema(), "ours"));
recordServices.execute(transaction);
assertThatRecord(pointeur).extracting("title", "stringMetadata").isEqualTo(asList(
"Pointeur d'", "Pointeur d'L'ours"));
getDataLayerFactory().newRecordDao().getBigVaultServer().getNestedSolrServer().deleteById("ours");
getDataLayerFactory().newRecordDao().getBigVaultServer().getNestedSolrServer().commit();
pointeur.set(Schemas.TITLE, "Pointeur d'ours brisé");
transaction = new Transaction(pointeur);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (RecordServicesRuntimeException.RecordServicesRuntimeException_ExceptionWhileCalculating e) {
//OK
}
transaction.getRecordUpdateOptions().setCatchBrokenReferenceErrors(true);
recordServices.execute(transaction);
assertThatRecord(pointeur).exists();
assertThatRecord(pointeur).extracting("title", "stringMetadata").isEqualTo(asList(
"Pointeur d'ours brisé", null));
}
@Test
public void givenBrokenReferencesInCopiedValueThenCatchedDependingOnTransactionOption()
throws Exception {
defineSchemasManager().using(schemas.withAReferenceFromAnotherSchemaToZeSchema()
.withAnotherSchemaStringMetadata().with(new MetadataSchemaTypesConfigurator() {
@Override
public void configure(MetadataSchemaTypesBuilder schemaTypes) {
MetadataSchemaBuilder anotherSchemaType = schemaTypes.getSchema("anotherSchemaType_default");
MetadataBuilder zeSchemaTypeTitle = schemaTypes.getMetadata("zeSchemaType_default_title");
anotherSchemaType.getMetadata("stringMetadata").defineDataEntry()
.asCopied(anotherSchemaType.get("referenceFromAnotherSchemaToZeSchema"), zeSchemaTypeTitle);
}
}));
Transaction transaction = new Transaction();
transaction.add(new TestRecord(zeSchema, "ours").set(TITLE, "L'ours"));
Record pointeur = transaction.add(new TestRecord(anotherSchema, "pointeur").set(TITLE, "Pointeur d'")
.set(anotherSchema.referenceFromAnotherSchemaToZeSchema(), "ours"));
recordServices.execute(transaction);
assertThatRecord(pointeur).extracting("title", "stringMetadata").isEqualTo(asList(
"Pointeur d'", "L'ours"));
getDataLayerFactory().newRecordDao().getBigVaultServer().getNestedSolrServer().deleteById("ours");
getDataLayerFactory().newRecordDao().getBigVaultServer().getNestedSolrServer().commit();
pointeur.set(Schemas.TITLE, "Pointeur d'ours brisé");
transaction = new Transaction(pointeur);
transaction.getRecordUpdateOptions().setForcedReindexationOfMetadatas(TransactionRecordsReindexation.ALL());
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (RecordServicesRuntimeException.RecordServicesRuntimeException_ExceptionWhileCalculating e) {
//OK
}
transaction.getRecordUpdateOptions().setCatchBrokenReferenceErrors(true);
recordServices.execute(transaction);
assertThatRecord(pointeur).exists();
assertThatRecord(pointeur).extracting("title", "stringMetadata").isEqualTo(asList(
"Pointeur d'ours brisé", null));
}
@Test
public void givenBrokenMultivalueReferencesInCopiedValueThenCatchedDependingOnTransactionOption()
throws Exception {
defineSchemasManager().using(schemas.withAReferenceFromAnotherSchemaToZeSchema(whichIsMultivalue)
.withAnotherSchemaStringMetadata().with(new MetadataSchemaTypesConfigurator() {
@Override
public void configure(MetadataSchemaTypesBuilder schemaTypes) {
MetadataSchemaBuilder anotherSchemaType = schemaTypes.getSchema("anotherSchemaType_default");
MetadataBuilder zeSchemaTypeTitle = schemaTypes.getMetadata("zeSchemaType_default_title");
anotherSchemaType.getMetadata("stringMetadata").setMultivalue(true).defineDataEntry()
.asCopied(anotherSchemaType.get("referenceFromAnotherSchemaToZeSchema"), zeSchemaTypeTitle);
}
}));
Transaction transaction = new Transaction();
transaction.add(new TestRecord(zeSchema, "ours").set(TITLE, "L'ours"));
Record pointeur = transaction.add(new TestRecord(anotherSchema, "pointeur").set(TITLE, "Pointeur d'")
.set(anotherSchema.referenceFromAnotherSchemaToZeSchema(), asList("ours")));
recordServices.execute(transaction);
getDataLayerFactory().newRecordDao().getBigVaultServer().getNestedSolrServer().deleteById("ours");
getDataLayerFactory().newRecordDao().getBigVaultServer().getNestedSolrServer().commit();
assertThatRecord(pointeur).extracting("title", "stringMetadata").isEqualTo(asList(
"Pointeur d'", asList("L'ours")));
pointeur.set(Schemas.TITLE, "Pointeur d'ours brisé");
transaction = new Transaction(pointeur);
transaction.getRecordUpdateOptions().setForcedReindexationOfMetadatas(TransactionRecordsReindexation.ALL());
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (RecordServicesRuntimeException.RecordServicesRuntimeException_ExceptionWhileCalculating e) {
//OK
}
transaction.getRecordUpdateOptions().setCatchBrokenReferenceErrors(true);
recordServices.execute(transaction);
assertThatRecord(pointeur).exists();
assertThatRecord(pointeur).extracting("title", "stringMetadata").isEqualTo(asList(
"Pointeur d'ours brisé", new ArrayList<>()));
}
@Test
public void givenBrokenMultivalueReferencesThenCatchedDependingOnTransactionOption()
throws Exception {
defineSchemasManager().using(schemas.withAReferenceFromAnotherSchemaToZeSchema(whichIsMultivalue)
.withAnotherSchemaStringMetadata(whichIsScripted("title + referenceFromAnotherSchemaToZeSchema.title")));
Transaction transaction = new Transaction();
transaction.add(new TestRecord(zeSchema, "ours").set(TITLE, "d'ours"));
Record pointeur = transaction.add(new TestRecord(anotherSchema, "pointeur").set(TITLE, "Pointeur ")
.set(anotherSchema.referenceFromAnotherSchemaToZeSchema(), asList("ours")));
recordServices.execute(transaction);
assertThatRecord(pointeur).extracting("title", "stringMetadata").isEqualTo(asList(
"Pointeur ", "Pointeur [d'ours]"));
getDataLayerFactory().newRecordDao().getBigVaultServer().getNestedSolrServer().deleteById("ours");
getDataLayerFactory().newRecordDao().getBigVaultServer().getNestedSolrServer().commit();
pointeur.set(Schemas.TITLE, "Pointeur d'ours brisé");
transaction = new Transaction(pointeur);
try {
recordServices.execute(transaction);
fail("Exception expected");
} catch (RecordServicesRuntimeException.RecordServicesRuntimeException_ExceptionWhileCalculating e) {
//OK
}
transaction.getRecordUpdateOptions().setCatchBrokenReferenceErrors(true);
recordServices.execute(transaction);
assertThatRecord(pointeur).exists();
assertThatRecord(pointeur).extracting("title", "stringMetadata").isEqualTo(asList(
"Pointeur d'ours brisé", "Pointeur d'ours brisé[]"));
}
private MetadataSchemaTypesConfigurator aMetadataInAnotherSchemaContainingAReferenceToZeSchemaAndACalculatorRetreivingIt() {
return new MetadataSchemaTypesConfigurator() {
@Override
public void configure(MetadataSchemaTypesBuilder schemaTypes) {
MetadataSchemaBuilder anotherSchemaBuilder = schemaTypes.getSchema(anotherSchema.code());
MetadataSchemaTypeBuilder zeSchemaTypeBuilder = schemaTypes.getSchemaType(zeSchema.typeCode());
anotherSchemaBuilder.create("aStringMetadata").setType(MetadataValueType.STRING);
anotherSchemaBuilder.create("aCalculatedMetadataToAReference").setType(MetadataValueType.REFERENCE)
.setMultivalue(true)
.defineReferencesTo(zeSchemaTypeBuilder)
.defineDataEntry().asCalculated(RecordServicesAcceptanceTestCalculator.class);
}
};
}
public static class RecordServicesAcceptanceTestCalculator implements MetadataValueCalculator<List<String>> {
LocalDependency<String> aStringMetadataParam = LocalDependency.toAString("aStringMetadata");
@Override
public List<String> calculate(CalculatorParameters parameters) {
String aStringMetadata = parameters.get(aStringMetadataParam);
return aStringMetadata == null ? null : Arrays.asList(aStringMetadata);
}
@Override
public List<String> getDefaultValue() {
return null;
}
@Override
public MetadataValueType getReturnType() {
return MetadataValueType.REFERENCE;
}
@Override
public boolean isMultiValue() {
return true;
}
@Override
public List<? extends Dependency> getDependencies() {
return asList(aStringMetadataParam);
}
}
private Record anotherSchemaRecordLinkedTo(Record record) {
Record anotherSchemaRecord = recordServices.newRecordWithSchema(schemas.anotherDefaultSchema());
anotherSchemaRecord.set(anotherSchema.referenceToZeSchema(), record.getId());
return anotherSchemaRecord;
}
private Record thirdSchemaRecordLinkedTo(Record record) {
Record anotherSchemaRecord = recordServices.newRecordWithSchema(schemas.aThirdDefaultSchema());
anotherSchemaRecord.set(thirdSchema.referenceToAnotherSchema(), record.getId());
return anotherSchemaRecord;
}
private Record zeSchemaRecordWithCopiedMeta(String value) {
Record record = recordServices.newRecordWithSchema(schemas.zeDefaultSchema());
record.set(zeSchema.getCopiedMeta(), value);
return record;
}
private String addRecordInAnotherSchemaWithStringMetadataValue(boolean multivalue)
throws RecordServicesException {
Record recordReference = new TestRecord(anotherSchema);
if (multivalue) {
recordReference.set(anotherSchema.stringMetadata(), Arrays.asList("Banana", "Apple"));
} else {
recordReference.set(anotherSchema.stringMetadata(), "Banana");
}
recordServices.add(recordReference);
return recordReference.getId();
}
private RecordImpl updateAndReload(Record record)
throws RecordServicesException {
recordServices.update(record);
return (RecordImpl) recordServices.getDocumentById(record.getId());
}
private RecordImpl saveZeSchemaRecordAndReload()
throws RecordServicesException {
Record record = new TestRecord(zeSchema);
recordServices.add(record);
return (RecordImpl) recordServices.getDocumentById(record.getId());
}
private Record saveAnotherSchemaRecordWithDateMetadataToJanuary1()
throws RecordServicesException {
Record record = new TestRecord(anotherSchema);
record.set(anotherSchema.dateMetadata(), january1);
recordServices.add(record);
return record;
}
private Record saveAnotherSchemaRecord()
throws RecordServicesException {
Record record = new TestRecord(anotherSchema);
recordServices.add(record);
return record;
}
private Record saveThirdSchemaRecord()
throws RecordServicesException {
Record record = new TestRecord(thirdSchema);
recordServices.add(record);
return record;
}
private Transaction newTransactionWithNRecords(int numberOfRecords) {
Transaction transaction = new Transaction();
for (int i = 0; i < numberOfRecords; i++) {
transaction.addUpdate(new TestRecord(zeSchema));
}
return transaction;
}
private Map<String, Object> asMap(String key1, String value1) {
Map<String, Object> parameters = new HashMap<>();
parameters.put(key1, value1);
return parameters;
}
public static final class TitleLengthCalculator implements MetadataValueCalculator<Double> {
LocalDependency<String> titleDependency = LocalDependency.toAString(Schemas.TITLE.getLocalCode());
@Override
public Double calculate(CalculatorParameters parameters) {
return (double) parameters.get(titleDependency).length();
}
@Override
public Double getDefaultValue() {
return 0.0;
}
@Override
public MetadataValueType getReturnType() {
return MetadataValueType.NUMBER;
}
@Override
public boolean isMultiValue() {
return false;
}
@Override
public List<? extends Dependency> getDependencies() {
return asList(titleDependency);
}
}
}