//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
//ORIGINAL LINE: @Test public void shouldProvidePopulatorThatAcceptsDuplicateEntries() throws Exception
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
            public virtual void ShouldProvidePopulatorThatAcceptsDuplicateEntries()
            {
                // when
                long offset = ValueSet1.Count;

                WithPopulator(IndexProvider.getPopulator(Descriptor, IndexSamplingConfig, heapBufferFactory(1024)), p =>
                {
                    p.add(Updates(ValueSet1, 0));
                    p.add(Updates(ValueSet1, offset));
                });

                // then
                using (IndexAccessor accessor = IndexProvider.getOnlineAccessor(Descriptor, IndexSamplingConfig))
                {
                    using (IndexReader reader = new QueryResultComparingIndexReader(accessor.NewReader()))
                    {
                        int propertyKeyId = Descriptor.schema().PropertyId;
                        foreach (NodeAndValue entry in ValueSet1)
                        {
                            NodeValueIterator nodes = new NodeValueIterator();
                            reader.Query(nodes, IndexOrder.NONE, false, IndexQuery.exact(propertyKeyId, entry.Value));
                            assertEquals(entry.Value.ToString(), asSet(entry.NodeId, entry.NodeId + offset), PrimitiveLongCollections.toSet(nodes));
                        }
                    }
                }
            }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
//ORIGINAL LINE: @Test public void shouldApplyUpdatesIdempotently() throws Exception
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
        public virtual void ShouldApplyUpdatesIdempotently()
        {
            // GIVEN
            IndexSamplingConfig indexSamplingConfig = new IndexSamplingConfig(Config.defaults());
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final org.neo4j.values.storable.Value propertyValue = org.neo4j.values.storable.Values.of("value1");
            Value propertyValue = Values.of("value1");

            WithPopulator(IndexProvider.getPopulator(Descriptor, indexSamplingConfig, heapBufferFactory(1024)), p =>
            {
                long nodeId = 1;

                // update using populator...
                IndexEntryUpdate <SchemaDescriptor> update = add(nodeId, Descriptor.schema(), propertyValue);
                p.add(singletonList(update));
                // ...is the same as update using updater
                using (IndexUpdater updater = p.newPopulatingUpdater((node, propertyId) => propertyValue))
                {
                    updater.Process(update);
                }
            });

            // THEN
            using (IndexAccessor accessor = IndexProvider.getOnlineAccessor(Descriptor, indexSamplingConfig))
            {
                using (IndexReader reader = new QueryResultComparingIndexReader(accessor.NewReader()))
                {
                    int          propertyKeyId = Descriptor.schema().PropertyId;
                    LongIterator nodes         = reader.Query(IndexQuery.exact(propertyKeyId, propertyValue));
                    assertEquals(asSet(1L), PrimitiveLongCollections.toSet(nodes));
                }
            }
        }
Beispiel #3
0
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
//ORIGINAL LINE: @Test public void shouldEnforceUniqueConstraintsDirectly() throws Exception
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
            public virtual void ShouldEnforceUniqueConstraintsDirectly()
            {
                // when
                IndexSamplingConfig indexSamplingConfig = new IndexSamplingConfig(Config.defaults());

                WithPopulator(IndexProvider.getPopulator(Descriptor, indexSamplingConfig, heapBufferFactory(1024)), p =>
                {
                    try
                    {
                        p.add(Arrays.asList(IndexEntryUpdate.Add(NodeId1, Descriptor.schema(), Value1, Value2), IndexEntryUpdate.Add(NodeId2, Descriptor.schema(), Value1, Value2)));
                        TestNodePropertyAccessor propertyAccessor = new TestNodePropertyAccessor(NodeId1, Descriptor.schema(), Value1, Value2);
                        propertyAccessor.AddNode(NodeId2, Descriptor.schema(), Value1, Value2);
                        p.scanCompleted(PhaseTracker.nullInstance);
                        p.verifyDeferredConstraints(propertyAccessor);

                        fail("expected exception");
                    }
                    // then
                    catch (IndexEntryConflictException conflict)
                    {
                        assertEquals(NodeId1, conflict.ExistingNodeId);
                        assertEquals(ValueTuple.of(Value1, Value2), conflict.PropertyValues);
                        assertEquals(NodeId2, conflict.AddedNodeId);
                    }
                }, false);
            }
