/*
* 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.mvcc.stage.delete;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Semaphore;
import org.junit.AfterClass;
import org.junit.Test;
import org.apache.usergrid.persistence.collection.MvccLogEntry;
import org.apache.usergrid.persistence.collection.serialization.MvccLogEntrySerializationStrategy;
import org.apache.usergrid.persistence.collection.serialization.SerializationFig;
import org.apache.usergrid.persistence.collection.serialization.UniqueValue;
import org.apache.usergrid.persistence.collection.serialization.UniqueValueSerializationStrategy;
import org.apache.usergrid.persistence.collection.util.LogEntryMock;
import org.apache.usergrid.persistence.collection.util.UniqueValueEntryMock;
import org.apache.usergrid.persistence.collection.util.VersionGenerator;
import org.apache.usergrid.persistence.core.scope.ApplicationScope;
import org.apache.usergrid.persistence.core.scope.ApplicationScopeImpl;
import org.apache.usergrid.persistence.model.entity.Id;
import org.apache.usergrid.persistence.model.entity.SimpleId;
import com.google.common.util.concurrent.ListenableFuture;
import com.netflix.astyanax.Keyspace;
import com.netflix.astyanax.MutationBatch;
import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.same;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class UniqueCleanupTest {
//
// private static final TaskExecutor taskExecutor = new NamedTaskExecutorImpl( "test", 4, 0 );
//
//
// @AfterClass
// public static void shutdown() {
// taskExecutor.shutdown();
// }
//
//
// @Test( timeout = 10000 )
// public void noListenerOneVersion() throws Exception {
//
//
// final SerializationFig serializationFig = mock( SerializationFig.class );
//
// when( serializationFig.getBufferSize() ).thenReturn( 10 );
//
// final MvccLogEntrySerializationStrategy less = mock( MvccLogEntrySerializationStrategy.class );
//
//
// final UniqueValueSerializationStrategy uvss = mock( UniqueValueSerializationStrategy.class );
//
// final Keyspace keyspace = mock( Keyspace.class );
//
// final MutationBatch entityBatch = mock( MutationBatch.class );
//
// when( keyspace.prepareMutationBatch() ).thenReturn(
// mock( MutationBatch.class ) ) // don't care what happens to this one
// .thenReturn( entityBatch );
//
// // intentionally no events
// final Set<EntityVersionDeleted> listeners = new HashSet<EntityVersionDeleted>();
//
// final Id applicationId = new SimpleId( "application" );
//
// final ApplicationScope appScope = new ApplicationScopeImpl( applicationId );
//
// final Id entityId = new SimpleId( "user" );
//
// final List<UUID> versions = VersionGenerator.generateVersions( 2 );
//
// // mock up a single log entry for our first test
// final LogEntryMock logEntryMock = LogEntryMock.createLogEntryMock( less, appScope, entityId, versions );
//
//
// //get the version we're keeping, it's first in our list
// final UUID version = logEntryMock.getEntryAtIndex( 0 ).getVersion();
//
// //mock up unique version output
// final UniqueValueEntryMock uniqueValueEntryMock =
// UniqueValueEntryMock.createUniqueMock( uvss, appScope, entityId, versions );
//
//
// EntityVersionCleanupTask cleanupTask =
// new EntityVersionCleanupTask( serializationFig, less, uvss, keyspace, listeners, appScope, entityId,
// version, false );
//
// final MutationBatch newBatch = mock( MutationBatch.class );
//
//
// // set up returning a mutator
// when( uvss.delete( same( appScope ), any( UniqueValue.class ) ) ).thenReturn( newBatch );
//
// //return a new batch when it's called
// when( less.delete( same( appScope ), same( entityId ), any( UUID.class ) ) ).thenReturn( newBatch );
//
//
// cleanupTask.call();
//
//
// //get the second field, this should be deleted
// final UniqueValue oldUniqueField = uniqueValueEntryMock.getEntryAtIndex( 1 );
//
// final MvccLogEntry expectedDeletedEntry = logEntryMock.getEntryAtIndex( 1 );
//
//
// //verify delete was invoked
// verify( uvss ).delete( same( appScope ), same( oldUniqueField ) );
//
// //verify the delete was invoked
// verify( less ).delete( same( appScope ), same( entityId ), same( expectedDeletedEntry.getVersion() ) );
//
// // verify it was run
// verify( entityBatch ).execute();
// }
//
//
// /**
// * Tests the cleanup task on the first version created
// */
// @Test( timeout = 10000 )
// public void noListenerNoVersions() throws Exception {
//
//
// final SerializationFig serializationFig = mock( SerializationFig.class );
//
// when( serializationFig.getBufferSize() ).thenReturn( 10 );
//
// final MvccLogEntrySerializationStrategy less = mock( MvccLogEntrySerializationStrategy.class );
//
//
// final UniqueValueSerializationStrategy uvss = mock( UniqueValueSerializationStrategy.class );
//
// final Keyspace keyspace = mock( Keyspace.class );
//
// final MutationBatch entityBatch = mock( MutationBatch.class );
//
// when( keyspace.prepareMutationBatch() ).thenReturn(
// mock( MutationBatch.class ) ) // don't care what happens to this one
// .thenReturn( entityBatch );
//
// // intentionally no events
// final Set<EntityVersionDeleted> listeners = new HashSet<>();
//
// final Id applicationId = new SimpleId( "application" );
//
// final ApplicationScope appScope = new ApplicationScopeImpl( applicationId );
//
// final Id entityId = new SimpleId( "user" );
//
//
// final List<UUID> versions = VersionGenerator.generateVersions( 1 );
//
// // mock up a single log entry, with no other entries
// final LogEntryMock logEntryMock = LogEntryMock.createLogEntryMock( less, appScope, entityId, versions );
//
//
// //get the version we're keeping, it's first in our list
// final UUID version = logEntryMock.getEntryAtIndex( 0 ).getVersion();
//
// //mock up unique version output
// final UniqueValueEntryMock uniqueValueEntryMock =
// UniqueValueEntryMock.createUniqueMock( uvss, appScope, entityId, versions );
//
//
// EntityVersionCleanupTask cleanupTask =
// new EntityVersionCleanupTask( serializationFig, less, uvss, keyspace, listeners, appScope, entityId, version, false );
//
// final MutationBatch newBatch = mock( MutationBatch.class );
//
//
// // set up returning a mutator
// when( uvss.delete( same( appScope ), any( UniqueValue.class ) ) ).thenReturn( newBatch );
//
// //return a new batch when it's called
// when( less.delete( same( appScope ), same( entityId ), any( UUID.class ) ) ).thenReturn( newBatch );
//
//
// cleanupTask.call();
//
//
// //verify delete was never invoked
// verify( uvss, never() ).delete( any( ApplicationScope.class ), any( UniqueValue.class ) );
//
// //verify the delete was never invoked
// verify( less, never() ).delete( any( ApplicationScope.class ), any( Id.class ), any( UUID.class ) );
// }
//
//
// @Test( timeout = 10000 )
// public void singleListenerSingleVersion() throws Exception {
//
//
// //create a latch for the event listener, and add it to the list of events
// final int sizeToReturn = 1;
//
// final CountDownLatch latch = new CountDownLatch( sizeToReturn );
//
// final EntityVersionDeletedTest eventListener = new EntityVersionDeletedTest( latch );
//
// final Set<EntityVersionDeleted> listeners = new HashSet<>();
//
// listeners.add( eventListener );
//
//
// final SerializationFig serializationFig = mock( SerializationFig.class );
//
// when( serializationFig.getBufferSize() ).thenReturn( 10 );
//
// final MvccLogEntrySerializationStrategy less = mock( MvccLogEntrySerializationStrategy.class );
//
// final UniqueValueSerializationStrategy uvss = mock( UniqueValueSerializationStrategy.class );
//
// final Keyspace keyspace = mock( Keyspace.class );
//
// final MutationBatch entityBatch = mock( MutationBatch.class );
//
// when( keyspace.prepareMutationBatch() ).thenReturn(
// mock( MutationBatch.class ) ) // don't care what happens to this one
// .thenReturn( entityBatch );
//
//
// final Id applicationId = new SimpleId( "application" );
//
// final ApplicationScope appScope = new ApplicationScopeImpl( applicationId );
//
// final Id entityId = new SimpleId( "user" );
//
//
// final List<UUID> versions = VersionGenerator.generateVersions( 2 );
//
//
// // mock up a single log entry for our first test
// final LogEntryMock logEntryMock = LogEntryMock.createLogEntryMock( less, appScope, entityId, versions );
//
//
// //get the version we're keeping, it's first in our list
// final UUID version = logEntryMock.getEntryAtIndex( 0 ).getVersion();
//
// //mock up unique version output
// final UniqueValueEntryMock uniqueValueEntryMock =
// UniqueValueEntryMock.createUniqueMock( uvss, appScope, entityId, versions );
//
//
// EntityVersionCleanupTask cleanupTask =
// new EntityVersionCleanupTask( serializationFig, less, uvss, keyspace, listeners, appScope, entityId,
// version, false );
//
// final MutationBatch newBatch = mock( MutationBatch.class );
//
//
// // set up returning a mutator
// when( uvss.delete( same( appScope ), any( UniqueValue.class ) ) ).thenReturn( newBatch );
//
// //return a new batch when it's called
// when( less.delete( same( appScope ), same( entityId ), any( UUID.class ) ) ).thenReturn( newBatch );
//
//
// cleanupTask.call();
//
//
// //get the second field, this should be deleted
// final UniqueValue oldUniqueField = uniqueValueEntryMock.getEntryAtIndex( 1 );
//
// final MvccLogEntry expectedDeletedEntry = logEntryMock.getEntryAtIndex( 1 );
//
//
// //verify delete was invoked
// verify( uvss ).delete( same( appScope ), same( oldUniqueField ) );
//
// //verify the delete was invoked
// verify( less ).delete( same( appScope ), same( entityId ), same( expectedDeletedEntry.getVersion() ) );
//
// // verify it was run
// verify( entityBatch ).execute();
//
//
// //the latch was executed
// latch.await();
// }
//
//
// @Test//(timeout=10000)
// public void multipleListenerMultipleVersions() throws Exception {
//
// final SerializationFig serializationFig = mock( SerializationFig.class );
//
// when( serializationFig.getBufferSize() ).thenReturn( 10 );
//
//
// //create a latch for the event listener, and add it to the list of events
// final int sizeToReturn = 10;
//
// final CountDownLatch latch = new CountDownLatch( sizeToReturn / serializationFig.getBufferSize() * 3 );
//
// final EntityVersionDeletedTest listener1 = new EntityVersionDeletedTest( latch );
// final EntityVersionDeletedTest listener2 = new EntityVersionDeletedTest( latch );
// final EntityVersionDeletedTest listener3 = new EntityVersionDeletedTest( latch );
//
// final Set<EntityVersionDeleted> listeners = new HashSet<>();
//
// listeners.add( listener1 );
// listeners.add( listener2 );
// listeners.add( listener3 );
//
//
//
//
// final MvccLogEntrySerializationStrategy less = mock( MvccLogEntrySerializationStrategy.class );
//
// final UniqueValueSerializationStrategy uvss = mock( UniqueValueSerializationStrategy.class );
//
// final Keyspace keyspace = mock( Keyspace.class );
//
// final MutationBatch entityBatch = mock( MutationBatch.class );
//
// when( keyspace.prepareMutationBatch() ).thenReturn(
// mock( MutationBatch.class ) ) // don't care what happens to this one
// .thenReturn( entityBatch );
//
//
//
//
// final Id applicationId = new SimpleId( "application" );
//
// final ApplicationScope appScope = new ApplicationScopeImpl( applicationId );
//
// final Id entityId = new SimpleId( "user" );
//
// final List<UUID> versions = VersionGenerator.generateVersions( 2 );
//
//
// // mock up a single log entry for our first test
// final LogEntryMock logEntryMock = LogEntryMock.createLogEntryMock( less, appScope, entityId, versions );
//
//
// //get the version we're keeping, it's first in our list
// final UUID version = logEntryMock.getEntryAtIndex( 0 ).getVersion();
//
// //mock up unique version output
// final UniqueValueEntryMock uniqueValueEntryMock =
// UniqueValueEntryMock.createUniqueMock( uvss, appScope, entityId, versions );
//
//
// EntityVersionCleanupTask cleanupTask =
// new EntityVersionCleanupTask( serializationFig, less, uvss, keyspace, listeners, appScope, entityId,
// version, false );
//
// final MutationBatch newBatch = mock( MutationBatch.class );
//
//
// // set up returning a mutator
// when( uvss.delete( same( appScope ), any( UniqueValue.class ) ) ).thenReturn( newBatch );
//
// //return a new batch when it's called
// when( less.delete( same( appScope ), same( entityId ), any( UUID.class ) ) ).thenReturn( newBatch );
//
//
// cleanupTask.call();
//
//
// //get the second field, this should be deleted
// final UniqueValue oldUniqueField = uniqueValueEntryMock.getEntryAtIndex( 1 );
//
// final MvccLogEntry expectedDeletedEntry = logEntryMock.getEntryAtIndex( 1 );
//
//
// //verify delete was invoked
// verify( uvss ).delete( same( appScope ), same( oldUniqueField ) );
//
// //verify the delete was invoked
// verify( less ).delete( same( appScope ), same( entityId ), same( expectedDeletedEntry.getVersion() ) );
//
// // verify it was run
// verify( entityBatch ).execute();
//
//
// //the latch was executed
// latch.await();
//
// //we deleted the version
// //verify we deleted everything
// //verify delete was invoked
// verify( uvss ).delete( same( appScope ), same( oldUniqueField ) );
//
// //verify the delete was invoked
// verify( less ).delete( same( appScope ), same( entityId ), same( expectedDeletedEntry.getVersion() ) );
//
// // verify it was run
// verify( entityBatch ).execute();
//
// //the latch was executed
// latch.await();
// }
//
//
// /**
// * Tests what happens when our listeners are VERY slow
// */
// @Test( timeout = 10000 )
// public void multipleListenerMultipleVersionsNoThreadsToRun()
// throws ExecutionException, InterruptedException, ConnectionException {
//
//
// final SerializationFig serializationFig = mock( SerializationFig.class );
//
// when( serializationFig.getBufferSize() ).thenReturn( 10 );
//
//
// //create a latch for the event listener, and add it to the list of events
// final int sizeToReturn = 10;
//
//
// final int listenerCount = 5;
//
// final CountDownLatch latch =
// new CountDownLatch( sizeToReturn / serializationFig.getBufferSize() * listenerCount );
// final Semaphore waitSemaphore = new Semaphore( 0 );
//
//
// final SlowListener listener1 = new SlowListener( latch, waitSemaphore );
// final SlowListener listener2 = new SlowListener( latch, waitSemaphore );
// final SlowListener listener3 = new SlowListener( latch, waitSemaphore );
// final SlowListener listener4 = new SlowListener( latch, waitSemaphore );
// final SlowListener listener5 = new SlowListener( latch, waitSemaphore );
//
// final Set<EntityVersionDeleted> listeners = new HashSet<EntityVersionDeleted>();
//
// listeners.add( listener1 );
// listeners.add( listener2 );
// listeners.add( listener3 );
// listeners.add( listener4 );
// listeners.add( listener5 );
//
//
// final MvccLogEntrySerializationStrategy less = mock( MvccLogEntrySerializationStrategy.class );
//
// final UniqueValueSerializationStrategy uvss = mock( UniqueValueSerializationStrategy.class );
//
// final Keyspace keyspace = mock( Keyspace.class );
//
// final MutationBatch entityBatch = mock( MutationBatch.class );
//
// when( keyspace.prepareMutationBatch() ).thenReturn(
// mock( MutationBatch.class ) ) // don't care what happens to this one
// .thenReturn( entityBatch );
//
//
// final Id applicationId = new SimpleId( "application" );
//
// final ApplicationScope appScope = new ApplicationScopeImpl( applicationId );
//
// final Id entityId = new SimpleId( "user" );
//
//
// final List<UUID> versions = VersionGenerator.generateVersions( 2 );
//
// // mock up a single log entry for our first test
// final LogEntryMock logEntryMock = LogEntryMock.createLogEntryMock( less, appScope, entityId, versions );
//
//
// //get the version we're keeping, it's first in our list
// final UUID version = logEntryMock.getEntryAtIndex( 0 ).getVersion();
//
//
// //mock up unique version output
// final UniqueValueEntryMock uniqueValueEntryMock =
// UniqueValueEntryMock.createUniqueMock( uvss, appScope, entityId, versions );
//
//
// EntityVersionCleanupTask cleanupTask =
// new EntityVersionCleanupTask( serializationFig, less, uvss, keyspace, listeners, appScope, entityId,
// version, false);
//
// final MutationBatch newBatch = mock( MutationBatch.class );
//
//
// // set up returning a mutator
// when( uvss.delete( same( appScope ), any( UniqueValue.class ) ) ).thenReturn( newBatch );
//
// //return a new batch when it's called
// when( less.delete( same( appScope ), same( entityId ), any( UUID.class ) ) ).thenReturn( newBatch );
//
//
// //start the task
// ListenableFuture<Void> future = taskExecutor.submit( cleanupTask );
//
// /**
// * While we're not done, release latches every 200 ms
// */
// while ( !future.isDone() ) {
// Thread.sleep( 200 );
// waitSemaphore.release( listenerCount );
// }
//
// //wait for the task
// future.get();
//
//
// //get the second field, this should be deleted
// final UniqueValue oldUniqueField = uniqueValueEntryMock.getEntryAtIndex( 1 );
//
// final MvccLogEntry expectedDeletedEntry = logEntryMock.getEntryAtIndex( 1 );
//
//
// //verify delete was invoked
// verify( uvss ).delete( same( appScope ), same( oldUniqueField ) );
//
// //verify the delete was invoked
// verify( less ).delete( same( appScope ), same( entityId ), same( expectedDeletedEntry.getVersion() ) );
//
// // verify it was run
// verify( entityBatch ).execute();
//
//
// //the latch was executed
// latch.await();
//
// //we deleted the version
// //verify we deleted everything
// //verify delete was invoked
// verify( uvss ).delete( same( appScope ), same( oldUniqueField ) );
//
// //verify the delete was invoked
// verify( less ).delete( same( appScope ), same( entityId ), same( expectedDeletedEntry.getVersion() ) );
//
// // verify it was run
// verify( entityBatch ).execute();
//
// //the latch was executed
// latch.await();
//
//
// //the latch was executed
// latch.await();
// }
//
//
// /**
// * Tests that our task will run in the caller if there's no threads, ensures that the task runs
// */
// @Test( timeout = 10000 )
// public void singleListenerSingleVersionRejected()
// throws ExecutionException, InterruptedException, ConnectionException {
//
//
//
// //create a latch for the event listener, and add it to the list of events
// final int sizeToReturn = 1;
//
// final CountDownLatch latch = new CountDownLatch( sizeToReturn );
//
// final EntityVersionDeletedTest eventListener = new EntityVersionDeletedTest( latch );
//
// final Set<EntityVersionDeleted> listeners = new HashSet<>();
//
// listeners.add( eventListener );
//
//
// final SerializationFig serializationFig = mock( SerializationFig.class );
//
// when( serializationFig.getBufferSize() ).thenReturn( 10 );
//
// final MvccLogEntrySerializationStrategy less = mock( MvccLogEntrySerializationStrategy.class );
//
// final UniqueValueSerializationStrategy uvss = mock( UniqueValueSerializationStrategy.class );
//
// final Keyspace keyspace = mock( Keyspace.class );
//
// final MutationBatch entityBatch = mock( MutationBatch.class );
//
// when( keyspace.prepareMutationBatch() ).thenReturn(
// mock( MutationBatch.class ) ) // don't care what happens to this one
// .thenReturn( entityBatch );
//
//
// final Id applicationId = new SimpleId( "application" );
//
// final ApplicationScope appScope = new ApplicationScopeImpl( applicationId );
//
// final Id entityId = new SimpleId( "user" );
//
//
// final List<UUID> versions = VersionGenerator.generateVersions( 2 );
//
//
// // mock up a single log entry for our first test
// final LogEntryMock logEntryMock = LogEntryMock.createLogEntryMock( less, appScope, entityId, versions );
//
//
// //get the version we're keeping, it's first in our list
// final UUID version = logEntryMock.getEntryAtIndex( 0 ).getVersion();
//
// //mock up unique version output
// final UniqueValueEntryMock uniqueValueEntryMock =
// UniqueValueEntryMock.createUniqueMock( uvss, appScope, entityId, versions );
//
//
// EntityVersionCleanupTask cleanupTask =
// new EntityVersionCleanupTask( serializationFig, less, uvss, keyspace, listeners, appScope, entityId,
// version, false );
//
// final MutationBatch newBatch = mock( MutationBatch.class );
//
//
// // set up returning a mutator
// when( uvss.delete( same( appScope ), any( UniqueValue.class ) ) ).thenReturn( newBatch );
//
// //return a new batch when it's called
// when( less.delete( same( appScope ), same( entityId ), any( UUID.class ) ) ).thenReturn( newBatch );
//
//
// cleanupTask.rejected();
//
//
// //get the second field, this should be deleted
// final UniqueValue oldUniqueField = uniqueValueEntryMock.getEntryAtIndex( 1 );
//
// final MvccLogEntry expectedDeletedEntry = logEntryMock.getEntryAtIndex( 1 );
//
//
// //verify delete was invoked
// verify( uvss ).delete( same( appScope ), same( oldUniqueField ) );
//
// //verify the delete was invoked
// verify( less ).delete( same( appScope ), same( entityId ), same( expectedDeletedEntry.getVersion() ) );
//
// // verify it was run
// verify( entityBatch ).execute();
//
//
// //the latch was executed
// latch.await();
// }
//
//
// private static class EntityVersionDeletedTest implements EntityVersionDeleted {
// final CountDownLatch invocationLatch;
//
//
// private EntityVersionDeletedTest( final CountDownLatch invocationLatch ) {
// this.invocationLatch = invocationLatch;
// }
//
//
// @Override
// public void versionDeleted( final ApplicationScope scope, final Id entityId,
// final List<MvccLogEntry> entityVersion ) {
// invocationLatch.countDown();
// }
// }
//
//
// private static class SlowListener extends EntityVersionDeletedTest {
// final Semaphore blockLatch;
//
//
// private SlowListener( final CountDownLatch invocationLatch, final Semaphore blockLatch ) {
// super( invocationLatch );
// this.blockLatch = blockLatch;
// }
//
//
// @Override
// public void versionDeleted( final ApplicationScope scope, final Id entityId,
// final List<MvccLogEntry> entityVersion ) {
//
// //wait for unblock to happen before counting down invocation latches
// try {
// blockLatch.acquire();
// }
// catch ( InterruptedException e ) {
// throw new RuntimeException( e );
// }
// super.versionDeleted( scope, entityId, entityVersion );
// }
// }
}