DATAREDIS-697 - Add support for BITPOS.
We now support the BITPOS command throughout the sync and reactive api. Original pull request: #335.
This commit is contained in:
committed by
Mark Paluch
parent
8215f68d9f
commit
e9a3a5b6d9
@@ -44,6 +44,7 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.domain.Range.Bound;
|
||||
import org.springframework.data.geo.Circle;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.GeoResults;
|
||||
@@ -70,6 +71,8 @@ import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.core.types.RedisClientInfo;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
import org.springframework.data.redis.test.util.HexStringUtils;
|
||||
import org.springframework.data.redis.test.util.RedisClientRule;
|
||||
import org.springframework.data.redis.test.util.RedisDriver;
|
||||
import org.springframework.data.redis.test.util.WithRedisDriver;
|
||||
@@ -2822,6 +2825,27 @@ public abstract class AbstractConnectionIntegrationTests {
|
||||
verifyResults(Arrays.asList(new Object[] { 0L }));
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-697
|
||||
@IfProfileValue(name = "redisVersion", value = "2.8.7+")
|
||||
public void bitPosShouldReturnPositionCorrectly() {
|
||||
|
||||
actual.add(connection.set("bitpos-1".getBytes(), HexStringUtils.hexToBytes("fff000")));
|
||||
actual.add(connection.bitPos("bitpos-1", false));
|
||||
|
||||
verifyResults(Arrays.asList(new Object[] { true, 12L }));
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-697
|
||||
@IfProfileValue(name = "redisVersion", value = "2.8.7+")
|
||||
public void bitPosShouldReturnPositionInRangeCorrectly() {
|
||||
|
||||
actual.add(connection.set("bitpos-1".getBytes(), HexStringUtils.hexToBytes("fff0f0")));
|
||||
actual.add(connection.bitPos("bitpos-1", true,
|
||||
org.springframework.data.domain.Range.of(Bound.inclusive(2L), Bound.unbounded())));
|
||||
|
||||
verifyResults(Arrays.asList(new Object[] { true, 16L }));
|
||||
}
|
||||
|
||||
protected void verifyResults(List<Object> expected) {
|
||||
assertEquals(expected, getResults());
|
||||
}
|
||||
@@ -2845,4 +2869,5 @@ public abstract class AbstractConnectionIntegrationTests {
|
||||
return (!connection.exists(key));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.domain.Range.Bound;
|
||||
import org.springframework.data.geo.Circle;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.GeoResults;
|
||||
@@ -59,6 +60,7 @@ import org.springframework.data.redis.connection.RedisZSetCommands.Tuple;
|
||||
import org.springframework.data.redis.core.Cursor;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.test.util.HexStringUtils;
|
||||
import org.springframework.data.redis.test.util.MinimumRedisVersionRule;
|
||||
import org.springframework.data.redis.test.util.RedisClusterRule;
|
||||
import org.springframework.test.annotation.IfProfileValue;
|
||||
@@ -2271,4 +2273,23 @@ public class JedisClusterConnectionTests implements ClusterConnectionTests {
|
||||
assertThat(clusterConnection.keyCommands().unlink(KEY_1_BYTES), is(0L));
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-697
|
||||
@IfProfileValue(name = "redisVersion", value = "2.8.7+")
|
||||
public void bitPosShouldReturnPositionCorrectly() {
|
||||
|
||||
nativeConnection.set(KEY_1_BYTES, HexStringUtils.hexToBytes("fff000"));
|
||||
|
||||
assertThat(clusterConnection.stringCommands().bitPos(KEY_1_BYTES, false), is(12L));
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-697
|
||||
@IfProfileValue(name = "redisVersion", value = "2.8.7+")
|
||||
public void bitPosShouldReturnPositionInRangeCorrectly() {
|
||||
|
||||
nativeConnection.set(KEY_1_BYTES, HexStringUtils.hexToBytes("fff0f0"));
|
||||
|
||||
assertThat(clusterConnection.stringCommands().bitPos(KEY_1_BYTES, true,
|
||||
org.springframework.data.domain.Range.of(Bound.inclusive(2L), Bound.unbounded())), is(16L));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import io.lettuce.core.RedisURI.Builder;
|
||||
import io.lettuce.core.api.sync.RedisHLLCommands;
|
||||
import io.lettuce.core.cluster.RedisClusterClient;
|
||||
import io.lettuce.core.cluster.api.sync.RedisAdvancedClusterCommands;
|
||||
import io.lettuce.core.codec.ByteArrayCodec;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.time.Duration;
|
||||
@@ -38,6 +39,7 @@ import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.domain.Range.Bound;
|
||||
import org.springframework.data.geo.Circle;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.GeoResults;
|
||||
@@ -54,6 +56,7 @@ import org.springframework.data.redis.connection.jedis.JedisConverters;
|
||||
import org.springframework.data.redis.core.Cursor;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.test.util.HexStringUtils;
|
||||
import org.springframework.data.redis.test.util.MinimumRedisVersionRule;
|
||||
import org.springframework.data.redis.test.util.RedisClusterRule;
|
||||
import org.springframework.test.annotation.IfProfileValue;
|
||||
@@ -89,6 +92,7 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests {
|
||||
|
||||
RedisClusterClient client;
|
||||
RedisAdvancedClusterCommands<String, String> nativeConnection;
|
||||
RedisAdvancedClusterCommands<byte[], byte[]> binaryConnection;
|
||||
LettuceClusterConnection clusterConnection;
|
||||
|
||||
public static @ClassRule RedisClusterRule clusterAvailable = new RedisClusterRule();
|
||||
@@ -104,6 +108,7 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests {
|
||||
client = RedisClusterClient.create(LettuceTestClientResources.getSharedClientResources(),
|
||||
Builder.redis(CLUSTER_HOST, MASTER_NODE_1_PORT).withTimeout(500, TimeUnit.MILLISECONDS).build());
|
||||
nativeConnection = client.connect().sync();
|
||||
binaryConnection = client.connect(ByteArrayCodec.INSTANCE).sync();
|
||||
clusterConnection = new LettuceClusterConnection(client);
|
||||
}
|
||||
|
||||
@@ -112,6 +117,7 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests {
|
||||
|
||||
clusterConnection.serverCommands().flushDb();
|
||||
nativeConnection.getStatefulConnection().close();
|
||||
binaryConnection.getStatefulConnection().close();
|
||||
clusterConnection.close();
|
||||
client.shutdown(0, 0, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
@@ -2294,4 +2300,21 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests {
|
||||
public void unlinkReturnsZeroIfNoKeysTouched() {
|
||||
assertThat(clusterConnection.keyCommands().unlink(KEY_1_BYTES), is(0L));
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-697
|
||||
public void bitPosShouldReturnPositionCorrectly() {
|
||||
|
||||
binaryConnection.set(KEY_1_BYTES, HexStringUtils.hexToBytes("fff000"));
|
||||
|
||||
assertThat(clusterConnection.stringCommands().bitPos(KEY_1_BYTES, false), is(12L));
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-697
|
||||
public void bitPosShouldReturnPositionInRangeCorrectly() {
|
||||
|
||||
binaryConnection.set(KEY_1_BYTES, HexStringUtils.hexToBytes("fff0f0"));
|
||||
|
||||
assertThat(clusterConnection.stringCommands().bitPos(KEY_1_BYTES, true,
|
||||
org.springframework.data.domain.Range.of(Bound.inclusive(2L), Bound.unbounded())), is(16L));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceReactiveRedisConnection.ByteBufferCodec;
|
||||
import org.springframework.data.redis.test.util.LettuceRedisClientProvider;
|
||||
import org.springframework.data.redis.test.util.LettuceRedisClusterClientProvider;
|
||||
|
||||
@@ -75,10 +76,12 @@ public abstract class LettuceReactiveCommandsTestsBase {
|
||||
|
||||
@Parameterized.Parameter(value = 0) public LettuceConnectionProvider connectionProvider;
|
||||
@Parameterized.Parameter(value = 1) public LettuceConnectionProvider nativeConnectionProvider;
|
||||
@Parameterized.Parameter(value = 2) public Object displayName;
|
||||
@Parameterized.Parameter(value = 2) public LettuceConnectionProvider nativeBinaryConnectionProvider;
|
||||
@Parameterized.Parameter(value = 3) public Object displayName;
|
||||
|
||||
LettuceReactiveRedisConnection connection;
|
||||
RedisClusterCommands<String, String> nativeCommands;
|
||||
RedisClusterCommands<ByteBuffer, ByteBuffer> nativeBinaryCommands;
|
||||
|
||||
@Parameterized.Parameters(name = "{2}")
|
||||
public static List<Object[]> parameters() {
|
||||
@@ -92,11 +95,14 @@ public abstract class LettuceReactiveCommandsTestsBase {
|
||||
LettuceReactiveRedisConnection.CODEC);
|
||||
StandaloneConnectionProvider nativeConnectionProvider = new StandaloneConnectionProvider(standalone.getClient(),
|
||||
StringCodec.UTF8);
|
||||
StandaloneConnectionProvider nativeBinaryConnectionProvider = new StandaloneConnectionProvider(
|
||||
standalone.getClient(), ByteBufferCodec.INSTANCE);
|
||||
|
||||
parameters.add(new Object[] { standaloneProvider, nativeConnectionProvider, "Standalone" });
|
||||
parameters.add(
|
||||
new Object[] { standaloneProvider, nativeConnectionProvider, nativeBinaryConnectionProvider, "Standalone" });
|
||||
parameters.add(new Object[] {
|
||||
new LettucePoolingConnectionProvider(standaloneProvider, LettucePoolingClientConfiguration.builder().build()),
|
||||
nativeConnectionProvider, "Standalone/Pooled" });
|
||||
nativeConnectionProvider, nativeBinaryConnectionProvider, "Standalone/Pooled" });
|
||||
|
||||
if (cluster.test()) {
|
||||
|
||||
@@ -104,8 +110,11 @@ public abstract class LettuceReactiveCommandsTestsBase {
|
||||
LettuceReactiveRedisConnection.CODEC);
|
||||
ClusterConnectionProvider nativeClusterConnectionProvider = new ClusterConnectionProvider(cluster.getClient(),
|
||||
StringCodec.UTF8);
|
||||
ClusterConnectionProvider nativeBinaryClusterConnectionProvider = new ClusterConnectionProvider(
|
||||
cluster.getClient(), ByteBufferCodec.INSTANCE);
|
||||
|
||||
parameters.add(new Object[] { clusterProvider, nativeClusterConnectionProvider, "Cluster" });
|
||||
parameters.add(new Object[] { clusterProvider, nativeClusterConnectionProvider,
|
||||
nativeBinaryClusterConnectionProvider, "Cluster" });
|
||||
}
|
||||
|
||||
return parameters;
|
||||
@@ -116,11 +125,13 @@ public abstract class LettuceReactiveCommandsTestsBase {
|
||||
|
||||
if (nativeConnectionProvider instanceof StandaloneConnectionProvider) {
|
||||
nativeCommands = nativeConnectionProvider.getConnection(StatefulRedisConnection.class).sync();
|
||||
nativeBinaryCommands = nativeBinaryConnectionProvider.getConnection(StatefulRedisConnection.class).sync();
|
||||
this.connection = new LettuceReactiveRedisConnection(connectionProvider);
|
||||
|
||||
} else {
|
||||
ClusterConnectionProvider clusterConnectionProvider = (ClusterConnectionProvider) nativeConnectionProvider;
|
||||
nativeCommands = nativeConnectionProvider.getConnection(StatefulRedisClusterConnection.class).sync();
|
||||
nativeBinaryCommands = nativeBinaryConnectionProvider.getConnection(StatefulRedisClusterConnection.class).sync();
|
||||
this.connection = new LettuceReactiveRedisClusterConnection(connectionProvider,
|
||||
clusterConnectionProvider.getRedisClient());
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import static org.junit.Assume.*;
|
||||
import org.springframework.data.redis.util.ByteUtils;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.publisher.MonoOperator;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -36,6 +37,7 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.domain.Range.Bound;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection.ByteBufferResponse;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection.CommandResponse;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection.KeyCommand;
|
||||
@@ -43,7 +45,7 @@ import org.springframework.data.redis.connection.ReactiveRedisConnection.MultiVa
|
||||
import org.springframework.data.redis.connection.ReactiveStringCommands.SetCommand;
|
||||
import org.springframework.data.redis.connection.RedisStringCommands.BitOperation;
|
||||
import org.springframework.data.redis.core.types.Expiration;
|
||||
import org.springframework.data.redis.test.util.LettuceRedisClientProvider;
|
||||
import org.springframework.data.redis.test.util.HexStringUtils;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
@@ -399,4 +401,22 @@ public class LettuceReactiveStringCommandsTests extends LettuceReactiveCommandsT
|
||||
.expectNext(7L) //
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-697
|
||||
public void bitPosShouldReturnPositionCorrectly() {
|
||||
|
||||
nativeBinaryCommands.set(KEY_1_BBUFFER, ByteBuffer.wrap(HexStringUtils.hexToBytes("fff000")));
|
||||
|
||||
StepVerifier.create(connection.stringCommands().bitPos(KEY_1_BBUFFER, false)).expectNext(12L).verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATAREDIS-697
|
||||
public void bitPosShouldReturnPositionInRangeCorrectly() {
|
||||
|
||||
nativeBinaryCommands.set(KEY_1_BBUFFER, ByteBuffer.wrap(HexStringUtils.hexToBytes("fff0f0")));
|
||||
|
||||
StepVerifier.create(connection.stringCommands().bitPos(KEY_1_BBUFFER, true,
|
||||
org.springframework.data.domain.Range.of(Bound.inclusive(2L), Bound.unbounded()))).expectNext(16L).verifyComplete();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2018 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.test.util;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Utils for working with Hex Stings.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @currentRead Beyong the Shadows - Brent Weeks
|
||||
*/
|
||||
public class HexStringUtils {
|
||||
|
||||
/**
|
||||
* Convert a given HEX {@link String} to its byte representation.
|
||||
*
|
||||
* @param source must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static byte[] hexToBytes(String source) {
|
||||
|
||||
Assert.notNull(source, "Source must not be null!");
|
||||
int len = source.length();
|
||||
|
||||
byte[] data = new byte[len / 2];
|
||||
for (int i = 0; i < len; i += 2) {
|
||||
data[i / 2] = (byte) ((Character.digit(source.charAt(i), 16) << 4) + Character.digit(source.charAt(i + 1), 16));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user