Beispiel #4
0
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: private void verifyRandomRanges(org.neo4j.values.storable.ValueType[] types, java.util.TreeSet<ValueAndId> sortedValues) throws Exception
            internal virtual void VerifyRandomRanges(ValueType[] types, SortedSet <ValueAndId> sortedValues)
            {
                for (int i = 0; i < 100; i++)
                {
                    Value     booleanValue = Random.randomValues().nextBooleanValue();
                    ValueType type         = Random.among(types);
                    Value     from         = Random.randomValues().nextValueOfType(type);
                    Value     to           = Random.randomValues().nextValueOfType(type);
                    if (Values.COMPARATOR.Compare(from, to) > 0)
                    {
                        Value tmp = from;
                        from = to;
                        to   = tmp;
                    }
                    bool fromInclusive = Random.nextBoolean();
                    bool toInclusive   = Random.nextBoolean();

                    // when
                    IList <long> expectedIds = expectedIds(sortedValues, booleanValue, from, to, fromInclusive, toInclusive);

                    // Depending on order capabilities we verify ids or order and ids.
                    IndexQuery[]    predicates      = new IndexQuery[] { IndexQuery.exact(100, booleanValue), IndexQuery.range(101, from, fromInclusive, to, toInclusive) };
                    ValueCategory[] valueCategories = GetValueCategories(predicates);
                    IndexOrder[]    indexOrders     = IndexProvider.getCapability(Descriptor).orderCapability(valueCategories);
                    foreach (IndexOrder order in indexOrders)
                    {
                        IList <long> actualIds = AssertInOrder(order, predicates);
                        actualIds.sort(long?.compare);
                        // then
                        assertThat(actualIds, equalTo(expectedIds));
                    }
                }
            }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: private void verifyRandomRanges(org.neo4j.values.storable.ValueType[] types, java.util.TreeSet<ValueAndId> sortedValues) throws Exception
        private void VerifyRandomRanges(ValueType[] types, SortedSet <ValueAndId> sortedValues)
        {
            for (int i = 0; i < 100; i++)
            {
                // Construct a random range query of random value type
                ValueType type = Random.among(types);
                Value     from = Random.randomValues().nextValueOfType(type);
                Value     to   = Random.randomValues().nextValueOfType(type);
                if (Values.COMPARATOR.Compare(from, to) > 0)
                {
                    Value tmp = from;
                    from = to;
                    to   = tmp;
                }
                bool fromInclusive = Random.nextBoolean();
                bool toInclusive   = Random.nextBoolean();

                // Expected result based on query
//JAVA TO C# CONVERTER WARNING: Java wildcard generics have no direct equivalent in .NET:
//ORIGINAL LINE: org.neo4j.internal.kernel.api.IndexQuery.RangePredicate<?> predicate = org.neo4j.internal.kernel.api.IndexQuery.range(0, from, fromInclusive, to, toInclusive);
                IndexQuery.RangePredicate <object> predicate = IndexQuery.range(0, from, fromInclusive, to, toInclusive);
                IList <long> expectedIds = expectedIds(sortedValues, from, to, fromInclusive, toInclusive);

                // Depending on order capabilities we verify ids or order and ids.
                IndexOrder[] indexOrders = IndexProvider.getCapability(Descriptor).orderCapability(predicate.ValueGroup().category());
                foreach (IndexOrder order in indexOrders)
                {
                    IList <long> actualIds = AssertInOrder(order, predicate);
                    actualIds.sort(long?.compare);
                    // then
                    assertThat(actualIds, equalTo(expectedIds));
                }
            }
        }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
