From ace7c40800cc9b37e3c191ed0a3379080d59b20c Mon Sep 17 00:00:00 2001 From: "viktoriya.kutsarova" Date: Tue, 28 Oct 2025 14:28:47 +0200 Subject: [PATCH] Expand bitwise operations with DIFF, DIFF1, ANDOR, ONE. Signed-off-by: viktoriya.kutsarova --- .../connection/ReactiveStringCommands.java | 2 +- .../redis/connection/RedisStringCommands.java | 2 +- .../connection/jedis/JedisConverters.java | 4 + .../LettuceReactiveStringCommands.java | 6 +- .../lettuce/LettuceStringCommands.java | 5 + .../AbstractConnectionIntegrationTests.java | 36 +++++++ ...ultStringRedisConnectionPipelineTests.java | 84 ++++++++++++++++ ...tStringRedisConnectionPipelineTxTests.java | 84 ++++++++++++++++ .../DefaultStringRedisConnectionTests.java | 98 +++++++++++++++++++ .../DefaultStringRedisConnectionTxTests.java | 84 ++++++++++++++++ .../jedis/JedisClusterConnectionTests.java | 77 +++++++++++++++ .../LettuceClusterConnectionTests.java | 77 +++++++++++++++ ...ClusterStringCommandsIntegrationTests.java | 65 ++++++++++++ ...eactiveStringCommandsIntegrationTests.java | 65 ++++++++++++ 14 files changed, 686 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/springframework/data/redis/connection/ReactiveStringCommands.java b/src/main/java/org/springframework/data/redis/connection/ReactiveStringCommands.java index ae941374f0..af8f785490 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReactiveStringCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/ReactiveStringCommands.java @@ -1289,7 +1289,7 @@ default Mono bitPos(ByteBuffer key, boolean bit, Range range) { } /** - * Emmit the the position of the first bit set to given {@code bit} in a string. Get the length of the value stored at + * Emit the position of the first bit set to given {@code bit} in a string. Get the length of the value stored at * {@literal key}. * * @param commands must not be {@literal null}. diff --git a/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java index 9f3c7c15db..e3dd392c87 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java @@ -38,7 +38,7 @@ public interface RedisStringCommands { enum BitOperation { - AND, OR, XOR, NOT; + AND, OR, XOR, NOT, DIFF, DIFF1, ANDOR, ONE; } /** diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConverters.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConverters.java index 98ba6a5525..b6f703ccc3 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConverters.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConverters.java @@ -285,6 +285,10 @@ public static BitOP toBitOp(BitOperation bitOp) { case OR -> BitOP.OR; case NOT -> BitOP.NOT; case XOR -> BitOP.XOR; + case DIFF -> BitOP.DIFF; + case DIFF1 -> BitOP.DIFF1; + case ANDOR -> BitOP.ANDOR; + case ONE -> BitOP.ONE; }; } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStringCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStringCommands.java index 20cee30e23..6ca36d10fa 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStringCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStringCommands.java @@ -22,6 +22,7 @@ import reactor.core.publisher.Mono; import java.nio.ByteBuffer; +import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -368,7 +369,10 @@ public Flux> bitOp(Publisher c Assert.isTrue(sourceKeys.length == 1, "BITOP NOT does not allow more than 1 source key."); yield reactiveCommands.bitopNot(destinationKey, sourceKeys[0]); } - default -> throw new IllegalArgumentException("Unknown BITOP '%s'".formatted(command.getBitOp())); + case DIFF -> reactiveCommands.bitopDiff(destinationKey, sourceKeys[0], Arrays.copyOfRange(sourceKeys, 1, sourceKeys.length)); + case DIFF1 -> reactiveCommands.bitopDiff1(destinationKey, sourceKeys[0], Arrays.copyOfRange(sourceKeys, 1, sourceKeys.length)); + case ANDOR -> reactiveCommands.bitopAndor(destinationKey, sourceKeys[0], Arrays.copyOfRange(sourceKeys, 1, sourceKeys.length)); + case ONE -> reactiveCommands.bitopOne(destinationKey, sourceKeys); }; return result.map(value -> new NumericResponse<>(command, value)); diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStringCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStringCommands.java index 87ab4b3e83..ffb3513002 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStringCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStringCommands.java @@ -18,6 +18,7 @@ import io.lettuce.core.BitFieldArgs; import io.lettuce.core.api.async.RedisStringAsyncCommands; +import java.util.Arrays; import java.util.List; import java.util.Map; @@ -307,6 +308,10 @@ public Long bitOp(@NonNull BitOperation op, byte @NonNull [] destination, byte @ } yield it.bitopNot(destination, keys[0]); } + case DIFF -> it.bitopDiff(destination, keys[0], Arrays.copyOfRange(keys, 1, keys.length)); + case DIFF1 -> it.bitopDiff1(destination, keys[0], Arrays.copyOfRange(keys, 1, keys.length)); + case ANDOR -> it.bitopAndor(destination, keys[0], Arrays.copyOfRange(keys, 1, keys.length)); + case ONE -> it.bitopOne(destination, keys); }); } diff --git a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java index d09bb78ddf..209e89e179 100644 --- a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java @@ -571,6 +571,42 @@ void testBitOpNotMultipleSources() { .isThrownBy(() -> connection.bitOp(BitOperation.NOT, "key3", "key1", "key2")); } + @Test + void testBitOpDiff() { + + actual.add(connection.set("key1", "foobar")); + actual.add(connection.set("key2", "abcdef")); + actual.add(connection.bitOp(BitOperation.DIFF, "key3", "key1", "key2")); + verifyResults(Arrays.asList(Boolean.TRUE, Boolean.TRUE, 6L)); + } + + @Test + void testBitOpDiff1() { + + actual.add(connection.set("key1", "foobar")); + actual.add(connection.set("key2", "abcdef")); + actual.add(connection.bitOp(BitOperation.DIFF1, "key3", "key1", "key2")); + verifyResults(Arrays.asList(Boolean.TRUE, Boolean.TRUE, 6L)); + } + + @Test + void testBitOpAndor() { + + actual.add(connection.set("key1", "foo")); + actual.add(connection.set("key2", "bar")); + actual.add(connection.bitOp(BitOperation.ANDOR, "key3", "key1", "key2")); + verifyResults(Arrays.asList(Boolean.TRUE, Boolean.TRUE, 3L)); + } + + @Test + void testBitOpOne() { + + actual.add(connection.set("key1", "foo")); + actual.add(connection.set("key2", "bar")); + actual.add(connection.bitOp(BitOperation.ONE, "key3", "key1", "key2")); + verifyResults(Arrays.asList(Boolean.TRUE, Boolean.TRUE, 3L)); + } + @Test @EnabledOnCommand("COPY") void testCopy() { diff --git a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTests.java b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTests.java index 0d977e00fa..1b290c2f0a 100644 --- a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTests.java +++ b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTests.java @@ -1010,6 +1010,90 @@ public void testBitOp() { super.testBitOp(); } + @Test + public void testBitOpOrBytes() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).closePipeline(); + super.testBitOpOrBytes(); + } + + @Test + public void testBitOpOr() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).closePipeline(); + super.testBitOpOr(); + } + + @Test + public void testBitOpXorBytes() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).closePipeline(); + super.testBitOpXorBytes(); + } + + @Test + public void testBitOpXor() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).closePipeline(); + super.testBitOpXor(); + } + + @Test + public void testBitOpNotBytes() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).closePipeline(); + super.testBitOpNotBytes(); + } + + @Test + public void testBitOpNot() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).closePipeline(); + super.testBitOpNot(); + } + + @Test + public void testBitOpDiffBytes() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).closePipeline(); + super.testBitOpDiffBytes(); + } + + @Test + public void testBitOpDiff() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).closePipeline(); + super.testBitOpDiff(); + } + + @Test + public void testBitOpDiff1Bytes() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).closePipeline(); + super.testBitOpDiff1Bytes(); + } + + @Test + public void testBitOpDiff1() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).closePipeline(); + super.testBitOpDiff1(); + } + + @Test + public void testBitOpAndorBytes() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).closePipeline(); + super.testBitOpAndorBytes(); + } + + @Test + public void testBitOpAndor() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).closePipeline(); + super.testBitOpAndor(); + } + + @Test + public void testBitOpOneBytes() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).closePipeline(); + super.testBitOpOneBytes(); + } + + @Test + public void testBitOpOne() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).closePipeline(); + super.testBitOpOne(); + } + @Test public void testSUnionBytes() { doReturn(Collections.singletonList(bytesSet)).when(nativeConnection).closePipeline(); diff --git a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTxTests.java b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTxTests.java index 6ad92f531b..88da63cd0a 100644 --- a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTxTests.java +++ b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionPipelineTxTests.java @@ -1025,6 +1025,90 @@ public void testBitOp() { super.testBitOp(); } + @Test + public void testBitOpOrBytes() { + doReturn(Collections.singletonList(Collections.singletonList(5L))).when(nativeConnection).closePipeline(); + super.testBitOpOrBytes(); + } + + @Test + public void testBitOpOr() { + doReturn(Collections.singletonList(Collections.singletonList(5L))).when(nativeConnection).closePipeline(); + super.testBitOpOr(); + } + + @Test + public void testBitOpXorBytes() { + doReturn(Collections.singletonList(Collections.singletonList(5L))).when(nativeConnection).closePipeline(); + super.testBitOpXorBytes(); + } + + @Test + public void testBitOpXor() { + doReturn(Collections.singletonList(Collections.singletonList(5L))).when(nativeConnection).closePipeline(); + super.testBitOpXor(); + } + + @Test + public void testBitOpNotBytes() { + doReturn(Collections.singletonList(Collections.singletonList(5L))).when(nativeConnection).closePipeline(); + super.testBitOpNotBytes(); + } + + @Test + public void testBitOpNot() { + doReturn(Collections.singletonList(Collections.singletonList(5L))).when(nativeConnection).closePipeline(); + super.testBitOpNot(); + } + + @Test + public void testBitOpDiffBytes() { + doReturn(Collections.singletonList(Collections.singletonList(5L))).when(nativeConnection).closePipeline(); + super.testBitOpDiffBytes(); + } + + @Test + public void testBitOpDiff() { + doReturn(Collections.singletonList(Collections.singletonList(5L))).when(nativeConnection).closePipeline(); + super.testBitOpDiff(); + } + + @Test + public void testBitOpDiff1Bytes() { + doReturn(Collections.singletonList(Collections.singletonList(5L))).when(nativeConnection).closePipeline(); + super.testBitOpDiff1Bytes(); + } + + @Test + public void testBitOpDiff1() { + doReturn(Collections.singletonList(Collections.singletonList(5L))).when(nativeConnection).closePipeline(); + super.testBitOpDiff1(); + } + + @Test + public void testBitOpAndorBytes() { + doReturn(Collections.singletonList(Collections.singletonList(5L))).when(nativeConnection).closePipeline(); + super.testBitOpAndorBytes(); + } + + @Test + public void testBitOpAndor() { + doReturn(Collections.singletonList(Collections.singletonList(5L))).when(nativeConnection).closePipeline(); + super.testBitOpAndor(); + } + + @Test + public void testBitOpOneBytes() { + doReturn(Collections.singletonList(Collections.singletonList(5L))).when(nativeConnection).closePipeline(); + super.testBitOpOneBytes(); + } + + @Test + public void testBitOpOne() { + doReturn(Collections.singletonList(Collections.singletonList(5L))).when(nativeConnection).closePipeline(); + super.testBitOpOne(); + } + @Test public void testSUnionBytes() { doReturn(Collections.singletonList(Collections.singletonList(bytesSet))).when(nativeConnection).closePipeline(); diff --git a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTests.java b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTests.java index e57589012a..8eab7d5061 100644 --- a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTests.java +++ b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTests.java @@ -1266,6 +1266,104 @@ public void testBitOp() { verifyResults(Collections.singletonList(5L)); } + @Test + public void testBitOpOrBytes() { + doReturn(5L).when(nativeConnection).bitOp(BitOperation.OR, fooBytes, barBytes); + actual.add(connection.bitOp(BitOperation.OR, fooBytes, barBytes)); + verifyResults(Collections.singletonList(5L)); + } + + @Test + public void testBitOpOr() { + doReturn(5L).when(nativeConnection).bitOp(BitOperation.OR, fooBytes, barBytes); + actual.add(connection.bitOp(BitOperation.OR, foo, bar)); + verifyResults(Collections.singletonList(5L)); + } + + @Test + public void testBitOpXorBytes() { + doReturn(5L).when(nativeConnection).bitOp(BitOperation.XOR, fooBytes, barBytes); + actual.add(connection.bitOp(BitOperation.XOR, fooBytes, barBytes)); + verifyResults(Collections.singletonList(5L)); + } + + @Test + public void testBitOpXor() { + doReturn(5L).when(nativeConnection).bitOp(BitOperation.XOR, fooBytes, barBytes); + actual.add(connection.bitOp(BitOperation.XOR, foo, bar)); + verifyResults(Collections.singletonList(5L)); + } + + @Test + public void testBitOpNotBytes() { + doReturn(5L).when(nativeConnection).bitOp(BitOperation.NOT, fooBytes, barBytes); + actual.add(connection.bitOp(BitOperation.NOT, fooBytes, barBytes)); + verifyResults(Collections.singletonList(5L)); + } + + @Test + public void testBitOpNot() { + doReturn(5L).when(nativeConnection).bitOp(BitOperation.NOT, fooBytes, barBytes); + actual.add(connection.bitOp(BitOperation.NOT, foo, bar)); + verifyResults(Collections.singletonList(5L)); + } + + @Test + public void testBitOpDiffBytes() { + doReturn(5L).when(nativeConnection).bitOp(BitOperation.DIFF, fooBytes, barBytes); + actual.add(connection.bitOp(BitOperation.DIFF, fooBytes, barBytes)); + verifyResults(Collections.singletonList(5L)); + } + + @Test + public void testBitOpDiff() { + doReturn(5L).when(nativeConnection).bitOp(BitOperation.DIFF, fooBytes, barBytes); + actual.add(connection.bitOp(BitOperation.DIFF, foo, bar)); + verifyResults(Collections.singletonList(5L)); + } + + @Test + public void testBitOpDiff1Bytes() { + doReturn(5L).when(nativeConnection).bitOp(BitOperation.DIFF1, fooBytes, barBytes); + actual.add(connection.bitOp(BitOperation.DIFF1, fooBytes, barBytes)); + verifyResults(Collections.singletonList(5L)); + } + + @Test + public void testBitOpDiff1() { + doReturn(5L).when(nativeConnection).bitOp(BitOperation.DIFF1, fooBytes, barBytes); + actual.add(connection.bitOp(BitOperation.DIFF1, foo, bar)); + verifyResults(Collections.singletonList(5L)); + } + + @Test + public void testBitOpAndorBytes() { + doReturn(5L).when(nativeConnection).bitOp(BitOperation.ANDOR, fooBytes, barBytes); + actual.add(connection.bitOp(BitOperation.ANDOR, fooBytes, barBytes)); + verifyResults(Collections.singletonList(5L)); + } + + @Test + public void testBitOpAndor() { + doReturn(5L).when(nativeConnection).bitOp(BitOperation.ANDOR, fooBytes, barBytes); + actual.add(connection.bitOp(BitOperation.ANDOR, foo, bar)); + verifyResults(Collections.singletonList(5L)); + } + + @Test + public void testBitOpOneBytes() { + doReturn(5L).when(nativeConnection).bitOp(BitOperation.ONE, fooBytes, barBytes); + actual.add(connection.bitOp(BitOperation.ONE, fooBytes, barBytes)); + verifyResults(Collections.singletonList(5L)); + } + + @Test + public void testBitOpOne() { + doReturn(5L).when(nativeConnection).bitOp(BitOperation.ONE, fooBytes, barBytes); + actual.add(connection.bitOp(BitOperation.ONE, foo, bar)); + verifyResults(Collections.singletonList(5L)); + } + @Test public void testSUnionBytes() { doReturn(bytesSet).when(nativeConnection).sUnion(fooBytes, barBytes); diff --git a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTxTests.java b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTxTests.java index 0e8fa6c1fb..3c9cdf0d62 100644 --- a/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTxTests.java +++ b/src/test/java/org/springframework/data/redis/connection/DefaultStringRedisConnectionTxTests.java @@ -995,6 +995,90 @@ public void testBitOp() { super.testBitOp(); } + @Test + public void testBitOpOrBytes() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).exec(); + super.testBitOpOrBytes(); + } + + @Test + public void testBitOpOr() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).exec(); + super.testBitOpOr(); + } + + @Test + public void testBitOpXorBytes() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).exec(); + super.testBitOpXorBytes(); + } + + @Test + public void testBitOpXor() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).exec(); + super.testBitOpXor(); + } + + @Test + public void testBitOpNotBytes() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).exec(); + super.testBitOpNotBytes(); + } + + @Test + public void testBitOpNot() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).exec(); + super.testBitOpNot(); + } + + @Test + public void testBitOpDiffBytes() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).exec(); + super.testBitOpDiffBytes(); + } + + @Test + public void testBitOpDiff() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).exec(); + super.testBitOpDiff(); + } + + @Test + public void testBitOpDiff1Bytes() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).exec(); + super.testBitOpDiff1Bytes(); + } + + @Test + public void testBitOpDiff1() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).exec(); + super.testBitOpDiff1(); + } + + @Test + public void testBitOpAndorBytes() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).exec(); + super.testBitOpAndorBytes(); + } + + @Test + public void testBitOpAndor() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).exec(); + super.testBitOpAndor(); + } + + @Test + public void testBitOpOneBytes() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).exec(); + super.testBitOpOneBytes(); + } + + @Test + public void testBitOpOne() { + doReturn(Collections.singletonList(5L)).when(nativeConnection).exec(); + super.testBitOpOne(); + } + @Test public void testSUnionBytes() { doReturn(Collections.singletonList(bytesSet)).when(nativeConnection).exec(); diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionTests.java index 08ee13c910..497fabeccb 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionTests.java @@ -78,6 +78,7 @@ * @author Pavel Khokhlov * @author Dennis Neufeld * @author Tihomir Mateev + * @author Viktoriya Kutsarova */ @EnabledOnRedisClusterAvailable @ExtendWith(JedisExtension.class) @@ -191,6 +192,82 @@ void bitOpShouldWorkCorrectly() { assertThat(nativeConnection.get(SAME_SLOT_KEY_3)).isEqualTo("bab"); } + @Test + void bitOpOrShouldWorkCorrectly() { + + nativeConnection.set(SAME_SLOT_KEY_1, "foo"); + nativeConnection.set(SAME_SLOT_KEY_2, "ugh"); + + clusterConnection.bitOp(BitOperation.OR, SAME_SLOT_KEY_3_BYTES, SAME_SLOT_KEY_1_BYTES, SAME_SLOT_KEY_2_BYTES); + + assertThat(nativeConnection.get(SAME_SLOT_KEY_3)).isEqualTo("woo"); + } + + @Test + void bitOpXorShouldWorkCorrectly() { + + nativeConnection.set(SAME_SLOT_KEY_1, "aaa"); + nativeConnection.set(SAME_SLOT_KEY_2, "___"); + + clusterConnection.bitOp(BitOperation.XOR, SAME_SLOT_KEY_3_BYTES, SAME_SLOT_KEY_1_BYTES, SAME_SLOT_KEY_2_BYTES); + + assertThat(nativeConnection.get(SAME_SLOT_KEY_3)).isEqualTo(">>>"); + } + + @Test + void bitOpNotShouldWorkCorrectly() { + + nativeConnection.set(SAME_SLOT_KEY_1, "foo"); + + clusterConnection.bitOp(BitOperation.NOT, SAME_SLOT_KEY_3_BYTES, SAME_SLOT_KEY_1_BYTES); + + assertThat(nativeConnection.get(SAME_SLOT_KEY_3)).isNotNull(); + } + + @Test + void bitOpDiffShouldWorkCorrectly() { + + nativeConnection.set(SAME_SLOT_KEY_1, "foobar"); + nativeConnection.set(SAME_SLOT_KEY_2, "abcdef"); + + clusterConnection.bitOp(BitOperation.DIFF, SAME_SLOT_KEY_3_BYTES, SAME_SLOT_KEY_1_BYTES, SAME_SLOT_KEY_2_BYTES); + + assertThat(nativeConnection.get(SAME_SLOT_KEY_3)).isNotNull(); + } + + @Test + void bitOpDiff1ShouldWorkCorrectly() { + + nativeConnection.set(SAME_SLOT_KEY_1, "foobar"); + nativeConnection.set(SAME_SLOT_KEY_2, "abcdef"); + + clusterConnection.bitOp(BitOperation.DIFF1, SAME_SLOT_KEY_3_BYTES, SAME_SLOT_KEY_1_BYTES, SAME_SLOT_KEY_2_BYTES); + + assertThat(nativeConnection.get(SAME_SLOT_KEY_3)).isNotNull(); + } + + @Test + void bitOpAndorShouldWorkCorrectly() { + + nativeConnection.set(SAME_SLOT_KEY_1, "foo"); + nativeConnection.set(SAME_SLOT_KEY_2, "bar"); + + clusterConnection.bitOp(BitOperation.ANDOR, SAME_SLOT_KEY_3_BYTES, SAME_SLOT_KEY_1_BYTES, SAME_SLOT_KEY_2_BYTES); + + assertThat(nativeConnection.get(SAME_SLOT_KEY_3)).isNotNull(); + } + + @Test + void bitOpOneShouldWorkCorrectly() { + + nativeConnection.set(SAME_SLOT_KEY_1, "foo"); + nativeConnection.set(SAME_SLOT_KEY_2, "bar"); + + clusterConnection.bitOp(BitOperation.ONE, SAME_SLOT_KEY_3_BYTES, SAME_SLOT_KEY_1_BYTES, SAME_SLOT_KEY_2_BYTES); + + assertThat(nativeConnection.get(SAME_SLOT_KEY_3)).isNotNull(); + } + @Test // DATAREDIS-315 public void blPopShouldPopElementCorrectly() { diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java index af6285dad9..562d50d93b 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java @@ -76,6 +76,7 @@ * @author Mark Paluch * @author Dennis Neufeld * @author Tihomir Mateev + * @author Viktoriya Kutsarova */ @SuppressWarnings("deprecation") @EnabledOnRedisClusterAvailable @@ -279,6 +280,82 @@ void bitOpShouldWorkCorrectly() { assertThat(nativeConnection.get(SAME_SLOT_KEY_3)).isEqualTo("bab"); } + @Test + void bitOpOrShouldWorkCorrectly() { + + nativeConnection.set(SAME_SLOT_KEY_1, "foo"); + nativeConnection.set(SAME_SLOT_KEY_2, "ugh"); + + clusterConnection.bitOp(BitOperation.OR, SAME_SLOT_KEY_3_BYTES, SAME_SLOT_KEY_1_BYTES, SAME_SLOT_KEY_2_BYTES); + + assertThat(nativeConnection.get(SAME_SLOT_KEY_3)).isEqualTo("woo"); + } + + @Test + void bitOpXorShouldWorkCorrectly() { + + nativeConnection.set(SAME_SLOT_KEY_1, "aaa"); + nativeConnection.set(SAME_SLOT_KEY_2, "___"); + + clusterConnection.bitOp(BitOperation.XOR, SAME_SLOT_KEY_3_BYTES, SAME_SLOT_KEY_1_BYTES, SAME_SLOT_KEY_2_BYTES); + + assertThat(nativeConnection.get(SAME_SLOT_KEY_3)).isEqualTo(">>>"); + } + + @Test + void bitOpNotShouldWorkCorrectly() { + + nativeConnection.set(SAME_SLOT_KEY_1, "foo"); + + clusterConnection.bitOp(BitOperation.NOT, SAME_SLOT_KEY_3_BYTES, SAME_SLOT_KEY_1_BYTES); + + assertThat(nativeConnection.get(SAME_SLOT_KEY_3)).isNotNull(); + } + + @Test + void bitOpDiffShouldWorkCorrectly() { + + nativeConnection.set(SAME_SLOT_KEY_1, "foobar"); + nativeConnection.set(SAME_SLOT_KEY_2, "abcdef"); + + clusterConnection.bitOp(BitOperation.DIFF, SAME_SLOT_KEY_3_BYTES, SAME_SLOT_KEY_1_BYTES, SAME_SLOT_KEY_2_BYTES); + + assertThat(nativeConnection.get(SAME_SLOT_KEY_3)).isNotNull(); + } + + @Test + void bitOpDiff1ShouldWorkCorrectly() { + + nativeConnection.set(SAME_SLOT_KEY_1, "foobar"); + nativeConnection.set(SAME_SLOT_KEY_2, "abcdef"); + + clusterConnection.bitOp(BitOperation.DIFF1, SAME_SLOT_KEY_3_BYTES, SAME_SLOT_KEY_1_BYTES, SAME_SLOT_KEY_2_BYTES); + + assertThat(nativeConnection.get(SAME_SLOT_KEY_3)).isNotNull(); + } + + @Test + void bitOpAndorShouldWorkCorrectly() { + + nativeConnection.set(SAME_SLOT_KEY_1, "foo"); + nativeConnection.set(SAME_SLOT_KEY_2, "bar"); + + clusterConnection.bitOp(BitOperation.ANDOR, SAME_SLOT_KEY_3_BYTES, SAME_SLOT_KEY_1_BYTES, SAME_SLOT_KEY_2_BYTES); + + assertThat(nativeConnection.get(SAME_SLOT_KEY_3)).isNotNull(); + } + + @Test + void bitOpOneShouldWorkCorrectly() { + + nativeConnection.set(SAME_SLOT_KEY_1, "foo"); + nativeConnection.set(SAME_SLOT_KEY_2, "bar"); + + clusterConnection.bitOp(BitOperation.ONE, SAME_SLOT_KEY_3_BYTES, SAME_SLOT_KEY_1_BYTES, SAME_SLOT_KEY_2_BYTES); + + assertThat(nativeConnection.get(SAME_SLOT_KEY_3)).isNotNull(); + } + @Test // DATAREDIS-315 public void blPopShouldPopElementCorrectly() { diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveClusterStringCommandsIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveClusterStringCommandsIntegrationTests.java index 1f56137cf2..3b3143e716 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveClusterStringCommandsIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveClusterStringCommandsIntegrationTests.java @@ -83,6 +83,27 @@ void bitOpOrShouldWorkAsExpectedWhenKeysMapToSameSlot() { assertThat(nativeCommands.get(SAME_SLOT_KEY_3)).isEqualTo(VALUE_3); } + @Test + void bitOpXorShouldWorkAsExpectedWhenKeysMapToSameSlot() { + + nativeCommands.set(SAME_SLOT_KEY_1, VALUE_1); + nativeCommands.set(SAME_SLOT_KEY_2, VALUE_2); + + assertThat(connection.stringCommands().bitOp(Arrays.asList(SAME_SLOT_KEY_1_BBUFFER, SAME_SLOT_KEY_2_BBUFFER), + RedisStringCommands.BitOperation.XOR, SAME_SLOT_KEY_3_BBUFFER).block()).isEqualTo(7L); + assertThat(nativeCommands.get(SAME_SLOT_KEY_3)).isNotNull(); + } + + @Test + void bitOpNotShouldWorkAsExpectedWhenKeysMapToSameSlot() { + + nativeCommands.set(SAME_SLOT_KEY_1, VALUE_1); + + assertThat(connection.stringCommands().bitOp(Arrays.asList(SAME_SLOT_KEY_1_BBUFFER), + RedisStringCommands.BitOperation.NOT, SAME_SLOT_KEY_3_BBUFFER).block()).isEqualTo(7L); + assertThat(nativeCommands.get(SAME_SLOT_KEY_3)).isNotNull(); + } + @Test // DATAREDIS-525 void bitNotShouldThrowExceptionWhenMoreThanOnSourceKeyAndKeysMapToSameSlot() { assertThatIllegalArgumentException().isThrownBy( @@ -90,4 +111,48 @@ void bitNotShouldThrowExceptionWhenMoreThanOnSourceKeyAndKeysMapToSameSlot() { RedisStringCommands.BitOperation.NOT, SAME_SLOT_KEY_3_BBUFFER).block()); } + @Test + void bitOpDiffShouldWorkAsExpectedWhenKeysMapToSameSlot() { + + nativeCommands.set(SAME_SLOT_KEY_1, "foobar"); + nativeCommands.set(SAME_SLOT_KEY_2, "abcdef"); + + assertThat(connection.stringCommands().bitOp(Arrays.asList(SAME_SLOT_KEY_1_BBUFFER, SAME_SLOT_KEY_2_BBUFFER), + RedisStringCommands.BitOperation.DIFF, SAME_SLOT_KEY_3_BBUFFER).block()).isEqualTo(6L); + assertThat(nativeCommands.get(SAME_SLOT_KEY_3)).isNotNull(); + } + + @Test + void bitOpDiff1ShouldWorkAsExpectedWhenKeysMapToSameSlot() { + + nativeCommands.set(SAME_SLOT_KEY_1, "foobar"); + nativeCommands.set(SAME_SLOT_KEY_2, "abcdef"); + + assertThat(connection.stringCommands().bitOp(Arrays.asList(SAME_SLOT_KEY_1_BBUFFER, SAME_SLOT_KEY_2_BBUFFER), + RedisStringCommands.BitOperation.DIFF1, SAME_SLOT_KEY_3_BBUFFER).block()).isEqualTo(6L); + assertThat(nativeCommands.get(SAME_SLOT_KEY_3)).isNotNull(); + } + + @Test + void bitOpAndorShouldWorkAsExpectedWhenKeysMapToSameSlot() { + + nativeCommands.set(SAME_SLOT_KEY_1, VALUE_1); + nativeCommands.set(SAME_SLOT_KEY_2, VALUE_2); + + assertThat(connection.stringCommands().bitOp(Arrays.asList(SAME_SLOT_KEY_1_BBUFFER, SAME_SLOT_KEY_2_BBUFFER), + RedisStringCommands.BitOperation.ANDOR, SAME_SLOT_KEY_3_BBUFFER).block()).isEqualTo(7L); + assertThat(nativeCommands.get(SAME_SLOT_KEY_3)).isNotNull(); + } + + @Test + void bitOpOneShouldWorkAsExpectedWhenKeysMapToSameSlot() { + + nativeCommands.set(SAME_SLOT_KEY_1, VALUE_1); + nativeCommands.set(SAME_SLOT_KEY_2, VALUE_2); + + assertThat(connection.stringCommands().bitOp(Arrays.asList(SAME_SLOT_KEY_1_BBUFFER, SAME_SLOT_KEY_2_BBUFFER), + RedisStringCommands.BitOperation.ONE, SAME_SLOT_KEY_3_BBUFFER).block()).isEqualTo(7L); + assertThat(nativeCommands.get(SAME_SLOT_KEY_3)).isNotNull(); + } + } diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStringCommandsIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStringCommandsIntegrationTests.java index 5f233cd40c..5634d283a6 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStringCommandsIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStringCommandsIntegrationTests.java @@ -61,6 +61,7 @@ * @author Christoph Strobl * @author Mark Paluch * @author Michele Mancioppi + * @author Viktoriya Kutsarova */ @ParameterizedClass public class LettuceReactiveStringCommandsIntegrationTests extends LettuceReactiveCommandsTestSupport { @@ -508,6 +509,70 @@ void bitNotShouldThrowExceptionWhenMoreThanOnSourceKey() { .verify(); } + @Test + void bitOpDiffShouldWorkAsExpected() { + + assumeTrue(connectionProvider instanceof StandaloneConnectionProvider); + + nativeCommands.set(KEY_1, "foobar"); + nativeCommands.set(KEY_2, "abcdef"); + + connection.stringCommands().bitOp(Arrays.asList(KEY_1_BBUFFER, KEY_2_BBUFFER), BitOperation.DIFF, KEY_3_BBUFFER) + .as(StepVerifier::create) // + .expectNext(6L) // + .verifyComplete(); + + assertThat(nativeCommands.get(KEY_3)).isNotNull(); + } + + @Test + void bitOpDiff1ShouldWorkAsExpected() { + + assumeTrue(connectionProvider instanceof StandaloneConnectionProvider); + + nativeCommands.set(KEY_1, "foobar"); + nativeCommands.set(KEY_2, "abcdef"); + + connection.stringCommands().bitOp(Arrays.asList(KEY_1_BBUFFER, KEY_2_BBUFFER), BitOperation.DIFF1, KEY_3_BBUFFER) + .as(StepVerifier::create) // + .expectNext(6L) // + .verifyComplete(); + + assertThat(nativeCommands.get(KEY_3)).isNotNull(); + } + + @Test + void bitOpAndorShouldWorkAsExpected() { + + assumeTrue(connectionProvider instanceof StandaloneConnectionProvider); + + nativeCommands.set(KEY_1, "foo"); + nativeCommands.set(KEY_2, "bar"); + + connection.stringCommands().bitOp(Arrays.asList(KEY_1_BBUFFER, KEY_2_BBUFFER), BitOperation.ANDOR, KEY_3_BBUFFER) + .as(StepVerifier::create) // + .expectNext(3L) // + .verifyComplete(); + + assertThat(nativeCommands.get(KEY_3)).isNotNull(); + } + + @Test + void bitOpOneShouldWorkAsExpected() { + + assumeTrue(connectionProvider instanceof StandaloneConnectionProvider); + + nativeCommands.set(KEY_1, VALUE_1); + nativeCommands.set(KEY_2, VALUE_2); + + connection.stringCommands().bitOp(Arrays.asList(KEY_1_BBUFFER, KEY_2_BBUFFER), BitOperation.ONE, KEY_3_BBUFFER) + .as(StepVerifier::create) // + .expectNext(7L) // + .verifyComplete(); + + assertThat(nativeCommands.get(KEY_3)).isNotNull(); + } + @Test // DATAREDIS-525 void strLenShouldReturnValueCorrectly() {