DATAREDIS-1084 - Add support for XCLAIM.

Original pull request: #512.
This commit is contained in:
Christoph Strobl
2020-02-21 09:42:00 +01:00
committed by Mark Paluch
parent ca01670c36
commit 52fd648157
12 changed files with 756 additions and 80 deletions

View File

@@ -57,6 +57,7 @@ import org.springframework.data.redis.RedisVersionUtils;
import org.springframework.data.redis.TestCondition;
import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation;
import org.springframework.data.redis.connection.RedisListCommands.Position;
import org.springframework.data.redis.connection.RedisStreamCommands.XClaimOptions;
import org.springframework.data.redis.connection.RedisStringCommands.BitOperation;
import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate;
@@ -3137,89 +3138,110 @@ public abstract class AbstractConnectionIntegrationTests {
assertThat(info.getPendingMessagesPerConsumer()).isEmpty();
}
@Test // DATAREDIS-1084
@IfProfileValue(name = "redisVersion", value = "5.0")
@WithRedisDriver({ RedisDriver.LETTUCE })
public void xPendingShouldLoadPendingMessages() {
@Test // DATAREDIS-1084
@IfProfileValue(name = "redisVersion", value = "5.0")
@WithRedisDriver({ RedisDriver.LETTUCE })
public void xPendingShouldLoadPendingMessages() {
actual.add(connection.xAdd(KEY_1, Collections.singletonMap(KEY_2, VALUE_2)));
actual.add(connection.xGroupCreate(KEY_1, ReadOffset.from("0"), "my-group"));
actual.add(connection.xReadGroupAsString(Consumer.from("my-group", "my-consumer"),
StreamOffset.create(KEY_1, ReadOffset.lastConsumed())));
actual.add(connection.xAdd(KEY_1, Collections.singletonMap(KEY_2, VALUE_2)));
actual.add(connection.xGroupCreate(KEY_1, ReadOffset.from("0"), "my-group"));
actual.add(connection.xReadGroupAsString(Consumer.from("my-group", "my-consumer"),
StreamOffset.create(KEY_1, ReadOffset.lastConsumed())));
actual.add(connection.xPending(KEY_1, "my-group", org.springframework.data.domain.Range.open("-", "+"), 10L));
actual.add(connection.xPending(KEY_1, "my-group", org.springframework.data.domain.Range.open("-", "+"), 10L));
List<Object> results = getResults();
assertThat(results).hasSize(4);
PendingMessages pending = (PendingMessages) results.get(3);
List<Object> results = getResults();
assertThat(results).hasSize(4);
PendingMessages pending = (PendingMessages) results.get(3);
assertThat(pending.size()).isOne();
assertThat(pending.get(0).getConsumerName()).isEqualTo("my-consumer");
assertThat(pending.get(0).getGroupName()).isEqualTo("my-group");
assertThat(pending.get(0).getTotalDeliveryCount()).isOne();
assertThat(pending.get(0).getStringId()).isNotNull();
assertThat(pending.size()).isOne();
assertThat(pending.get(0).getConsumerName()).isEqualTo("my-consumer");
assertThat(pending.get(0).getGroupName()).isEqualTo("my-group");
assertThat(pending.get(0).getTotalDeliveryCount()).isOne();
assertThat(pending.get(0).getStringId()).isNotNull();
}
}
@Test // DATAREDIS-1084
@IfProfileValue(name = "redisVersion", value = "5.0")
@WithRedisDriver({ RedisDriver.LETTUCE })
public void xPendingShouldLoadPendingMessagesForConsumer() {
@Test // DATAREDIS-1084
@IfProfileValue(name = "redisVersion", value = "5.0")
@WithRedisDriver({ RedisDriver.LETTUCE })
public void xPendingShouldLoadPendingMessagesForConsumer() {
actual.add(connection.xAdd(KEY_1, Collections.singletonMap(KEY_2, VALUE_2)));
actual.add(connection.xGroupCreate(KEY_1, ReadOffset.from("0"), "my-group"));
actual.add(connection.xReadGroupAsString(Consumer.from("my-group", "my-consumer"),
StreamOffset.create(KEY_1, ReadOffset.lastConsumed())));
actual.add(connection.xAdd(KEY_1, Collections.singletonMap(KEY_2, VALUE_2)));
actual.add(connection.xGroupCreate(KEY_1, ReadOffset.from("0"), "my-group"));
actual.add(connection.xReadGroupAsString(Consumer.from("my-group", "my-consumer"),
StreamOffset.create(KEY_1, ReadOffset.lastConsumed())));
actual.add(connection.xPending(KEY_1, "my-group", "my-consumer", org.springframework.data.domain.Range.open("-", "+"), 10L));
actual.add(connection.xPending(KEY_1, "my-group", "my-consumer",
org.springframework.data.domain.Range.open("-", "+"), 10L));
List<Object> results = getResults();
assertThat(results).hasSize(4);
PendingMessages pending = (PendingMessages) results.get(3);
List<Object> results = getResults();
assertThat(results).hasSize(4);
PendingMessages pending = (PendingMessages) results.get(3);
assertThat(pending.size()).isOne();
assertThat(pending.get(0).getConsumerName()).isEqualTo("my-consumer");
assertThat(pending.get(0).getGroupName()).isEqualTo("my-group");
assertThat(pending.get(0).getTotalDeliveryCount()).isOne();
assertThat(pending.get(0).getStringId()).isNotNull();
}
assertThat(pending.size()).isOne();
assertThat(pending.get(0).getConsumerName()).isEqualTo("my-consumer");
assertThat(pending.get(0).getGroupName()).isEqualTo("my-group");
assertThat(pending.get(0).getTotalDeliveryCount()).isOne();
assertThat(pending.get(0).getStringId()).isNotNull();
}
@Test // DATAREDIS-1084
@IfProfileValue(name = "redisVersion", value = "5.0")
@WithRedisDriver({ RedisDriver.LETTUCE })
public void xPendingShouldLoadPendingMessagesForNonExistingConsumer() {
@Test // DATAREDIS-1084
@IfProfileValue(name = "redisVersion", value = "5.0")
@WithRedisDriver({ RedisDriver.LETTUCE })
public void xPendingShouldLoadPendingMessagesForNonExistingConsumer() {
actual.add(connection.xAdd(KEY_1, Collections.singletonMap(KEY_2, VALUE_2)));
actual.add(connection.xGroupCreate(KEY_1, ReadOffset.from("0"), "my-group"));
actual.add(connection.xReadGroupAsString(Consumer.from("my-group", "my-consumer"),
StreamOffset.create(KEY_1, ReadOffset.lastConsumed())));
actual.add(connection.xAdd(KEY_1, Collections.singletonMap(KEY_2, VALUE_2)));
actual.add(connection.xGroupCreate(KEY_1, ReadOffset.from("0"), "my-group"));
actual.add(connection.xReadGroupAsString(Consumer.from("my-group", "my-consumer"),
StreamOffset.create(KEY_1, ReadOffset.lastConsumed())));
actual.add(connection.xPending(KEY_1, "my-group", "my-consumer-2", org.springframework.data.domain.Range.open("-", "+"), 10L));
actual.add(connection.xPending(KEY_1, "my-group", "my-consumer-2",
org.springframework.data.domain.Range.open("-", "+"), 10L));
List<Object> results = getResults();
assertThat(results).hasSize(4);
PendingMessages pending = (PendingMessages) results.get(3);
List<Object> results = getResults();
assertThat(results).hasSize(4);
PendingMessages pending = (PendingMessages) results.get(3);
assertThat(pending.size()).isZero();
}
assertThat(pending.size()).isZero();
}
@Test // DATAREDIS-1084
@IfProfileValue(name = "redisVersion", value = "5.0")
@WithRedisDriver({ RedisDriver.LETTUCE })
public void xPendingShouldLoadEmptyPendingMessages() {
@Test // DATAREDIS-1084
@IfProfileValue(name = "redisVersion", value = "5.0")
@WithRedisDriver({ RedisDriver.LETTUCE })
public void xPendingShouldLoadEmptyPendingMessages() {
actual.add(connection.xAdd(KEY_1, Collections.singletonMap(KEY_2, VALUE_2)));
actual.add(connection.xGroupCreate(KEY_1, ReadOffset.from("0"), "my-group"));
actual.add(connection.xAdd(KEY_1, Collections.singletonMap(KEY_2, VALUE_2)));
actual.add(connection.xGroupCreate(KEY_1, ReadOffset.from("0"), "my-group"));
actual.add(connection.xPending(KEY_1, "my-group", org.springframework.data.domain.Range.open("-", "+"), 10L));
actual.add(connection.xPending(KEY_1, "my-group", org.springframework.data.domain.Range.open("-", "+"), 10L));
List<Object> results = getResults();
assertThat(results).hasSize(3);
PendingMessages pending = (PendingMessages) results.get(2);
List<Object> results = getResults();
assertThat(results).hasSize(3);
PendingMessages pending = (PendingMessages) results.get(2);
assertThat(pending.size()).isZero();
}
assertThat(pending.size()).isZero();
}
@Test // DATAREDIS-1084
@IfProfileValue(name = "redisVersion", value = "5.0")
@WithRedisDriver({ RedisDriver.LETTUCE })
public void xClaim() throws InterruptedException {
actual.add(connection.xAdd(KEY_1, Collections.singletonMap(KEY_2, VALUE_2)));
actual.add(connection.xGroupCreate(KEY_1, ReadOffset.from("0"), "my-group"));
actual.add(connection.xReadGroupAsString(Consumer.from("my-group", "my-consumer"),
StreamOffset.create(KEY_1, ReadOffset.lastConsumed())));
List<MapRecord<String, String, String>> messages = (List<MapRecord<String, String, String>>) getResults().get(2);
TimeUnit.MILLISECONDS.sleep(5);
actual.add(connection.xClaim(KEY_1, "my-group", "my-consumer",
XClaimOptions.minIdle(Duration.ofMillis(1)).ids(messages.get(0).getId())));
List<MapRecord<String, String, String>> claimed = (List<MapRecord<String, String, String>>) getResults().get(3);
assertThat(claimed).containsAll(messages);
}
protected void verifyResults(List<Object> expected) {
assertThat(getResults()).isEqualTo(expected);

View File

@@ -126,6 +126,12 @@ abstract public class AbstractConnectionPipelineIntegrationTests extends Abstrac
super.scanShouldReadEntireValueRangeWhenIdividualScanIterationsReturnEmptyCollection();
}
@Test
@Ignore
public void xClaim() throws InterruptedException {
super.xClaim();
}
protected void initConnection() {
connection.openPipeline();
}