//ORIGINAL LINE: @Test public void shouldPopulateAndUpdate() throws Exception
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
        public virtual void ShouldPopulateAndUpdate()
        {
            // GIVEN
            WithPopulator(IndexProvider.getPopulator(Descriptor, IndexSamplingConfig, heapBufferFactory(1024)), p => p.add(Updates(ValueSet1)));

            using (IndexAccessor accessor = IndexProvider.getOnlineAccessor(Descriptor, IndexSamplingConfig))
            {
                // WHEN
                using (IndexUpdater updater = accessor.NewUpdater(IndexUpdateMode.ONLINE))
                {
//JAVA TO C# CONVERTER WARNING: Java wildcard generics have no direct equivalent in .NET:
//ORIGINAL LINE: java.util.List<IndexEntryUpdate<?>> updates = updates(valueSet2);
                    IList <IndexEntryUpdate <object> > updates = updates(ValueSet2);
//JAVA TO C# CONVERTER WARNING: Java wildcard generics have no direct equivalent in .NET:
//ORIGINAL LINE: for (IndexEntryUpdate<?> update : updates)
                    foreach (IndexEntryUpdate <object> update in updates)
                    {
                        updater.Process(update);
                    }
                }

                // THEN
                using (IndexReader reader = new QueryResultComparingIndexReader(accessor.NewReader()))
                {
                    int propertyKeyId = Descriptor.schema().PropertyId;
                    foreach (NodeAndValue entry in Iterables.concat(ValueSet1, ValueSet2))
                    {
                        NodeValueIterator nodes = new NodeValueIterator();
                        reader.Query(nodes, IndexOrder.NONE, false, IndexQuery.exact(propertyKeyId, entry.Value));
                        assertEquals(entry.NodeId, nodes.Next());
                        assertFalse(nodes.HasNext());
                    }
                }
            }
        }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
//ORIGINAL LINE: @Test public void shouldPopulateWithAllValues() throws Exception
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
        public virtual void ShouldPopulateWithAllValues()
        {
            // GIVEN
            WithPopulator(IndexProvider.getPopulator(Descriptor, IndexSamplingConfig, heapBufferFactory(1024)), p => p.add(Updates(ValueSet1)));

            // THEN
            AssertHasAllValues(ValueSet1);
        }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
//ORIGINAL LINE: @Before public void before() throws Exception
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
        public virtual void Before()
        {
            IndexSamplingConfig indexSamplingConfig = new IndexSamplingConfig(Config.defaults());
            IndexPopulator      populator           = IndexProvider.getPopulator(Descriptor, indexSamplingConfig, heapBufferFactory(1024));

            populator.Create();
            populator.Close(true);
            Accessor = IndexProvider.getOnlineAccessor(Descriptor, indexSamplingConfig);
        }
 internal virtual IndexOrder[] OrderCapability(params IndexQuery[] predicates)
 {
     ValueCategory[] categories = new ValueCategory[predicates.Length];
     for (int i = 0; i < predicates.Length; i++)
     {
         categories[i] = predicates[i].ValueGroup().category();
     }
     return(IndexProvider.getCapability(Descriptor).orderCapability(categories));
 }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
//ORIGINAL LINE: @Test public void shouldStorePopulationFailedForRetrievalFromProviderLater() throws Exception
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
        public virtual void ShouldStorePopulationFailedForRetrievalFromProviderLater()
        {
            // GIVEN
            string failure = "The contrived failure";
            IndexSamplingConfig indexSamplingConfig = new IndexSamplingConfig(Config.defaults());

            // WHEN (this will attempt to call close)
            WithPopulator(IndexProvider.getPopulator(Descriptor, indexSamplingConfig, heapBufferFactory(1024)), p => p.markAsFailed(failure), false);
            // THEN
            assertThat(IndexProvider.getPopulationFailure(Descriptor), containsString(failure));
        }
Beispiel #11
0
        public override bool Equals(object o)
        {
            if (this == o)
            {
                return(true);
            }
            if (o == null || this.GetType() != o.GetType())
            {
                return(false);
            }

            IndexProvider other = ( IndexProvider )o;

            return(_providerDescriptor.Equals(other._providerDescriptor));
        }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
