Skip to content

Commit

Permalink
Test for order capability
Browse files Browse the repository at this point in the history
  • Loading branch information
burqen committed Oct 3, 2018
1 parent 66b383d commit 0198851
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 72 deletions.
Expand Up @@ -30,6 +30,7 @@

import org.neo4j.gis.spatial.index.curves.StandardConfiguration;
import org.neo4j.index.internal.gbptree.RecoveryCleanupWorkCollector;
import org.neo4j.internal.kernel.api.IndexCapability;
import org.neo4j.io.fs.FileSystemAbstraction;
import org.neo4j.io.pagecache.PageCache;
import org.neo4j.kernel.api.index.IndexProvider;
Expand All @@ -53,52 +54,62 @@ public static Collection<Object[]> data()
{"Number",
numberAccessorFactory(),
RandomValues.typesOfGroup( ValueGroup.NUMBER ),
(IndexLayoutFactory) NumberLayoutNonUnique::new
(IndexLayoutFactory) NumberLayoutNonUnique::new,
NumberIndexProvider.CAPABILITY
},
{"String",
stringAccessorFactory(),
RandomValues.typesOfGroup( ValueGroup.TEXT ),
(IndexLayoutFactory) StringLayout::new
(IndexLayoutFactory) StringLayout::new,
StringIndexProvider.CAPABILITY
},
{"Date",
temporalAccessorFactory( ValueGroup.DATE ),
RandomValues.typesOfGroup( ValueGroup.DATE ),
(IndexLayoutFactory) DateLayout::new
(IndexLayoutFactory) DateLayout::new,
TemporalIndexProvider.CAPABILITY
},
{"DateTime",
temporalAccessorFactory( ValueGroup.ZONED_DATE_TIME ),
RandomValues.typesOfGroup( ValueGroup.ZONED_DATE_TIME ),
(IndexLayoutFactory) ZonedDateTimeLayout::new
(IndexLayoutFactory) ZonedDateTimeLayout::new,
TemporalIndexProvider.CAPABILITY
},
{"Duration",
temporalAccessorFactory( ValueGroup.DURATION ),
RandomValues.typesOfGroup( ValueGroup.DURATION ),
(IndexLayoutFactory) DurationLayout::new
(IndexLayoutFactory) DurationLayout::new,
TemporalIndexProvider.CAPABILITY
},
{"LocalDateTime",
temporalAccessorFactory( ValueGroup.LOCAL_DATE_TIME ),
RandomValues.typesOfGroup( ValueGroup.LOCAL_DATE_TIME ),
(IndexLayoutFactory) LocalDateTimeLayout::new
(IndexLayoutFactory) LocalDateTimeLayout::new,
TemporalIndexProvider.CAPABILITY
},
{"LocalTime",
temporalAccessorFactory( ValueGroup.LOCAL_TIME ),
RandomValues.typesOfGroup( ValueGroup.LOCAL_TIME ),
(IndexLayoutFactory) LocalTimeLayout::new
(IndexLayoutFactory) LocalTimeLayout::new,
TemporalIndexProvider.CAPABILITY
},
{"LocalDateTime",
temporalAccessorFactory( ValueGroup.LOCAL_DATE_TIME ),
RandomValues.typesOfGroup( ValueGroup.LOCAL_DATE_TIME ),
(IndexLayoutFactory) LocalDateTimeLayout::new
(IndexLayoutFactory) LocalDateTimeLayout::new,
TemporalIndexProvider.CAPABILITY
},
{"Time",
temporalAccessorFactory( ValueGroup.ZONED_TIME ),
RandomValues.typesOfGroup( ValueGroup.ZONED_TIME ),
(IndexLayoutFactory) ZonedTimeLayout::new
(IndexLayoutFactory) ZonedTimeLayout::new,
TemporalIndexProvider.CAPABILITY
},
{"Generic",
genericAccessorFactory(),
RandomValues.Type.values(),
(IndexLayoutFactory) () -> new GenericLayout( 1, spaceFillingCurveSettings )
(IndexLayoutFactory) () -> new GenericLayout( 1, spaceFillingCurveSettings ),
GenericNativeIndexProvider.CAPABILITY
},
//{ Spatial has it's own subclass because it need to override some of the test methods }
} );
Expand All @@ -111,16 +122,19 @@ public static Collection<Object[]> data()
private final AccessorFactory<KEY,VALUE> accessorFactory;
private final RandomValues.Type[] supportedTypes;
private final IndexLayoutFactory<KEY,VALUE> indexLayoutFactory;
private final IndexCapability indexCapability;

@SuppressWarnings( "unused" )
public NativeIndexAccessorTest( String name,
AccessorFactory<KEY,VALUE> accessorFactory,
RandomValues.Type[] supportedTypes,
IndexLayoutFactory<KEY,VALUE> indexLayoutFactory )
IndexLayoutFactory<KEY,VALUE> indexLayoutFactory,
IndexCapability indexCapability )
{
this.accessorFactory = accessorFactory;
this.supportedTypes = supportedTypes;
this.indexLayoutFactory = indexLayoutFactory;
this.indexCapability = indexCapability;
}

