DATAREDIS-417 - Add failing tests for ScanCursor throwing NoSuchElementException.

Add failing tests for scanning key sets where Redis returns a scan iteration pointing to the next cursor but having no actual values itself like in:

    scan 0 match key*9
      1) 1966080
      2) (empty list or set)
This commit is contained in:
Christoph Strobl
2015-10-15 14:23:09 +02:00
parent 0579c3dae4
commit df4ad35057
4 changed files with 152 additions and 8 deletions

View File

@@ -1977,6 +1977,27 @@ public abstract class AbstractConnectionIntegrationTests {
assertThat(i, is(itemCount));
}
/**
* @see DATAREDIS-417
*/
@Test
@IfProfileValue(name = "redisVersion", value = "2.8+")
@WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE })
public void scanShouldReadEntireValueRangeWhenIdividualScanIterationsReturnEmptyCollection() {
connection.execute("DEBUG", "POPULATE".getBytes(), "100".getBytes());
Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match("key*9").count(10).build());
int i = 0;
while (cursor.hasNext()) {
assertThat(new String(cursor.next()), containsString("key:"));
i++;
}
assertThat(i, is(10));
}
/**
* @see DATAREDIS-306
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2013 the original author or authors.
* Copyright 2011-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,15 +16,14 @@
package org.springframework.data.redis.connection;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.test.annotation.IfProfileValue;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.test.annotation.IfProfileValue;
/**
* Base test class for integration tests that execute each operation of a Connection while a pipeline is open, verifying
@@ -34,6 +33,7 @@ import static org.junit.Assert.assertTrue;
* test overrides {@link AbstractConnectionIntegrationTests} when result types are different
*
* @author Jennifer Hickey
* @author Christoph Strobl
*/
abstract public class AbstractConnectionPipelineIntegrationTests extends AbstractConnectionIntegrationTests {
@@ -120,6 +120,16 @@ abstract public class AbstractConnectionPipelineIntegrationTests extends Abstrac
assertTrue(results.isEmpty());
}
/**
* @see DATAREDIS-417
*/
@Test
@Ignore
@Override
public void scanShouldReadEntireValueRangeWhenIdividualScanIterationsReturnEmptyCollection() {
super.scanShouldReadEntireValueRangeWhenIdividualScanIterationsReturnEmptyCollection();
}
protected void initConnection() {
connection.openPipeline();
}

View File

@@ -1,6 +1,22 @@
/*
* Copyright 2013-2015 the original author or authors.
*
* Licensed 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.springframework.data.redis.connection;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.List;
@@ -9,6 +25,11 @@ import org.junit.Ignore;
import org.junit.Test;
import org.springframework.test.annotation.IfProfileValue;
/**
* @author Jennifer Hickey
* @author Thomas Darimont
* @author Christoph Strobl
*/
abstract public class AbstractConnectionTransactionIntegrationTests extends AbstractConnectionIntegrationTests {
@Ignore
@@ -86,6 +107,16 @@ abstract public class AbstractConnectionTransactionIntegrationTests extends Abst
connection.scriptKill();
}
/**
* @see DATAREDIS-417
*/
@Test
@Ignore
@Override
public void scanShouldReadEntireValueRangeWhenIdividualScanIterationsReturnEmptyCollection() {
super.scanShouldReadEntireValueRangeWhenIdividualScanIterationsReturnEmptyCollection();
}
protected void initConnection() {
connection.multi();
}

View File

@@ -16,11 +16,15 @@
package org.springframework.data.redis.core;
import static org.hamcrest.core.Is.*;
import static org.hamcrest.core.IsCollectionContaining.*;
import static org.junit.Assert.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.Stack;
@@ -163,6 +167,83 @@ public class ScanCursorUnitTests {
assertThat(cursor.getPosition(), is(2L));
}
/**
* @see DATAREDIS-417
*/
@Test
public void hasNextShouldCallScanUntilFinishedWhenScanResultIsAnEmptyCollection() {
LinkedList<ScanIteration<String>> values = new LinkedList<ScanIteration<String>>();
values.add(createIteration(1, "spring"));
values.add(createIteration(2));
values.add(createIteration(3));
values.add(createIteration(4));
values.add(createIteration(5));
values.add(createIteration(0, "redis"));
Cursor<String> cursor = initCursor(values);
List<String> result = new ArrayList<String>();
while (cursor.hasNext()) {
result.add(cursor.next());
}
assertThat(result.size(), is(2));
assertThat(result, hasItems("spring", "redis"));
}
/**
* @see DATAREDIS-417
*/
@Test
public void hasNextShouldStopWhenScanResultIsAnEmptyCollectionAndStateIsFinished() {
LinkedList<ScanIteration<String>> values = new LinkedList<ScanIteration<String>>();
values.add(createIteration(1, "spring"));
values.add(createIteration(2));
values.add(createIteration(3));
values.add(createIteration(4));
values.add(createIteration(5));
values.add(createIteration(6));
values.add(createIteration(7, "data"));
values.add(createIteration(0));
Cursor<String> cursor = initCursor(values);
List<String> result = new ArrayList<String>();
while (cursor.hasNext()) {
result.add(cursor.next());
}
assertThat(result.size(), is(2));
assertThat(result, hasItems("spring", "data"));
}
/**
* @see DATAREDIS-417
*/
@Test
public void hasNextShouldStopCorrectlyWhenWholeScanIterationDoesNotReturnResultsAndStateIsFinished() {
LinkedList<ScanIteration<String>> values = new LinkedList<ScanIteration<String>>();
values.add(createIteration(1));
values.add(createIteration(2));
values.add(createIteration(3));
values.add(createIteration(4));
values.add(createIteration(5));
values.add(createIteration(0));
Cursor<String> cursor = initCursor(values);
assertThat(cursor.getPosition(), is(0L));
int loops = 0;
while (cursor.hasNext()) {
cursor.next();
loops++;
}
assertThat(loops, is(0));
assertThat(cursor.getCursorId(), is(0L));
}
private CapturingCursorDummy initCursor(Queue<ScanIteration<String>> values) {
CapturingCursorDummy cursor = new CapturingCursorDummy(values);
cursor.open();
@@ -170,7 +251,8 @@ public class ScanCursorUnitTests {
}
private ScanIteration<String> createIteration(long cursorId, String... values) {
return new ScanIteration<String>(cursorId, Arrays.asList(values));
return new ScanIteration<String>(cursorId, values.length > 0 ? Arrays.asList(values)
: Collections.<String> emptyList());
}
private class CapturingCursorDummy extends ScanCursor<String> {