//ORIGINAL LINE: @Test public void shouldBeAbleToDropAClosedIndexPopulator() throws Exception
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
        public virtual void ShouldBeAbleToDropAClosedIndexPopulator()
        {
            // GIVEN
            IndexSamplingConfig indexSamplingConfig = new IndexSamplingConfig(Config.defaults());
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final IndexPopulator p = indexProvider.getPopulator(descriptor, indexSamplingConfig, heapBufferFactory(1024));
            IndexPopulator p = IndexProvider.getPopulator(Descriptor, indexSamplingConfig, heapBufferFactory(1024));

            p.Close(false);

            // WHEN
            p.Drop();

            // THEN - no exception should be thrown (it's been known to!)
        }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
//ORIGINAL LINE: @Test public void shouldUpdateWithAllValuesDuringPopulation() throws Exception
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
        public virtual void ShouldUpdateWithAllValuesDuringPopulation()
        {
            // GIVEN
            WithPopulator(IndexProvider.getPopulator(Descriptor, IndexSamplingConfig, heapBufferFactory(1024)), p =>
            {
                using (IndexUpdater updater = p.newPopulatingUpdater(this.valueSet1Lookup))
                {
                    foreach (NodeAndValue entry in ValueSet1)
                    {
                        updater.Process(add(entry.NodeId, Descriptor.schema(), entry.Value));
                    }
                }
            });

            // THEN
            AssertHasAllValues(ValueSet1);
        }
Beispiel #14
0
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
//ORIGINAL LINE: @Test public void shouldProvidePopulatorThatAcceptsDuplicateEntries() throws Exception
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
            public virtual void ShouldProvidePopulatorThatAcceptsDuplicateEntries()
            {
                // when
                IndexSamplingConfig indexSamplingConfig = new IndexSamplingConfig(Config.defaults());

                WithPopulator(IndexProvider.getPopulator(Descriptor, indexSamplingConfig, heapBufferFactory(1024)), p => p.add(Arrays.asList(add(1, Descriptor.schema(), "v1", "v2"), add(2, Descriptor.schema(), "v1", "v2"))));

                // then
                using (IndexAccessor accessor = IndexProvider.getOnlineAccessor(Descriptor, indexSamplingConfig))
                {
                    using (IndexReader reader = new QueryResultComparingIndexReader(accessor.NewReader()))
                    {
                        LongIterator nodes = reader.Query(IndexQuery.exact(1, "v1"), IndexQuery.exact(1, "v2"));
                        assertEquals(asSet(1L, 2L), PrimitiveLongCollections.toSet(nodes));
                    }
                }
            }
Beispiel #15
0
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
//ORIGINAL LINE: @Test public void shouldNotRestrictUpdatesDifferingOnSecondProperty() throws Exception
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
            public virtual void ShouldNotRestrictUpdatesDifferingOnSecondProperty()
            {
                // given
                IndexSamplingConfig indexSamplingConfig = new IndexSamplingConfig(Config.defaults());

                WithPopulator(IndexProvider.getPopulator(Descriptor, indexSamplingConfig, heapBufferFactory(1024)), p =>
                {
                    // when
                    p.add(Arrays.asList(IndexEntryUpdate.Add(NodeId1, Descriptor.schema(), Value1, Value2), IndexEntryUpdate.Add(NodeId2, Descriptor.schema(), Value1, Value3)));

                    TestNodePropertyAccessor propertyAccessor = new TestNodePropertyAccessor(NodeId1, Descriptor.schema(), Value1, Value2);
                    propertyAccessor.AddNode(NodeId2, Descriptor.schema(), Value1, Value3);

                    // then this should pass fine
                    p.verifyDeferredConstraints(propertyAccessor);
                });
            }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
