diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/FilteringNumberHitIterator.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/FilteringNativeHitIterator.java similarity index 88% rename from community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/FilteringNumberHitIterator.java rename to community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/FilteringNativeHitIterator.java index bd749e106c705..eab9bbee95d9d 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/FilteringNumberHitIterator.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/FilteringNativeHitIterator.java @@ -27,11 +27,11 @@ import org.neo4j.internal.kernel.api.IndexQuery; import org.neo4j.values.storable.Value; -class FilteringNumberHitIterator extends NumberHitIterator +class FilteringNativeHitIterator extends NativeHitIterator { private final IndexQuery[] filters; - FilteringNumberHitIterator( RawCursor,IOException> seeker, + FilteringNativeHitIterator( RawCursor,IOException> seeker, Collection,IOException>> toRemoveFromWhenExhausted, IndexQuery[] filters ) { super( seeker, toRemoveFromWhenExhausted ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberHitIterator.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeHitIterator.java similarity index 90% rename from community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberHitIterator.java rename to community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeHitIterator.java index 2edf92abcbbbe..ee5ed5632f9ef 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NumberHitIterator.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeHitIterator.java @@ -36,7 +36,7 @@ * @param type of {@link NumberSchemaKey}. * @param type of {@link NativeSchemaValue}. */ -public class NumberHitIterator +public class NativeHitIterator extends PrimitiveLongCollections.PrimitiveLongBaseIterator implements PrimitiveLongResourceIterator { @@ -44,7 +44,7 @@ public class NumberHitIterator,IOException>> toRemoveFromWhenExhausted; private boolean closed; - NumberHitIterator( RawCursor,IOException> seeker, + NativeHitIterator( RawCursor,IOException> seeker, Collection,IOException>> toRemoveFromWhenExhausted ) { this.seeker = seeker; @@ -58,9 +58,10 @@ protected boolean fetchNext() { while ( seeker.next() ) { - if ( acceptValue( seeker.get().key().asValue() ) ) + KEY key = seeker.get().key(); + if ( acceptValue( key.asValue() ) ) { - return next( seeker.get().key().getEntityId() ); + return next( key.getEntityId() ); } } return false; diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeSchemaIndexReader.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeSchemaIndexReader.java index 611365ddd541a..ca241cec819fe 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeSchemaIndexReader.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/NativeSchemaIndexReader.java @@ -123,7 +123,7 @@ public PrimitiveLongResourceIterator query( IndexQuery... predicates ) { RawCursor,IOException> seeker = tree.seek( treeKeyFrom, treeKeyTo ); openSeekers.add( seeker ); - return getNumberHitIterator( seeker, needFilter, predicates ); + return getHitIterator( seeker, needFilter, predicates ); } catch ( IOException e ) { @@ -131,16 +131,10 @@ public PrimitiveLongResourceIterator query( IndexQuery... predicates ) } } - private PrimitiveLongResourceIterator getNumberHitIterator( RawCursor,IOException> seeker, boolean needFilter, IndexQuery[] predicates ) + private PrimitiveLongResourceIterator getHitIterator( RawCursor,IOException> seeker, boolean needFilter, IndexQuery[] predicates ) { - if ( needFilter ) - { - return new FilteringNumberHitIterator<>( seeker, openSeekers, predicates ); - } - else - { - return new NumberHitIterator<>( seeker, openSeekers ); - } + return needFilter ? new FilteringNativeHitIterator( seeker, openSeekers, predicates ) + : new NativeHitIterator( seeker, openSeekers ); } @Override @@ -194,14 +188,8 @@ RawCursor,IOException> makeIndexSeeker( KEY treeKeyFrom, KEY tree private IndexProgressor getIndexProgressor( RawCursor,IOException> seeker, IndexProgressor.NodeValueClient client, boolean needFilter, IndexQuery[] query ) { - if ( needFilter ) - { - return new FilteringNativeHitIndexProgressor<>( seeker, client, openSeekers, query ); - } - else - { - return new NativeHitIndexProgressor<>( seeker, client, openSeekers ); - } + return needFilter ? new FilteringNativeHitIndexProgressor( seeker, client, openSeekers, query ) + : new NativeHitIndexProgressor( seeker, client, openSeekers ); } private boolean isBackwardsSeek( KEY treeKeyFrom, KEY treeKeyTo ) diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/StringSchemaKey.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/StringSchemaKey.java index edc9b1286fe9f..70a18eb2ce7c0 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/StringSchemaKey.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/StringSchemaKey.java @@ -173,7 +173,6 @@ public void writeString( String value ) @Override public void writeString( char value ) { - // TODO more efficient impl writeString( String.valueOf( value ) ); } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexBase.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexBase.java index fcfc7b861b05c..3cd220cee11a4 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexBase.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexBase.java @@ -34,7 +34,6 @@ public abstract class FusionIndexBase { private static final int INSTANCE_COUNT = 5; - private static final String[] NAMES = { "string", "number", "spatial", "temporal", "lucene" }; static final int STRING = 0; static final int NUMBER = 1; @@ -67,11 +66,6 @@ static R[] instancesAs( T[] instances, Class cls, T return result; } - static String nameOf( int slot ) - { - return NAMES[slot]; - } - /** * NOTE: duplicate of {@link #forAll(ThrowingConsumer, Iterable)} to avoid having to wrap subjects of one form into another. * There are some real use cases for passing in an array instead of {@link Iterable} out there... diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexProvider.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexProvider.java index 44d3796bbe4e3..ebe1e9721a126 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexProvider.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexProvider.java @@ -33,6 +33,9 @@ import org.neo4j.kernel.api.index.IndexProvider; import org.neo4j.kernel.api.schema.index.SchemaIndexDescriptor; import org.neo4j.kernel.impl.api.index.sampling.IndexSamplingConfig; +import org.neo4j.kernel.impl.index.schema.NumberIndexProvider; +import org.neo4j.kernel.impl.index.schema.StringIndexProvider; +import org.neo4j.kernel.impl.index.schema.TemporalIndexProvider; import org.neo4j.kernel.impl.newapi.UnionIndexCapability; import org.neo4j.kernel.impl.storemigration.StoreMigrationParticipant; import org.neo4j.values.storable.Value; @@ -42,7 +45,6 @@ import static org.neo4j.internal.kernel.api.InternalIndexState.FAILED; import static org.neo4j.internal.kernel.api.InternalIndexState.POPULATING; import static org.neo4j.kernel.impl.index.schema.fusion.FusionIndexBase.instancesAs; -import static org.neo4j.kernel.impl.index.schema.fusion.FusionIndexBase.nameOf; /** * This {@link IndexProvider index provider} act as one logical index but is backed by four physical @@ -66,10 +68,10 @@ default T select( T[] instances, Value... values ) public FusionIndexProvider( // good to be strict with specific providers here since this is dev facing - IndexProvider stringProvider, - IndexProvider numberProvider, - IndexProvider spatialProvider, - IndexProvider temporalProvider, + StringIndexProvider stringProvider, + NumberIndexProvider numberProvider, + SpatialFusionIndexProvider spatialProvider, + TemporalIndexProvider temporalProvider, IndexProvider luceneProvider, Selector selector, Descriptor descriptor, @@ -115,6 +117,15 @@ public String getPopulationFailure( long indexId, SchemaIndexDescriptor descript throw new IllegalStateException( "None of the indexes were in a failed state" ); } + /** + * @param subProviderIndex the index into the providers array to get the name of. + * @return some name distinguishing the provider of this subProviderIndex from other providers. + */ + private String nameOf( int subProviderIndex ) + { + return providers[subProviderIndex].getClass().getSimpleName(); + } + private void writeFailure( String indexName, StringBuilder builder, IndexProvider provider, long indexId, SchemaIndexDescriptor descriptor ) { try diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/FilteringNativeHitIndexProgressorTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/FilteringNativeHitIndexProgressorTest.java new file mode 100644 index 0000000000000..01b1d3a8169bf --- /dev/null +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/FilteringNativeHitIndexProgressorTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2002-2018 "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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.kernel.impl.index.schema; + +import org.junit.Rule; +import org.junit.Test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Predicate; + +import org.neo4j.cursor.RawCursor; +import org.neo4j.index.internal.gbptree.Hit; +import org.neo4j.internal.kernel.api.IndexQuery; +import org.neo4j.kernel.api.schema.index.SchemaIndexDescriptorFactory; +import org.neo4j.test.rule.RandomRule; +import org.neo4j.values.storable.TextValue; +import org.neo4j.values.storable.Value; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class FilteringNativeHitIndexProgressorTest +{ + @Rule + public final RandomRule random = new RandomRule(); + + @Test + public void shouldFilterResults() + { + // given + List keys = new ArrayList<>(); + for ( int i = 0; i < 100; i++ ) + { + // duplicates are fine + keys.add( random.string() ); + } + + RawCursor,IOException> cursor = new ResultCursor( keys.iterator() ); + NodeValueIterator valueClient = new NodeValueIterator() + { + @Override + public boolean needsValues() + { + return true; + } + }; + IndexQuery[] predicates = new IndexQuery[]{mock( IndexQuery.class )}; + Predicate filter = string -> string.contains( "a" ); + when( predicates[0].acceptsValue( any( Value.class ) ) ).then( invocation -> filter.test( ((TextValue)invocation.getArgument( 0 )).stringValue() ) ); + FilteringNativeHitIndexProgressor progressor = new FilteringNativeHitIndexProgressor<>( cursor, valueClient, + new ArrayList<>(), predicates ); + valueClient.initialize( SchemaIndexDescriptorFactory.forLabel( 0, 0 ), progressor, predicates ); + List result = new ArrayList<>(); + + // when + while ( valueClient.hasNext() ) + { + result.add( valueClient.next() ); + } + + // then + for ( int i = 0; i < keys.size(); i++ ) + { + if ( filter.test( keys.get( i ) ) ) + { + assertTrue( result.remove( (long) i ) ); + } + } + assertTrue( result.isEmpty() ); + } +} diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/FilteringNativeHitIteratorTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/FilteringNativeHitIteratorTest.java new file mode 100644 index 0000000000000..126127c54ccf9 --- /dev/null +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/FilteringNativeHitIteratorTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2002-2018 "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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.kernel.impl.index.schema; + +import org.junit.Rule; +import org.junit.Test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Predicate; + +import org.neo4j.cursor.RawCursor; +import org.neo4j.index.internal.gbptree.Hit; +import org.neo4j.internal.kernel.api.IndexQuery; +import org.neo4j.test.rule.RandomRule; +import org.neo4j.values.storable.TextValue; +import org.neo4j.values.storable.Value; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class FilteringNativeHitIteratorTest +{ + @Rule + public final RandomRule random = new RandomRule(); + + @Test + public void shouldFilterResults() + { + // given + List keys = new ArrayList<>(); + for ( int i = 0; i < 100; i++ ) + { + // duplicates are fine + keys.add( random.string() ); + } + + RawCursor,IOException> cursor = new ResultCursor( keys.iterator() ); + IndexQuery[] predicates = new IndexQuery[]{mock( IndexQuery.class )}; + Predicate filter = string -> string.contains( "a" ); + when( predicates[0].acceptsValue( any( Value.class ) ) ).then( invocation -> filter.test( ((TextValue)invocation.getArgument( 0 )).stringValue() ) ); + FilteringNativeHitIterator iterator = new FilteringNativeHitIterator<>( cursor, new ArrayList<>(), predicates ); + List result = new ArrayList<>(); + + // when + while ( iterator.hasNext() ) + { + result.add( iterator.next() ); + } + + // then + for ( int i = 0; i < keys.size(); i++ ) + { + if ( filter.test( keys.get( i ) ) ) + { + assertTrue( result.remove( (long) i ) ); + } + } + assertTrue( result.isEmpty() ); + } +} diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/NativeSchemaIndexTestUtil.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/NativeSchemaIndexTestUtil.java index 4fce2ebb2402e..8ac242d857e39 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/NativeSchemaIndexTestUtil.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/NativeSchemaIndexTestUtil.java @@ -29,7 +29,6 @@ import java.util.Arrays; import java.util.Comparator; import java.util.List; -import java.util.Objects; import org.neo4j.cursor.RawCursor; import org.neo4j.index.internal.gbptree.GBPTree; @@ -191,57 +190,4 @@ void assertFileNotPresent() { assertFalse( fs.fileExists( indexFile ) ); } - - private class SimpleHit implements Hit - { - private final KEY key; - private final VALUE value; - - SimpleHit( KEY key, VALUE value ) - { - this.key = key; - this.value = value; - } - - @Override - public KEY key() - { - return key; - } - - @Override - public VALUE value() - { - return value; - } - - @Override - public boolean equals( Object o ) - { - if ( this == o ) - { - return true; - } - if ( o == null || getClass() != o.getClass() ) - { - return false; - } - @SuppressWarnings( "unchecked" ) - Hit simpleHit = (Hit) o; - return Objects.equals( key(), simpleHit.key() ) && - Objects.equals( value, simpleHit.value() ); - } - - @Override - public int hashCode() - { - return Objects.hash( key, value ); - } - - @Override - public String toString() - { - return "[" + key + "," + value + "]"; - } - } } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/ResultCursor.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/ResultCursor.java new file mode 100644 index 0000000000000..268ff5dc3d22a --- /dev/null +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/ResultCursor.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2002-2018 "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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.kernel.impl.index.schema; + +import java.io.IOException; +import java.util.Iterator; + +import org.neo4j.cursor.RawCursor; +import org.neo4j.index.internal.gbptree.Hit; + +import static org.neo4j.values.storable.Values.stringValue; + +class ResultCursor implements RawCursor,IOException> +{ + private final Iterator iterator; + private String current; + private int pos = -1; + + ResultCursor( Iterator keys ) + { + iterator = keys; + } + + @Override + public boolean next() + { + if ( iterator.hasNext() ) + { + current = iterator.next(); + pos++; + return true; + } + return false; + } + + @Override + public void close() + { + // do nothing + } + + @Override + public Hit get() + { + StringSchemaKey key = new StringSchemaKey(); + key.from( pos, stringValue( current ) ); + return new SimpleHit<>( key, NativeSchemaValue.INSTANCE ); + } +} diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/SimpleHit.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/SimpleHit.java new file mode 100644 index 0000000000000..943f19da5ef83 --- /dev/null +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/SimpleHit.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2002-2018 "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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.kernel.impl.index.schema; + +import java.util.Objects; + +import org.neo4j.index.internal.gbptree.Hit; + +public class SimpleHit implements Hit +{ + private final KEY key; + private final VALUE value; + + public SimpleHit( KEY key, VALUE value ) + { + this.key = key; + this.value = value; + } + + @Override + public KEY key() + { + return key; + } + + @Override + public VALUE value() + { + return value; + } + + @Override + public boolean equals( Object o ) + { + if ( this == o ) + { + return true; + } + if ( o == null || getClass() != o.getClass() ) + { + return false; + } + @SuppressWarnings( "unchecked" ) + Hit simpleHit = (Hit) o; + return Objects.equals( key(), simpleHit.key() ) && + Objects.equals( value, simpleHit.value() ); + } + + @Override + public int hashCode() + { + return Objects.hash( key, value ); + } + + @Override + public String toString() + { + return "[" + key + "," + value + "]"; + } +} diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexProviderTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexProviderTest.java index 7a51ee921b918..6349e0e301007 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexProviderTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexProviderTest.java @@ -28,6 +28,9 @@ import org.neo4j.kernel.api.index.IndexProvider; import org.neo4j.kernel.api.schema.index.SchemaIndexDescriptor; import org.neo4j.kernel.api.schema.index.SchemaIndexDescriptorFactory; +import org.neo4j.kernel.impl.index.schema.NumberIndexProvider; +import org.neo4j.kernel.impl.index.schema.StringIndexProvider; +import org.neo4j.kernel.impl.index.schema.TemporalIndexProvider; import org.neo4j.kernel.impl.index.schema.fusion.FusionIndexProvider.Selector; import org.neo4j.storageengine.api.schema.IndexSample; import org.neo4j.test.rule.RandomRule; @@ -50,20 +53,20 @@ public class FusionIndexProviderTest { private static final IndexProvider.Descriptor DESCRIPTOR = new IndexProvider.Descriptor( "test-fusion", "1" ); - private IndexProvider stringProvider; - private IndexProvider numberProvider; - private IndexProvider spatialProvider; - private IndexProvider temporalProvider; + private StringIndexProvider stringProvider; + private NumberIndexProvider numberProvider; + private SpatialFusionIndexProvider spatialProvider; + private TemporalIndexProvider temporalProvider; private IndexProvider luceneProvider; private IndexProvider[] providers; @Before public void setup() { - stringProvider = mock( IndexProvider.class ); - numberProvider = mock( IndexProvider.class ); - spatialProvider = mock( IndexProvider.class ); - temporalProvider = mock( IndexProvider.class ); + stringProvider = mock( StringIndexProvider.class ); + numberProvider = mock( NumberIndexProvider.class ); + spatialProvider = mock( SpatialFusionIndexProvider.class ); + temporalProvider = mock( TemporalIndexProvider.class ); luceneProvider = mock( IndexProvider.class ); when( stringProvider.getProviderDescriptor() ).thenReturn( new IndexProvider.Descriptor( "string", "1" ) ); when( numberProvider.getProviderDescriptor() ).thenReturn( new IndexProvider.Descriptor( "number", "1" ) );