| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. 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. |
| */ |
| |
| package org.apache.usergrid.persistence.collection.serialization.impl; |
| |
| |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.Set; |
| import java.util.UUID; |
| |
| import org.junit.Before; |
| import org.junit.Rule; |
| import org.junit.Test; |
| |
| import org.apache.usergrid.persistence.collection.MvccEntity; |
| import org.apache.usergrid.persistence.collection.mvcc.entity.impl.MvccEntityImpl; |
| import org.apache.usergrid.persistence.collection.serialization.MvccEntitySerializationStrategy; |
| import org.apache.usergrid.persistence.core.CassandraFig; |
| import org.apache.usergrid.persistence.core.guice.MigrationManagerRule; |
| import org.apache.usergrid.persistence.core.scope.ApplicationScope; |
| import org.apache.usergrid.persistence.core.scope.ApplicationScopeImpl; |
| 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.ArrayField; |
| import org.apache.usergrid.persistence.model.field.BooleanField; |
| import org.apache.usergrid.persistence.model.field.DoubleField; |
| import org.apache.usergrid.persistence.model.field.Field; |
| import org.apache.usergrid.persistence.model.field.IntegerField; |
| import org.apache.usergrid.persistence.model.field.LongField; |
| import org.apache.usergrid.persistence.model.field.StringField; |
| import org.apache.usergrid.persistence.model.field.UUIDField; |
| import org.apache.usergrid.persistence.model.util.EntityUtils; |
| import org.apache.usergrid.persistence.model.util.UUIDGenerator; |
| |
| import com.google.common.base.Optional; |
| import com.google.inject.Inject; |
| import com.netflix.astyanax.connectionpool.exceptions.ConnectionException; |
| |
| import static junit.framework.TestCase.assertEquals; |
| import static junit.framework.TestCase.assertFalse; |
| import static junit.framework.TestCase.assertNotNull; |
| import static junit.framework.TestCase.assertNull; |
| import static junit.framework.TestCase.assertTrue; |
| import static org.mockito.Mockito.mock; |
| |
| //import org.safehaus.chop.api.IterationChop; |
| |
| |
| /** |
| * Tests for serialization strategy |
| */ |
| public abstract class MvccEntitySerializationStrategyImplTest { |
| |
| |
| protected MvccEntitySerializationStrategy serializationStrategy; |
| |
| |
| @Inject |
| @Rule |
| public MigrationManagerRule migrationManagerRule; |
| |
| @Inject |
| public CassandraFig cassandraFig; |
| |
| |
| @Before |
| public void setup() { |
| assertNotNull( cassandraFig ); |
| serializationStrategy = getMvccEntitySerializationStrategy(); |
| } |
| |
| |
| @Test |
| public void writeLoadDelete() throws ConnectionException { |
| |
| final Id organizationId = new SimpleId( "organization" ); |
| |
| ApplicationScope context = new ApplicationScopeImpl( organizationId ); |
| |
| |
| final UUID entityId = UUIDGenerator.newTimeUUID(); |
| final UUID version = UUIDGenerator.newTimeUUID(); |
| final String type = "test"; |
| |
| final Id id = new SimpleId( entityId, type ); |
| |
| Entity entity = new Entity( id ); |
| |
| EntityUtils.setVersion( entity, version ); |
| |
| |
| BooleanField boolField = new BooleanField( "boolean", false ); |
| DoubleField doubleField = new DoubleField( "double", 1d ); |
| IntegerField intField = new IntegerField( "long", 1 ); |
| LongField longField = new LongField( "int", 1l ); |
| StringField stringField = new StringField( "name", "test" ); |
| UUIDField uuidField = new UUIDField( "uuid", UUIDGenerator.newTimeUUID() ); |
| |
| ArrayField arrayField = new ArrayField("array"); |
| arrayField.add("item1"); |
| arrayField.add("item2"); |
| |
| entity.setField( boolField ); |
| entity.setField( doubleField ); |
| entity.setField( intField ); |
| entity.setField( longField ); |
| entity.setField( stringField ); |
| entity.setField( uuidField ); |
| entity.setField( arrayField ); |
| |
| MvccEntity saved = new MvccEntityImpl( id, version, MvccEntity.Status.COMPLETE, Optional.of( entity ) ); |
| |
| |
| //persist the entity |
| serializationStrategy.write( context, saved ).execute(); |
| |
| //now load it back |
| |
| MvccEntity returned = serializationStrategy.load( context, Collections.singleton( id), version ).getEntity( id ); |
| |
| assertEquals( "Mvcc entities are the same", saved, returned ); |
| |
| |
| assertEquals( id, returned.getId() ); |
| |
| |
| Field<Boolean> boolFieldReturned = returned.getEntity().get().getField( boolField.getName() ); |
| |
| assertEquals( boolField, boolFieldReturned ); |
| |
| Field<Double> doubleFieldReturned = returned.getEntity().get().getField( doubleField.getName() ); |
| |
| assertEquals( doubleField, doubleFieldReturned ); |
| |
| Field<Integer> intFieldReturned = returned.getEntity().get().getField( intField.getName() ); |
| |
| assertEquals( intField, intFieldReturned ); |
| |
| Field<Long> longFieldReturned = returned.getEntity().get().getField( longField.getName() ); |
| |
| assertEquals( longField, longFieldReturned ); |
| |
| Field<String> stringFieldReturned = returned.getEntity().get().getField( stringField.getName() ); |
| |
| assertEquals( stringField, stringFieldReturned ); |
| |
| Field<UUID> uuidFieldReturned = returned.getEntity().get().getField( uuidField.getName() ); |
| |
| assertEquals( uuidField, uuidFieldReturned ); |
| |
| Field<ArrayField> arrayFieldReturned = returned.getEntity().get().getField( arrayField.getName() ); |
| |
| assertEquals( arrayField, arrayFieldReturned ); |
| |
| |
| Set<Field> results = new HashSet<Field>(); |
| results.addAll( returned.getEntity().get().getFields()); |
| |
| |
| assertTrue( results.contains( boolField ) ); |
| assertTrue( results.contains( doubleField ) ); |
| assertTrue( results.contains( intField ) ); |
| assertTrue( results.contains( longField ) ); |
| assertTrue( results.contains( stringField ) ); |
| assertTrue( results.contains( uuidField ) ); |
| |
| assertEquals( 7, results.size() ); |
| |
| |
| assertEquals( id, entity.getId() ); |
| assertEquals( version, entity.getVersion() ); |
| |
| |
| //now delete it, should remove it from cass |
| serializationStrategy.delete( context, id, version ).execute(); |
| |
| //now get it, should be gone |
| |
| returned = serializationStrategy.load( context, Collections.singleton( id), version ).getEntity( id ); |
| |
| assertNull( returned ); |
| } |
| |
| @Test |
| public void writeLoadClearDelete() throws ConnectionException { |
| |
| final Id applicationId = new SimpleId( "application" ); |
| |
| ApplicationScope context = new ApplicationScopeImpl( applicationId ); |
| |
| |
| final UUID version = UUIDGenerator.newTimeUUID(); |
| |
| final Id entityId = new SimpleId( "test" ); |
| |
| Entity entity = new Entity( entityId ); |
| |
| EntityUtils.setVersion( entity, version ); |
| |
| |
| MvccEntity saved = new MvccEntityImpl( entityId, version, MvccEntity.Status.COMPLETE, Optional.of( entity ) ); |
| |
| |
| //persist the entity |
| serializationStrategy.write( context, saved ).execute(); |
| |
| //now load it back |
| |
| MvccEntity returned = serializationStrategy.load( context, Collections.singleton( entityId ), version ).getEntity( entityId ); |
| |
| assertEquals( "Mvcc entities are the same", saved, returned ); |
| |
| |
| assertEquals( entityId, returned.getId() ); |
| |
| //check the target entity has the right id |
| assertEquals( entityId, returned.getEntity().get().getId() ); |
| |
| |
| //now mark it |
| |
| serializationStrategy.mark( context, entityId, version ).execute(); |
| |
| returned = serializationStrategy.load( context, Collections.singleton( entityId ), version ).getEntity( entityId ); |
| |
| assertEquals( entityId, returned.getId() ); |
| assertEquals( version, returned.getVersion() ); |
| assertFalse( returned.getEntity().isPresent() ); |
| assertEquals( MvccEntity.Status.DELETED, returned.getStatus()); |
| |
| //now delete it |
| serializationStrategy.delete( context, entityId, version ).execute(); |
| |
| //now get it, should be gone |
| |
| returned = serializationStrategy.load( context, Collections.singleton( entityId ), version ).getEntity( entityId ); |
| |
| assertNull( returned ); |
| } |
| |
| @Test |
| public void writeLoadDeleteMinimalFields() throws ConnectionException { |
| |
| final Id applicationId = new SimpleId( "application" ); |
| |
| ApplicationScope context = new ApplicationScopeImpl( applicationId ); |
| |
| |
| final UUID entityId = UUIDGenerator.newTimeUUID(); |
| final UUID version = UUIDGenerator.newTimeUUID(); |
| final String type = "test"; |
| |
| final Id id = new SimpleId( entityId, type ); |
| |
| Entity entity = new Entity( id ); |
| |
| EntityUtils.setVersion( entity, version ); |
| |
| BooleanField boolField = new BooleanField( "boolean", false ); |
| |
| entity.setField( boolField ); |
| |
| MvccEntity saved = new MvccEntityImpl( id, version, MvccEntity.Status.COMPLETE, Optional.of( entity ) ); |
| |
| |
| //persist the entity |
| serializationStrategy.write( context, saved ).execute(); |
| |
| //now load it back |
| |
| MvccEntity returned = serializationStrategy.load( context, Collections.singleton( id ), version ).getEntity( id ); |
| |
| assertEquals( "Mvcc entities are the same", saved, returned ); |
| |
| |
| assertEquals( id, entity.getId() ); |
| |
| //TODO: TN-> shouldn't this be testing the returned value to make sure we were able to load it correctly? |
| //YES THIS SHOULD BE DOING WHA TI THOUGHT< BUT ITSN:T |
| Field<Boolean> boolFieldReturned = returned.getEntity().get().getField( boolField.getName() ); |
| |
| assertEquals( boolField, boolFieldReturned ); |
| |
| Set<Field> results = new HashSet<Field>(); |
| results.addAll( entity.getFields() ); |
| |
| |
| assertTrue( results.contains( boolField ) ); |
| |
| |
| assertEquals( 1, results.size() ); |
| |
| assertEquals( id, entity.getId() ); |
| assertEquals( version, entity.getVersion() ); |
| |
| |
| //now delete it |
| serializationStrategy.delete( context, id, version ).execute(); |
| |
| //now get it, should be gone |
| |
| returned = serializationStrategy.load( context, Collections.singleton( id ) , version ).getEntity( id ); |
| |
| assertNull( returned ); |
| } |
| |
| @Test |
| public void writeX2ClearDelete() throws ConnectionException { |
| |
| final Id applicationId = new SimpleId( "application" ); |
| |
| ApplicationScope context = new ApplicationScopeImpl( applicationId ); |
| |
| |
| final UUID entityId = UUIDGenerator.newTimeUUID(); |
| final UUID version1 = UUIDGenerator.newTimeUUID(); |
| final String type = "test"; |
| |
| final Id id = new SimpleId( entityId, type ); |
| |
| Entity entityv1 = new Entity( id ); |
| |
| EntityUtils.setVersion( entityv1, version1 ); |
| |
| |
| MvccEntity saved = new MvccEntityImpl( id, version1, MvccEntity.Status.COMPLETE, Optional.of( entityv1 ) ); |
| |
| |
| //persist the entity |
| serializationStrategy.write( context, saved ).execute(); |
| |
| //now load it back |
| |
| MvccEntity returnedV1 = |
| serializationStrategy.load( context, Collections.singleton( id ), version1 ).getEntity( id ); |
| |
| assertEquals( "Mvcc entities are the same", saved, returnedV1 ); |
| |
| |
| //now write a new version of it |
| |
| |
| Entity entityv2 = new Entity( id ); |
| |
| UUID version2 = UUIDGenerator.newTimeUUID(); |
| |
| |
| EntityUtils.setVersion( entityv1, version2 ); |
| |
| |
| MvccEntity savedV2 = new MvccEntityImpl( id, version2, MvccEntity.Status.COMPLETE, Optional.of( entityv2 ) ); |
| |
| serializationStrategy.write( context, savedV2 ).execute(); |
| |
| MvccEntity returnedV2 = |
| serializationStrategy.load( context, Collections.singleton( id ), version2 ).getEntity( id ); |
| |
| assertEquals( "Mvcc entities are the same", savedV2, returnedV2 ); |
| |
| |
| //now mark it at v3 |
| |
| UUID version3 = UUIDGenerator.newTimeUUID(); |
| |
| serializationStrategy.mark( context, id, version3 ).execute(); |
| |
| |
| final Optional<Entity> empty = Optional.absent(); |
| |
| MvccEntity clearedV3 = new MvccEntityImpl( id, version3, MvccEntity.Status.DELETED, empty ); |
| |
| MvccEntity returnedV3 = |
| serializationStrategy.load( context, Collections.singleton( id ), version3 ).getEntity( id ); |
| |
| assertEquals( "entities are the same", clearedV3, returnedV3 ); |
| |
| //now ask for up to 10 versions from the current version, we should get cleared, v2, v1 |
| UUID current = UUIDGenerator.newTimeUUID(); |
| |
| MvccEntity first = serializationStrategy.load( context, id ).get(); |
| |
| assertEquals( clearedV3, first ); |
| |
| |
| //now delete v2 and v1, we should still get v3 |
| serializationStrategy.delete( context, id, version1 ).execute(); |
| serializationStrategy.delete( context, id, version2 ).execute(); |
| |
| first = serializationStrategy.load( context, id ).get(); |
| |
| assertEquals( clearedV3, first ); |
| |
| |
| //now get it, should be gone |
| serializationStrategy.delete( context, id, version3 ).execute(); |
| |
| |
| assertFalse( "Not loaded", serializationStrategy.load( context, id ).isPresent() ); |
| |
| } |
| |
| @Test |
| public void loadAscendingHistory() throws ConnectionException { |
| final Id applicationId = new SimpleId( "application" ); |
| |
| ApplicationScope context = new ApplicationScopeImpl( applicationId ); |
| |
| |
| final UUID entityId = UUIDGenerator.newTimeUUID(); |
| final UUID version1 = UUIDGenerator.newTimeUUID(); |
| final String type = "test"; |
| |
| final Id id = new SimpleId(entityId, type); |
| Entity entityv1 = new Entity(id); |
| EntityUtils.setVersion(entityv1, version1); |
| MvccEntity saved = new MvccEntityImpl(id, version1, MvccEntity.Status.COMPLETE, Optional.of(entityv1)); |
| //persist the entity |
| serializationStrategy.write(context, saved).execute(); |
| |
| //now write a new version of it |
| Entity entityv2 = new Entity(id); |
| UUID version2 = UUIDGenerator.newTimeUUID(); |
| EntityUtils.setVersion(entityv1, version2); |
| MvccEntity savedV2 = new MvccEntityImpl(id, version2, MvccEntity.Status.COMPLETE, Optional.of(entityv2)); |
| serializationStrategy.write(context, savedV2).execute(); |
| |
| Iterator<MvccEntity> entities = serializationStrategy.loadAscendingHistory( context, id, savedV2.getVersion(), |
| 20 ); |
| assertTrue(entities.hasNext()); |
| assertEquals(saved.getVersion(), entities.next().getVersion()); |
| assertEquals(savedV2.getVersion(), entities.next().getVersion()); |
| assertFalse(entities.hasNext()); |
| |
| } |
| |
| |
| /** |
| * We no longer support partial writes, ensure that an exception is thrown when this occurs after v3 |
| * @throws ConnectionException |
| */ |
| @Test(expected = UnsupportedOperationException.class) |
| public void writeLoadDeletePartial() throws ConnectionException { |
| |
| final Id applicationId = new SimpleId( "application" ); |
| |
| ApplicationScope context = new ApplicationScopeImpl( applicationId ); |
| |
| |
| final UUID entityId = UUIDGenerator.newTimeUUID(); |
| final UUID version = UUIDGenerator.newTimeUUID(); |
| final String type = "test"; |
| |
| final Id id = new SimpleId( entityId, type ); |
| |
| Entity entity = new Entity( id ); |
| |
| EntityUtils.setVersion( entity, version ); |
| |
| |
| BooleanField boolField = new BooleanField( "boolean", false ); |
| DoubleField doubleField = new DoubleField( "double", 1d ); |
| IntegerField intField = new IntegerField( "long", 1 ); |
| LongField longField = new LongField( "int", 1l ); |
| StringField stringField = new StringField( "name", "test" ); |
| UUIDField uuidField = new UUIDField( "uuid", UUIDGenerator.newTimeUUID() ); |
| |
| entity.setField( boolField ); |
| entity.setField( doubleField ); |
| entity.setField( intField ); |
| entity.setField( longField ); |
| entity.setField( stringField ); |
| entity.setField( uuidField ); |
| |
| |
| MvccEntity saved = new MvccEntityImpl( id, version, MvccEntity.Status.PARTIAL, Optional.of( entity ) ); |
| |
| |
| //persist the entity |
| serializationStrategy.write( context, saved ).execute(); |
| |
| } |
| |
| |
| |
| |
| @Test(expected = NullPointerException.class) |
| public void writeParamsContext() throws ConnectionException { |
| serializationStrategy.write( null, mock( MvccEntity.class ) ); |
| } |
| |
| |
| @Test(expected = NullPointerException.class) |
| public void writeParamsEntity() throws ConnectionException { |
| serializationStrategy.write( |
| new ApplicationScopeImpl( new SimpleId( "organization" )), null ); |
| } |
| |
| |
| @Test(expected = NullPointerException.class) |
| public void deleteParamContext() throws ConnectionException { |
| serializationStrategy.delete( null, new SimpleId( "test" ), UUIDGenerator.newTimeUUID() ); |
| } |
| |
| |
| @Test(expected = NullPointerException.class) |
| public void deleteParamEntityId() throws ConnectionException { |
| |
| serializationStrategy.delete( |
| new ApplicationScopeImpl( new SimpleId( "organization" ) ), null, |
| UUIDGenerator.newTimeUUID() ); |
| } |
| |
| |
| @Test(expected = NullPointerException.class) |
| public void deleteParamVersion() throws ConnectionException { |
| |
| serializationStrategy |
| .delete( new ApplicationScopeImpl( new SimpleId( "organization" )), |
| new SimpleId( "test" ), null ); |
| } |
| |
| |
| @Test(expected = NullPointerException.class) |
| public void loadParamContext() throws ConnectionException { |
| serializationStrategy.load( null, Collections.<Id>emptyList(), UUIDGenerator.newTimeUUID() ); |
| } |
| |
| |
| @Test(expected = NullPointerException.class) |
| public void loadParamEntityId() throws ConnectionException { |
| |
| serializationStrategy |
| .load( new ApplicationScopeImpl(new SimpleId( "organization" ) ), null, UUIDGenerator.newTimeUUID() ); |
| } |
| |
| |
| @Test(expected = NullPointerException.class) |
| public void loadParamVersion() throws ConnectionException { |
| |
| serializationStrategy |
| .load( new ApplicationScopeImpl(new SimpleId( "organization" ) ), Collections.<Id>singleton( new SimpleId( "test" )), null ); |
| } |
| |
| |
| @Test(expected = NullPointerException.class) |
| public void loadListParamContext() throws ConnectionException { |
| serializationStrategy.loadDescendingHistory( null, new SimpleId( "test" ), UUIDGenerator.newTimeUUID(), 1 ); |
| } |
| |
| |
| @Test(expected = NullPointerException.class) |
| public void loadListParamEntityId() throws ConnectionException { |
| |
| serializationStrategy |
| .loadDescendingHistory( |
| new ApplicationScopeImpl( new SimpleId( "organization" ) ), null, |
| UUIDGenerator.newTimeUUID(), 1 ); |
| } |
| |
| |
| @Test(expected = NullPointerException.class) |
| public void loadListParamVersion() throws ConnectionException { |
| |
| serializationStrategy |
| .loadDescendingHistory( |
| new ApplicationScopeImpl( new SimpleId( "organization" ) ), |
| new SimpleId( "test" ), null, 1 ); |
| } |
| |
| |
| @Test(expected = IllegalArgumentException.class) |
| public void loadListParamSize() throws ConnectionException { |
| |
| serializationStrategy.loadDescendingHistory( |
| new ApplicationScopeImpl( new SimpleId( "organization" ) ), |
| new SimpleId( "test" ), UUIDGenerator.newTimeUUID(), 0 ); |
| } |
| |
| |
| /** |
| * Get the serialization strategy to test |
| * @return |
| */ |
| protected abstract MvccEntitySerializationStrategy getMvccEntitySerializationStrategy(); |
| |
| |
| } |