View File

@@ -114,6 +114,12 @@ abstract public class AbstractConnectionTransactionIntegrationTests extends Abst
super.scanShouldReadEntireValueRangeWhenIdividualScanIterationsReturnEmptyCollection();
}
@Test
@Ignore
public void xClaim() throws InterruptedException {
super.xClaim();
}
protected void initConnection() {
connection.multi();
}

View File

@@ -21,6 +21,7 @@ import static org.junit.Assume.*;
import io.lettuce.core.XReadArgs;
import reactor.test.StepVerifier;
import java.time.Duration;
import java.util.Collections;
import org.junit.Before;
@@ -28,6 +29,7 @@ import org.junit.Ignore;
import org.junit.Test;
import org.springframework.data.domain.Range;
import org.springframework.data.redis.RedisTestProfileValueSource;
import org.springframework.data.redis.connection.RedisStreamCommands.XClaimOptions;
import org.springframework.data.redis.connection.RedisZSetCommands.Limit;
import org.springframework.data.redis.connection.stream.Consumer;
import org.springframework.data.redis.connection.stream.ReadOffset;
@@ -291,8 +293,8 @@ public class LettuceReactiveStreamCommandsTests extends LettuceReactiveCommandsT
.then().as(StepVerifier::create) //
.verifyComplete();
connection.streamCommands().xPending(KEY_1_BBUFFER, "my-group", "my-consumer", Range.open("-", "+"), 10L).as(StepVerifier::create)
.assertNext(it -> {
connection.streamCommands().xPending(KEY_1_BBUFFER, "my-group", "my-consumer", Range.open("-", "+"), 10L)
.as(StepVerifier::create).assertNext(it -> {
assertThat(it.size()).isOne();
assertThat(it.get(0).getConsumerName()).isEqualTo("my-consumer");
@@ -316,8 +318,8 @@ public class LettuceReactiveStreamCommandsTests extends LettuceReactiveCommandsT
.then().as(StepVerifier::create) //
.verifyComplete();
connection.streamCommands().xPending(KEY_1_BBUFFER, "my-group", "my-consumer-2", Range.open("-", "+"), 10L).as(StepVerifier::create)
.assertNext(it -> {
connection.streamCommands().xPending(KEY_1_BBUFFER, "my-group", "my-consumer-2", Range.open("-", "+"), 10L)
.as(StepVerifier::create).assertNext(it -> {
assertThat(it.size()).isZero();
}).verifyComplete();
@@ -337,4 +339,26 @@ public class LettuceReactiveStreamCommandsTests extends LettuceReactiveCommandsT
}).verifyComplete();
}
@Test // DATAREDIS-1084
public void xClaim() {
String initialMessage = nativeCommands.xadd(KEY_1, KEY_1, VALUE_1);
nativeCommands.xgroupCreate(XReadArgs.StreamOffset.from(KEY_1, initialMessage), "my-group");
String expected = nativeCommands.xadd(KEY_1, KEY_2, VALUE_2);
connection.streamCommands()
.xReadGroup(Consumer.from("my-group", "my-consumer"),
StreamOffset.create(KEY_1_BBUFFER, ReadOffset.lastConsumed())) //
.delayElements(Duration.ofMillis(5)).next() //
.flatMapMany(record -> {
return connection.streamCommands().xClaim(KEY_1_BBUFFER, "my-group", "my-consumer",
XClaimOptions.minIdle(Duration.ofMillis(1)).ids(record.getId()));
}
).as(StepVerifier::create) //
.assertNext(it -> assertThat(it.getId().getValue()).isEqualTo(expected)) //
.verifyComplete();
}
}