/**
* Copyright (c) 2002-2012 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.consistency.checking.full;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import static org.neo4j.consistency.store.RecordReference.SkippingReference.skipReference;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.junit.runners.Suite;
import org.neo4j.consistency.store.DiffRecordAccess;
import org.neo4j.consistency.store.RecordReference;
import org.neo4j.kernel.impl.nioneo.store.AbstractBaseRecord;
import org.neo4j.kernel.impl.nioneo.store.DynamicRecord;
import org.neo4j.kernel.impl.nioneo.store.NodeRecord;
import org.neo4j.kernel.impl.nioneo.store.PropertyRecord;
import org.neo4j.kernel.impl.nioneo.store.RecordStore;
import org.neo4j.kernel.impl.nioneo.store.RelationshipRecord;
import org.neo4j.kernel.impl.nioneo.store.StoreAccess;
@RunWith(Suite.class)
@Suite.SuiteClasses({
MultiPassStoreTest.Nodes.class,
MultiPassStoreTest.Relationships.class,
MultiPassStoreTest.Properties.class,
MultiPassStoreTest.Strings.class,
MultiPassStoreTest.Arrays.class
})
public abstract class MultiPassStoreTest
{
@Test
public void createsListOfFiltersWhichEachSkipRecordsOutsideOfARangeOfMappableIds() throws Exception
{
// given
StoreAccess storeAccess = storeAccess( 1000L, 9 );
DiffRecordAccess recordAccess = mock( DiffRecordAccess.class );
long memoryPerPass = 900L;
// when
List<DiffRecordAccess> filters = multiPassStore().multiPassFilters( memoryPerPass, storeAccess, recordAccess );
// then
assertEquals( 11, filters.size() );
assertFinds( record( filters.get( 0 ), 0 ) );
assertFinds( record( filters.get( 0 ), 99 ) );
assertFinds( record( filters.get( 1 ), 100 ) );
assertFinds( record( filters.get( 1 ), 199 ) );
assertFinds( record( filters.get( 2 ), 200 ) );
assertFinds( record( filters.get( 2 ), 299 ) );
assertFinds( record( filters.get( 10 ), 1000 ) );
assertSkips( record( filters.get( 1 ), 0 ) );
assertSkips( record( filters.get( 1 ), 99 ) );
assertSkips( record( filters.get( 2 ), 100 ) );
assertSkips( record( filters.get( 2 ), 199 ) );
assertSkips( record( filters.get( 0 ), 100 ) );
assertSkips( record( filters.get( 0 ), 199 ) );
assertSkips( record( filters.get( 1 ), 200 ) );
assertSkips( record( filters.get( 1 ), 299 ) );
}
@Test
public void shouldSkipOtherKindsOfRecords() throws Exception
{
// given
StoreAccess storeAccess = storeAccess( 1000L, 9 );
DiffRecordAccess recordAccess = mock( DiffRecordAccess.class );
long memoryPerPass = 900L;
// when
List<DiffRecordAccess> filters = multiPassStore().multiPassFilters( memoryPerPass, storeAccess, recordAccess );
// then
for ( DiffRecordAccess filter : filters )
{
for ( long id : new long[] {0, 100, 200, 300, 400, 500, 600, 700, 800, 900} )
{
otherRecords( filter, id );
}
}
verifyZeroInteractions( recordAccess );
}
private static <RECORD extends AbstractBaseRecord> void assertSkips( RecordReference<RECORD> recordReference )
{
assertSame( skipReference(), recordReference );
}
private static <RECORD extends AbstractBaseRecord> void assertFinds( RecordReference<RECORD> recordReference )
{
assertNotSame( skipReference(), recordReference );
}
@SuppressWarnings("unchecked")
private StoreAccess storeAccess( long highId, int recordSize )
{
StoreAccess storeAccess = mock( StoreAccess.class );
RecordStore recordStore = mock( RecordStore.class );
when( multiPassStore().getRecordStore( storeAccess ) ).thenReturn( recordStore );
when( recordStore.getHighId() ).thenReturn( highId );
when( recordStore.getRecordSize() ).thenReturn( recordSize );
return storeAccess;
}
protected abstract MultiPassStore multiPassStore();
protected abstract RecordReference<? extends AbstractBaseRecord> record( DiffRecordAccess filter, long id );
protected abstract void otherRecords( DiffRecordAccess filter, long id );
@RunWith(JUnit4.class)
public static class Nodes extends MultiPassStoreTest
{
@Override
protected MultiPassStore multiPassStore()
{
return MultiPassStore.NODES;
}
@Override
protected RecordReference<NodeRecord> record( DiffRecordAccess filter, long id )
{
return filter.node( id );
}
protected void otherRecords( DiffRecordAccess filter, long id )
{
filter.relationship( id );
filter.property( id );
filter.string( id );
filter.array( id );
}
}
@RunWith(JUnit4.class)
public static class Relationships extends MultiPassStoreTest
{
@Override
protected MultiPassStore multiPassStore()
{
return MultiPassStore.RELATIONSHIPS;
}
@Override
protected RecordReference<RelationshipRecord> record( DiffRecordAccess filter, long id )
{
return filter.relationship( id );
}
protected void otherRecords( DiffRecordAccess filter, long id )
{
filter.node( id );
filter.property( id );
filter.string( id );
filter.array( id );
}
}
@RunWith(JUnit4.class)
public static class Properties extends MultiPassStoreTest
{
@Override
protected MultiPassStore multiPassStore()
{
return MultiPassStore.PROPERTIES;
}
@Override
protected RecordReference<PropertyRecord> record( DiffRecordAccess filter, long id )
{
return filter.property( id );
}
protected void otherRecords( DiffRecordAccess filter, long id )
{
filter.node( id );
filter.relationship( id );
filter.string( id );
filter.array( id );
}
}
@RunWith(JUnit4.class)
public static class Strings extends MultiPassStoreTest
{
@Override
protected MultiPassStore multiPassStore()
{
return MultiPassStore.STRINGS;
}
@Override
protected RecordReference<DynamicRecord> record( DiffRecordAccess filter, long id )
{
return filter.string( id );
}
protected void otherRecords( DiffRecordAccess filter, long id )
{
filter.node( id );
filter.relationship( id );
filter.property( id );
filter.array( id );
}
}
@RunWith(JUnit4.class)
public static class Arrays extends MultiPassStoreTest
{
@Override
protected MultiPassStore multiPassStore()
{
return MultiPassStore.ARRAYS;
}
@Override
protected RecordReference<DynamicRecord> record( DiffRecordAccess filter, long id )
{
return filter.array( id );
}
protected void otherRecords( DiffRecordAccess filter, long id )
{
filter.node( id );
filter.relationship( id );
filter.property( id );
filter.string( id );
}
}
}