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 1e9fd94f3..c46373774 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 @@ public interface ReactiveHashCommands { 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 interface ReactiveHashCommands { 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 f2d736b8e..d03870852 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 @@ public interface RedisHashCommands { * @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 @@ public interface RedisHashCommands { * @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 @@ public interface RedisHashCommands { * @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 @@ public interface RedisHashCommands { * @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 @@ public interface RedisHashCommands { * @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 @@ public interface RedisHashCommands { * @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 @@ public interface RedisHashCommands { * @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 5ff0e9946..1069e430c 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 @@ public interface StringRedisConnection extends RedisConnection { * @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 @@ public interface StringRedisConnection extends RedisConnection { * @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 @@ public interface StringRedisConnection extends RedisConnection { * @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 @@ public interface StringRedisConnection extends RedisConnection { * @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 33e0ff82e..d49041a66 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 @@ import org.springframework.lang.Nullable; 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 @@ public interface BoundHashFieldExpirationOperations { 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 @@ public interface BoundHashFieldExpirationOperations { 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 @@ public interface BoundHashFieldExpirationOperations { 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 @@ public interface BoundHashFieldExpirationOperations { 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 8c97c43fc..540b35177 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.concurrent.TimeUnit; 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 @@ class DefaultReactiveHashOperations implements ReactiveHashOperations } @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 67c4ce0fa..f57143c73 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 @@ public interface HashOperations { * @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 757dbcea7..2fe3b0c65 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 @@ public interface ReactiveHashOperations { */ 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 @@ public interface ReactiveHashOperations { * @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 @@ public interface ReactiveHashOperations { * * @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 @@ public interface ReactiveHashOperations { * * @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 @@ public interface ReactiveHashOperations { * @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 def0dca04..8c1ad67ad 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 @@ public interface RedisOperations { @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 94b8db765..573f10524 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 @@ public abstract class AbstractConnectionIntegrationTests { assertThat(stringSerializer.deserialize((byte[]) getResults().get(1))).isEqualTo("bar"); } - @Test + @Test // GH- @EnabledOnCommand("HEXPIRE") void testExecuteHashFieldExpiration() { @@ -3473,7 +3497,7 @@ public abstract class AbstractConnectionIntegrationTests { verifyResults(Arrays.asList(new Object[] { 0L })); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hExpireReturnsSuccessAndSetsTTL() { @@ -3484,10 +3508,10 @@ public abstract class AbstractConnectionIntegrationTests { 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 abstract class AbstractConnectionIntegrationTests { 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 abstract class AbstractConnectionIntegrationTests { verifyResults(Arrays.asList(Boolean.TRUE, List.of(2L))); } - @Test + @Test // GH-3054 @EnabledOnCommand("HPEXPIRE") public void hpExpireReturnsSuccessAndSetsTTL() { @@ -3519,10 +3543,10 @@ public abstract class AbstractConnectionIntegrationTests { 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 abstract class AbstractConnectionIntegrationTests { 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 abstract class AbstractConnectionIntegrationTests { verifyResults(Arrays.asList(Boolean.TRUE, List.of(2L))); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIREAT") public void hExpireAtReturnsSuccessAndSetsTTL() { @@ -3556,10 +3580,10 @@ public abstract class AbstractConnectionIntegrationTests { 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 abstract class AbstractConnectionIntegrationTests { 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 abstract class AbstractConnectionIntegrationTests { verifyResults(Arrays.asList(Boolean.TRUE, List.of(2L))); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIREAT") public void hpExpireAtReturnsSuccessAndSetsTTL() { @@ -3597,10 +3621,10 @@ public abstract class AbstractConnectionIntegrationTests { 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 abstract class AbstractConnectionIntegrationTests { 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 abstract class AbstractConnectionIntegrationTests { verifyResults(Arrays.asList(Boolean.TRUE, List.of(2L))); } - @Test + @Test // GH-3054 @EnabledOnCommand("HPERSIST") public void hPersistReturnsSuccessAndPersistsField() { @@ -3637,7 +3661,7 @@ public abstract class AbstractConnectionIntegrationTests { 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 abstract class AbstractConnectionIntegrationTests { verifyResults(Arrays.asList(Boolean.TRUE, List.of(-1L))); } - @Test + @Test // GH-3054 @EnabledOnCommand("HPERSIST") public void hPersistReturnsMinusTwoWhenFieldOrKeyMissing() { @@ -3658,7 +3682,7 @@ public abstract class AbstractConnectionIntegrationTests { 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 abstract class AbstractConnectionIntegrationTests { verifyResults(Arrays.asList(Boolean.TRUE, List.of(-1L))); } - @Test + @Test // GH-3054 @EnabledOnCommand("HTTL") public void hTtlReturnsMinusIndependendOfTimeUnitOneWhenFieldHasNoExpiration() { @@ -3678,7 +3702,7 @@ public abstract class AbstractConnectionIntegrationTests { 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 4e41e6095..4bed88c0a 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.Charset; 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 class JedisClusterConnectionTests implements ClusterConnectionTests { 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 class JedisClusterConnectionTests implements ClusterConnectionTests { .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 class JedisClusterConnectionTests implements ClusterConnectionTests { 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 class JedisClusterConnectionTests implements ClusterConnectionTests { 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 class JedisClusterConnectionTests implements ClusterConnectionTests { 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 class JedisClusterConnectionTests implements ClusterConnectionTests { 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 class JedisClusterConnectionTests implements ClusterConnectionTests { .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 @@ public class JedisClusterConnectionTests implements ClusterConnectionTests { 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 @@ public class JedisClusterConnectionTests implements ClusterConnectionTests { 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 @@ public class JedisClusterConnectionTests implements ClusterConnectionTests { 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 @@ public class JedisClusterConnectionTests implements ClusterConnectionTests { 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 5611fb351..1d45dc739 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 io.lettuce.core.codec.ByteArrayCodec; 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.Circle; 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 class LettuceClusterConnectionTests implements ClusterConnectionTests { 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 class LettuceClusterConnectionTests implements ClusterConnectionTests { 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 class LettuceClusterConnectionTests implements ClusterConnectionTests { 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 class LettuceClusterConnectionTests implements ClusterConnectionTests { .allSatisfy(val -> assertThat(val).isBetween(0L, 5000L)); } - @Test + @Test // GH-3054 @EnabledOnCommand("HEXPIRE") public void hpExpireReturnsMinusTwoWhenFieldDoesNotExist() { @@ -1147,7 +1188,7 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests { 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 class LettuceClusterConnectionTests implements ClusterConnectionTests { 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 class LettuceClusterConnectionTests implements ClusterConnectionTests { 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 class LettuceClusterConnectionTests implements ClusterConnectionTests { 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 class LettuceClusterConnectionTests implements ClusterConnectionTests { 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 class LettuceClusterConnectionTests implements ClusterConnectionTests { 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 class LettuceClusterConnectionTests implements ClusterConnectionTests { 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 class LettuceClusterConnectionTests implements ClusterConnectionTests { 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 4ef5fcffe..bc1f8cc20 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.LinkedHashMap; 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 @@ public class LettuceReactiveHashCommandsIntegrationTests extends LettuceReactive 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 @@ public class LettuceReactiveHashCommandsIntegrationTests extends LettuceReactive 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 @@ public class LettuceReactiveHashCommandsIntegrationTests extends LettuceReactive 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 @@ public class LettuceReactiveHashCommandsIntegrationTests extends LettuceReactive .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 bbb84a76d..6499ae325 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 java.util.concurrent.TimeUnit; 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 @@ public class DefaultHashOperationsIntegrationTests { assertThat(values).hasSize(2).containsEntry(key1, val1).containsEntry(key2, val2); } - @EnabledOnCommand("HEXPIRE") + @EnabledOnCommand("HEXPIRE") // GH-3054 @ParameterizedRedisTest void testExpireAndGetExpireMillis() { @@ -237,7 +237,7 @@ public class DefaultHashOperationsIntegrationTests { }); } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void testExpireAndGetExpireSeconds() { @@ -268,7 +268,7 @@ public class DefaultHashOperationsIntegrationTests { }); } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void testBoundExpireAndGetExpireSeconds() { @@ -300,7 +300,7 @@ public class DefaultHashOperationsIntegrationTests { }); } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void testExpireAtAndGetExpireMillis() { @@ -325,7 +325,7 @@ public class DefaultHashOperationsIntegrationTests { }); } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void expireThrowsErrorOfNanoPrecision() { @@ -336,7 +336,7 @@ public class DefaultHashOperationsIntegrationTests { .isThrownBy(() -> redisTemplate.opsForHash().getTimeToLive(key, TimeUnit.NANOSECONDS, List.of(key1))); } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void testExpireWithOptionsNone() { @@ -349,12 +349,13 @@ public class DefaultHashOperationsIntegrationTests { 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 @@ public class DefaultHashOperationsIntegrationTests { 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 2d574ee12..48532b2fe 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 java.util.concurrent.TimeUnit; 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 @@ public class DefaultReactiveHashOperationsIntegrationTests { .verifyComplete(); } - @EnabledOnCommand("HEXPIRE") + @EnabledOnCommand("HEXPIRE") // GH-3054 @ParameterizedRedisTest void testExpireAndGetExpireMillis() { @@ -531,7 +530,7 @@ public class DefaultReactiveHashOperationsIntegrationTests { }).verifyComplete(); } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void testExpireWithOptions() { @@ -543,23 +542,32 @@ public class DefaultReactiveHashOperationsIntegrationTests { 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(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(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 @@ public class DefaultReactiveHashOperationsIntegrationTests { 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 @@ public class DefaultReactiveHashOperationsIntegrationTests { }).verifyComplete(); } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void testPersistAndGetExpireMillis() { @@ -638,7 +645,6 @@ public class DefaultReactiveHashOperationsIntegrationTests { .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 0a03b7340..31e93d06a 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 java.util.concurrent.TimeUnit; 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 @@ public abstract class AbstractRedisMapIntegrationTests { 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 @@ public abstract class AbstractRedisMapIntegrationTests { assertThat(ops.persist()).satisfies(ExpireChanges::allOk); } - @ParameterizedRedisTest + @ParameterizedRedisTest // GH-3054 @EnabledOnCommand("HEXPIRE") void testExpireAt() {