/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. The ASF licenses this file to You * under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. For additional information regarding * copyright in this work, please see the NOTICE file in the top level * directory of this distribution. */ package org.apache.usergrid.persistence.collection; import com.fasterxml.uuid.UUIDComparator; import com.google.inject.Inject; import com.netflix.astyanax.connectionpool.exceptions.ConnectionException; import net.jcip.annotations.NotThreadSafe; import org.apache.usergrid.persistence.actorsystem.ActorSystemManager; import org.apache.usergrid.persistence.collection.exception.WriteUniqueVerifyException; import org.apache.usergrid.persistence.collection.guice.TestCollectionModule; import org.apache.usergrid.persistence.collection.mvcc.entity.Stage; import org.apache.usergrid.persistence.collection.serialization.MvccEntitySerializationStrategy; import org.apache.usergrid.persistence.collection.serialization.SerializationFig; import org.apache.usergrid.persistence.collection.serialization.UniqueValueSerializationStrategy; import org.apache.usergrid.persistence.collection.serialization.UniqueValueSet; import org.apache.usergrid.persistence.collection.uniquevalues.UniqueValuesService; import org.apache.usergrid.persistence.collection.util.EntityHelper; import org.apache.usergrid.persistence.core.guice.MigrationManagerRule; import org.apache.usergrid.persistence.core.guicyfig.SetConfigTestBypass; import org.apache.usergrid.persistence.core.scope.ApplicationScope; import org.apache.usergrid.persistence.core.scope.ApplicationScopeImpl; import org.apache.usergrid.persistence.core.test.ITRunner; import org.apache.usergrid.persistence.core.test.UseModules; import org.apache.usergrid.persistence.core.util.Health; import org.apache.usergrid.persistence.model.entity.Entity; import org.apache.usergrid.persistence.model.entity.Id; import org.apache.usergrid.persistence.model.entity.SimpleId; import org.apache.usergrid.persistence.model.field.BooleanField; import org.apache.usergrid.persistence.model.field.Field; import org.apache.usergrid.persistence.model.field.IntegerField; import org.apache.usergrid.persistence.model.field.StringField; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import rx.Observable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.UUID; import static org.junit.Assert.*; /** @author tnine */ @RunWith( ITRunner.class ) @UseModules( TestCollectionModule.class ) @NotThreadSafe // this added due to multiple datastax client's causing issues during parallel test execution public class EntityCollectionManagerIT extends AbstractUniqueValueTest { private static final Logger logger = LoggerFactory.getLogger( EntityCollectionManagerIT.class ); @Inject private EntityCollectionManagerFactory factory; @Inject @Rule public MigrationManagerRule migrationManagerRule; @Inject private SerializationFig serializationFig; @Inject private UniqueValueSerializationStrategy uniqueValueSerializationStrategy; @Inject private MvccEntitySerializationStrategy entitySerializationStrategy; @Inject ActorSystemManager actorSystemManager; @Inject UniqueValuesService uniqueValuesService; @Before public void initAkka() { initAkka( 2551, actorSystemManager, uniqueValuesService ); } @Test public void write() { ApplicationScope context = new ApplicationScopeImpl( new SimpleId( "organization" ) ); Entity newEntity = new Entity( new SimpleId( "test" ) ); EntityCollectionManager manager = factory.createCollectionManager( context ); Observable<Entity> observable = manager.write( newEntity, null ); Entity returned = observable.toBlocking().lastOrDefault( null ); assertNotNull( "Returned has a uuid", returned.getId() ); assertNotNull( "Version exists", returned.getVersion() ); } @Test public void writeWithUniqueValues() { ApplicationScope context = new ApplicationScopeImpl( new SimpleId( "organization" ) ); EntityCollectionManager manager = factory.createCollectionManager( context ); { Entity newEntity = new Entity( new SimpleId( "test" ) ); newEntity.setField( new IntegerField( "count", 5, true ) ); Observable<Entity> observable = manager.write( newEntity, null ); Entity returned = observable.toBlocking().lastOrDefault( null ); } { try { Entity newEntity = new Entity( new SimpleId( "test" ) ); newEntity.setField( new IntegerField( "count", 5, true ) ); manager.write( newEntity, null ).toBlocking().last(); fail( "Write should have thrown an exception" ); } catch ( Exception ex ) { WriteUniqueVerifyException e = ( WriteUniqueVerifyException ) ex; assertEquals( 1, e.getViolations().size() ); } } } @Test public void writeAndLoad() { ApplicationScope context = new ApplicationScopeImpl( new SimpleId( "organization" ) ); Entity newEntity = new Entity( new SimpleId( "test" ) ); EntityCollectionManager manager = factory.createCollectionManager( context ); Observable<Entity> observable = manager.write( newEntity, null ); Entity createReturned = observable.toBlocking().lastOrDefault( null ); assertNotNull( "Id was assigned", createReturned.getId() ); assertNotNull( "Version was assigned", createReturned.getVersion() ); Observable<Entity> loadObservable = manager.load( createReturned.getId() ); Entity loadReturned = loadObservable.toBlocking().lastOrDefault( null ); assertEquals( "Same value", createReturned, loadReturned ); } @Test public void writeLoadDelete() { ApplicationScope context = new ApplicationScopeImpl( new SimpleId( "organization" ) ); Entity newEntity = new Entity( new SimpleId( "test" ) ); EntityCollectionManager manager = factory.createCollectionManager( context ); Observable<Entity> observable = manager.write( newEntity, null ); Entity createReturned = observable.toBlocking().lastOrDefault( null ); assertNotNull( "Id was assigned", createReturned.getId() ); Observable<Entity> loadObservable = manager.load( createReturned.getId() ); Entity loadReturned = loadObservable.toBlocking().lastOrDefault( null ); assertEquals( "Same value", createReturned, loadReturned ); manager.mark( createReturned.getId(), null ).toBlocking().last(); loadObservable = manager.load( createReturned.getId() ); //load may return null, use last or default loadReturned = loadObservable.toBlocking().lastOrDefault( null ); assertNull( "Entity was deleted", loadReturned ); } @Test public void writeLoadUpdateLoad() { ApplicationScope context = new ApplicationScopeImpl( new SimpleId( "organization" ) ); Entity newEntity = new Entity( new SimpleId( "test" ) ); newEntity.setField( new IntegerField( "counter", 1 ) ); EntityCollectionManager manager = factory.createCollectionManager( context ); Observable<Entity> observable = manager.write( newEntity, null ); Entity createReturned = observable.toBlocking().lastOrDefault( null ); assertNotNull( "Id was assigned", createReturned.getId() ); Observable<Entity> loadObservable = manager.load( createReturned.getId() ); Entity loadReturned = loadObservable.toBlocking().lastOrDefault( null ); assertEquals( "Same value", createReturned, loadReturned ); assertEquals( "Field value correct", createReturned.getField( "counter" ), loadReturned.getField( "counter" ) ); //update the field to 2 createReturned.setField( new IntegerField( "counter", 2 ) ); //wait for the write to complete manager.write( createReturned, null ).toBlocking().lastOrDefault( null ); loadObservable = manager.load( createReturned.getId() ); loadReturned = loadObservable.toBlocking().lastOrDefault( null ); assertEquals( "Same value", createReturned, loadReturned ); assertEquals( "Field value correct", createReturned.getField( "counter" ), loadReturned.getField( "counter" ) ); } @Test public void writeAndLoadScopeClosure() { ApplicationScope collectionScope1 = new ApplicationScopeImpl( new SimpleId( "organization" ) ); Entity newEntity = new Entity( new SimpleId( "test" ) ); EntityCollectionManager manager = factory.createCollectionManager( collectionScope1 ); Observable<Entity> observable = manager.write( newEntity, null ); Entity createReturned = observable.toBlocking().lastOrDefault( null ); assertNotNull( "Id was assigned", createReturned.getId() ); assertNotNull( "Version was assigned", createReturned.getVersion() ); Observable<Entity> loadObservable = manager.load( createReturned.getId() ); Entity loadReturned = loadObservable.toBlocking().lastOrDefault( null ); assertEquals( "Same value", createReturned, loadReturned ); ApplicationScope collectionScope2 = new ApplicationScopeImpl( new SimpleId( "organization" ) ); //now make sure we can't load it from another scope, using the same org EntityCollectionManager manager2 = factory.createCollectionManager( collectionScope2 ); Entity loaded = manager2.load( createReturned.getId() ).toBlocking().lastOrDefault( null ); assertNull( "CollectionScope works correctly", loaded ); } @Test public void writeAndGetField() { ApplicationScope collectionScope1 = new ApplicationScopeImpl( new SimpleId( "organization" ) ); Entity newEntity = new Entity( new SimpleId( "test" ) ); Field field = new StringField( "testField", "unique", true ); newEntity.setField( field ); EntityCollectionManager manager = factory.createCollectionManager( collectionScope1 ); Observable<Entity> observable = manager.write( newEntity, null ); Entity createReturned = observable.toBlocking().lastOrDefault( null ); assertNotNull( "Id was assigned", createReturned.getId() ); assertNotNull( "Version was assigned", createReturned.getVersion() ); Id id = manager.getIdField( newEntity.getId().getType(), field ).toBlocking().lastOrDefault( null ); assertNotNull( id ); assertEquals( newEntity.getId(), id ); Field fieldNull = new StringField( "testFieldNotThere", "uniquely", true ); id = manager.getIdField( newEntity.getId().getType(), fieldNull ).toBlocking().lastOrDefault( null ); assertNull( id ); } @Test public void writeAndGetField2X() throws InterruptedException { // create entity with unique testField ApplicationScope collectionScope1 = new ApplicationScopeImpl( new SimpleId( "organization" ) ); final Id entityId = new SimpleId( "test" ); Entity firstInstance = new Entity( entityId ); Field firstField = new StringField( "testField", "unique", true ); firstInstance.setField( firstField ); EntityCollectionManager manager = factory.createCollectionManager( collectionScope1 ); Observable<Entity> observable = manager.write( firstInstance, null ); Entity createReturned = observable.toBlocking().lastOrDefault( null ); assertNotNull( "Id was assigned", createReturned.getId() ); assertNotNull( "Version was assigned", createReturned.getVersion() ); // get entity via that unique field, should get correct entity final Id existingId = manager.getIdField( firstInstance.getId().getType(), firstField ) .toBlocking().lastOrDefault( null ); assertNotNull( existingId ); assertEquals( firstInstance.getId(), existingId ); // get entity via bogus unique field that does not exist, should get null Field fieldNull = new StringField( "testFieldNotThere", "uniquely", true ); final Id noId = manager.getIdField( firstInstance.getId().getType(), fieldNull ) .toBlocking().lastOrDefault( null ); assertNull( noId ); // ensure we clean up // set a different unique field to the entity we created above // this should effectively remove the original unique testField that we created above Entity secondInstance = new Entity( entityId ); Field secondField = new StringField( firstField.getName(), "unique2", true ); secondInstance.setField( secondField ); Observable<Entity> observableSecond = manager.write( secondInstance, null ); Entity createReturnedSecond = observableSecond.toBlocking().lastOrDefault( null ); assertNotNull( "Id was assigned", createReturnedSecond.getId() ); assertNotNull( "Version was assigned", createReturnedSecond.getVersion() ); assertNotEquals( "Versions should not be equal", createReturned.getVersion(), createReturnedSecond.getVersion() ); // sanity check, get the entity to ensure it's the right version final Entity loadedVersion = manager.load( entityId ).toBlocking().last(); assertEquals(entityId, loadedVersion.getId()); assertEquals(createReturnedSecond.getVersion(), loadedVersion.getVersion()); // give clean time to run. need to finish the todo below Id idFirst = null; int retries = 0; while ( retries++ < 20 ) { //TODO, we need to implement verify and repair on this idFirst = manager.getIdField( firstInstance.getId().getType(), firstField ) .toBlocking().lastOrDefault( null ); if ( idFirst == null ) { break; } logger.error("Clean no run yet, waiting ({})", retries); Thread.sleep( 2000 ); } assertNull(idFirst); final Id idSecond = manager.getIdField( secondInstance.getId().getType(), secondField ) .toBlocking().lastOrDefault( null ); assertNotNull( idSecond ); assertEquals( secondInstance.getId(), idSecond ); } @Test public void updateVersioning() { // create entity Entity origEntity = new Entity( new SimpleId( "testUpdate" ) ); origEntity.setField( new StringField( "testField", "value" ) ); ApplicationScope context = new ApplicationScopeImpl( new SimpleId( "organization" ) ); EntityCollectionManager manager = factory.createCollectionManager( context ); Entity returned = manager.write( origEntity, null ).toBlocking().lastOrDefault( null ); // note its version UUID oldVersion = returned.getVersion(); // partial update entity but with new entity that has version = null assertNotNull( "A version must be assigned", oldVersion ); // partial update entity but we don't have version number Entity updateEntity = new Entity( origEntity.getId() ); updateEntity.setField( new StringField( "addedField", "other value" ) ); manager.write( updateEntity, null ).toBlocking().lastOrDefault( null ); // get entity now, it must have a new version returned = manager.load( origEntity.getId() ).toBlocking().lastOrDefault( null ); UUID newVersion = returned.getVersion(); assertNotNull( "A new version must be assigned", newVersion ); // new Version should be > old version assertTrue( UUIDComparator.staticCompare( newVersion, oldVersion ) > 0 ); } @Test public void writeMultiget() { final ApplicationScope context = new ApplicationScopeImpl( new SimpleId( "organization" ) ); final EntityCollectionManager manager = factory.createCollectionManager( context ); final int multigetSize = serializationFig.getMaxLoadSize(); final List<Entity> writtenEntities = new ArrayList<>( multigetSize ); final List<Id> entityIds = new ArrayList<>( multigetSize ); for ( int i = 0; i < multigetSize; i++ ) { final Entity entity = new Entity( new SimpleId( "test" ) ); final Entity written = manager.write( entity, null ).toBlocking().last(); writtenEntities.add( written ); entityIds.add( written.getId() ); } final EntitySet entitySet = manager.load( entityIds ).toBlocking().lastOrDefault( null ); assertNotNull( entitySet ); assertEquals( multigetSize, entitySet.size() ); assertFalse( entitySet.isEmpty() ); /** * Validate every element exists */ for ( int i = 0; i < multigetSize; i++ ) { final Entity expected = writtenEntities.get( i ); final MvccEntity returned = entitySet.getEntity( expected.getId() ); assertEquals( "Same entity returned", expected, returned.getEntity().get() ); } } /** * Perform a multiget where every entity will need repaired on load */ @Test public void writeMultigetRepair() { final ApplicationScope context = new ApplicationScopeImpl( new SimpleId( "organization" ) ); final EntityCollectionManager manager = factory.createCollectionManager( context ); final int multigetSize = serializationFig.getMaxLoadSize(); final List<Entity> writtenEntities = new ArrayList<>( multigetSize ); final List<Id> entityIds = new ArrayList<>( multigetSize ); for ( int i = 0; i < multigetSize; i++ ) { final Entity entity = new Entity( new SimpleId( "test" ) ); final Entity written = manager.write( entity, null ).toBlocking().last(); written.setField( new BooleanField( "updated", true ) ); final Entity updated = manager.write( written, null ).toBlocking().last(); writtenEntities.add( updated ); entityIds.add( updated.getId() ); } final EntitySet entitySet = manager.load( entityIds ).toBlocking().lastOrDefault( null ); assertNotNull( entitySet ); assertEquals( multigetSize, entitySet.size() ); assertFalse( entitySet.isEmpty() ); /** * Validate every element exists */ for ( int i = 0; i < multigetSize; i++ ) { final Entity expected = writtenEntities.get( i ); final MvccEntity returned = entitySet.getEntity( expected.getId() ); assertEquals( "Same entity returned", expected, returned.getEntity().get() ); assertTrue( ( Boolean ) returned.getEntity().get().getField( "updated" ).getValue() ); } } @Test( expected = IllegalArgumentException.class ) public void readTooLarge() { final ApplicationScope context = new ApplicationScopeImpl( new SimpleId( "organization" ) ); final EntityCollectionManager manager = factory.createCollectionManager( context ); final int multigetSize = serializationFig.getMaxLoadSize() + 1; final List<Id> entityIds = new ArrayList<>( multigetSize ); for ( int i = 0; i < multigetSize; i++ ) { entityIds.add( new SimpleId( "simple" ) ); } //should throw an exception manager.load( entityIds ).toBlocking().lastOrDefault( null ); } @Test public void testGetVersion() { ApplicationScope context = new ApplicationScopeImpl( new SimpleId( "organization" ) ); final EntityCollectionManager manager = factory.createCollectionManager( context ); final Entity newEntity = new Entity( new SimpleId( "test" ) ); Entity created1 = manager.write( newEntity, null ).toBlocking().lastOrDefault( null ); assertNotNull( "Id was assigned", created1.getId() ); assertNotNull( "Version was assigned", created1.getVersion() ); Entity secondEntity = new Entity( new SimpleId( "test" ) ); Entity created2 = manager.write( secondEntity, null ).toBlocking().lastOrDefault( null ); assertNotNull( "Id was assigned", created2.getId() ); assertNotNull( "Version was assigned", created2.getVersion() ); VersionSet results = manager.getLatestVersion( Arrays.asList( created1.getId(), created2.getId() ) ).toBlocking().last(); final MvccLogEntry version1Log = results.getMaxVersion( created1.getId() ); assertEquals( created1.getId(), version1Log.getEntityId() ); assertEquals( created1.getVersion(), version1Log.getVersion() ); assertEquals( MvccLogEntry.State.COMPLETE, version1Log.getState() ); assertEquals( Stage.COMMITTED, version1Log.getStage() ); final MvccLogEntry version2Log = results.getMaxVersion( created2.getId() ); assertEquals( created2.getId(), version2Log.getEntityId() ); assertEquals( created2.getVersion(), version2Log.getVersion() ); assertEquals( MvccLogEntry.State.COMPLETE, version2Log.getState() ); assertEquals( Stage.COMMITTED, version2Log.getStage() ); } @Test public void testVersionLogWrite() { ApplicationScope context = new ApplicationScopeImpl( new SimpleId( "organization" ) ); final EntityCollectionManager manager = factory.createCollectionManager( context ); final Entity newEntity = new Entity( new SimpleId( "test" ) ); final Entity v1Created = manager.write( newEntity, null ).toBlocking().lastOrDefault( null ); assertNotNull( "Id was assigned", v1Created.getId() ); assertNotNull( "Version was assigned", v1Created.getVersion() ); final UUID v1Version = v1Created.getVersion(); final VersionSet resultsV1 = manager.getLatestVersion( Arrays.asList( v1Created.getId() ) ).toBlocking().last(); final MvccLogEntry version1Log = resultsV1.getMaxVersion( v1Created.getId() ); assertEquals( v1Created.getId(), version1Log.getEntityId() ); assertEquals( v1Version, version1Log.getVersion() ); assertEquals( MvccLogEntry.State.COMPLETE, version1Log.getState() ); assertEquals( Stage.COMMITTED, version1Log.getStage() ); final Entity v2Created = manager.write( v1Created, null ).toBlocking().last(); final UUID v2Version = v2Created.getVersion(); assertTrue( "Newer version in v2", UUIDComparator.staticCompare( v2Version, v1Version ) > 0 ); final VersionSet resultsV2 = manager.getLatestVersion( Arrays.asList( v1Created.getId() ) ).toBlocking().last(); final MvccLogEntry version2Log = resultsV2.getMaxVersion( v1Created.getId() ); assertEquals( v1Created.getId(), version2Log.getEntityId() ); assertEquals( v2Version, version2Log.getVersion() ); assertEquals( MvccLogEntry.State.COMPLETE, version2Log.getState() ); assertEquals( Stage.COMMITTED, version2Log.getStage() ); } @Test public void testVersionLogUpdate() { ApplicationScope context = new ApplicationScopeImpl( new SimpleId( "organization" ) ); final EntityCollectionManager manager = factory.createCollectionManager( context ); final Entity newEntity = new Entity( new SimpleId( "test" ) ); final Entity v1Created = manager.write( newEntity, null ).toBlocking().lastOrDefault( null ); assertNotNull( "Id was assigned", v1Created.getId() ); assertNotNull( "Version was assigned", v1Created.getVersion() ); final UUID v1Version = v1Created.getVersion(); final VersionSet resultsV1 = manager.getLatestVersion( Arrays.asList( v1Created.getId() ) ).toBlocking().last(); final MvccLogEntry version1Log = resultsV1.getMaxVersion( v1Created.getId() ); assertEquals( v1Created.getId(), version1Log.getEntityId() ); assertEquals( v1Version, version1Log.getVersion() ); assertEquals( MvccLogEntry.State.COMPLETE, version1Log.getState() ); assertEquals( Stage.COMMITTED, version1Log.getStage() ); final Entity v2Created = manager.write( v1Created, null ).toBlocking().last(); final UUID v2Version = v2Created.getVersion(); assertEquals( "Same entityId", v1Created.getId(), v2Created.getId() ); assertTrue( "Newer version in v2", UUIDComparator.staticCompare( v2Version, v1Version ) > 0 ); final VersionSet resultsV2 = manager.getLatestVersion( Arrays.asList( v1Created.getId() ) ).toBlocking().last(); final MvccLogEntry version2Log = resultsV2.getMaxVersion( v1Created.getId() ); assertEquals( v2Created.getId(), version2Log.getEntityId() ); assertEquals( v2Version, version2Log.getVersion() ); assertEquals( MvccLogEntry.State.COMPLETE, version2Log.getState() ); assertEquals( Stage.COMMITTED, version2Log.getStage() ); } @Test public void healthTest() { ApplicationScope context = new ApplicationScopeImpl( new SimpleId( "organization" ) ); final EntityCollectionManager manager = factory.createCollectionManager( context ); assertEquals( Health.GREEN, manager.getHealth() ); } /** * Tests an entity with more than 65535 bytes worth of data */ @Test public void largeEntityWriteRead() { final int setSize = 65535 * 2; final int currentMaxSize = serializationFig.getMaxEntitySize(); //override our default SetConfigTestBypass.setValueByPass( serializationFig, "getMaxEntitySize", 65535 * 10 + "" ); final Entity entity = EntityHelper.generateEntity( setSize ); //now we have one massive, entity, save it and retrieve it. ApplicationScope context = new ApplicationScopeImpl( new SimpleId( "organization" ) ); final EntityCollectionManager manager = factory.createCollectionManager( context ); final Entity saved = manager.write( entity, null ).toBlocking().last(); assertEquals( entity, saved ); //now load it final Entity loaded = manager.load( entity.getId() ).toBlocking().last(); EntityHelper.verifyDeepEquals( entity, loaded ); //override our default SetConfigTestBypass.setValueByPass( serializationFig, "getMaxEntitySize", currentMaxSize + "" ); } @Test public void invalidNameRepair() throws ConnectionException { //write an entity with a unique field ApplicationScope context = new ApplicationScopeImpl( new SimpleId( "organization" ) ); Entity newEntity = new Entity( new SimpleId( "test" ) ); //if we add a second field we get a second entity that is the exact same. Is this expected? final IntegerField expectedInteger = new IntegerField( "count", 5, true ); // final StringField expectedString = new StringField( "yes", "fred", true ); newEntity.setField( expectedInteger ); // newEntity.setField( expectedString ); EntityCollectionManager manager = factory.createCollectionManager( context ); Observable<Entity> observable = manager.write( newEntity, null ); Entity createReturned = observable.toBlocking().lastOrDefault( null ); assertNotNull( "Need entity to be created before proceeding", createReturned ); assertNotNull( "Id was assigned", createReturned.getId() ); assertNotNull( "Version was assigned", createReturned.getVersion() ); FieldSet fieldResults = manager.getEntitiesFromFields( newEntity.getId().getType(), Arrays.<Field>asList( expectedInteger ), true) .toBlocking().last(); assertEquals( 1, fieldResults.size() ); //verify the entity is correct. assertEquals( "Same value", createReturned, fieldResults.getEntity( expectedInteger ).getEntity().get() ); //loadReturned ); //use the entity serializationStrategy to remove the entity data. //do a mark as one test, and a delete as another entitySerializationStrategy.delete( context, createReturned.getId(), createReturned.getVersion() ).execute(); //try to load via the unique field, should have triggered repair final FieldSet results = manager.getEntitiesFromFields( newEntity.getId().getType(), Arrays.<Field>asList( expectedInteger ), true) .toBlocking().last(); //verify no entity returned assertTrue( results.isEmpty() ); //user the unique serialization to verify it's been deleted from cassandra UniqueValueSet uniqueValues = uniqueValueSerializationStrategy.load( context, newEntity.getId().getType(), createReturned.getFields() ); assertFalse( uniqueValues.iterator().hasNext() ); } @Test public void testGetIdField() throws Exception { ApplicationScope context = new ApplicationScopeImpl( new SimpleId( "organization" ) ); EntityCollectionManager manager = factory.createCollectionManager( context ); // create an entity of type "item" with a unique_id field value = 1 Entity entity1 = new Entity( new SimpleId( "item" ) ); entity1.setField( new StringField( "unique_id", "1", true ) ); manager.write( entity1, null ).toBlocking().last(); final Observable<Id> idObs = manager.getIdField( "item", new StringField( "unique_id", "1" ) ); Id id = idObs.toBlocking().lastOrDefault( null ); assertEquals( entity1.getId(), id ); // create an entity of type "deleted_item" with a unique_id field value = 1 Entity entity2 = new Entity( new SimpleId( "deleted_item" ) ); entity2.setField( new StringField( "unique_id", "1", true ) ); manager = factory.createCollectionManager( context ); manager.write( entity2, null ).toBlocking().last(); final Observable<Id> id2Obs = manager.getIdField( "deleted_item", new StringField( "unique_id", "1" ) ); Id id2 = id2Obs.toBlocking().lastOrDefault( null ); assertEquals( entity2.getId(), id2 ); } @Test public void writeGetVersionsDelete() { ApplicationScope context = new ApplicationScopeImpl( new SimpleId( "organization" ) ); Entity entity = new Entity( new SimpleId( "test" ) ); entity.setField( new IntegerField( "counter", 0 ) ); EntityCollectionManager manager = factory.createCollectionManager( context ); Entity createReturned = manager.write( entity, null ).toBlocking().lastOrDefault( null ); assertNotNull( "Id was assigned", createReturned.getId() ); final int size = 200; final Id entityId = createReturned.getId(); List<UUID> versions = new ArrayList<>( size ); versions.add( entity.getVersion() ); //write new versions for ( int i = 1; i < size; i++ ) { final Entity newEntity = new Entity( entityId ); newEntity.setField( new IntegerField( "counter", i ) ); final Entity returnedEntity = manager.write( newEntity, null ).toBlocking().last(); versions.add( returnedEntity.getVersion() ); } //now get our values, and load the latest version final Entity lastVersion = manager.load( entityId ).toBlocking().last(); //ensure the latest version is correct assertEquals( versions.get( versions.size() - 1 ), lastVersion.getVersion() ); // now ensure all versions are correct final List<MvccLogEntry> entries = manager.getVersions( entityId ).toList().toBlocking().last(); assertEquals( "Same size expected", versions.size(), entries.size() ); for ( int i = 0; i < versions.size(); i++ ) { assertEquals( versions.get( i ), entries.get( i ).getVersion() ); } //now get all the log versions, and delete them all we do it in 2+ batches to ensure we clean up as expected manager.getVersions( entityId ).toList().flatMap( bufferList -> manager.delete( bufferList ) ) .toBlocking().last(); //now load them, there shouldn't be any versions final List<MvccLogEntry> postDeleteEntries = manager.getVersions( entityId ).toList().toBlocking().last(); assertEquals( "All log entries should be removed", 0, postDeleteEntries.size() ); final Entity postDeleteLastVersion = manager.load( entityId ).toBlocking().lastOrDefault( null ); //ensure the latest version is correct assertNull( "Last version was deleted", postDeleteLastVersion ); } }