//ORIGINAL LINE: @Test public void shouldReportInitialStateAsFailedIfPopulationFailed() throws Exception
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
        public virtual void ShouldReportInitialStateAsFailedIfPopulationFailed()
        {
            // GIVEN
            IndexSamplingConfig indexSamplingConfig = new IndexSamplingConfig(Config.defaults());

            WithPopulator(IndexProvider.getPopulator(Descriptor, indexSamplingConfig, heapBufferFactory(1024)), p =>
            {
                string failure = "The contrived failure";

                // WHEN
                p.markAsFailed(failure);
                p.close(false);

                // THEN
                assertEquals(FAILED, IndexProvider.getInitialState(Descriptor));
            }, false);
        }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: private void assertHasAllValues(java.util.List<NodeAndValue> values) throws java.io.IOException, org.neo4j.internal.kernel.api.exceptions.schema.IndexNotApplicableKernelException
        private void AssertHasAllValues(IList <NodeAndValue> values)
        {
            using (IndexAccessor accessor = IndexProvider.getOnlineAccessor(Descriptor, IndexSamplingConfig))
            {
                using (IndexReader reader = new QueryResultComparingIndexReader(accessor.NewReader()))
                {
                    int propertyKeyId = Descriptor.schema().PropertyId;
                    foreach (NodeAndValue entry in values)
                    {
                        NodeValueIterator nodes = new NodeValueIterator();
                        reader.Query(nodes, IndexOrder.NONE, false, IndexQuery.exact(propertyKeyId, entry.Value));
                        assertEquals(entry.NodeId, nodes.Next());
                        assertFalse(nodes.HasNext());
                    }
                }
            }
        }
            /// <summary>
            /// This is also checked by the UniqueConstraintCompatibility test, only not on this abstraction level.
            /// </summary>
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
//ORIGINAL LINE: @Test public void shouldProvidePopulatorThatEnforcesUniqueConstraints() throws Exception
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
            public virtual void ShouldProvidePopulatorThatEnforcesUniqueConstraints()
            {
                // when
                Value value   = Values.of("value1");
                int   nodeId1 = 1;
                int   nodeId2 = 2;

                WithPopulator(IndexProvider.getPopulator(Descriptor, IndexSamplingConfig, heapBufferFactory(1024)), p =>
                {
                    try
                    {
                        p.add(Arrays.asList(add(nodeId1, Descriptor.schema(), value), add(nodeId2, Descriptor.schema(), value)));
                        TestNodePropertyAccessor propertyAccessor = new TestNodePropertyAccessor(nodeId1, Descriptor.schema(), value);
                        propertyAccessor.AddNode(nodeId2, Descriptor.schema(), value);
                        p.scanCompleted(PhaseTracker.nullInstance);
                        p.verifyDeferredConstraints(propertyAccessor);

                        fail("expected exception");
                    }
                    // then
                    catch (Exception e)
                    {
                        Exception root = Exceptions.rootCause(e);
                        if (root is IndexEntryConflictException)
                        {
                            IndexEntryConflictException conflict = ( IndexEntryConflictException )root;
                            assertEquals(nodeId1, conflict.ExistingNodeId);
                            assertEquals(ValueTuple.of(value), conflict.PropertyValues);
                            assertEquals(nodeId2, conflict.AddedNodeId);
                        }
                        else
                        {
                            throw e;
                        }
                    }
                }, false);
            }
Beispiel #19
0
 public Monitor_Fields(IndexProvider outerInstance)
 {
     this._outerInstance = outerInstance;
 }
Beispiel #20
0
 protected internal IndexProvider(IndexProvider copySource) : this(copySource._providerDescriptor, copySource._directoryStructureFactory)
 {
 }
