From 06f35914c5c190a3b53cfe471abdede2ab17cbc7 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Wed, 5 Mar 2025 11:59:20 +0100 Subject: [PATCH] Polishing. Update javadoc and format sources. See #3054. --- .../connection/ReactiveHashCommands.java | 38 +++++ .../redis/connection/RedisHashCommands.java | 55 ++++--- .../connection/StringRedisConnection.java | 20 +-- .../BoundHashFieldExpirationOperations.java | 44 ++---- .../core/DefaultReactiveHashOperations.java | 6 +- .../data/redis/core/HashOperations.java | 32 +--- .../redis/core/ReactiveHashOperations.java | 43 ++++-- .../data/redis/core/RedisOperations.java | 1 - .../AbstractConnectionIntegrationTests.java | 96 +++++++----- .../jedis/JedisClusterConnectionTests.java | 137 ++++++++++++------ .../LettuceClusterConnectionTests.java | 105 ++++++++++---- ...eReactiveHashCommandsIntegrationTests.java | 48 ++---- ...DefaultHashOperationsIntegrationTests.java | 35 +++-- ...eactiveHashOperationsIntegrationTests.java | 56 +++---- .../AbstractRedisMapIntegrationTests.java | 10 +- 15 files changed, 432 insertions(+), 294 deletions(-) diff --git a/src/main/java/org/springframework/data/redis/connection/ReactiveHashCommands.java b/src/main/java/org/springframework/data/redis/connection/ReactiveHashCommands.java index 1e9fd94f3a..c463737747 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReactiveHashCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/ReactiveHashCommands.java @@ -865,22 +865,52 @@ private ExpireCommand(@Nullable ByteBuffer key, List fields, Expirat this.options = options; } + /** + * Creates a new {@link ExpireCommand}. + * + * @param fields the {@code field} names to apply expiration to + * @param timeout the actual timeout + * @param unit the unit of measure for the {@code timeout}. + * @return new instance of {@link ExpireCommand}. + */ public static ExpireCommand expire(List fields, long timeout, TimeUnit unit) { Assert.notNull(fields, "Field must not be null"); return expire(fields, Expiration.from(timeout, unit)); } + /** + * Creates a new {@link ExpireCommand}. + * + * @param fields the {@code field} names to apply expiration to. + * @param ttl the actual timeout. + * @return new instance of {@link ExpireCommand}. + */ public static ExpireCommand expire(List fields, Duration ttl) { Assert.notNull(fields, "Field must not be null"); return expire(fields, Expiration.from(ttl)); } + /** + * Creates a new {@link ExpireCommand}. + * + * @param fields the {@code field} names to apply expiration to + * @param expiration the {@link Expiration} to apply to the given {@literal fields}. + * @return new instance of {@link ExpireCommand}. + */ public static ExpireCommand expire(List fields, Expiration expiration) { return new ExpireCommand(null, fields, expiration, FieldExpirationOptions.none()); } + /** + * Creates a new {@link ExpireCommand}. + * + * @param fields the {@code field} names to apply expiration to + * @param ttl the unix point in time when to expire the given {@literal fields}. + * @param precision can be {@link TimeUnit#SECONDS} or {@link TimeUnit#MILLISECONDS}. + * @return new instance of {@link ExpireCommand}. + */ public static ExpireCommand expireAt(List fields, Instant ttl, TimeUnit precision) { if (precision.compareTo(TimeUnit.MILLISECONDS) > 0) { @@ -890,10 +920,18 @@ public static ExpireCommand expireAt(List fields, Instant ttl, TimeU return expire(fields, Expiration.unixTimestamp(ttl.toEpochMilli(), TimeUnit.MILLISECONDS)); } + /** + * @param key the {@literal key} from which to expire the {@literal fields} from. + * @return new instance of {@link ExpireCommand}. + */ public ExpireCommand from(ByteBuffer key) { return new ExpireCommand(key, getFields(), expiration, options); } + /** + * @param options additional options to be sent along with the command. + * @return new instance of {@link ExpireCommand}. + */ public ExpireCommand withOptions(FieldExpirationOptions options) { return new ExpireCommand(getKey(), getFields(), getExpiration(), options); } diff --git a/src/main/java/org/springframework/data/redis/connection/RedisHashCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisHashCommands.java index f2d736b8ef..d038708526 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisHashCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisHashCommands.java @@ -255,11 +255,34 @@ public interface RedisHashCommands { @Nullable Long hStrLen(byte[] key, byte[] field); + /** + * Apply a given {@link org.springframework.data.redis.core.types.Expiration} to the given {@literal fields}. + * + * @param key must not be {@literal null}. + * @param expiration the {@link org.springframework.data.redis.core.types.Expiration} to apply. + * @param fields the names of the {@literal fields} to apply the {@literal expiration} to. + * @return a {@link List} holding the command result for each field in order - {@code 2} indicating the specific field + * is deleted already due to expiration, or provided expiry interval is 0; {@code 1} indicating expiration + * time is set/updated; {@code 0} indicating the expiration time is not set; {@code -2} indicating there is no + * such field; + * @since 3.5 + */ default @Nullable List applyExpiration(byte[] key, org.springframework.data.redis.core.types.Expiration expiration, byte[]... fields) { return applyExpiration(key, expiration, FieldExpirationOptions.none(), fields); } + /** + * @param key must not be {@literal null}. + * @param expiration the {@link org.springframework.data.redis.core.types.Expiration} to apply. + * @param options additional options to be sent along with the command. + * @param fields the names of the {@literal fields} to apply the {@literal expiration} to. + * @return a {@link List} holding the command result for each field in order - {@code 2} indicating the specific field + * is deleted already due to expiration, or provided expiry interval is 0; {@code 1} indicating expiration + * time is set/updated; {@code 0} indicating the expiration time is not set (a provided NX | XX | GT | LT + * condition is not met); {@code -2} indicating there is no such field; + * @since 3.5 + */ @Nullable default List applyExpiration(byte[] key, org.springframework.data.redis.core.types.Expiration expiration, FieldExpirationOptions options, byte[]... fields) { @@ -304,9 +327,8 @@ default List applyExpiration(byte[] key, org.springframework.data.redis.co * @param fields must not be {@literal null}. * @return a list of {@link Long} values for each of the fields provided: {@code 2} indicating the specific field is * deleted already due to expiration, or provided expiry interval is 0; {@code 1} indicating expiration time - * is set/updated; {@code 0} indicating the expiration time is not set (a provided NX | XX | GT | LT condition - * is not met); {@code -2} indicating there is no such field; {@literal null} when used in pipeline / - * transaction. + * is set/updated; {@code 0} indicating the expiration time is not set; {@code -2} indicating there is no such + * field; {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HEXPIRE * @since 3.5 */ @@ -324,9 +346,8 @@ default List hExpire(byte[] key, long seconds, byte[]... fields) { * @param fields must not be {@literal null}. * @return a list of {@link Long} values for each of the fields provided: {@code 2} indicating the specific field is * deleted already due to expiration, or provided expiry interval is 0; {@code 1} indicating expiration time - * is set/updated; {@code 0} indicating the expiration time is not set (a provided NX | XX | GT | LT condition - * is not met); {@code -2} indicating there is no such field; {@literal null} when used in pipeline / - * transaction. + * is set/updated; {@code 0} indicating the expiration time is not set; {@code -2} indicating there is no such + * field; {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HEXPIRE * @since 3.5 */ @@ -362,9 +383,8 @@ default List hExpire(byte[] key, Duration ttl, byte[]... fields) { * @param fields must not be {@literal null}. * @return a list of {@link Long} values for each of the fields provided: {@code 2} indicating the specific field is * deleted already due to expiration, or provided expiry interval is 0; {@code 1} indicating expiration time - * is set/updated; {@code 0} indicating the expiration time is not set (a provided NX | XX | GT | LT condition - * is not met); {@code -2} indicating there is no such field; {@literal null} when used in pipeline / - * transaction. + * is set/updated; {@code 0} indicating the expiration time is not set ; {@code -2} indicating there is no + * such field; {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HPEXPIRE * @since 3.5 */ @@ -382,9 +402,8 @@ default List hpExpire(byte[] key, long millis, byte[]... fields) { * @param fields must not be {@literal null}. * @return a list of {@link Long} values for each of the fields provided: {@code 2} indicating the specific field is * deleted already due to expiration, or provided expiry interval is 0; {@code 1} indicating expiration time - * is set/updated; {@code 0} indicating the expiration time is not set (a provided NX | XX | GT | LT condition - * is not met); {@code -2} indicating there is no such field; {@literal null} when used in pipeline / - * transaction. + * is set/updated; {@code 0} indicating the expiration time is not set; {@code -2} indicating there is no such + * field; {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HPEXPIRE * @since 3.5 */ @@ -420,9 +439,8 @@ default List hpExpire(byte[] key, Duration ttl, byte[]... fields) { * @param fields must not be {@literal null}. * @return a list of {@link Long} values for each of the fields provided: {@code 2} indicating the specific field is * deleted already due to expiration, or provided expiry interval is in the past; {@code 1} indicating - * expiration time is set/updated; {@code 0} indicating the expiration time is not set (a provided NX | XX | - * GT | LT condition is not met); {@code -2} indicating there is no such field; {@literal null} when used in - * pipeline / transaction. + * expiration time is set/updated; {@code 0} indicating the expiration time is not set; {@code -2} indicating + * there is no such field; {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HEXPIREAT * @since 3.5 */ @@ -457,9 +475,8 @@ default List hExpireAt(byte[] key, long unixTime, byte[]... fields) { * @param fields must not be {@literal null}. * @return a list of {@link Long} values for each of the fields provided: {@code 2} indicating the specific field is * deleted already due to expiration, or provided expiry interval is in the past; {@code 1} indicating - * expiration time is set/updated; {@code 0} indicating the expiration time is not set (a provided NX | XX | - * GT | LT condition is not met); {@code -2} indicating there is no such field; {@literal null} when used in - * pipeline / transaction. + * expiration time is set/updated; {@code 0} indicating the expiration time is not set; {@code -2} indicating + * there is no such field; {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HPEXPIREAT * @since 3.5 */ @@ -531,8 +548,6 @@ List hpExpireAt(byte[] key, long unixTimeInMillis, FieldExpirationOptions. * @since 3.5 */ @Nullable - // TODO: this is complete nonsense as it would jeopardize negative values - // TODO: this should be a List> List hTtl(byte[] key, TimeUnit timeUnit, byte[]... fields); /** diff --git a/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java index 5ff0e9946f..1069e430c8 100644 --- a/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java @@ -2341,9 +2341,8 @@ Long zRangeStoreRevByScore(String dstKey, String srcKey, * @param fields must not be {@literal null}. * @return a list of {@link Long} values for each of the fields provided: {@code 2} indicating the specific field is * deleted already due to expiration, or provided expiry interval is 0; {@code 1} indicating expiration time - * is set/updated; {@code 0} indicating the expiration time is not set (a provided NX | XX | GT | LT condition - * is not met); {@code -2} indicating there is no such field; {@literal null} when used in pipeline / - * transaction. + * is set/updated; {@code 0} indicating the expiration time is not set; {@code -2} indicating there is no such + * field; {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HEXPIRE * @since 3.5 */ @@ -2377,9 +2376,8 @@ default List hExpire(String key, long seconds, String... fields) { * @param fields must not be {@literal null}. * @return a list of {@link Long} values for each of the fields provided: {@code 2} indicating the specific field is * deleted already due to expiration, or provided expiry interval is 0; {@code 1} indicating expiration time - * is set/updated; {@code 0} indicating the expiration time is not set (a provided NX | XX | GT | LT condition - * is not met); {@code -2} indicating there is no such field; {@literal null} when used in pipeline / - * transaction. + * is set/updated; {@code 0} indicating the expiration time is not set; {@code -2} indicating there is no such + * field; {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HPEXPIRE * @since 3.5 */ @@ -2413,9 +2411,8 @@ default List hpExpire(String key, long millis, String... fields) { * @param fields must not be {@literal null}. * @return a list of {@link Long} values for each of the fields provided: {@code 2} indicating the specific field is * deleted already due to expiration, or provided expiry interval is in the past; {@code 1} indicating - * expiration time is set/updated; {@code 0} indicating the expiration time is not set (a provided NX | XX | - * GT | LT condition is not met); {@code -2} indicating there is no such field; {@literal null} when used in - * pipeline / transaction. + * expiration time is set/updated; {@code 0} indicating the expiration time is not set; {@code -2} indicating + * there is no such field; {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HEXPIREAT * @since 3.5 */ @@ -2449,9 +2446,8 @@ default List hExpireAt(String key, long unixTime, String... fields) { * @param fields must not be {@literal null}. * @return a list of {@link Long} values for each of the fields provided: {@code 2} indicating the specific field is * deleted already due to expiration, or provided expiry interval is in the past; {@code 1} indicating - * expiration time is set/updated; {@code 0} indicating the expiration time is not set (a provided NX | XX | - * GT | LT condition is not met); {@code -2} indicating there is no such field; {@literal null} when used in - * pipeline / transaction. + * expiration time is set/updated; {@code 0} indicating the expiration time is not set; {@code -2} indicating + * there is no such field; {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HPEXPIREAT * @since 3.5 */ diff --git a/src/main/java/org/springframework/data/redis/core/BoundHashFieldExpirationOperations.java b/src/main/java/org/springframework/data/redis/core/BoundHashFieldExpirationOperations.java index 33e0ff82e6..d49041a66d 100644 --- a/src/main/java/org/springframework/data/redis/core/BoundHashFieldExpirationOperations.java +++ b/src/main/java/org/springframework/data/redis/core/BoundHashFieldExpirationOperations.java @@ -34,33 +34,30 @@ public interface BoundHashFieldExpirationOperations { /** - * Apply {@link Expiration} to the hash without any additional constraints. + * Apply {@link Expiration} to the bound hash key/hash fields without any additional constraints. * * @param expiration the expiration definition. - * @return changes to the hash fields. + * @return changes to the hash fields. {@literal null} when used in pipeline / transaction. */ default ExpireChanges expire(Expiration expiration) { return expire(expiration, Hash.FieldExpirationOptions.none()); } /** - * Apply {@link Expiration} to the hash fields given {@link Hash.FieldExpirationOptions expiration options}. + * Apply {@link Expiration} to the bound hash key/hash fields given {@link Hash.FieldExpirationOptions expiration + * options}. * * @param expiration the expiration definition. * @param options expiration options. - * @return changes to the hash fields. + * @return changes to the hash fields. {@literal null} when used in pipeline / transaction. */ ExpireChanges expire(Expiration expiration, Hash.FieldExpirationOptions options); /** - * Set time to live for given {@code hashKey}. + * Set time to live for the bound hash key/hash fields. * * @param timeout the amount of time after which the key will be expired, must not be {@literal null}. - * @return a list of {@link Long} values for each of the fields provided: {@code 2} indicating the specific field is - * deleted already due to expiration, or provided expiry interval is 0; {@code 1} indicating expiration time - * is set/updated; {@code 0} indicating the expiration time is not set (a provided NX | XX | GT | LT condition - * is not met); {@code -2} indicating there is no such field; {@literal null} when used in pipeline / - * transaction. + * @return changes to the hash fields. {@literal null} when used in pipeline / transaction. * @throws IllegalArgumentException if the timeout is {@literal null}. * @see Redis Documentation: HEXPIRE * @since 3.5 @@ -69,14 +66,10 @@ default ExpireChanges expire(Expiration expiration) { ExpireChanges expire(Duration timeout); /** - * Set the expiration for given {@code hashKey} as a {@literal date} timestamp. + * Set the expiration for the bound hash key/hash fields as a {@literal date} timestamp. * * @param expireAt must not be {@literal null}. - * @return a list of {@link Long} values for each of the fields provided: {@code 2} indicating the specific field is - * deleted already due to expiration, or provided expiry interval is in the past; {@code 1} indicating - * expiration time is set/updated; {@code 0} indicating the expiration time is not set (a provided NX | XX | - * GT | LT condition is not met); {@code -2} indicating there is no such field; {@literal null} when used in - * pipeline / transaction. + * @return changes to the hash fields. {@literal null} when used in pipeline / transaction. * @throws IllegalArgumentException if the instant is {@literal null} or too large to represent as a {@code Date}. * @see Redis Documentation: HEXPIRE * @since 3.5 @@ -85,11 +78,9 @@ default ExpireChanges expire(Expiration expiration) { ExpireChanges expireAt(Instant expireAt); /** - * Remove the expiration from given {@code hashKey} . + * Remove the expiration from the bound hash key/hash fields. * - * @return a list of {@link Long} values for each of the fields provided: {@code 1} indicating expiration time is - * removed; {@code -1} field has no expiration time to be removed; {@code -2} indicating there is no such - * field; {@literal null} when used in pipeline / transaction. + * @return changes to the hash fields. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HPERSIST * @since 3.5 */ @@ -97,12 +88,9 @@ default ExpireChanges expire(Expiration expiration) { ExpireChanges persist(); /** - * Get the time to live for {@code hashKey} in seconds. + * Get the time to live for bound hash key/hash fields in seconds. * - * @return a list of {@link Long} values for each of the fields provided: the time to live in seconds; or a negative - * value to signal an error. The command returns {@code -1} if the key exists but has no associated expiration - * time. The command returns {@code -2} if the key does not exist; {@literal null} when used in pipeline / - * transaction. + * @return the actual expirations in seconds for the hash fields. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HTTL * @since 3.5 */ @@ -110,12 +98,10 @@ default ExpireChanges expire(Expiration expiration) { Expirations getTimeToLive(); /** - * Get the time to live for {@code hashKey} and convert it to the given {@link TimeUnit}. + * Get the time to live for the bound hash key/hash fields and convert it to the given {@link TimeUnit}. * * @param timeUnit must not be {@literal null}. - * @return a list of {@link Long} values for each of the fields provided: the time to live in seconds; or a negative - * value to signal an error. The command returns {@code -1} if the key exists but has no associated expiration - * time. The command returns {@code -2} if the key does not exist; {@literal null} when used in pipeline / + * @return the actual expirations for the hash fields in the given time unit. {@literal null} when used in pipeline / * transaction. * @see Redis Documentation: HTTL * @since 3.5 diff --git a/src/main/java/org/springframework/data/redis/core/DefaultReactiveHashOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultReactiveHashOperations.java index 8c97c43fcd..540b351778 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultReactiveHashOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultReactiveHashOperations.java @@ -29,7 +29,6 @@ import java.util.function.Function; import org.reactivestreams.Publisher; - import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.connection.Hash.FieldExpirationOptions; import org.springframework.data.redis.connection.ReactiveHashCommands; @@ -249,13 +248,14 @@ public Mono> expire(H key, Duration timeout, Collection ha } @Override - public Mono> expire(H key, Expiration expiration, FieldExpirationOptions options, Collection hashKeys) { + public Mono> expire(H key, Expiration expiration, FieldExpirationOptions options, + Collection hashKeys) { List orderedKeys = List.copyOf(hashKeys); ByteBuffer rawKey = rawKey(key); List rawHashKeys = orderedKeys.stream().map(this::rawHashKey).toList(); - Mono> raw =createFlux(connection -> { + Mono> raw = createFlux(connection -> { return connection .applyExpiration(Mono.just(ExpireCommand.expire(rawHashKeys, expiration).from(rawKey).withOptions(options))) .map(NumericResponse::getOutput); diff --git a/src/main/java/org/springframework/data/redis/core/HashOperations.java b/src/main/java/org/springframework/data/redis/core/HashOperations.java index 67c4ce0fa8..f57143c737 100644 --- a/src/main/java/org/springframework/data/redis/core/HashOperations.java +++ b/src/main/java/org/springframework/data/redis/core/HashOperations.java @@ -235,11 +235,7 @@ public interface HashOperations { * @param key must not be {@literal null}. * @param timeout the amount of time after which the key will be expired, must not be {@literal null}. * @param hashKeys must not be {@literal null}. - * @return a list of {@link Long} values for each of the fields provided: {@code 2} indicating the specific field is - * deleted already due to expiration, or provided expiry interval is 0; {@code 1} indicating expiration time - * is set/updated; {@code 0} indicating the expiration time is not set (a provided NX | XX | GT | LT condition - * is not met); {@code -2} indicating there is no such field; {@literal null} when used in pipeline / - * transaction. + * @return changes to the hash fields. {@literal null} when used in pipeline / transaction. * @throws IllegalArgumentException if the timeout is {@literal null}. * @see Redis Documentation: HEXPIRE * @since 3.5 @@ -253,11 +249,7 @@ public interface HashOperations { * @param key must not be {@literal null}. * @param expireAt must not be {@literal null}. * @param hashKeys must not be {@literal null}. - * @return a list of {@link Long} values for each of the fields provided: {@code 2} indicating the specific field is - * deleted already due to expiration, or provided expiry interval is in the past; {@code 1} indicating - * expiration time is set/updated; {@code 0} indicating the expiration time is not set (a provided NX | XX | - * GT | LT condition is not met); {@code -2} indicating there is no such field; {@literal null} when used in - * pipeline / transaction. + * @return changes to the hash fields. {@literal null} when used in pipeline / transaction. * @throws IllegalArgumentException if the instant is {@literal null} or too large to represent as a {@code Date}. * @see Redis Documentation: HEXPIRE * @since 3.5 @@ -272,11 +264,7 @@ public interface HashOperations { * @param expiration must not be {@literal null}. * @param options must not be {@literal null}. * @param hashKeys must not be {@literal null}. - * @return a list of {@link Long} values for each of the fields provided: {@code 2} indicating the specific field is - * deleted already due to expiration, or provided expiry interval is in the past; {@code 1} indicating - * expiration time is set/updated; {@code 0} indicating the expiration time is not set (a provided NX | XX | - * GT | LT condition is not met); {@code -2} indicating there is no such field; {@literal null} when used in - * pipeline / transaction. + * @return changes to the hash fields. {@literal null} when used in pipeline / transaction. * @throws IllegalArgumentException if the instant is {@literal null} or too large to represent as a {@code Date}. * @see Redis Documentation: HEXPIRE * @since 3.5 @@ -289,9 +277,7 @@ public interface HashOperations { * * @param key must not be {@literal null}. * @param hashKeys must not be {@literal null}. - * @return a list of {@link Long} values for each of the fields provided: {@code 1} indicating expiration time is - * removed; {@code -1} field has no expiration time to be removed; {@code -2} indicating there is no such - * field; {@literal null} when used in pipeline / transaction. + * @return changes to the hash fields. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HPERSIST * @since 3.5 */ @@ -303,10 +289,7 @@ public interface HashOperations { * * @param key must not be {@literal null}. * @param hashKeys must not be {@literal null}. - * @return a list of {@link Long} values for each of the fields provided: the time to live in seconds; or a negative - * value to signal an error. The command returns {@code -1} if the key exists but has no associated expiration - * time. The command returns {@code -2} if the key does not exist; {@literal null} when used in pipeline / - * transaction. + * @return the actual expirations in seconds for the hash fields. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HTTL * @since 3.5 */ @@ -321,10 +304,7 @@ default Expirations getTimeToLive(H key, Collection hashKeys) { * @param key must not be {@literal null}. * @param timeUnit must not be {@literal null}. * @param hashKeys must not be {@literal null}. - * @return a list of {@link Long} values for each of the fields provided: the time to live in seconds; or a negative - * value to signal an error. The command returns {@code -1} if the key exists but has no associated expiration - * time. The command returns {@code -2} if the key does not exist; {@literal null} when used in pipeline / - * transaction. + * @return the actual expirations for the hash fields. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HTTL * @since 3.5 */ diff --git a/src/main/java/org/springframework/data/redis/core/ReactiveHashOperations.java b/src/main/java/org/springframework/data/redis/core/ReactiveHashOperations.java index 757dbcea76..2fe3b0c65b 100644 --- a/src/main/java/org/springframework/data/redis/core/ReactiveHashOperations.java +++ b/src/main/java/org/springframework/data/redis/core/ReactiveHashOperations.java @@ -238,8 +238,31 @@ default Flux> scan(H key) { */ Flux> scan(H key, ScanOptions options); + /** + * Set time to live for given {@literal hashKeys} stored within {@literal key}. + * + * @param key must not be {@literal null}. + * @param timeout the amount of time after which the key will be expired, must not be {@literal null}. + * @param hashKeys must not be {@literal null}. + * @return a {@link Mono} emitting changes to the hash fields. + * @throws IllegalArgumentException if the timeout is {@literal null}. + * @see Redis Documentation: HEXPIRE + * @since 3.5 + */ Mono> expire(H key, Duration timeout, Collection hashKeys); + /** + * Set time to live for given {@literal hashKeys} stored within {@literal key}. + * + * @param key must not be {@literal null}. + * @param expiration must not be {@literal null}. + * @param options additional options to apply. + * @param hashKeys must not be {@literal null}. + * @return a {@link Mono} emitting changes to the hash fields. + * @throws IllegalArgumentException if the timeout is {@literal null}. + * @see Redis Documentation: HEXPIRE + * @since 3.5 + */ Mono> expire(H key, Expiration expiration, FieldExpirationOptions options, Collection hashKeys); /** @@ -248,11 +271,7 @@ default Flux> scan(H key) { * @param key must not be {@literal null}. * @param expireAt must not be {@literal null}. * @param hashKeys must not be {@literal null}. - * @return a list of {@link Long} values for each of the fields provided: {@code 2} indicating the specific field is - * deleted already due to expiration, or provided expiry interval is in the past; {@code 1} indicating - * expiration time is set/updated; {@code 0} indicating the expiration time is not set (a provided NX | XX | - * GT | LT condition is not met); {@code -2} indicating there is no such field; {@literal null} when used in - * pipeline / transaction. + * @return a {@link Mono} emitting changes to the hash fields. * @throws IllegalArgumentException if the instant is {@literal null} or too large to represent as a {@code Date}. * @see Redis Documentation: HEXPIRE * @since 3.5 @@ -265,9 +284,7 @@ default Flux> scan(H key) { * * @param key must not be {@literal null}. * @param hashKeys must not be {@literal null}. - * @return a list of {@link Long} values for each of the fields provided: {@code 1} indicating expiration time is - * removed; {@code -1} field has no expiration time to be removed; {@code -2} indicating there is no such - * field; {@literal null} when used in pipeline / transaction. + * @return a {@link Mono} emitting changes to the hash fields. * @see Redis Documentation: HPERSIST * @since 3.5 */ @@ -279,10 +296,7 @@ default Flux> scan(H key) { * * @param key must not be {@literal null}. * @param hashKeys must not be {@literal null}. - * @return a list of {@link Long} values for each of the fields provided: the time to live in seconds; or a negative - * value to signal an error. The command returns {@code -1} if the key exists but has no associated expiration - * time. The command returns {@code -2} if the key does not exist; {@literal null} when used in pipeline / - * transaction. + * @return a {@link Mono} emitting {@link Expirations} of the hash fields. * @see Redis Documentation: HTTL * @since 3.5 */ @@ -297,10 +311,7 @@ default Mono> getTimeToLive(H key, Collection hashKeys) { * @param key must not be {@literal null}. * @param timeUnit must not be {@literal null}. * @param hashKeys must not be {@literal null}. - * @return a list of {@link Long} values for each of the fields provided: the time to live in seconds; or a negative - * value to signal an error. The command returns {@code -1} if the key exists but has no associated expiration - * time. The command returns {@code -2} if the key does not exist; {@literal null} when used in pipeline / - * transaction. + * @return a {@link Mono} emitting {@link Expirations} of the hash fields. * @see Redis Documentation: HTTL * @since 3.5 */ diff --git a/src/main/java/org/springframework/data/redis/core/RedisOperations.java b/src/main/java/org/springframework/data/redis/core/RedisOperations.java index def0dca04b..8c1ad67ad6 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisOperations.java +++ b/src/main/java/org/springframework/data/redis/core/RedisOperations.java @@ -376,7 +376,6 @@ default Boolean expireAt(K key, Instant expireAt) { @Nullable Boolean persist(K key); - // TODO: Add TimeToLive (getTimeToLive) /** * Get the time to live for {@code key} in seconds. * 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 94b8db7657..573f105247 100644 --- a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java @@ -15,24 +15,48 @@ */ package org.springframework.data.redis.connection; -import static org.assertj.core.api.Assertions.*; -import static org.assertj.core.api.Assumptions.*; -import static org.awaitility.Awaitility.*; -import static org.junit.jupiter.api.condition.OS.*; -import static org.springframework.data.redis.connection.BitFieldSubCommands.*; -import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldIncrBy.Overflow.*; -import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.*; -import static org.springframework.data.redis.connection.ClusterTestVariables.*; -import static org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit.*; -import static org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs.*; -import static org.springframework.data.redis.connection.RedisGeoCommands.GeoSearchStoreCommandArgs.*; -import static org.springframework.data.redis.core.ScanOptions.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.fail; +import static org.assertj.core.api.Assertions.within; +import static org.assertj.core.api.Assumptions.assumeThat; +import static org.awaitility.Awaitility.await; +import static org.junit.jupiter.api.condition.OS.MAC; +import static org.springframework.data.redis.connection.BitFieldSubCommands.create; +import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldIncrBy.Overflow.FAIL; +import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.INT_8; +import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.signed; +import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.unsigned; +import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_1; +import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_2; +import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_3; +import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_1; +import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_2; +import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_3; +import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_4; +import static org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit.KILOMETERS; +import static org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs; +import static org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs.newGeoSearchArgs; +import static org.springframework.data.redis.connection.RedisGeoCommands.GeoSearchStoreCommandArgs.newGeoSearchStoreArgs; +import static org.springframework.data.redis.core.ScanOptions.scanOptions; import java.nio.charset.StandardCharsets; import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.BlockingDeque; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; @@ -753,7 +777,7 @@ void testExecute() { assertThat(stringSerializer.deserialize((byte[]) getResults().get(1))).isEqualTo("bar"); } - @Test + @Test // GH- @EnabledOnCommand("HEXPIRE") void testExecuteHashFieldExpiration() { @@ -3473,7 +3497,7 @@ void hStrLenReturnsZeroWhenKeyDoesNotExist() { verifyResults(Arrays.asList(new Object[] { 0L })); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hExpireReturnsSuccessAndSetsTTL() { @@ -3484,10 +3508,10 @@ public void hExpireReturnsSuccessAndSetsTTL() { List results = getResults(); assertThat(results.get(0)).isEqualTo(Boolean.TRUE); assertThat((List) results.get(1)).contains(1L); - assertThat((List) results.get(2)).allSatisfy( value -> assertThat((Long)value).isBetween(0L, 5L)); + assertThat((List) results.get(2)).allSatisfy(value -> assertThat((Long) value).isBetween(0L, 5L)); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hExpireReturnsMinusTwoWhenFieldDoesNotExist() { @@ -3498,7 +3522,7 @@ public void hExpireReturnsMinusTwoWhenFieldDoesNotExist() { verifyResults(Arrays.asList(Boolean.TRUE, List.of(-2L), List.of(-2L))); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hExpireReturnsTwoWhenZeroProvided() { @@ -3508,7 +3532,7 @@ public void hExpireReturnsTwoWhenZeroProvided() { verifyResults(Arrays.asList(Boolean.TRUE, List.of(2L))); } - @Test + @Test // GH-3054 @EnabledOnCommand("HPEXPIRE") public void hpExpireReturnsSuccessAndSetsTTL() { @@ -3519,10 +3543,10 @@ public void hpExpireReturnsSuccessAndSetsTTL() { List results = getResults(); assertThat(results.get(0)).isEqualTo(Boolean.TRUE); assertThat((List) results.get(1)).contains(1L); - assertThat((List) results.get(2)).allSatisfy( value -> assertThat((Long)value).isBetween(0L, 5000L)); + assertThat((List) results.get(2)).allSatisfy(value -> assertThat((Long) value).isBetween(0L, 5000L)); } - @Test + @Test // GH-3054 @EnabledOnCommand("HPEXPIRE") public void hpExpireReturnsMinusTwoWhenFieldDoesNotExist() { @@ -3533,7 +3557,7 @@ public void hpExpireReturnsMinusTwoWhenFieldDoesNotExist() { verifyResults(Arrays.asList(Boolean.TRUE, List.of(-2L), List.of(-2L))); } - @Test + @Test // GH-3054 @EnabledOnCommand("HPEXPIRE") public void hpExpireReturnsTwoWhenZeroProvided() { @@ -3543,7 +3567,7 @@ public void hpExpireReturnsTwoWhenZeroProvided() { verifyResults(Arrays.asList(Boolean.TRUE, List.of(2L))); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIREAT") public void hExpireAtReturnsSuccessAndSetsTTL() { @@ -3556,10 +3580,10 @@ public void hExpireAtReturnsSuccessAndSetsTTL() { List results = getResults(); assertThat(results.get(0)).isEqualTo(Boolean.TRUE); assertThat((List) results.get(1)).contains(1L); - assertThat((List) results.get(2)).allSatisfy( value -> assertThat((Long)value).isBetween(0L, 5L)); + assertThat((List) results.get(2)).allSatisfy(value -> assertThat((Long) value).isBetween(0L, 5L)); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIREAT") public void hExpireAtReturnsMinusTwoWhenFieldDoesNotExist() { @@ -3572,7 +3596,7 @@ public void hExpireAtReturnsMinusTwoWhenFieldDoesNotExist() { verifyResults(Arrays.asList(Boolean.TRUE, List.of(-2L), List.of(-2L))); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIREAT") public void hExpireAtReturnsTwoWhenZeroProvided() { @@ -3584,7 +3608,7 @@ public void hExpireAtReturnsTwoWhenZeroProvided() { verifyResults(Arrays.asList(Boolean.TRUE, List.of(2L))); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIREAT") public void hpExpireAtReturnsSuccessAndSetsTTL() { @@ -3597,10 +3621,10 @@ public void hpExpireAtReturnsSuccessAndSetsTTL() { List results = getResults(); assertThat(results.get(0)).isEqualTo(Boolean.TRUE); assertThat((List) results.get(1)).contains(1L); - assertThat((List) results.get(2)).allSatisfy( value -> assertThat((Long)value).isBetween(0L, 5L)); + assertThat((List) results.get(2)).allSatisfy(value -> assertThat((Long) value).isBetween(0L, 5L)); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIREAT") public void hpExpireAtReturnsMinusTwoWhenFieldDoesNotExist() { @@ -3613,7 +3637,7 @@ public void hpExpireAtReturnsMinusTwoWhenFieldDoesNotExist() { verifyResults(Arrays.asList(Boolean.TRUE, List.of(-2L), List.of(-2L))); } - @Test + @Test // GH-3054 @EnabledOnCommand("HPEXPIREAT") public void hpExpireAdReturnsTwoWhenZeroProvided() { @@ -3625,7 +3649,7 @@ public void hpExpireAdReturnsTwoWhenZeroProvided() { verifyResults(Arrays.asList(Boolean.TRUE, List.of(2L))); } - @Test + @Test // GH-3054 @EnabledOnCommand("HPERSIST") public void hPersistReturnsSuccessAndPersistsField() { @@ -3637,7 +3661,7 @@ public void hPersistReturnsSuccessAndPersistsField() { verifyResults(Arrays.asList(Boolean.TRUE, List.of(1L), List.of(1L), List.of(-1L))); } - @Test + @Test // GH-3054 @EnabledOnCommand("HPERSIST") public void hPersistReturnsMinusOneWhenFieldDoesNotHaveExpiration() { @@ -3647,7 +3671,7 @@ public void hPersistReturnsMinusOneWhenFieldDoesNotHaveExpiration() { verifyResults(Arrays.asList(Boolean.TRUE, List.of(-1L))); } - @Test + @Test // GH-3054 @EnabledOnCommand("HPERSIST") public void hPersistReturnsMinusTwoWhenFieldOrKeyMissing() { @@ -3658,7 +3682,7 @@ public void hPersistReturnsMinusTwoWhenFieldOrKeyMissing() { verifyResults(Arrays.asList(Boolean.TRUE, List.of(-2L), List.of(-2L))); } - @Test + @Test // GH-3054 @EnabledOnCommand("HTTL") public void hTtlReturnsMinusOneWhenFieldHasNoExpiration() { @@ -3668,7 +3692,7 @@ public void hTtlReturnsMinusOneWhenFieldHasNoExpiration() { verifyResults(Arrays.asList(Boolean.TRUE, List.of(-1L))); } - @Test + @Test // GH-3054 @EnabledOnCommand("HTTL") public void hTtlReturnsMinusIndependendOfTimeUnitOneWhenFieldHasNoExpiration() { @@ -3678,7 +3702,7 @@ public void hTtlReturnsMinusIndependendOfTimeUnitOneWhenFieldHasNoExpiration() { verifyResults(Arrays.asList(Boolean.TRUE, List.of(-1L))); } - @Test + @Test // GH-3054 @EnabledOnCommand("HTTL") public void hTtlReturnsMinusTwoWhenFieldOrKeyMissing() { 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 4e41e60954..4bed88c0a5 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 @@ -15,17 +15,37 @@ */ package org.springframework.data.redis.connection.jedis; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.fail; import static org.assertj.core.data.Offset.offset; -import static org.springframework.data.redis.connection.BitFieldSubCommands.*; -import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldIncrBy.Overflow.*; -import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.*; -import static org.springframework.data.redis.connection.ClusterTestVariables.*; -import static org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit.*; -import static org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs.*; -import static org.springframework.data.redis.connection.RedisListCommands.*; -import static org.springframework.data.redis.connection.RedisZSetCommands.*; -import static org.springframework.data.redis.core.ScanOptions.*; +import static org.springframework.data.redis.connection.BitFieldSubCommands.create; +import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldIncrBy.Overflow.FAIL; +import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.INT_8; +import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.signed; +import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.unsigned; +import static org.springframework.data.redis.connection.ClusterTestVariables.CLUSTER_HOST; +import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_1; +import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_2; +import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_3; +import static org.springframework.data.redis.connection.ClusterTestVariables.MASTER_NODE_1_PORT; +import static org.springframework.data.redis.connection.ClusterTestVariables.MASTER_NODE_2_PORT; +import static org.springframework.data.redis.connection.ClusterTestVariables.MASTER_NODE_3_PORT; +import static org.springframework.data.redis.connection.ClusterTestVariables.REPLICAOF_NODE_1_PORT; +import static org.springframework.data.redis.connection.ClusterTestVariables.SAME_SLOT_KEY_1; +import static org.springframework.data.redis.connection.ClusterTestVariables.SAME_SLOT_KEY_2; +import static org.springframework.data.redis.connection.ClusterTestVariables.SAME_SLOT_KEY_3; +import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_1; +import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_2; +import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_3; +import static org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit.KILOMETERS; +import static org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs; +import static org.springframework.data.redis.connection.RedisListCommands.Direction; +import static org.springframework.data.redis.connection.RedisListCommands.Position; +import static org.springframework.data.redis.connection.RedisZSetCommands.Range; +import static org.springframework.data.redis.core.ScanOptions.NONE; +import static org.springframework.data.redis.core.ScanOptions.scanOptions; import redis.clients.jedis.ConnectionPool; import redis.clients.jedis.HostAndPort; @@ -37,14 +57,23 @@ import java.nio.charset.StandardCharsets; import java.time.Duration; import java.time.Instant; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.ExtendWith; - import org.springframework.dao.DataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.domain.Range.Bound; @@ -1040,9 +1069,10 @@ public void hStrLenReturnsZeroWhenKeyDoesNotExist() { assertThat(clusterConnection.hashCommands().hStrLen(KEY_1_BYTES, KEY_1_BYTES)).isEqualTo(0L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hExpireReturnsSuccessAndSetsTTL() { + nativeConnection.hset(KEY_1, KEY_2, VALUE_3); assertThat(clusterConnection.hashCommands().hExpire(KEY_1_BYTES, 5L, KEY_2_BYTES)).contains(1L); @@ -1050,9 +1080,10 @@ public void hExpireReturnsSuccessAndSetsTTL() { .allSatisfy(val -> assertThat(val).isBetween(0L, 5L)); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hExpireReturnsMinusTwoWhenFieldDoesNotExist() { + nativeConnection.hset(KEY_1, KEY_2, VALUE_3); // missing field assertThat(clusterConnection.hashCommands().hExpire(KEY_1_BYTES, 5L, KEY_1_BYTES)).contains(-2L); @@ -1060,27 +1091,30 @@ public void hExpireReturnsMinusTwoWhenFieldDoesNotExist() { assertThat(clusterConnection.hashCommands().hExpire(KEY_2_BYTES, 5L, KEY_2_BYTES)).contains(-2L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hExpireReturnsTwoWhenZeroProvided() { + nativeConnection.hset(KEY_1, KEY_2, VALUE_3); assertThat(clusterConnection.hashCommands().hExpire(KEY_1_BYTES, 0L, KEY_2_BYTES)).contains(2L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hpExpireReturnsSuccessAndSetsTTL() { + nativeConnection.hset(KEY_1, KEY_2, VALUE_3); assertThat(clusterConnection.hashCommands().hpExpire(KEY_1_BYTES, 5000L, KEY_2_BYTES)).contains(1L); - assertThat(clusterConnection.hashCommands().hTtl(KEY_1_BYTES, TimeUnit.MILLISECONDS,KEY_2_BYTES)) + assertThat(clusterConnection.hashCommands().hTtl(KEY_1_BYTES, TimeUnit.MILLISECONDS, KEY_2_BYTES)) .allSatisfy(val -> assertThat(val).isBetween(0L, 5000L)); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hpExpireReturnsMinusTwoWhenFieldDoesNotExist() { + nativeConnection.hset(KEY_1, KEY_2, VALUE_3); // missing field assertThat(clusterConnection.hashCommands().hpExpire(KEY_1_BYTES, 5L, KEY_1_BYTES)).contains(-2L); @@ -1088,26 +1122,31 @@ public void hpExpireReturnsMinusTwoWhenFieldDoesNotExist() { assertThat(clusterConnection.hashCommands().hpExpire(KEY_2_BYTES, 5L, KEY_2_BYTES)).contains(-2L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hpExpireReturnsTwoWhenZeroProvided() { + nativeConnection.hset(KEY_1, KEY_2, VALUE_3); assertThat(clusterConnection.hashCommands().hpExpire(KEY_1_BYTES, 0L, KEY_2_BYTES)).contains(2L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hExpireAtReturnsSuccessAndSetsTTL() { + nativeConnection.hset(KEY_1, KEY_2, VALUE_3); long inFiveSeconds = Instant.now().plusSeconds(5L).getEpochSecond(); + assertThat(clusterConnection.hashCommands().hExpireAt(KEY_1_BYTES, inFiveSeconds, KEY_2_BYTES)).contains(1L); - assertThat(clusterConnection.hashCommands().hTtl(KEY_1_BYTES, KEY_2_BYTES)).allSatisfy(val -> assertThat(val).isBetween(0L, 5L)); + assertThat(clusterConnection.hashCommands().hTtl(KEY_1_BYTES, KEY_2_BYTES)) + .allSatisfy(val -> assertThat(val).isBetween(0L, 5L)); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hExpireAtReturnsMinusTwoWhenFieldDoesNotExist() { + nativeConnection.hset(KEY_1, KEY_2, VALUE_3); long inFiveSeconds = Instant.now().plusSeconds(5L).getEpochSecond(); @@ -1117,27 +1156,31 @@ public void hExpireAtReturnsMinusTwoWhenFieldDoesNotExist() { assertThat(clusterConnection.hashCommands().hExpireAt(KEY_2_BYTES, inFiveSeconds, KEY_2_BYTES)).contains(-2L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hExpireAdReturnsTwoWhenZeroProvided() { + nativeConnection.hset(KEY_1, KEY_2, VALUE_3); assertThat(clusterConnection.hashCommands().hExpireAt(KEY_1_BYTES, 0L, KEY_2_BYTES)).contains(2L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hpExpireAtReturnsSuccessAndSetsTTL() { + nativeConnection.hset(KEY_1, KEY_2, VALUE_3); long inFiveSeconds = Instant.now().plusSeconds(5L).toEpochMilli(); + assertThat(clusterConnection.hashCommands().hpExpireAt(KEY_1_BYTES, inFiveSeconds, KEY_2_BYTES)).contains(1L); assertThat(clusterConnection.hashCommands().hTtl(KEY_1_BYTES, TimeUnit.MILLISECONDS, KEY_2_BYTES)) .allSatisfy(val -> assertThat(val).isBetween(0L, 5000L)); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hpExpireAtReturnsMinusTwoWhenFieldDoesNotExist() { + nativeConnection.hset(KEY_1, KEY_2, VALUE_3); long inFiveSeconds = Instant.now().plusSeconds(5L).toEpochMilli(); @@ -1147,55 +1190,60 @@ public void hpExpireAtReturnsMinusTwoWhenFieldDoesNotExist() { assertThat(clusterConnection.hashCommands().hpExpireAt(KEY_2_BYTES, inFiveSeconds, KEY_2_BYTES)).contains(-2L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hpExpireAdReturnsTwoWhenZeroProvided() { + nativeConnection.hset(KEY_1, KEY_2, VALUE_3); assertThat(clusterConnection.hashCommands().hpExpireAt(KEY_1_BYTES, 0L, KEY_2_BYTES)).contains(2L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hPersistReturnsSuccessAndPersistsField() { + nativeConnection.hset(KEY_1, KEY_2, VALUE_3); + assertThat(clusterConnection.hashCommands().hExpire(KEY_1_BYTES, 5L, KEY_2_BYTES)).contains(1L); - assertThat(clusterConnection.hashCommands().hPersist(KEY_1_BYTES, KEY_2_BYTES)).contains(1L); + assertThat(clusterConnection.hashCommands().hPersist(KEY_1_BYTES, KEY_2_BYTES)).contains(1L); assertThat(clusterConnection.hashCommands().hTtl(KEY_1_BYTES, KEY_2_BYTES)).contains(-1L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hPersistReturnsMinusOneWhenFieldDoesNotHaveExpiration() { + nativeConnection.hset(KEY_1, KEY_2, VALUE_3); assertThat(clusterConnection.hashCommands().hPersist(KEY_1_BYTES, KEY_2_BYTES)).contains(-1L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hPersistReturnsMinusTwoWhenFieldOrKeyMissing() { + nativeConnection.hset(KEY_1, KEY_2, VALUE_3); assertThat(clusterConnection.hashCommands().hPersist(KEY_1_BYTES, KEY_1_BYTES)).contains(-2L); - assertThat(clusterConnection.hashCommands().hPersist(KEY_3_BYTES,KEY_2_BYTES)).contains(-2L); + assertThat(clusterConnection.hashCommands().hPersist(KEY_3_BYTES, KEY_2_BYTES)).contains(-2L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hTtlReturnsMinusOneWhenFieldHasNoExpiration() { + nativeConnection.hset(KEY_1, KEY_2, VALUE_3); assertThat(clusterConnection.hashCommands().hTtl(KEY_1_BYTES, KEY_2_BYTES)).contains(-1L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hTtlReturnsMinusTwoWhenFieldOrKeyMissing() { assertThat(clusterConnection.hashCommands().hTtl(KEY_1_BYTES, KEY_1_BYTES)).contains(-2L); - assertThat(clusterConnection.hashCommands().hTtl(KEY_3_BYTES,KEY_2_BYTES)).contains(-2L); - + assertThat(clusterConnection.hashCommands().hTtl(KEY_3_BYTES, KEY_2_BYTES)).contains(-2L); } @Test // DATAREDIS-315 @@ -1346,7 +1394,7 @@ public void blMoveShouldMoveElementsCorrectly() { .isEqualTo(VALUE_2_BYTES); assertThat( clusterConnection.bLMove(SAME_SLOT_KEY_1_BYTES, SAME_SLOT_KEY_2_BYTES, Direction.RIGHT, Direction.LEFT, 0.01)) - .isNull(); + .isNull(); assertThat(nativeConnection.lrange(SAME_SLOT_KEY_1, 0, -1)).isEmpty(); assertThat(nativeConnection.lrange(SAME_SLOT_KEY_2, 0, -1)).containsExactly(VALUE_2, VALUE_3); @@ -2946,13 +2994,13 @@ void bitFieldIncrByWithOverflowShouldWorkCorrectly() { assertThat(clusterConnection.stringCommands().bitField(JedisConverters.toBytes(KEY_1), create().incr(unsigned(2)).valueAt(BitFieldSubCommands.Offset.offset(102L)).overflow(FAIL).by(1L))) - .containsExactly(1L); + .containsExactly(1L); assertThat(clusterConnection.stringCommands().bitField(JedisConverters.toBytes(KEY_1), create().incr(unsigned(2)).valueAt(BitFieldSubCommands.Offset.offset(102L)).overflow(FAIL).by(1L))) - .containsExactly(2L); + .containsExactly(2L); assertThat(clusterConnection.stringCommands().bitField(JedisConverters.toBytes(KEY_1), create().incr(unsigned(2)).valueAt(BitFieldSubCommands.Offset.offset(102L)).overflow(FAIL).by(1L))) - .containsExactly(3L); + .containsExactly(3L); assertThat(clusterConnection.stringCommands() .bitField(JedisConverters.toBytes(KEY_1), create().incr(unsigned(2)).valueAt(BitFieldSubCommands.Offset.offset(102L)).overflow(FAIL).by(1L)) @@ -2964,7 +3012,7 @@ void bitfieldShouldAllowMultipleSubcommands() { assertThat(clusterConnection.stringCommands().bitField(JedisConverters.toBytes(KEY_1), create().incr(signed(5)).valueAt(BitFieldSubCommands.Offset.offset(100L)).by(1L).get(unsigned(4)).valueAt(0L))) - .containsExactly(1L, 0L); + .containsExactly(1L, 0L); } @Test // DATAREDIS-562 @@ -2974,13 +3022,13 @@ void bitfieldShouldWorkUsingNonZeroBasedOffset() { clusterConnection.stringCommands().bitField(JedisConverters.toBytes(KEY_1), create().set(INT_8).valueAt(BitFieldSubCommands.Offset.offset(0L).multipliedByTypeLength()).to(100L) .set(INT_8).valueAt(BitFieldSubCommands.Offset.offset(1L).multipliedByTypeLength()).to(200L))) - .containsExactly(0L, 0L); + .containsExactly(0L, 0L); assertThat( clusterConnection.stringCommands() .bitField(JedisConverters.toBytes(KEY_1), create().get(INT_8).valueAt(BitFieldSubCommands.Offset.offset(0L).multipliedByTypeLength()).get(INT_8) - .valueAt(BitFieldSubCommands.Offset.offset(1L).multipliedByTypeLength()))).containsExactly(100L, - -56L); + .valueAt(BitFieldSubCommands.Offset.offset(1L).multipliedByTypeLength()))) + .containsExactly(100L, -56L); } @Test // DATAREDIS-1005 @@ -3125,7 +3173,8 @@ void shouldUseCachedTopology() { assertThat(topology).isInstanceOf(JedisClusterConnection.JedisClusterTopology.class); assertThat(provider.shouldUseCachedValue(null)).isFalse(); - assertThat(provider.shouldUseCachedValue(new JedisClusterConnection.JedisClusterTopology(Set.of(), System.currentTimeMillis() - 101, 100))).isFalse(); + assertThat(provider.shouldUseCachedValue( + new JedisClusterConnection.JedisClusterTopology(Set.of(), System.currentTimeMillis() - 101, 100))).isFalse(); assertThat(provider.shouldUseCachedValue( new JedisClusterConnection.JedisClusterTopology(Set.of(), System.currentTimeMillis() + 100, 100))).isTrue(); } 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 5611fb351f..1d45dc739e 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 @@ -15,16 +15,35 @@ */ package org.springframework.data.redis.connection.lettuce; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.data.Offset.offset; -import static org.springframework.data.redis.connection.BitFieldSubCommands.*; -import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldIncrBy.Overflow.*; -import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.*; -import static org.springframework.data.redis.connection.ClusterTestVariables.*; -import static org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit.*; -import static org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs.*; -import static org.springframework.data.redis.connection.RedisZSetCommands.*; -import static org.springframework.data.redis.core.ScanOptions.*; +import static org.springframework.data.redis.connection.BitFieldSubCommands.create; +import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldIncrBy.Overflow.FAIL; +import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.INT_8; +import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.signed; +import static org.springframework.data.redis.connection.BitFieldSubCommands.BitFieldType.unsigned; +import static org.springframework.data.redis.connection.ClusterTestVariables.CLUSTER_HOST; +import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_1; +import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_2; +import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_3; +import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_4; +import static org.springframework.data.redis.connection.ClusterTestVariables.MASTER_NODE_1_PORT; +import static org.springframework.data.redis.connection.ClusterTestVariables.MASTER_NODE_2_PORT; +import static org.springframework.data.redis.connection.ClusterTestVariables.MASTER_NODE_3_PORT; +import static org.springframework.data.redis.connection.ClusterTestVariables.REPLICAOF_NODE_1_PORT; +import static org.springframework.data.redis.connection.ClusterTestVariables.SAME_SLOT_KEY_1; +import static org.springframework.data.redis.connection.ClusterTestVariables.SAME_SLOT_KEY_2; +import static org.springframework.data.redis.connection.ClusterTestVariables.SAME_SLOT_KEY_3; +import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_1; +import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_2; +import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_3; +import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_4; +import static org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit.KILOMETERS; +import static org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs; +import static org.springframework.data.redis.connection.RedisZSetCommands.Range; +import static org.springframework.data.redis.core.ScanOptions.scanOptions; import io.lettuce.core.cluster.RedisClusterClient; import io.lettuce.core.cluster.api.sync.RedisAdvancedClusterCommands; @@ -33,7 +52,17 @@ import java.nio.charset.StandardCharsets; import java.time.Duration; import java.time.Instant; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; import java.util.concurrent.TimeUnit; import org.assertj.core.data.Offset; @@ -49,11 +78,21 @@ import org.springframework.data.geo.Distance; import org.springframework.data.geo.GeoResults; import org.springframework.data.geo.Point; -import org.springframework.data.redis.connection.*; +import org.springframework.data.redis.connection.BitFieldSubCommands; +import org.springframework.data.redis.connection.ClusterConnectionTests; +import org.springframework.data.redis.connection.ClusterSlotHashUtil; +import org.springframework.data.redis.connection.ClusterTestVariables; +import org.springframework.data.redis.connection.DataType; +import org.springframework.data.redis.connection.DefaultSortParameters; import org.springframework.data.redis.connection.Limit; +import org.springframework.data.redis.connection.RedisClusterConfiguration; +import org.springframework.data.redis.connection.RedisClusterConnection; +import org.springframework.data.redis.connection.RedisClusterNode; import org.springframework.data.redis.connection.RedisClusterNode.SlotRange; import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation; +import org.springframework.data.redis.connection.RedisListCommands; import org.springframework.data.redis.connection.RedisListCommands.Position; +import org.springframework.data.redis.connection.RedisNode; import org.springframework.data.redis.connection.RedisServerCommands.FlushOption; import org.springframework.data.redis.connection.RedisStringCommands.BitOperation; import org.springframework.data.redis.connection.RedisStringCommands.SetOption; @@ -1097,7 +1136,7 @@ public void hStrLenReturnsZeroWhenKeyDoesNotExist() { assertThat(clusterConnection.hashCommands().hStrLen(KEY_1_BYTES, KEY_1_BYTES)).isEqualTo(0L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hExpireReturnsSuccessAndSetsTTL() { @@ -1107,7 +1146,7 @@ public void hExpireReturnsSuccessAndSetsTTL() { assertThat(clusterConnection.hTtl(KEY_1_BYTES, KEY_2_BYTES)).allSatisfy(val -> assertThat(val).isBetween(0L, 5L)); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hExpireReturnsMinusTwoWhenFieldDoesNotExist() { @@ -1118,17 +1157,19 @@ public void hExpireReturnsMinusTwoWhenFieldDoesNotExist() { assertThat(clusterConnection.hashCommands().hExpire(KEY_2_BYTES, 5L, KEY_2_BYTES)).contains(-2L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hExpireReturnsTwoWhenZeroProvided() { + nativeConnection.hset(KEY_1, KEY_2, VALUE_3); assertThat(clusterConnection.hashCommands().hExpire(KEY_1_BYTES, 0L, KEY_2_BYTES)).contains(2L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hpExpireReturnsSuccessAndSetsTTL() { + nativeConnection.hset(KEY_1, KEY_2, VALUE_3); assertThat(clusterConnection.hashCommands().hpExpire(KEY_1_BYTES, 5000L, KEY_2_BYTES)).contains(1L); @@ -1136,7 +1177,7 @@ public void hpExpireReturnsSuccessAndSetsTTL() { .allSatisfy(val -> assertThat(val).isBetween(0L, 5000L)); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hpExpireReturnsMinusTwoWhenFieldDoesNotExist() { @@ -1147,7 +1188,7 @@ public void hpExpireReturnsMinusTwoWhenFieldDoesNotExist() { assertThat(clusterConnection.hashCommands().hpExpire(KEY_2_BYTES, 5L, KEY_2_BYTES)).contains(-2L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hpExpireReturnsTwoWhenZeroProvided() { @@ -1156,17 +1197,18 @@ public void hpExpireReturnsTwoWhenZeroProvided() { assertThat(clusterConnection.hashCommands().hpExpire(KEY_1_BYTES, 0L, KEY_2_BYTES)).contains(2L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hExpireAtReturnsSuccessAndSetsTTL() { nativeConnection.hset(KEY_1, KEY_2, VALUE_3); long inFiveSeconds = Instant.now().plusSeconds(5L).getEpochSecond(); + assertThat(clusterConnection.hashCommands().hExpireAt(KEY_1_BYTES, inFiveSeconds, KEY_2_BYTES)).contains(1L); assertThat(clusterConnection.hTtl(KEY_1_BYTES, KEY_2_BYTES)).allSatisfy(val -> assertThat(val).isBetween(0L, 5L)); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hExpireAtReturnsMinusTwoWhenFieldDoesNotExist() { @@ -1180,9 +1222,10 @@ public void hExpireAtReturnsMinusTwoWhenFieldDoesNotExist() { assertThat(clusterConnection.hashCommands().hExpireAt(KEY_2_BYTES, inFiveSeconds, KEY_2_BYTES)).contains(-2L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hExpireAdReturnsTwoWhenZeroProvided() { + nativeConnection.hset(KEY_1, KEY_2, VALUE_3); assertThat(clusterConnection.hashCommands().hExpireAt(KEY_1_BYTES, 0L, KEY_2_BYTES)).contains(2L); @@ -1194,12 +1237,13 @@ public void hpExpireAtReturnsSuccessAndSetsTTL() { nativeConnection.hset(KEY_1, KEY_2, VALUE_3); long inFiveSeconds = Instant.now().plusSeconds(5L).toEpochMilli(); + assertThat(clusterConnection.hashCommands().hpExpireAt(KEY_1_BYTES, inFiveSeconds, KEY_2_BYTES)).contains(1L); assertThat(clusterConnection.hpTtl(KEY_1_BYTES, KEY_2_BYTES)) .allSatisfy(val -> assertThat(val).isGreaterThan(1000L).isLessThanOrEqualTo(5000L)); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hpExpireAtReturnsMinusTwoWhenFieldDoesNotExist() { @@ -1212,7 +1256,7 @@ public void hpExpireAtReturnsMinusTwoWhenFieldDoesNotExist() { assertThat(clusterConnection.hashCommands().hpExpireAt(KEY_2_BYTES, inFiveSeconds, KEY_2_BYTES)).contains(-2L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hpExpireAdReturnsTwoWhenZeroProvided() { @@ -1221,17 +1265,17 @@ public void hpExpireAdReturnsTwoWhenZeroProvided() { assertThat(clusterConnection.hashCommands().hpExpireAt(KEY_1_BYTES, 0L, KEY_2_BYTES)).contains(2L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hPersistReturnsSuccessAndPersistsField() { nativeConnection.hset(KEY_1, KEY_2, VALUE_3); assertThat(clusterConnection.hashCommands().hExpire(KEY_1_BYTES, 5L, KEY_2_BYTES)).contains(1L); - assertThat(clusterConnection.hashCommands().hPersist(KEY_1_BYTES, KEY_2_BYTES)).contains(1L); + assertThat(clusterConnection.hashCommands().hPersist(KEY_1_BYTES, KEY_2_BYTES)).contains(1L); assertThat(clusterConnection.hTtl(KEY_1_BYTES, KEY_2_BYTES)).contains(-1L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hPersistReturnsMinusOneWhenFieldDoesNotHaveExpiration() { @@ -1239,17 +1283,18 @@ public void hPersistReturnsMinusOneWhenFieldDoesNotHaveExpiration() { assertThat(clusterConnection.hashCommands().hPersist(KEY_1_BYTES, KEY_2_BYTES)).contains(-1L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hPersistReturnsMinusTwoWhenFieldOrKeyMissing() { + nativeConnection.hset(KEY_1, KEY_2, VALUE_3); assertThat(clusterConnection.hashCommands().hPersist(KEY_1_BYTES, KEY_1_BYTES)).contains(-2L); - assertThat(clusterConnection.hashCommands().hPersist(KEY_3_BYTES,KEY_2_BYTES)).contains(-2L); + assertThat(clusterConnection.hashCommands().hPersist(KEY_3_BYTES, KEY_2_BYTES)).contains(-2L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hTtlReturnsMinusOneWhenFieldHasNoExpiration() { @@ -1259,12 +1304,12 @@ public void hTtlReturnsMinusOneWhenFieldHasNoExpiration() { assertThat(clusterConnection.hashCommands().hTtl(KEY_1_BYTES, TimeUnit.HOURS, KEY_2_BYTES)).contains(-1L); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hTtlReturnsMinusTwoWhenFieldOrKeyMissing() { assertThat(clusterConnection.hashCommands().hTtl(KEY_1_BYTES, KEY_1_BYTES)).contains(-2L); - assertThat(clusterConnection.hashCommands().hTtl(KEY_3_BYTES,KEY_2_BYTES)).contains(-2L); + assertThat(clusterConnection.hashCommands().hTtl(KEY_3_BYTES, KEY_2_BYTES)).contains(-2L); } @Test // DATAREDIS-315 diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveHashCommandsIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveHashCommandsIntegrationTests.java index 4ef5fcffe3..bc1f8cc204 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveHashCommandsIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveHashCommandsIntegrationTests.java @@ -15,9 +15,8 @@ */ package org.springframework.data.redis.connection.lettuce; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; -import org.springframework.data.redis.test.condition.EnabledOnCommand; import reactor.test.StepVerifier; import java.nio.ByteBuffer; @@ -31,6 +30,7 @@ import java.util.Map; import org.springframework.data.redis.core.ScanOptions; +import org.springframework.data.redis.test.condition.EnabledOnCommand; import org.springframework.data.redis.test.extension.parametrized.ParameterizedRedisTest; /** @@ -107,8 +107,7 @@ void hMGetShouldReturnValueForFields() { nativeCommands.hset(KEY_1, FIELD_3, VALUE_3); connection.hashCommands().hMGet(KEY_1_BBUFFER, Arrays.asList(FIELD_1_BBUFFER, FIELD_3_BBUFFER)) - .as(StepVerifier::create) - .consumeNextWith(actual -> { + .as(StepVerifier::create).consumeNextWith(actual -> { assertThat(actual).contains(VALUE_1_BBUFFER, VALUE_3_BBUFFER); @@ -124,13 +123,11 @@ void hMGetShouldReturnNullValueForFieldsThatHaveNoValue() { connection.hashCommands().hMGet(KEY_1_BBUFFER, Collections.singletonList(FIELD_1_BBUFFER)).as(StepVerifier::create) .expectNext(Collections.singletonList(VALUE_1_BBUFFER)).verifyComplete(); - connection.hashCommands().hMGet(KEY_1_BBUFFER, Collections.singletonList(FIELD_2_BBUFFER)) - .as(StepVerifier::create) + connection.hashCommands().hMGet(KEY_1_BBUFFER, Collections.singletonList(FIELD_2_BBUFFER)).as(StepVerifier::create) .expectNext(Collections.singletonList(null)).verifyComplete(); connection.hashCommands().hMGet(KEY_1_BBUFFER, Arrays.asList(FIELD_1_BBUFFER, FIELD_2_BBUFFER, FIELD_3_BBUFFER)) - .as(StepVerifier::create) - .expectNext(Arrays.asList(VALUE_1_BBUFFER, null, VALUE_3_BBUFFER)).verifyComplete(); + .as(StepVerifier::create).expectNext(Arrays.asList(VALUE_1_BBUFFER, null, VALUE_3_BBUFFER)).verifyComplete(); } @ParameterizedRedisTest // DATAREDIS-525 @@ -197,8 +194,7 @@ void hDelShouldRemoveMultipleFieldsCorrectly() { nativeCommands.hset(KEY_1, FIELD_3, VALUE_3); connection.hashCommands().hDel(KEY_1_BBUFFER, Arrays.asList(FIELD_1_BBUFFER, FIELD_3_BBUFFER)) - .as(StepVerifier::create) - .expectNext(2L).verifyComplete(); + .as(StepVerifier::create).expectNext(2L).verifyComplete(); } @ParameterizedRedisTest // DATAREDIS-525 @@ -293,62 +289,50 @@ void hStrLenReturnsZeroWhenKeyDoesNotExist() { .verifyComplete(); } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void hExpireShouldHandleMultipleParametersCorrectly() { + assertThat(nativeCommands.hset(KEY_1, FIELD_1, VALUE_1)).isTrue(); assertThat(nativeCommands.hset(KEY_1, FIELD_2, VALUE_2)).isTrue(); final var fields = Arrays.asList(FIELD_1_BBUFFER, FIELD_2_BBUFFER, FIELD_3_BBUFFER); connection.hashCommands().hExpire(KEY_1_BBUFFER, Duration.ofSeconds(1), fields).as(StepVerifier::create) // - .expectNext(1L) - .expectNext(1L) - .expectNext(-2L) - .expectComplete() - .verify(); + .expectNext(1L).expectNext(1L).expectNext(-2L).expectComplete().verify(); assertThat(nativeCommands.httl(KEY_1, FIELD_1)).allSatisfy(it -> assertThat(it).isBetween(0L, 1000L)); assertThat(nativeCommands.httl(KEY_1, FIELD_2)).allSatisfy(it -> assertThat(it).isBetween(0L, 1000L)); assertThat(nativeCommands.httl(KEY_1, FIELD_3)).allSatisfy(it -> assertThat(it).isEqualTo(-2L)); - } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void hExpireAtShouldHandleMultipleParametersCorrectly() { + assertThat(nativeCommands.hset(KEY_1, FIELD_1, VALUE_1)).isTrue(); assertThat(nativeCommands.hset(KEY_1, FIELD_2, VALUE_2)).isTrue(); final var fields = Arrays.asList(FIELD_1_BBUFFER, FIELD_2_BBUFFER, FIELD_3_BBUFFER); connection.hashCommands().hExpireAt(KEY_1_BBUFFER, Instant.now().plusSeconds(1), fields).as(StepVerifier::create) // - .expectNext(1L) - .expectNext(1L) - .expectNext(-2L) - .expectComplete() - .verify(); + .expectNext(1L).expectNext(1L).expectNext(-2L).expectComplete().verify(); assertThat(nativeCommands.httl(KEY_1, FIELD_1, FIELD_2)).allSatisfy(it -> assertThat(it).isBetween(0L, 1000L)); assertThat(nativeCommands.httl(KEY_1, FIELD_3)).allSatisfy(it -> assertThat(it).isEqualTo(-2L)); - } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void hPersistShouldPersistFields() { + assertThat(nativeCommands.hset(KEY_1, FIELD_1, VALUE_1)).isTrue(); assertThat(nativeCommands.hset(KEY_1, FIELD_2, VALUE_2)).isTrue(); - assertThat(nativeCommands.hexpire(KEY_1, 1000, FIELD_1)) - .allSatisfy(it -> assertThat(it).isEqualTo(1L)); + assertThat(nativeCommands.hexpire(KEY_1, 1000, FIELD_1)).allSatisfy(it -> assertThat(it).isEqualTo(1L)); final var fields = Arrays.asList(FIELD_1_BBUFFER, FIELD_2_BBUFFER, FIELD_3_BBUFFER); connection.hashCommands().hPersist(KEY_1_BBUFFER, fields).as(StepVerifier::create) // - .expectNext(1L) - .expectNext(-1L) - .expectNext(-2L) - .expectComplete() - .verify(); + .expectNext(1L).expectNext(-1L).expectNext(-2L).expectComplete().verify(); assertThat(nativeCommands.httl(KEY_1, FIELD_1, FIELD_2)).allSatisfy(it -> assertThat(it).isEqualTo(-1L)); } diff --git a/src/test/java/org/springframework/data/redis/core/DefaultHashOperationsIntegrationTests.java b/src/test/java/org/springframework/data/redis/core/DefaultHashOperationsIntegrationTests.java index bbb84a76de..6499ae325a 100644 --- a/src/test/java/org/springframework/data/redis/core/DefaultHashOperationsIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/core/DefaultHashOperationsIntegrationTests.java @@ -15,8 +15,9 @@ */ package org.springframework.data.redis.core; -import static org.assertj.core.api.Assertions.*; -import static org.assertj.core.api.Assumptions.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assumptions.assumeThat; import java.io.IOException; import java.time.Duration; @@ -29,7 +30,6 @@ import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.jupiter.api.BeforeEach; - import org.springframework.data.redis.ObjectFactory; import org.springframework.data.redis.RawObjectFactory; import org.springframework.data.redis.StringObjectFactory; @@ -212,7 +212,7 @@ void randomValue() { assertThat(values).hasSize(2).containsEntry(key1, val1).containsEntry(key2, val2); } - @EnabledOnCommand("HEXPIRE") + @EnabledOnCommand("HEXPIRE") // GH-3054 @ParameterizedRedisTest void testExpireAndGetExpireMillis() { @@ -237,7 +237,7 @@ void testExpireAndGetExpireMillis() { }); } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void testExpireAndGetExpireSeconds() { @@ -268,7 +268,7 @@ void testExpireAndGetExpireSeconds() { }); } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void testBoundExpireAndGetExpireSeconds() { @@ -300,7 +300,7 @@ void testBoundExpireAndGetExpireSeconds() { }); } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void testExpireAtAndGetExpireMillis() { @@ -325,7 +325,7 @@ void testExpireAtAndGetExpireMillis() { }); } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void expireThrowsErrorOfNanoPrecision() { @@ -336,7 +336,7 @@ void expireThrowsErrorOfNanoPrecision() { .isThrownBy(() -> redisTemplate.opsForHash().getTimeToLive(key, TimeUnit.NANOSECONDS, List.of(key1))); } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void testExpireWithOptionsNone() { @@ -349,12 +349,13 @@ void testExpireWithOptionsNone() { hashOps.put(key, key1, val1); hashOps.put(key, key2, val2); - ExpireChanges expire = redisTemplate.opsForHash().expire(key, org.springframework.data.redis.core.types.Expiration.seconds(20), FieldExpirationOptions.none(), List.of(key1)); + ExpireChanges expire = redisTemplate.opsForHash().expire(key, + org.springframework.data.redis.core.types.Expiration.seconds(20), FieldExpirationOptions.none(), List.of(key1)); assertThat(expire.allOk()).isTrue(); } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void testExpireWithOptions() { @@ -367,16 +368,20 @@ void testExpireWithOptions() { hashOps.put(key, key1, val1); hashOps.put(key, key2, val2); - redisTemplate.opsForHash().expire(key, org.springframework.data.redis.core.types.Expiration.seconds(20), FieldExpirationOptions.none(), List.of(key1)); - redisTemplate.opsForHash().expire(key, org.springframework.data.redis.core.types.Expiration.seconds(60), FieldExpirationOptions.none(), List.of(key2)); + redisTemplate.opsForHash().expire(key, org.springframework.data.redis.core.types.Expiration.seconds(20), + FieldExpirationOptions.none(), List.of(key1)); + redisTemplate.opsForHash().expire(key, org.springframework.data.redis.core.types.Expiration.seconds(60), + FieldExpirationOptions.none(), List.of(key2)); - ExpireChanges changes = redisTemplate.opsForHash().expire(key, org.springframework.data.redis.core.types.Expiration.seconds(30), FieldExpirationOptions.builder().gt().build(), List.of(key1, key2)); + ExpireChanges changes = redisTemplate.opsForHash().expire(key, + org.springframework.data.redis.core.types.Expiration.seconds(30), FieldExpirationOptions.builder().gt().build(), + List.of(key1, key2)); assertThat(changes.ok()).containsExactly(key1); assertThat(changes.skipped()).containsExactly(key2); } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void testPersistAndGetExpireMillis() { diff --git a/src/test/java/org/springframework/data/redis/core/DefaultReactiveHashOperationsIntegrationTests.java b/src/test/java/org/springframework/data/redis/core/DefaultReactiveHashOperationsIntegrationTests.java index 2d574ee123..48532b2feb 100644 --- a/src/test/java/org/springframework/data/redis/core/DefaultReactiveHashOperationsIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/core/DefaultReactiveHashOperationsIntegrationTests.java @@ -15,9 +15,9 @@ */ package org.springframework.data.redis.core; -import static org.assertj.core.api.Assertions.*; -import static org.assertj.core.api.Assumptions.*; -import static org.junit.jupiter.api.condition.OS.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assumptions.assumeThat; +import static org.junit.jupiter.api.condition.OS.MAC; import reactor.test.StepVerifier; @@ -33,7 +33,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.condition.DisabledOnOs; - import org.springframework.data.redis.ObjectFactory; import org.springframework.data.redis.RawObjectFactory; import org.springframework.data.redis.SettingsUtils; @@ -506,7 +505,7 @@ void scan() { .verifyComplete(); } - @EnabledOnCommand("HEXPIRE") + @EnabledOnCommand("HEXPIRE") // GH-3054 @ParameterizedRedisTest void testExpireAndGetExpireMillis() { @@ -531,7 +530,7 @@ void testExpireAndGetExpireMillis() { }).verifyComplete(); } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void testExpireWithOptions() { @@ -543,23 +542,32 @@ void testExpireWithOptions() { putAll(key, key1, val1, key2, val2); - hashOperations.expire(key, org.springframework.data.redis.core.types.Expiration.seconds(20), FieldExpirationOptions.none(), List.of(key1)).as(StepVerifier::create)// - .assertNext(changes -> { - assertThat(changes.allOk()).isTrue(); - }).verifyComplete(); - hashOperations.expire(key, org.springframework.data.redis.core.types.Expiration.seconds(60), FieldExpirationOptions.none(), List.of(key2)).as(StepVerifier::create)// - .assertNext(changes -> { - assertThat(changes.allOk()).isTrue(); - }).verifyComplete(); - - hashOperations.expire(key, org.springframework.data.redis.core.types.Expiration.seconds(30), FieldExpirationOptions.builder().gt().build(), List.of(key1, key2)).as(StepVerifier::create)// - .assertNext(changes -> { - assertThat(changes.ok()).containsExactly(key1); - assertThat(changes.skipped()).containsExactly(key2); - }).verifyComplete(); + hashOperations + .expire(key, org.springframework.data.redis.core.types.Expiration.seconds(20), FieldExpirationOptions.none(), + List.of(key1)) + .as(StepVerifier::create)// + .assertNext(changes -> { + assertThat(changes.allOk()).isTrue(); + }).verifyComplete(); + hashOperations + .expire(key, org.springframework.data.redis.core.types.Expiration.seconds(60), FieldExpirationOptions.none(), + List.of(key2)) + .as(StepVerifier::create)// + .assertNext(changes -> { + assertThat(changes.allOk()).isTrue(); + }).verifyComplete(); + + hashOperations + .expire(key, org.springframework.data.redis.core.types.Expiration.seconds(30), + FieldExpirationOptions.builder().gt().build(), List.of(key1, key2)) + .as(StepVerifier::create)// + .assertNext(changes -> { + assertThat(changes.ok()).containsExactly(key1); + assertThat(changes.skipped()).containsExactly(key2); + }).verifyComplete(); } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void testExpireAndGetExpireSeconds() { @@ -583,10 +591,9 @@ void testExpireAndGetExpireSeconds() { assertThat(it.expirationOf(key1).raw()).isBetween(0L, 5L); assertThat(it.expirationOf(key2).raw()).isBetween(0L, 5L); }).verifyComplete(); - } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void testExpireAtAndGetExpireMillis() { @@ -611,7 +618,7 @@ void testExpireAtAndGetExpireMillis() { }).verifyComplete(); } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void testPersistAndGetExpireMillis() { @@ -638,7 +645,6 @@ void testPersistAndGetExpireMillis() { .assertNext(expirations -> { assertThat(expirations.persistent()).contains(key1, key2); }).verifyComplete(); - } @ParameterizedRedisTest // DATAREDIS-602 diff --git a/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisMapIntegrationTests.java b/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisMapIntegrationTests.java index 0a03b7340e..31e93d06ac 100644 --- a/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisMapIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisMapIntegrationTests.java @@ -15,8 +15,9 @@ */ package org.springframework.data.redis.support.collections; -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.*; -import static org.assertj.core.api.Assumptions.*; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assumptions.assumeThat; import java.io.IOException; import java.text.DecimalFormat; @@ -35,7 +36,6 @@ import org.assertj.core.api.Assumptions; import org.junit.jupiter.api.BeforeEach; - import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.DoubleAsStringObjectFactory; import org.springframework.data.redis.LongAsStringObjectFactory; @@ -197,7 +197,7 @@ void testIncrement() { assertThat(map.increment(k1, 10)).isEqualTo(Long.valueOf(Long.valueOf((String) v1) + 10)); } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void testExpire() { @@ -216,7 +216,7 @@ void testExpire() { assertThat(ops.persist()).satisfies(ExpireChanges::allOk); } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void testExpireAt() {