@Override
Expand All @@ -129,6 +143,12 @@ NativeIndexAccessor<KEY,VALUE> makeAccessor() throws IOException
return accessorFactory.create( pageCache, fs, getIndexFile(), layout, RecoveryCleanupWorkCollector.immediate(), monitor, indexDescriptor );
}

@Override
IndexCapability indexCapability()
{
return indexCapability;
}

@Override
ValueCreatorUtil<KEY,VALUE> createValueCreatorUtil()
{
Expand Down
Expand Up @@ -20,6 +20,7 @@
package org.neo4j.kernel.impl.index.schema;

import org.eclipse.collections.api.iterator.LongIterator;
import org.hamcrest.CoreMatchers;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
Expand All @@ -41,6 +42,7 @@

import org.neo4j.collection.PrimitiveLongCollections;
import org.neo4j.graphdb.ResourceIterator;
import org.neo4j.internal.kernel.api.IndexCapability;
import org.neo4j.internal.kernel.api.IndexOrder;
import org.neo4j.internal.kernel.api.IndexQuery;
import org.neo4j.internal.kernel.api.exceptions.schema.IndexNotApplicableKernelException;
Expand All @@ -54,9 +56,12 @@
import org.neo4j.storageengine.api.schema.IndexReader;
import org.neo4j.storageengine.api.schema.IndexSample;
import org.neo4j.storageengine.api.schema.IndexSampler;
import org.neo4j.storageengine.api.schema.SimpleNodeValueClient;
import org.neo4j.values.storable.PointValue;
import org.neo4j.values.storable.RandomValues;
import org.neo4j.values.storable.Value;
import org.neo4j.values.storable.ValueGroup;
import org.neo4j.values.storable.Values;

import static java.lang.String.format;
import static org.junit.Assert.assertArrayEquals;
Expand Down Expand Up @@ -85,7 +90,6 @@
public abstract class NativeIndexAccessorTests<KEY extends NativeIndexKey<KEY>, VALUE extends NativeIndexValue>
extends NativeIndexTestUtil<KEY,VALUE>
{
private static final int N_VALUES = 10;
private NativeIndexAccessor<KEY,VALUE> accessor;

@Rule
Expand All @@ -99,6 +103,8 @@ public void setupAccessor() throws IOException

abstract NativeIndexAccessor<KEY,VALUE> makeAccessor() throws IOException;

abstract IndexCapability indexCapability();

@After
public void closeAccessor()
{
Expand Down Expand Up @@ -726,65 +732,81 @@ public void shouldNotSeeFilteredEntries() throws Exception
assertFalse( iter.hasNext() );
}

// TODO IndexOrder tests copied from old NumberIndexAccessor test, to be implemented generically
// @Test
// public void respectIndexOrder() throws Exception
// {
// // given
// IndexEntryUpdate<IndexDescriptor>[] someUpdates = someUpdates();
// processAll( someUpdates );
// Value[] expectedValues = valueCreatorUtil.extractValuesFromUpdates( someUpdates );
//
// // when
// IndexReader reader = accessor.newReader();
// IndexQuery.RangePredicate<?> supportedQuery =
// IndexQuery.range( 0, Double.NEGATIVE_INFINITY, true, Double.POSITIVE_INFINITY, true );
//
// for ( IndexOrder supportedOrder : NumberIndexProvider.CAPABILITY.orderCapability( ValueCategory.NUMBER ) )
// {
// if ( supportedOrder == IndexOrder.ASCENDING )
// {
// Arrays.sort( expectedValues, Values.COMPARATOR );
// }
// if ( supportedOrder == IndexOrder.DESCENDING )
// {
// Arrays.sort( expectedValues, Values.COMPARATOR.reversed() );
// }
//
// SimpleNodeValueClient client = new SimpleNodeValueClient();
// reader.query( client, supportedOrder, client.needsValues(), supportedQuery );
// int i = 0;
// while ( client.next() )
// {
// assertEquals( "values in order", expectedValues[i++], client.values[0] );
// }
// assertEquals( "found all values", i, expectedValues.length );
// }
// }
//
// // <READER ordering>
//
// @Test
// public void throwForUnsupportedIndexOrder() throws Exception
// {
// // given
// // Unsupported index order for query
// IndexReader reader = accessor.newReader();
// IndexOrder unsupportedOrder = IndexOrder.DESCENDING;
// IndexQuery.ExactPredicate unsupportedQuery = IndexQuery.exact( 0, "Legolas" );
//
// // then
// expected.expect( UnsupportedOperationException.class );
// expected.expectMessage( CoreMatchers.allOf(
// CoreMatchers.containsString( "unsupported order" ),
// CoreMatchers.containsString( unsupportedOrder.toString() ),
// CoreMatchers.containsString( unsupportedQuery.toString() ) ) );
//
// // when
// reader.query( new SimpleNodeValueClient(), unsupportedOrder, false, unsupportedQuery );
// }
//
// // </READER ordering>
// <READER ordering>

@Test
public void respectIndexOrder() throws Exception
{
// given
int nUpdates = 10000;
RandomValues.Type[] types = supportedTypesExcludingNonOrderable();
Iterator<IndexEntryUpdate<IndexDescriptor>> randomUpdateGenerator =
valueCreatorUtil.randomUpdateGenerator( random, types );
//noinspection unchecked
IndexEntryUpdate<IndexDescriptor>[] someUpdates = new IndexEntryUpdate[nUpdates];
for ( int i = 0; i < nUpdates; i++ )
{
someUpdates[i] = randomUpdateGenerator.next();
}
processAll( someUpdates );
Value[] allValues = valueCreatorUtil.extractValuesFromUpdates( someUpdates );

// when
IndexReader reader = accessor.newReader();
ValueGroup valueGroup = random.among( allValues ).valueGroup();
IndexQuery.RangePredicate<?> supportedQuery = IndexQuery.range( 0, valueGroup );

IndexOrder[] supportedOrders = indexCapability().orderCapability( valueGroup.category() );
for ( IndexOrder supportedOrder : supportedOrders )
{
if ( supportedOrder == IndexOrder.NONE )
{
continue;
}
Value[] expectedValues = Arrays.stream( allValues )
.filter( v -> v.valueGroup() == valueGroup )
.toArray( Value[]::new );
if ( supportedOrder == IndexOrder.ASCENDING )
{
Arrays.sort( expectedValues, Values.COMPARATOR );
}
if ( supportedOrder == IndexOrder.DESCENDING )
{
Arrays.sort( expectedValues, Values.COMPARATOR.reversed() );
}

SimpleNodeValueClient client = new SimpleNodeValueClient();
reader.query( client, supportedOrder, true, supportedQuery );
int i = 0;
while ( client.next() )
{
assertEquals( "values in order", expectedValues[i++], client.values[0] );
}
assertEquals( "found all values", i, expectedValues.length );
}
}

@Test
public void throwForUnsupportedIndexOrder() throws Exception
{
// given
// Unsupported index order for query
IndexReader reader = accessor.newReader();
IndexOrder unsupportedOrder = IndexOrder.DESCENDING;
IndexQuery.ExactPredicate unsupportedQuery = IndexQuery.exact( 0, PointValue.MAX_VALUE ); // <- Any spatial value would do

// then
expected.expect( UnsupportedOperationException.class );
expected.expectMessage( CoreMatchers.allOf(
CoreMatchers.containsString( "unsupported order" ),
CoreMatchers.containsString( unsupportedOrder.toString() ),
CoreMatchers.containsString( unsupportedQuery.toString() ) ) );

// when
reader.query( new SimpleNodeValueClient(), unsupportedOrder, false, unsupportedQuery );
}

// </READER ordering>

private Value generateUniqueValue( IndexEntryUpdate<IndexDescriptor>[] updates )
{
Expand Down
Expand Up @@ -25,6 +25,7 @@
import java.io.IOException;

import org.neo4j.gis.spatial.index.curves.StandardConfiguration;
import org.neo4j.internal.kernel.api.IndexCapability;
import org.neo4j.internal.kernel.api.exceptions.schema.IndexNotApplicableKernelException;
import org.neo4j.kernel.api.exceptions.index.IndexEntryConflictException;
import org.neo4j.kernel.api.index.IndexEntryUpdate;
Expand Down Expand Up @@ -54,6 +55,12 @@ NativeIndexAccessor<SpatialIndexKey,NativeIndexValue> makeAccessor() throws IOEx
new StandardConfiguration() );
}

@Override
IndexCapability indexCapability()
{
return SpatialIndexProvider.CAPABILITY;
}

@Override
protected ValueCreatorUtil<SpatialIndexKey,NativeIndexValue> createValueCreatorUtil()
{
Expand Down Expand Up @@ -151,4 +158,9 @@ public void shouldReturnNoEntriesForRangePredicateOutsideAnyMatch()
{
// Accidental hits outside range is handled via a postfilter for spatial
}

@Override
public void respectIndexOrder()
{ // Spatial is non-orderable so test does not make sense
}
}
Expand Up @@ -127,7 +127,12 @@ IndexEntryUpdate<IndexDescriptor>[] someUpdatesWithDuplicateValues( RandomRule r

Iterator<IndexEntryUpdate<IndexDescriptor>> randomUpdateGenerator( RandomRule randomRule )
{
Iterator<Value> valueIterator = new RandomValueGenerator( randomRule.randomValues(), supportedTypes(), fractionDuplicates() );
return randomUpdateGenerator( randomRule, supportedTypes() );
}

Iterator<IndexEntryUpdate<IndexDescriptor>> randomUpdateGenerator( RandomRule random, RandomValues.Type[] types )
{
Iterator<Value> valueIterator = new RandomValueGenerator( random.randomValues(), types, fractionDuplicates() );
return new RandomUpdateGenerator( valueIterator );
}

Expand Down

0 comments on commit 0198851

Please sign in to comment.