Beispiel #21
0
 public Monitor_Adaptor(IndexProvider outerInstance)
 {
     this._outerInstance = outerInstance;
 }
        /// <summary>
        /// This test target a bug around minimal splitter in gbpTree and unique index populator. It goes like this:
        /// Given a set of updates (value,entityId):
        /// - ("A01",1), ("A90",3), ("A9",2)
        /// If ("A01",1) and ("A90",3) would cause a split to occur they would produce a minimal splitter ("A9",3).
        /// Note that the value in this minimal splitter is equal to our last update ("A9",2).
        /// When making insertions with the unique populator we don't compare entityId which would means ("A9",2)
        /// ends up to the right of ("A9",3), even though it belongs to the left because of entityId being smaller.
        /// At this point the tree is in an inconsistent (key on wrong side of splitter).
        ///
        /// To work around this problem the entityId is only kept in minimal splitter if strictly necessary to divide
        /// left from right. This means the minimal splitter between ("A01",1) and ("A90",3) is ("A9",-1) and ("A9",2)
        /// will correctly be placed on the right side of this splitter.
        ///
        /// To trigger this scenario this test first insert a bunch of values that are all unique and that will cause a
        /// split to happen. This is the firstBatch.
        /// The second batch are constructed so that at least one of them will have a value equal to the splitter key
        /// constructed during the firstBatch.
        /// It's important that the secondBatch has ids that are lower than the first batch to align with example described above.
        /// </summary>
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
//ORIGINAL LINE: @Test public void shouldPopulateAndRemoveEntriesWithSimilarMinimalSplitter() throws Exception
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
        public virtual void ShouldPopulateAndRemoveEntriesWithSimilarMinimalSplitter()
        {
            string prefix     = "Work out your own salvation. Do not depend on others. ";
            int    nbrOfNodes = 200;
            long   nodeId     = 0;

            // Second batch has lower ids
            IList <NodeAndValue> secondBatch = new List <NodeAndValue>();

            for (int i = 0; i < nbrOfNodes; i++)
            {
                secondBatch.Add(new NodeAndValue(nodeId++, stringValue(prefix + i)));
            }

            // First batch has higher ids and minimal splitter among values in first batch will be found among second batch
            IList <NodeAndValue> firstBatch = new List <NodeAndValue>();

            for (int i = 0; i < nbrOfNodes; i++)
            {
                firstBatch.Add(new NodeAndValue(nodeId++, stringValue(prefix + i + " " + i)));
            }

            WithPopulator(IndexProvider.getPopulator(Descriptor, IndexSamplingConfig, heapBufferFactory(1024)), p =>
            {
                p.add(Updates(firstBatch));
                p.add(Updates(secondBatch));

                // Index should be consistent
            });

            IList <NodeAndValue> toRemove = new List <NodeAndValue>();

            ((IList <NodeAndValue>)toRemove).AddRange(firstBatch);
            ((IList <NodeAndValue>)toRemove).AddRange(secondBatch);
            Collections.shuffle(toRemove);

            // And we should be able to remove the entries in any order
            using (IndexAccessor accessor = IndexProvider.getOnlineAccessor(Descriptor, IndexSamplingConfig))
            {
                // WHEN
                using (IndexUpdater updater = accessor.NewUpdater(IndexUpdateMode.ONLINE))
                {
                    foreach (NodeAndValue nodeAndValue in toRemove)
                    {
                        updater.Process(IndexEntryUpdate.Remove(nodeAndValue.NodeId, Descriptor, nodeAndValue.Value));
                    }
                }

                // THEN
                using (IndexReader reader = new QueryResultComparingIndexReader(accessor.NewReader()))
                {
                    int propertyKeyId = Descriptor.schema().PropertyId;
                    foreach (NodeAndValue nodeAndValue in toRemove)
                    {
                        NodeValueIterator nodes = new NodeValueIterator();
                        reader.Query(nodes, IndexOrder.NONE, false, IndexQuery.exact(propertyKeyId, nodeAndValue.Value));
                        bool anyHits = false;

                        StringJoiner nodesStillLeft = new StringJoiner(", ", "[", "]");
                        while (nodes.HasNext())
                        {
                            anyHits = true;
                            nodesStillLeft.add(Convert.ToString(nodes.Next()));
                        }
                        assertFalse("Expected this query to have zero hits but found " + nodesStillLeft.ToString(), anyHits);
                    }
                }
            }
        }