From f840580111a241a34b6e2c41d848382d21f4728f Mon Sep 17 00:00:00 2001 From: Chloe Yip Date: Wed, 3 Jul 2024 11:28:28 -0700 Subject: [PATCH 01/23] current progress --- .../api/commands/StreamBaseCommands.java | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/java/client/src/main/java/glide/api/commands/StreamBaseCommands.java b/java/client/src/main/java/glide/api/commands/StreamBaseCommands.java index 41c405ee50..86ea7cea55 100644 --- a/java/client/src/main/java/glide/api/commands/StreamBaseCommands.java +++ b/java/client/src/main/java/glide/api/commands/StreamBaseCommands.java @@ -24,6 +24,9 @@ */ public interface StreamBaseCommands { + /** Redis API keyword used to change the reply to return an array of IDs. */ + String JUSTID_FOR_STREAM_REDIS_API = "JUSTID"; + /** * Adds an entry to the specified stream stored at key.
* If the key doesn't exist, the stream is created. @@ -1036,4 +1039,73 @@ CompletableFuture xclaimJustId( long minIdleTime, String[] ids, StreamClaimOptions options); + + /** + * Transfers ownership of pending stream entries that match the specified criteria. + * + * @see valkey.io for details. + * @param key The key of the stream. + * @param group The consumer group name + * @param consumer The group consumer. + * @param minIdleTime The minimum idle time for the message to be claimed. + * @param start Filters the claimed entries to those that have an ID equal or greater than the specified value. + */ + CompletableFuture xautoclaim( + String key, String group, String consumer, long minIdleTime, String start); + + /** + * Transfers ownership of pending stream entries that match the specified criteria. + * + * @see valkey.io for details. + * @param key The key of the stream. + * @param group The consumer group name + * @param consumer The group consumer. + * @param minIdleTime The minimum idle time for the message to be claimed. + * @param start Filters the claimed entries to those that have an ID equal or greater than the specified value. + * @param count Limits the number of claimed entries to the specified value. + */ + CompletableFuture xautoclaim( + String key, String group, String consumer, long minIdleTime, String start, long count); + + /** + * Transfers ownership of pending stream entries that match the specified criteria. This command + * uses the JUSTID argument to further specify that the return value should contain a list of + * claimed IDs without their field-value info. + * + * @see valkey.io for details. + * @param key The key of the stream. + * @param group The consumer group name + * @param consumer The group consumer. + * @param minIdleTime The minimum idle time for the message to be claimed. + * @param start Filters the claimed entries to those that have an ID equal or greater than the specified value. + */ + CompletableFuture xautoclaimJustId( + String key, + String group, + String consumer, + long minIdleTime, + String start, + String JUSTID_FOR_STREAM_REDIS_API); + + /** + * Transfers ownership of pending stream entries that match the specified criteria. This command + * uses the JUSTID argument to further specify that the return value should contain a list of + * claimed IDs without their field-value info. + * + * @see valkey.io for details. + * @param key The key of the stream. + * @param group The consumer group name + * @param consumer The group consumer. + * @param minIdleTime The minimum idle time for the message to be claimed. + * @param start Filters the claimed entries to those that have an ID equal or greater than the specified value. + * @param count Limits the number of claimed entries to the specified value. + */ + CompletableFuture xuatoclaimJustId( + String key, + String group, + String consumer, + long minIdleTime, + String start, + long count, + String JUSTID_FOR_STREAM_REDIS_API); } From 6a9158df0c6ae8b733f102e045c4ff4e65b3cad3 Mon Sep 17 00:00:00 2001 From: Chloe Yip Date: Wed, 3 Jul 2024 11:50:40 -0700 Subject: [PATCH 02/23] update streamBaseCommands example docs --- .../api/commands/StreamBaseCommands.java | 86 +++++++++++++------ 1 file changed, 62 insertions(+), 24 deletions(-) diff --git a/java/client/src/main/java/glide/api/commands/StreamBaseCommands.java b/java/client/src/main/java/glide/api/commands/StreamBaseCommands.java index 86ea7cea55..60c7ad1f01 100644 --- a/java/client/src/main/java/glide/api/commands/StreamBaseCommands.java +++ b/java/client/src/main/java/glide/api/commands/StreamBaseCommands.java @@ -24,9 +24,6 @@ */ public interface StreamBaseCommands { - /** Redis API keyword used to change the reply to return an array of IDs. */ - String JUSTID_FOR_STREAM_REDIS_API = "JUSTID"; - /** * Adds an entry to the specified stream stored at key.
* If the key doesn't exist, the stream is created. @@ -1048,7 +1045,25 @@ CompletableFuture xclaimJustId( * @param group The consumer group name * @param consumer The group consumer. * @param minIdleTime The minimum idle time for the message to be claimed. - * @param start Filters the claimed entries to those that have an ID equal or greater than the specified value. + * @param start Filters the claimed entries to those that have an ID equal or greater than the + * specified value. + * @return An array containing the following elements: + * - A stream ID to be used as the start + * argument for the next call to XAUTOCLAIM. This ID is equivalent to the next ID + * in the stream after the entries that were scanned, or "0-0" if the entire stream was + * scanned. + * - A mapping of the claimed entries, with the keys being the claimed entry IDs and + * the values being a 2D list of the field-value pairs in the format `[[field1, value1], + * [field2, value2], ...]`. + * - If you are using Redis 7.0.0 or above, the response list will + * also include a list containing the message IDs that were in the Pending Entries List but no + * longer exist in the stream. These IDs are deleted from the Pending Entries List. + * @example + *
+     *      // Redis version < 7.0.0:
+     *      Object[] results = client.xautoclaim("my_stream", "my_group", "my_consumer", 3_600_000L, "0-0").get();
+     *  
+ * */ CompletableFuture xautoclaim( String key, String group, String consumer, long minIdleTime, String start); @@ -1061,51 +1076,74 @@ CompletableFuture xautoclaim( * @param group The consumer group name * @param consumer The group consumer. * @param minIdleTime The minimum idle time for the message to be claimed. - * @param start Filters the claimed entries to those that have an ID equal or greater than the specified value. + * @param start Filters the claimed entries to those that have an ID equal or greater than the + * specified value. * @param count Limits the number of claimed entries to the specified value. + * @return An array containing the following elements: + * - A stream ID to be used as the start + * argument for the next call to XAUTOCLAIM. This ID is equivalent to the next ID + * in the stream after the entries that were scanned, or "0-0" if the entire stream was + * scanned. + * - A mapping of the claimed entries, with the keys being the claimed entry IDs and + * the values being a 2D list of the field-value pairs in the format `[[field1, value1], + * [field2, value2], ...]`. + * - If you are using Redis 7.0.0 or above, the response list will + * also include a list containing the message IDs that were in the Pending Entries List but no + * longer exist in the stream. These IDs are deleted from the Pending Entries List. */ CompletableFuture xautoclaim( String key, String group, String consumer, long minIdleTime, String start, long count); /** * Transfers ownership of pending stream entries that match the specified criteria. This command - * uses the JUSTID argument to further specify that the return value should contain a list of - * claimed IDs without their field-value info. + * uses the JUSTID argument to further specify that the return value should contain a + * list of claimed IDs without their field-value info. * * @see valkey.io for details. * @param key The key of the stream. * @param group The consumer group name * @param consumer The group consumer. * @param minIdleTime The minimum idle time for the message to be claimed. - * @param start Filters the claimed entries to those that have an ID equal or greater than the specified value. + * @param start Filters the claimed entries to those that have an ID equal or greater than the + * specified value. + * @return An array containing the following elements: + * - A stream ID to be used as the start + * argument for the next call to XAUTOCLAIM. This ID is equivalent to the next ID + * in the stream after the entries that were scanned, or "0-0" if the entire stream was + * scanned. + * - A list of the IDs for the claimed entries. + * - If you are using Redis 7.0.0 or + * above, the response list will also include a list containing the message IDs that were in + * the Pending Entries List but no longer exist in the stream. These IDs are deleted from the + * Pending Entries List. */ CompletableFuture xautoclaimJustId( - String key, - String group, - String consumer, - long minIdleTime, - String start, - String JUSTID_FOR_STREAM_REDIS_API); + String key, String group, String consumer, long minIdleTime, String start); /** * Transfers ownership of pending stream entries that match the specified criteria. This command - * uses the JUSTID argument to further specify that the return value should contain a list of - * claimed IDs without their field-value info. + * uses the JUSTID argument to further specify that the return value should contain a + * list of claimed IDs without their field-value info. * * @see valkey.io for details. * @param key The key of the stream. * @param group The consumer group name * @param consumer The group consumer. * @param minIdleTime The minimum idle time for the message to be claimed. - * @param start Filters the claimed entries to those that have an ID equal or greater than the specified value. + * @param start Filters the claimed entries to those that have an ID equal or greater than the + * specified value. * @param count Limits the number of claimed entries to the specified value. + * @return An array containing the following elements: + * - A stream ID to be used as the start + * argument for the next call to XAUTOCLAIM. This ID is equivalent to the next ID + * in the stream after the entries that were scanned, or "0-0" if the entire stream was + * scanned. + * - A list of the IDs for the claimed entries. + * - If you are using Redis 7.0.0 or + * above, the response list will also include a list containing the message IDs that were in + * the Pending Entries List but no longer exist in the stream. These IDs are deleted from the + * Pending Entries List. */ CompletableFuture xuatoclaimJustId( - String key, - String group, - String consumer, - long minIdleTime, - String start, - long count, - String JUSTID_FOR_STREAM_REDIS_API); + String key, String group, String consumer, long minIdleTime, String start, long count); } From 84e2d08f6db4fc3b9b68ad475ecef7437462b52f Mon Sep 17 00:00:00 2001 From: Chloe Yip Date: Wed, 3 Jul 2024 12:11:38 -0700 Subject: [PATCH 03/23] fix documentation --- .../java/glide/api/commands/StreamBaseCommands.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/java/client/src/main/java/glide/api/commands/StreamBaseCommands.java b/java/client/src/main/java/glide/api/commands/StreamBaseCommands.java index 60c7ad1f01..6d267a92f8 100644 --- a/java/client/src/main/java/glide/api/commands/StreamBaseCommands.java +++ b/java/client/src/main/java/glide/api/commands/StreamBaseCommands.java @@ -1048,7 +1048,7 @@ CompletableFuture xclaimJustId( * @param start Filters the claimed entries to those that have an ID equal or greater than the * specified value. * @return An array containing the following elements: - * - A stream ID to be used as the start + * - A stream ID to be used as the start * argument for the next call to XAUTOCLAIM. This ID is equivalent to the next ID * in the stream after the entries that were scanned, or "0-0" if the entire stream was * scanned. @@ -1062,6 +1062,17 @@ CompletableFuture xclaimJustId( *
      *      // Redis version < 7.0.0:
      *      Object[] results = client.xautoclaim("my_stream", "my_group", "my_consumer", 3_600_000L, "0-0").get();
+     * for (Object element: results) {
+     *     System.out.println(element);
+     *
+     *     for (String key: element.get(key)) {
+     *
+     *          for(String entry: ){
+     *             System.out.println(ke);
+     *          }
+     *     }
+     * }
+     *      // Redis version 7.0.0 and above
      *  
* */ From 0184ded7a859a61d97cf14c2133b645bbda7aa0e Mon Sep 17 00:00:00 2001 From: Chloe Yip Date: Wed, 3 Jul 2024 13:39:22 -0700 Subject: [PATCH 04/23] add baseclient --- .../src/main/java/glide/api/BaseClient.java | 68 +++++++++++++++++++ .../api/commands/StreamBaseCommands.java | 37 ++++------ 2 files changed, 80 insertions(+), 25 deletions(-) diff --git a/java/client/src/main/java/glide/api/BaseClient.java b/java/client/src/main/java/glide/api/BaseClient.java index 0ed1a89913..2ae1be4c0e 100644 --- a/java/client/src/main/java/glide/api/BaseClient.java +++ b/java/client/src/main/java/glide/api/BaseClient.java @@ -140,6 +140,7 @@ import static redis_request.RedisRequestOuterClass.RequestType.Watch; import static redis_request.RedisRequestOuterClass.RequestType.XAck; import static redis_request.RedisRequestOuterClass.RequestType.XAdd; +import static redis_request.RedisRequestOuterClass.RequestType.XAutoClaim; import static redis_request.RedisRequestOuterClass.RequestType.XClaim; import static redis_request.RedisRequestOuterClass.RequestType.XDel; import static redis_request.RedisRequestOuterClass.RequestType.XGroupCreate; @@ -2507,6 +2508,73 @@ public CompletableFuture xclaimJustId( XClaim, args, response -> castArray(handleArrayResponse(response), String.class)); } + @Override + public CompletableFuture xautoclaim( + @NonNull String key, + @NonNull String group, + @NonNull String consumer, + long minIdleTime, + @NonNull String start) { + String[] args = + concatenateArrays(new String[] {key, group, consumer, Long.toString(minIdleTime), start}); + return commandManager.submitNewCommand( + XAutoClaim, args, response -> castArray(handleArrayResponse(response), String.class)); + } + + @Override + public CompletableFuture xautoclaim( + @NonNull String key, + @NonNull String group, + @NonNull String consumer, + long minIdleTime, + @NonNull String start, + long count) { + String[] args = + concatenateArrays( + new String[] { + key, group, consumer, Long.toString(minIdleTime), start, Long.toString(count) + }); + return commandManager.submitNewCommand( + XAutoClaim, args, response -> castArray(handleArrayResponse(response), String.class)); + } + + @Override + public CompletableFuture xautoclaimJustId( + @NonNull String key, + @NonNull String group, + @NonNull String consumer, + long minIdleTime, + @NonNull String start) { + String[] args = + concatenateArrays( + new String[] {key, group, consumer, Long.toString(minIdleTime), start, "JUSTID"}); + return commandManager.submitNewCommand( + XAutoClaim, args, response -> castArray(handleArrayResponse(response), String.class)); + } + + @Override + public CompletableFuture xautoclaimJustId( + @NonNull String key, + @NonNull String group, + @NonNull String consumer, + long minIdleTime, + @NonNull String start, + long count) { + String[] args = + concatenateArrays( + new String[] { + key, + group, + consumer, + Long.toString(minIdleTime), + start, + Long.toString(count), + "JUSTID" + }); + return commandManager.submitNewCommand( + XAutoClaim, args, response -> castArray(handleArrayResponse(response), String.class)); + } + @Override public CompletableFuture pttl(@NonNull String key) { return commandManager.submitNewCommand(PTTL, new String[] {key}, this::handleLongResponse); diff --git a/java/client/src/main/java/glide/api/commands/StreamBaseCommands.java b/java/client/src/main/java/glide/api/commands/StreamBaseCommands.java index 6d267a92f8..e8159df499 100644 --- a/java/client/src/main/java/glide/api/commands/StreamBaseCommands.java +++ b/java/client/src/main/java/glide/api/commands/StreamBaseCommands.java @@ -1047,19 +1047,16 @@ CompletableFuture xclaimJustId( * @param minIdleTime The minimum idle time for the message to be claimed. * @param start Filters the claimed entries to those that have an ID equal or greater than the * specified value. - * @return An array containing the following elements: - * - A stream ID to be used as the start + * @return An array containing the following elements: - A stream ID to be used as the start * argument for the next call to XAUTOCLAIM. This ID is equivalent to the next ID * in the stream after the entries that were scanned, or "0-0" if the entire stream was - * scanned. - * - A mapping of the claimed entries, with the keys being the claimed entry IDs and + * scanned. - A mapping of the claimed entries, with the keys being the claimed entry IDs and * the values being a 2D list of the field-value pairs in the format `[[field1, value1], - * [field2, value2], ...]`. - * - If you are using Redis 7.0.0 or above, the response list will + * [field2, value2], ...]`. - If you are using Redis 7.0.0 or above, the response list will * also include a list containing the message IDs that were in the Pending Entries List but no * longer exist in the stream. These IDs are deleted from the Pending Entries List. * @example - *
+     *     
      *      // Redis version < 7.0.0:
      *      Object[] results = client.xautoclaim("my_stream", "my_group", "my_consumer", 3_600_000L, "0-0").get();
      * for (Object element: results) {
@@ -1074,7 +1071,6 @@ CompletableFuture xclaimJustId(
      * }
      *      // Redis version 7.0.0 and above
      *  
- * */ CompletableFuture xautoclaim( String key, String group, String consumer, long minIdleTime, String start); @@ -1090,15 +1086,12 @@ CompletableFuture xautoclaim( * @param start Filters the claimed entries to those that have an ID equal or greater than the * specified value. * @param count Limits the number of claimed entries to the specified value. - * @return An array containing the following elements: - * - A stream ID to be used as the start + * @return An array containing the following elements: - A stream ID to be used as the start * argument for the next call to XAUTOCLAIM. This ID is equivalent to the next ID * in the stream after the entries that were scanned, or "0-0" if the entire stream was - * scanned. - * - A mapping of the claimed entries, with the keys being the claimed entry IDs and + * scanned. - A mapping of the claimed entries, with the keys being the claimed entry IDs and * the values being a 2D list of the field-value pairs in the format `[[field1, value1], - * [field2, value2], ...]`. - * - If you are using Redis 7.0.0 or above, the response list will + * [field2, value2], ...]`. - If you are using Redis 7.0.0 or above, the response list will * also include a list containing the message IDs that were in the Pending Entries List but no * longer exist in the stream. These IDs are deleted from the Pending Entries List. */ @@ -1117,13 +1110,10 @@ CompletableFuture xautoclaim( * @param minIdleTime The minimum idle time for the message to be claimed. * @param start Filters the claimed entries to those that have an ID equal or greater than the * specified value. - * @return An array containing the following elements: - * - A stream ID to be used as the start + * @return An array containing the following elements: - A stream ID to be used as the start * argument for the next call to XAUTOCLAIM. This ID is equivalent to the next ID * in the stream after the entries that were scanned, or "0-0" if the entire stream was - * scanned. - * - A list of the IDs for the claimed entries. - * - If you are using Redis 7.0.0 or + * scanned. - A list of the IDs for the claimed entries. - If you are using Redis 7.0.0 or * above, the response list will also include a list containing the message IDs that were in * the Pending Entries List but no longer exist in the stream. These IDs are deleted from the * Pending Entries List. @@ -1144,17 +1134,14 @@ CompletableFuture xautoclaimJustId( * @param start Filters the claimed entries to those that have an ID equal or greater than the * specified value. * @param count Limits the number of claimed entries to the specified value. - * @return An array containing the following elements: - * - A stream ID to be used as the start + * @return An array containing the following elements: - A stream ID to be used as the start * argument for the next call to XAUTOCLAIM. This ID is equivalent to the next ID * in the stream after the entries that were scanned, or "0-0" if the entire stream was - * scanned. - * - A list of the IDs for the claimed entries. - * - If you are using Redis 7.0.0 or + * scanned. - A list of the IDs for the claimed entries. - If you are using Redis 7.0.0 or * above, the response list will also include a list containing the message IDs that were in * the Pending Entries List but no longer exist in the stream. These IDs are deleted from the * Pending Entries List. */ - CompletableFuture xuatoclaimJustId( + CompletableFuture xautoclaimJustId( String key, String group, String consumer, long minIdleTime, String start, long count); } From 3ebc3aee0ca2d814206df04818d9b07f2fd49e72 Mon Sep 17 00:00:00 2001 From: Chloe Yip Date: Wed, 3 Jul 2024 13:55:44 -0700 Subject: [PATCH 05/23] finished base transaction --- .../glide/api/models/BaseTransaction.java | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/java/client/src/main/java/glide/api/models/BaseTransaction.java b/java/client/src/main/java/glide/api/models/BaseTransaction.java index 3052ebcdf1..df8fcc764d 100644 --- a/java/client/src/main/java/glide/api/models/BaseTransaction.java +++ b/java/client/src/main/java/glide/api/models/BaseTransaction.java @@ -163,6 +163,7 @@ import static redis_request.RedisRequestOuterClass.RequestType.Wait; import static redis_request.RedisRequestOuterClass.RequestType.XAck; import static redis_request.RedisRequestOuterClass.RequestType.XAdd; +import static redis_request.RedisRequestOuterClass.RequestType.XAutoClaim; import static redis_request.RedisRequestOuterClass.RequestType.XClaim; import static redis_request.RedisRequestOuterClass.RequestType.XDel; import static redis_request.RedisRequestOuterClass.RequestType.XGroupCreate; @@ -4044,6 +4045,159 @@ public T xclaimJustId( return getThis(); } + /** + * Transfers ownership of pending stream entries that match the specified criteria. + * + * @see valkey.io for details. + * @param key The key of the stream. + * @param group The consumer group name + * @param consumer The group consumer. + * @param minIdleTime The minimum idle time for the message to be claimed. + * @param start Filters the claimed entries to those that have an ID equal or greater than the + * specified value. + * @return An array containing the following elements: - A stream ID to be used as the start + * argument for the next call to XAUTOCLAIM. This ID is equivalent to the next ID + * in the stream after the entries that were scanned, or "0-0" if the entire stream was + * scanned. - A mapping of the claimed entries, with the keys being the claimed entry IDs and + * the values being a 2D list of the field-value pairs in the format `[[field1, value1], + * [field2, value2], ...]`. - If you are using Redis 7.0.0 or above, the response list will + * also include a list containing the message IDs that were in the Pending Entries List but no + * longer exist in the stream. These IDs are deleted from the Pending Entries List. + */ + public T xautoclaim( + @NonNull String key, + @NonNull String group, + @NonNull String consumer, + long minIdleTime, + @NonNull String start) { + protobufTransaction.addCommands( + buildCommand( + XAutoClaim, + newArgsBuilder().add(key).add(group).add(consumer).add(minIdleTime).add(start))); + return getThis(); + } + + /** + * Transfers ownership of pending stream entries that match the specified criteria. + * + * @see valkey.io for details. + * @param key The key of the stream. + * @param group The consumer group name + * @param consumer The group consumer. + * @param minIdleTime The minimum idle time for the message to be claimed. + * @param start Filters the claimed entries to those that have an ID equal or greater than the + * specified value. + * @param count Limits the number of claimed entries to the specified value. + * @return An array containing the following elements: - A stream ID to be used as the start + * argument for the next call to XAUTOCLAIM. This ID is equivalent to the next ID + * in the stream after the entries that were scanned, or "0-0" if the entire stream was + * scanned. - A mapping of the claimed entries, with the keys being the claimed entry IDs and + * the values being a 2D list of the field-value pairs in the format `[[field1, value1], + * [field2, value2], ...]`. - If you are using Redis 7.0.0 or above, the response list will + * also include a list containing the message IDs that were in the Pending Entries List but no + * longer exist in the stream. These IDs are deleted from the Pending Entries List. + */ + public T xautoclaim( + @NonNull String key, + @NonNull String group, + @NonNull String consumer, + long minIdleTime, + @NonNull String start, + long count) { + protobufTransaction.addCommands( + buildCommand( + XAutoClaim, + newArgsBuilder() + .add(key) + .add(group) + .add(consumer) + .add(minIdleTime) + .add(start) + .add(count))); + return getThis(); + } + + /** + * Transfers ownership of pending stream entries that match the specified criteria. This command + * uses the JUSTID argument to further specify that the return value should contain a + * list of claimed IDs without their field-value info. + * + * @see valkey.io for details. + * @param key The key of the stream. + * @param group The consumer group name + * @param consumer The group consumer. + * @param minIdleTime The minimum idle time for the message to be claimed. + * @param start Filters the claimed entries to those that have an ID equal or greater than the + * specified value. + * @return An array containing the following elements: - A stream ID to be used as the start + * argument for the next call to XAUTOCLAIM. This ID is equivalent to the next ID + * in the stream after the entries that were scanned, or "0-0" if the entire stream was + * scanned. - A list of the IDs for the claimed entries. - If you are using Redis 7.0.0 or + * above, the response list will also include a list containing the message IDs that were in + * the Pending Entries List but no longer exist in the stream. These IDs are deleted from the + * Pending Entries List. + */ + public T xautoclaimJustId( + @NonNull String key, + @NonNull String group, + @NonNull String consumer, + long minIdleTime, + @NonNull String start) { + protobufTransaction.addCommands( + buildCommand( + XAutoClaim, + newArgsBuilder() + .add(key) + .add(group) + .add(consumer) + .add(minIdleTime) + .add(start) + .add(JUST_ID_REDIS_API))); + return getThis(); + } + + /** + * Transfers ownership of pending stream entries that match the specified criteria. This command + * uses the JUSTID argument to further specify that the return value should contain a + * list of claimed IDs without their field-value info. + * + * @see valkey.io for details. + * @param key The key of the stream. + * @param group The consumer group name + * @param consumer The group consumer. + * @param minIdleTime The minimum idle time for the message to be claimed. + * @param start Filters the claimed entries to those that have an ID equal or greater than the + * specified value. + * @param count Limits the number of claimed entries to the specified value. + * @return An array containing the following elements: - A stream ID to be used as the start + * argument for the next call to XAUTOCLAIM. This ID is equivalent to the next ID + * in the stream after the entries that were scanned, or "0-0" if the entire stream was + * scanned. - A list of the IDs for the claimed entries. - If you are using Redis 7.0.0 or + * above, the response list will also include a list containing the message IDs that were in + * the Pending Entries List but no longer exist in the stream. These IDs are deleted from the + * Pending Entries List. + */ + public T xautoclaimJustId( + @NonNull String key, + @NonNull String group, + @NonNull String consumer, + long minIdleTime, + @NonNull String start, + long count) { + protobufTransaction.addCommands( + buildCommand( + XAutoClaim, + newArgsBuilder() + .add(key) + .add(group) + .add(consumer) + .add(minIdleTime) + .add(start) + .add(count) + .add(JUST_ID_REDIS_API))); + return getThis(); + } + /** * Returns the remaining time to live of key that has a timeout, in milliseconds. * From 6071dd77eb81f75ccae8c1cd7cf5ad68941c3537 Mon Sep 17 00:00:00 2001 From: Yi-Pin Chen Date: Wed, 3 Jul 2024 16:02:54 -0700 Subject: [PATCH 06/23] Python: add FUNCTION DUMP and FUNCTION RESTORE commands (#1769) * Initial commit for function dump and restore commands * Split UT to standalone and cluster tests * Fixed mypy errors * Addressed review comments * Addressed review comment * Addressed review comments * Updated examples --- CHANGELOG.md | 2 +- python/python/glide/__init__.py | 2 + .../glide/async_commands/cluster_commands.py | 71 ++++++++ python/python/glide/async_commands/core.py | 16 ++ .../async_commands/standalone_commands.py | 53 ++++++ python/python/tests/test_async_client.py | 166 ++++++++++++++++++ 6 files changed, 309 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0283eb2686..7d595d5328 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -79,7 +79,7 @@ * Python: Added DUMP and Restore commands ([#1733](https://github.com/aws/glide-for-redis/pull/1733)) * Java: Added SCAN command ([#1751](https://github.com/aws/glide-for-redis/pull/1751)) * Python: Type migration for entries_read ([#1768](https://github.com/aws/glide-for-redis/pull/1768)) - +* Python: Added FUNCTION DUMP and FUNCTION RESTORE commands ([#1769](https://github.com/aws/glide-for-redis/pull/1769)) ### Breaking Changes * Node: Update XREAD to return a Map of Map ([#1494](https://github.com/aws/glide-for-redis/pull/1494)) diff --git a/python/python/glide/__init__.py b/python/python/glide/__init__.py index 70d490a6b2..53564a5127 100644 --- a/python/python/glide/__init__.py +++ b/python/python/glide/__init__.py @@ -26,6 +26,7 @@ ExpiryType, ExpiryTypeGetEx, FlushMode, + FunctionRestorePolicy, InfoSection, InsertPosition, UpdateOptions, @@ -144,6 +145,7 @@ "ExpiryType", "ExpiryTypeGetEx", "FlushMode", + "FunctionRestorePolicy", "GeoSearchByBox", "GeoSearchByRadius", "GeoSearchCount", diff --git a/python/python/glide/async_commands/cluster_commands.py b/python/python/glide/async_commands/cluster_commands.py index e447ae59a6..98b83f21fb 100644 --- a/python/python/glide/async_commands/cluster_commands.py +++ b/python/python/glide/async_commands/cluster_commands.py @@ -8,6 +8,7 @@ from glide.async_commands.core import ( CoreCommands, FlushMode, + FunctionRestorePolicy, InfoSection, _build_sort_args, ) @@ -554,6 +555,76 @@ async def fcall_ro_route( await self._execute_command(RequestType.FCallReadOnly, args, route), ) + async def function_dump( + self, route: Optional[Route] = None + ) -> TClusterResponse[bytes]: + """ + Returns the serialized payload of all loaded libraries. + + See https://valkey.io/commands/function-dump/ for more details. + + Args: + route (Optional[Route]): The command will be routed to a random node, unless + `route` is provided, in which case the client will route the command to the + nodes defined by `route`. + + Returns: + TClusterResponse[bytes]: The serialized payload of all loaded libraries. + + Examples: + >>> payload = await client.function_dump() + # The serialized payload of all loaded libraries. This response can + # be used to restore loaded functions on any Valkey instance. + >>> await client.function_restore(payload) + "OK" # The serialized dump response was used to restore the libraries. + + Since: Redis 7.0.0. + """ + return cast( + TClusterResponse[bytes], + await self._execute_command(RequestType.FunctionDump, [], route), + ) + + async def function_restore( + self, + payload: TEncodable, + policy: Optional[FunctionRestorePolicy] = None, + route: Optional[Route] = None, + ) -> TOK: + """ + Restores libraries from the serialized payload returned by the `function_dump` command. + + See https://valkey.io/commands/function-restore/ for more details. + + Args: + payload (bytes): The serialized data from the `function_dump` command. + policy (Optional[FunctionRestorePolicy]): A policy for handling existing libraries. + route (Optional[Route]): The command will be sent to all primaries, unless + `route` is provided, in which case the client will route the command to the + nodes defined by `route`. + + Returns: + TOK: OK. + + Examples: + >>> payload = await client.function_dump() + # The serialized payload of all loaded libraries. This response can + # be used to restore loaded functions on any Valkey instance. + >>> await client.function_restore(payload, AllPrimaries()) + "OK" # The serialized dump response was used to restore the libraries with the specified route. + >>> await client.function_restore(payload, FunctionRestorePolicy.FLUSH, AllPrimaries()) + "OK" # The serialized dump response was used to restore the libraries with the specified route and policy. + + Since: Redis 7.0.0. + """ + args: List[TEncodable] = [payload] + if policy is not None: + args.append(policy.value) + + return cast( + TOK, await self._execute_command(RequestType.FunctionRestore, args, route) + ) + async def time( self, route: Optional[Route] = None ) -> TClusterResponse[List[bytes]]: diff --git a/python/python/glide/async_commands/core.py b/python/python/glide/async_commands/core.py index d02ffb2d5f..4169b5d4af 100644 --- a/python/python/glide/async_commands/core.py +++ b/python/python/glide/async_commands/core.py @@ -307,6 +307,22 @@ class FlushMode(Enum): SYNC = "SYNC" +class FunctionRestorePolicy(Enum): + """ + Options for the FUNCTION RESTORE command. + + - APPEND: Appends the restored libraries to the existing libraries and aborts on collision. This is the + default policy. + - FLUSH: Deletes all existing libraries before restoring the payload. + - REPLACE: Appends the restored libraries to the existing libraries, replacing any existing ones in case + of name collisions. Note that this policy doesn't prevent function name collisions, only libraries. + """ + + APPEND = "APPEND" + FLUSH = "FLUSH" + REPLACE = "REPLACE" + + def _build_sort_args( key: TEncodable, by_pattern: Optional[TEncodable] = None, diff --git a/python/python/glide/async_commands/standalone_commands.py b/python/python/glide/async_commands/standalone_commands.py index 925b0dd2a9..83823ca6b9 100644 --- a/python/python/glide/async_commands/standalone_commands.py +++ b/python/python/glide/async_commands/standalone_commands.py @@ -8,6 +8,7 @@ from glide.async_commands.core import ( CoreCommands, FlushMode, + FunctionRestorePolicy, InfoSection, _build_sort_args, ) @@ -361,6 +362,58 @@ async def function_delete(self, library_name: TEncodable) -> TOK: ), ) + async def function_dump(self) -> bytes: + """ + Returns the serialized payload of all loaded libraries. + + See https://valkey.io/docs/latest/commands/function-dump/ for more details. + + Returns: + bytes: The serialized payload of all loaded libraries. + + Examples: + >>> payload = await client.function_dump() + # The serialized payload of all loaded libraries. This response can + # be used to restore loaded functions on any Valkey instance. + >>> await client.function_restore(payload) + "OK" # The serialized dump response was used to restore the libraries. + + Since: Redis 7.0.0. + """ + return cast(bytes, await self._execute_command(RequestType.FunctionDump, [])) + + async def function_restore( + self, payload: TEncodable, policy: Optional[FunctionRestorePolicy] = None + ) -> TOK: + """ + Restores libraries from the serialized payload returned by the `function_dump` command. + + See https://valkey.io/docs/latest/commands/function-restore/ for more details. + + Args: + payload (TEncodable): The serialized data from the `function_dump` command. + policy (Optional[FunctionRestorePolicy]): A policy for handling existing libraries. + + Returns: + TOK: OK. + + Examples: + >>> payload = await client.function_dump() + # The serialized payload of all loaded libraries. This response can + # be used to restore loaded functions on any Valkey instance. + >>> await client.function_restore(payload) + "OK" # The serialized dump response was used to restore the libraries. + >>> await client.function_restore(payload, FunctionRestorePolicy.FLUSH) + "OK" # The serialized dump response was used to restore the libraries with the specified policy. + + Since: Redis 7.0.0. + """ + args: List[TEncodable] = [payload] + if policy is not None: + args.append(policy.value) + + return cast(TOK, await self._execute_command(RequestType.FunctionRestore, args)) + async def time(self) -> List[bytes]: """ Returns the server time. diff --git a/python/python/tests/test_async_client.py b/python/python/tests/test_async_client.py index 686639340c..b4a9106b02 100644 --- a/python/python/tests/test_async_client.py +++ b/python/python/tests/test_async_client.py @@ -34,6 +34,7 @@ ExpiryType, ExpiryTypeGetEx, FlushMode, + FunctionRestorePolicy, InfBound, InfoSection, InsertPosition, @@ -8047,6 +8048,171 @@ async def test_fcall_readonly_function(self, redis_client: GlideClusterClient): == 42 ) + @pytest.mark.parametrize("cluster_mode", [False]) + @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) + async def test_function_dump_restore_standalone(self, redis_client: GlideClient): + min_version = "7.0.0" + if await check_if_server_version_lt(redis_client, min_version): + return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + + assert await redis_client.function_flush(FlushMode.SYNC) is OK + + # Dump an empty lib + emptyDump = await redis_client.function_dump() + assert emptyDump is not None and len(emptyDump) > 0 + + name1 = f"Foster{get_random_string(5)}" + name2 = f"Dogster{get_random_string(5)}" + + # function name1 returns first argument; function name2 returns argument array len + code = generate_lua_lib_code( + name1, {name1: "return args[1]", name2: "return #args"}, False + ) + assert await redis_client.function_load(code, True) == name1.encode() + flist = await redis_client.function_list(with_code=True) + + dump = await redis_client.function_dump() + assert dump is not None + + # restore without cleaning the lib and/or overwrite option causes an error + with pytest.raises(RequestError) as e: + assert await redis_client.function_restore(dump) + assert "already exists" in str(e) + + # APPEND policy also fails for the same reason (name collision) + with pytest.raises(RequestError) as e: + assert await redis_client.function_restore( + dump, FunctionRestorePolicy.APPEND + ) + assert "already exists" in str(e) + + # REPLACE policy succeed + assert ( + await redis_client.function_restore(dump, FunctionRestorePolicy.REPLACE) + is OK + ) + + # but nothing changed - all code overwritten + assert await redis_client.function_list(with_code=True) == flist + + # create lib with another name, but with the same function names + assert await redis_client.function_flush(FlushMode.SYNC) is OK + code = generate_lua_lib_code( + name2, {name1: "return args[1]", name2: "return #args"}, False + ) + assert await redis_client.function_load(code, True) == name2.encode() + + # REPLACE policy now fails due to a name collision + with pytest.raises(RequestError) as e: + await redis_client.function_restore(dump, FunctionRestorePolicy.REPLACE) + assert "already exists" in str(e) + + # FLUSH policy succeeds, but deletes the second lib + assert ( + await redis_client.function_restore(dump, FunctionRestorePolicy.FLUSH) is OK + ) + assert await redis_client.function_list(with_code=True) == flist + + # call restored functions + assert ( + await redis_client.fcall(name1, arguments=["meow", "woem"]) + == "meow".encode() + ) + assert await redis_client.fcall(name2, arguments=["meow", "woem"]) == 2 + + @pytest.mark.parametrize("cluster_mode", [True]) + @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) + async def test_function_dump_restore_cluster( + self, redis_client: GlideClusterClient + ): + min_version = "7.0.0" + if await check_if_server_version_lt(redis_client, min_version): + return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + + assert await redis_client.function_flush(FlushMode.SYNC) is OK + + # Dump an empty lib + emptyDump = await redis_client.function_dump() + assert emptyDump is not None and len(emptyDump) > 0 + + name1 = f"Foster{get_random_string(5)}" + libname1 = f"FosterLib{get_random_string(5)}" + name2 = f"Dogster{get_random_string(5)}" + libname2 = f"DogsterLib{get_random_string(5)}" + + # function name1 returns first argument; function name2 returns argument array len + code = generate_lua_lib_code( + libname1, {name1: "return args[1]", name2: "return #args"}, True + ) + assert await redis_client.function_load(code, True) == libname1.encode() + flist = await redis_client.function_list(with_code=True) + dump = await redis_client.function_dump(RandomNode()) + assert dump is not None and isinstance(dump, bytes) + + # restore without cleaning the lib and/or overwrite option causes an error + with pytest.raises(RequestError) as e: + assert await redis_client.function_restore(dump) + assert "already exists" in str(e) + + # APPEND policy also fails for the same reason (name collision) + with pytest.raises(RequestError) as e: + assert await redis_client.function_restore( + dump, FunctionRestorePolicy.APPEND + ) + assert "already exists" in str(e) + + # REPLACE policy succeed + assert ( + await redis_client.function_restore( + dump, FunctionRestorePolicy.REPLACE, route=AllPrimaries() + ) + is OK + ) + + # but nothing changed - all code overwritten + restoredFunctionList = await redis_client.function_list(with_code=True) + assert restoredFunctionList is not None + assert isinstance(restoredFunctionList, List) and len(restoredFunctionList) == 1 + assert restoredFunctionList[0]["library_name".encode()] == libname1.encode() + + # Note that function ordering may differ across nodes so we can't do a deep equals + assert len(restoredFunctionList[0]["functions".encode()]) == 2 + + # create lib with another name, but with the same function names + assert await redis_client.function_flush(FlushMode.SYNC) is OK + code = generate_lua_lib_code( + libname2, {name1: "return args[1]", name2: "return #args"}, True + ) + assert await redis_client.function_load(code, True) == libname2.encode() + restoredFunctionList = await redis_client.function_list(with_code=True) + assert restoredFunctionList is not None + assert isinstance(restoredFunctionList, List) and len(restoredFunctionList) == 1 + assert restoredFunctionList[0]["library_name".encode()] == libname2.encode() + + # REPLACE policy now fails due to a name collision + with pytest.raises(RequestError) as e: + await redis_client.function_restore(dump, FunctionRestorePolicy.REPLACE) + assert "already exists" in str(e) + + # FLUSH policy succeeds, but deletes the second lib + assert ( + await redis_client.function_restore(dump, FunctionRestorePolicy.FLUSH) is OK + ) + restoredFunctionList = await redis_client.function_list(with_code=True) + assert restoredFunctionList is not None + assert isinstance(restoredFunctionList, List) and len(restoredFunctionList) == 1 + assert restoredFunctionList[0]["library_name".encode()] == libname1.encode() + + # Note that function ordering may differ across nodes so we can't do a deep equals + assert len(restoredFunctionList[0]["functions".encode()]) == 2 + + # call restored functions + assert ( + await redis_client.fcall_ro(name1, arguments=["meow", "woem"]) + == "meow".encode() + ) + assert await redis_client.fcall_ro(name2, arguments=["meow", "woem"]) == 2 + @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_srandmember(self, redis_client: TGlideClient): From ffd7a8adbd07783eb7f4f8444e55a02821a4d08e Mon Sep 17 00:00:00 2001 From: talxsha <160726520+talxsha@users.noreply.github.com> Date: Thu, 4 Jul 2024 10:00:38 +0300 Subject: [PATCH 07/23] xpending and xclaim binary version (xautoclaim not implemented in Glide java) (#1759) * xpending and xclaim binary version (xautoclaim not implemented in Glide java) Co-authored-by: Ubuntu --- .../src/main/java/glide/api/BaseClient.java | 100 ++++ .../api/commands/StreamBaseCommands.java | 241 ++++++++ .../test/java/glide/api/RedisClientTest.java | 255 +++++++++ .../test/java/glide/SharedCommandTests.java | 517 ++++++++++++++++++ 4 files changed, 1113 insertions(+) diff --git a/java/client/src/main/java/glide/api/BaseClient.java b/java/client/src/main/java/glide/api/BaseClient.java index 2ae1be4c0e..ecd432e970 100644 --- a/java/client/src/main/java/glide/api/BaseClient.java +++ b/java/client/src/main/java/glide/api/BaseClient.java @@ -2425,6 +2425,13 @@ public CompletableFuture xpending(@NonNull String key, @NonNull String XPending, new String[] {key, group}, this::handleArrayOrNullResponse); } + @Override + public CompletableFuture xpending( + @NonNull GlideString key, @NonNull GlideString group) { + return commandManager.submitNewCommand( + XPending, new GlideString[] {key, group}, this::handleArrayOrNullResponseBinary); + } + @Override public CompletableFuture xpending( @NonNull String key, @@ -2435,6 +2442,16 @@ public CompletableFuture xpending( return xpending(key, group, start, end, count, StreamPendingOptions.builder().build()); } + @Override + public CompletableFuture xpending( + @NonNull GlideString key, + @NonNull GlideString group, + @NonNull StreamRange start, + @NonNull StreamRange end, + long count) { + return xpending(key, group, start, end, count, StreamPendingOptions.builder().build()); + } + @Override public CompletableFuture xpending( @NonNull String key, @@ -2448,6 +2465,22 @@ public CompletableFuture xpending( XPending, args, response -> castArray(handleArrayResponse(response), Object[].class)); } + @Override + public CompletableFuture xpending( + @NonNull GlideString key, + @NonNull GlideString group, + @NonNull StreamRange start, + @NonNull StreamRange end, + long count, + @NonNull StreamPendingOptions options) { + String[] toArgsString = options.toArgs(start, end, count); + GlideString[] toArgs = + Arrays.stream(toArgsString).map(GlideString::gs).toArray(GlideString[]::new); + GlideString[] args = concatenateArrays(new GlideString[] {key, group}, toArgs); + return commandManager.submitNewCommand( + XPending, args, response -> castArray(handleArrayResponse(response), Object[].class)); + } + @Override public CompletableFuture> xclaim( @NonNull String key, @@ -2460,6 +2493,19 @@ public CompletableFuture> xclaim( return commandManager.submitNewCommand(XClaim, args, this::handleMapResponse); } + @Override + public CompletableFuture> xclaim( + @NonNull GlideString key, + @NonNull GlideString group, + @NonNull GlideString consumer, + long minIdleTime, + @NonNull GlideString[] ids) { + GlideString[] args = + concatenateArrays( + new GlideString[] {key, group, consumer, gs(Long.toString(minIdleTime))}, ids); + return commandManager.submitNewCommand(XClaim, args, this::handleBinaryStringMapResponse); + } + @Override public CompletableFuture> xclaim( @NonNull String key, @@ -2474,6 +2520,23 @@ public CompletableFuture> xclaim( return commandManager.submitNewCommand(XClaim, args, this::handleMapResponse); } + @Override + public CompletableFuture> xclaim( + @NonNull GlideString key, + @NonNull GlideString group, + @NonNull GlideString consumer, + long minIdleTime, + @NonNull GlideString[] ids, + @NonNull StreamClaimOptions options) { + String[] toArgsString = options.toArgs(); + GlideString[] toArgs = + Arrays.stream(toArgsString).map(GlideString::gs).toArray(GlideString[]::new); + GlideString[] args = + concatenateArrays( + new GlideString[] {key, group, consumer, gs(Long.toString(minIdleTime))}, ids, toArgs); + return commandManager.submitNewCommand(XClaim, args, this::handleBinaryStringMapResponse); + } + @Override public CompletableFuture xclaimJustId( @NonNull String key, @@ -2490,6 +2553,22 @@ public CompletableFuture xclaimJustId( XClaim, args, response -> castArray(handleArrayResponse(response), String.class)); } + @Override + public CompletableFuture xclaimJustId( + @NonNull GlideString key, + @NonNull GlideString group, + @NonNull GlideString consumer, + long minIdleTime, + @NonNull GlideString[] ids) { + GlideString[] args = + concatenateArrays( + new GlideString[] {key, group, consumer, gs(Long.toString(minIdleTime))}, + ids, + new GlideString[] {gs(JUST_ID_REDIS_API)}); + return commandManager.submitNewCommand( + XClaim, args, response -> castArray(handleArrayResponse(response), GlideString.class)); + } + @Override public CompletableFuture xclaimJustId( @NonNull String key, @@ -2508,6 +2587,27 @@ public CompletableFuture xclaimJustId( XClaim, args, response -> castArray(handleArrayResponse(response), String.class)); } + @Override + public CompletableFuture xclaimJustId( + @NonNull GlideString key, + @NonNull GlideString group, + @NonNull GlideString consumer, + long minIdleTime, + @NonNull GlideString[] ids, + @NonNull StreamClaimOptions options) { + String[] toArgsString = options.toArgs(); + GlideString[] toArgs = + Arrays.stream(toArgsString).map(GlideString::gs).toArray(GlideString[]::new); + GlideString[] args = + concatenateArrays( + new GlideString[] {key, group, consumer, gs(Long.toString(minIdleTime))}, + ids, + toArgs, + new GlideString[] {gs(JUST_ID_REDIS_API)}); + return commandManager.submitNewCommand( + XClaim, args, response -> castArray(handleArrayResponse(response), GlideString.class)); + } + @Override public CompletableFuture xautoclaim( @NonNull String key, diff --git a/java/client/src/main/java/glide/api/commands/StreamBaseCommands.java b/java/client/src/main/java/glide/api/commands/StreamBaseCommands.java index e8159df499..59d76d6d71 100644 --- a/java/client/src/main/java/glide/api/commands/StreamBaseCommands.java +++ b/java/client/src/main/java/glide/api/commands/StreamBaseCommands.java @@ -831,6 +831,33 @@ CompletableFuture>> xreadgroup( */ CompletableFuture xpending(String key, String group); + /** + * Returns stream message summary information for pending messages matching a given range of IDs. + * + * @see valkey.io for details. + * @param key The key of the stream. + * @param group The consumer group name. + * @return An array that includes the summary of pending messages, with the format + * [NumOfMessages, StartId, EndId, [Consumer, NumOfMessages]], where: + *
    + *
  • NumOfMessages: The total number of pending messages for this consumer group. + *
  • StartId: The smallest ID among the pending messages. + *
  • EndId: The greatest ID among the pending messages. + *
  • [[Consumer, NumOfMessages], ...]: A 2D-array of every consumer + * in the consumer group with at least one pending message, and the number of pending messages it has. + *
+ * @example + *
{@code
+     * // Retrieve a summary of all pending messages from key "my_stream"
+     * Object[] result = client.xpending(gs("my_stream"), gs("my_group")).get();
+     * System.out.println("Number of pending messages: " + result[0]);
+     * System.out.println("Start and End ID of messages: [" + result[1] + ", " + result[2] + "]");
+     * for (Object[] consumerResult : (Object[][]) result[3]) {
+     *     System.out.println("Number of Consumer messages: [" + consumerResult[0] + ", " + consumerResult[1] + "]");
+     * }
+ */ + CompletableFuture xpending(GlideString key, GlideString group); + /** * Returns an extended form of stream message information for pending messages matching a given range of IDs. * @@ -870,6 +897,45 @@ CompletableFuture>> xreadgroup( CompletableFuture xpending( String key, String group, StreamRange start, StreamRange end, long count); + /** + * Returns an extended form of stream message information for pending messages matching a given range of IDs. + * + * @see valkey.io for details. + * @param key The key of the stream. + * @param group The consumer group name. + * @param start Starting stream ID bound for range. + *
    + *
  • Use {@link IdBound#of} to specify a stream ID. + *
  • Use {@link IdBound#ofExclusive} to specify an exclusive bounded stream ID. + *
  • Use {@link InfRangeBound#MIN} to start with the minimum available ID. + *
+ * + * @param end Ending stream ID bound for range. + *
    + *
  • Use {@link IdBound#of} to specify a stream ID. + *
  • Use {@link IdBound#ofExclusive} to specify an exclusive bounded stream ID. + *
  • Use {@link InfRangeBound#MAX} to end with the maximum available ID. + *
+ * @param count Limits the number of messages returned. + * @return A 2D-array of 4-tuples containing extended message information with the format + * [[ID, Consumer, TimeElapsed, NumOfDelivered], ... ], where: + *
    + *
  • ID: The ID of the message. + *
  • Consumer: The name of the consumer that fetched the message and has still to acknowledge it. We call it the current owner of the message. + *
  • TimeElapsed: The number of milliseconds that elapsed since the last time this message was delivered to this consumer. + *
  • NumOfDelivered: The number of times this message was delivered. + *
+ * @example + *
{@code
+     * // Retrieve up to 10 pending messages from key "my_stream" in extended form
+     * Object[][] result = client.xpending(gs("my_stream"), gs("my_group"), InfRangeBound.MIN, InfRangeBound.MAX, 10L).get();
+     * for (Object[] messageResult : result) {
+     *     System.out.printf("Message %s from consumer %s was read %s times", messageResult[0], messageResult[1], messageResult[2]);
+     * }
+ */ + CompletableFuture xpending( + GlideString key, GlideString group, StreamRange start, StreamRange end, long count); + /** * Returns an extended form of stream message information for pending messages matching a given range of IDs. * @@ -922,6 +988,58 @@ CompletableFuture xpending( long count, StreamPendingOptions options); + /** + * Returns an extended form of stream message information for pending messages matching a given range of IDs. + * + * @see valkey.io for details. + * @param key The key of the stream. + * @param group The consumer group name. + * @param start Starting stream ID bound for range. + *
    + *
  • Use {@link IdBound#of} to specify a stream ID. + *
  • Use {@link IdBound#ofExclusive} to specify an exclusive bounded stream ID. + *
  • Use {@link InfRangeBound#MIN} to start with the minimum available ID. + *
+ * + * @param end Ending stream ID bound for range. + *
    + *
  • Use {@link IdBound#of} to specify a stream ID. + *
  • Use {@link IdBound#ofExclusive} to specify an exclusive bounded stream ID. + *
  • Use {@link InfRangeBound#MAX} to end with the maximum available ID. + *
+ * @param count Limits the number of messages returned. + * @param options Stream add options {@link StreamPendingOptions}. + * @return A 2D-array of 4-tuples containing extended message information with the format + * [[ID, Consumer, TimeElapsed, NumOfDelivered], ... ], where: + *
    + *
  • ID: The ID of the message. + *
  • Consumer: The name of the consumer that fetched the message and has still to acknowledge it. We call it the current owner of the message. + *
  • TimeElapsed: The number of milliseconds that elapsed since the last time this message was delivered to this consumer. + *
  • NumOfDelivered: The number of times this message was delivered. + *
+ * @example + *
{@code
+     * // Retrieve up to 10 pending messages from key "my_stream" and consumer "my_consumer" in extended form
+     * Object[][] result = client.xpending(
+     *     gs("my_stream"),
+     *     gs("my_group"),
+     *     InfRangeBound.MIN,
+     *     InfRangeBound.MAX,
+     *     10L,
+     *     StreamPendingOptions.builder().consumer("my_consumer").build()
+     * ).get();
+     * for (Object[] messageResult : result) {
+     *     System.out.printf("Message %s from consumer %s was read %s times", messageResult[0], messageResult[1], messageResult[2]);
+     * }
+ */ + CompletableFuture xpending( + GlideString key, + GlideString group, + StreamRange start, + StreamRange end, + long count, + StreamPendingOptions options); + /** * Changes the ownership of a pending message. * @@ -950,6 +1068,38 @@ CompletableFuture xpending( CompletableFuture> xclaim( String key, String group, String consumer, long minIdleTime, String[] ids); + /** + * Changes the ownership of a pending message. + * + * @see valkey.io for details. + * @param key The key of the stream. + * @param group The consumer group name. + * @param consumer The group consumer. + * @param minIdleTime The minimum idle time for the message to be claimed. + * @param ids A array of entry ids. + * @return A Map of message entries with the format + * {"entryId": [["entry", "data"], ...], ...} that are claimed by the consumer. + * @example + *
+     * // read messages from streamId for consumer1
+     * var readResult = client.xreadgroup(Map.of(gs("mystream"), gs(">")), gs("mygroup"), gs("consumer1")).get();
+     * // "entryId" is now read, and we can assign the pending messages to consumer2
+     * Map results = client.xclaim(gs("mystream"), gs("mygroup"), gs("consumer2"), 0L, new GlideString[] {entryId}).get();
+     * for (GlideString key: results.keySet()) {
+     *     System.out.println(key);
+     *     for (GlideString[] entry: results.get(key)) {
+     *         System.out.printf("{%s=%s}%n", entry[0], entry[1]);
+     *     }
+     * }
+     * 
+ */ + CompletableFuture> xclaim( + GlideString key, + GlideString group, + GlideString consumer, + long minIdleTime, + GlideString[] ids); + /** * Changes the ownership of a pending message. * @@ -983,6 +1133,39 @@ CompletableFuture> xclaim( String[] ids, StreamClaimOptions options); + /** + * Changes the ownership of a pending message. + * + * @see valkey.io for details. + * @param key The key of the stream. + * @param group The consumer group name. + * @param consumer The group consumer. + * @param minIdleTime The minimum idle time for the message to be claimed. + * @param ids An array of entry ids. + * @param options Stream claim options {@link StreamClaimOptions}. + * @return A Map of message entries with the format + * {"entryId": [["entry", "data"], ...], ...} that are claimed by the consumer. + * @example + *
+     * // assign (force) unread and unclaimed messages to consumer2
+     * StreamClaimOptions options = StreamClaimOptions.builder().force().build();
+     * Map results = client.xclaim(gs("mystream"), gs("mygroup"), gs("consumer2"), 0L, new GlideString[] {entryId}, options).get();
+     * for (GlideString key: results.keySet()) {
+     *     System.out.println(key);
+     *     for (GlideString[] entry: results.get(key)) {
+     *         System.out.printf("{%s=%s}%n", entry[0], entry[1]);
+     *     }
+     * }
+     * 
+ */ + CompletableFuture> xclaim( + GlideString key, + GlideString group, + GlideString consumer, + long minIdleTime, + GlideString[] ids, + StreamClaimOptions options); + /** * Changes the ownership of a pending message. This function returns an array with * only the message/entry IDs, and is equivalent to using JUSTID in the Redis API. @@ -1008,6 +1191,35 @@ CompletableFuture> xclaim( CompletableFuture xclaimJustId( String key, String group, String consumer, long minIdleTime, String[] ids); + /** + * Changes the ownership of a pending message. This function returns an array with + * only the message/entry IDs, and is equivalent to using JUSTID in the Redis API. + * + * @see valkey.io for details. + * @param key The key of the stream. + * @param group The consumer group name. + * @param consumer The group consumer. + * @param minIdleTime The minimum idle time for the message to be claimed. + * @param ids An array of entry ids. + * @return An array of message ids claimed by the consumer. + * @example + *
+     * // read messages from streamId for consumer1
+     * var readResult = client.xreadgroup(Map.of(gs("mystream"), gs(">")), gs("mygroup"), gs("consumer1")).get();
+     * // "entryId" is now read, and we can assign the pending messages to consumer2
+     * GlideString[] results = client.xclaimJustId(gs("mystream"), gs("mygroup"), gs("consumer2"), 0L, new GlideString[] {entryId}).get();
+     * for (GlideString id: results) {
+     *     System.out.printf("consumer2 claimed stream entry ID: %s %n", id);
+     * }
+     * 
+ */ + CompletableFuture xclaimJustId( + GlideString key, + GlideString group, + GlideString consumer, + long minIdleTime, + GlideString[] ids); + /** * Changes the ownership of a pending message. This function returns an array with * only the message/entry IDs, and is equivalent to using JUSTID in the Redis API. @@ -1037,6 +1249,35 @@ CompletableFuture xclaimJustId( String[] ids, StreamClaimOptions options); + /** + * Changes the ownership of a pending message. This function returns an array with + * only the message/entry IDs, and is equivalent to using JUSTID in the Redis API. + * + * @see valkey.io for details. + * @param key The key of the stream. + * @param group The consumer group name. + * @param consumer The group consumer. + * @param minIdleTime The minimum idle time for the message to be claimed. + * @param ids An array of entry ids. + * @param options Stream claim options {@link StreamClaimOptions}. + * @return An array of message ids claimed by the consumer. + * @example + *
+     * // assign (force) unread and unclaimed messages to consumer2
+     * StreamClaimOptions options = StreamClaimOptions.builder().force().build();
+     * GlideString[] results = client.xclaimJustId(gs("mystream"), gs("mygroup"), gs("consumer2"), 0L, new GlideString[] {entryId}, options).get();
+     * for (GlideString id: results) {
+     *     System.out.printf("consumer2 claimed stream entry ID: %s %n", id);
+     * }
+     */
+    CompletableFuture xclaimJustId(
+            GlideString key,
+            GlideString group,
+            GlideString consumer,
+            long minIdleTime,
+            GlideString[] ids,
+            StreamClaimOptions options);
+
     /**
      * Transfers ownership of pending stream entries that match the specified criteria.
      *
diff --git a/java/client/src/test/java/glide/api/RedisClientTest.java b/java/client/src/test/java/glide/api/RedisClientTest.java
index 4e8bfdfc24..35a7601ffc 100644
--- a/java/client/src/test/java/glide/api/RedisClientTest.java
+++ b/java/client/src/test/java/glide/api/RedisClientTest.java
@@ -6929,6 +6929,38 @@ public void xclaim_returns_success() {
         assertEquals(mockResult, payload);
     }
 
+    @SneakyThrows
+    @Test
+    public void xclaim_biary_returns_success() {
+        // setup
+        GlideString key = gs("testKey");
+        GlideString groupName = gs("testGroupName");
+        GlideString consumer = gs("testConsumer");
+        Long minIdleTime = 18L;
+        GlideString[] ids = new GlideString[] {gs("testId")};
+        GlideString[] arguments =
+                concatenateArrays(new GlideString[] {key, groupName, consumer, gs("18")}, ids);
+        Map mockResult =
+                Map.of(gs("1234-0"), new GlideString[][] {{gs("message"), gs("log")}});
+
+        CompletableFuture> testResponse = new CompletableFuture<>();
+        testResponse.complete(mockResult);
+
+        // match on protobuf request
+        when(commandManager.>submitNewCommand(
+                        eq(XClaim), eq(arguments), any()))
+                .thenReturn(testResponse);
+
+        // exercise
+        CompletableFuture> response =
+                service.xclaim(key, groupName, consumer, minIdleTime, ids);
+        Map payload = response.get();
+
+        // verify
+        assertEquals(testResponse, response);
+        assertEquals(mockResult, payload);
+    }
+
     @SneakyThrows
     @Test
     public void xclaim_with_options_returns_success() {
@@ -6974,6 +7006,53 @@ public void xclaim_with_options_returns_success() {
         assertEquals(mockResult, payload);
     }
 
+    @SneakyThrows
+    @Test
+    public void xclaim_binary_with_options_returns_success() {
+        // setup
+        GlideString key = gs("testKey");
+        GlideString groupName = gs("testGroupName");
+        GlideString consumer = gs("testConsumer");
+        Long minIdleTime = 18L;
+        GlideString[] ids = new GlideString[] {gs("testId")};
+        StreamClaimOptions options =
+                StreamClaimOptions.builder().force().idle(11L).idleUnixTime(12L).retryCount(5L).build();
+        GlideString[] arguments =
+                new GlideString[] {
+                    key,
+                    groupName,
+                    consumer,
+                    gs("18"),
+                    gs("testId"),
+                    gs(IDLE_REDIS_API),
+                    gs("11"),
+                    gs(TIME_REDIS_API),
+                    gs("12"),
+                    gs(RETRY_COUNT_REDIS_API),
+                    gs("5"),
+                    gs(FORCE_REDIS_API)
+                };
+        Map mockResult =
+                Map.of(gs("1234-0"), new GlideString[][] {{gs("message"), gs("log")}});
+
+        CompletableFuture> testResponse = new CompletableFuture<>();
+        testResponse.complete(mockResult);
+
+        // match on protobuf request
+        when(commandManager.>submitNewCommand(
+                        eq(XClaim), eq(arguments), any()))
+                .thenReturn(testResponse);
+
+        // exercise
+        CompletableFuture> response =
+                service.xclaim(key, groupName, consumer, minIdleTime, ids, options);
+        Map payload = response.get();
+
+        // verify
+        assertEquals(testResponse, response);
+        assertEquals(mockResult, payload);
+    }
+
     @SneakyThrows
     @Test
     public void xclaimJustId_returns_success() {
@@ -7003,6 +7082,36 @@ public void xclaimJustId_returns_success() {
         assertEquals(mockResult, payload);
     }
 
+    @SneakyThrows
+    @Test
+    public void xclaimJustId_binary_returns_success() {
+        // setup
+        GlideString key = gs("testKey");
+        GlideString groupName = gs("testGroupName");
+        GlideString consumer = gs("testConsumer");
+        Long minIdleTime = 18L;
+        GlideString[] ids = new GlideString[] {gs("testId")};
+        GlideString[] arguments =
+                new GlideString[] {key, groupName, consumer, gs("18"), gs("testId"), gs(JUST_ID_REDIS_API)};
+        GlideString[] mockResult = {gs("message"), gs("log")};
+
+        CompletableFuture testResponse = new CompletableFuture<>();
+        testResponse.complete(mockResult);
+
+        // match on protobuf request
+        when(commandManager.submitNewCommand(eq(XClaim), eq(arguments), any()))
+                .thenReturn(testResponse);
+
+        // exercise
+        CompletableFuture response =
+                service.xclaimJustId(key, groupName, consumer, minIdleTime, ids);
+        GlideString[] payload = response.get();
+
+        // verify
+        assertEquals(testResponse, response);
+        assertEquals(mockResult, payload);
+    }
+
     @SneakyThrows
     @Test
     public void xclaimJustId_with_options_returns_success() {
@@ -7049,6 +7158,52 @@ public void xclaimJustId_with_options_returns_success() {
         assertEquals(mockResult, payload);
     }
 
+    @SneakyThrows
+    @Test
+    public void xclaimJustId_binary_with_options_returns_success() {
+        // setup
+        GlideString key = gs("testKey");
+        GlideString groupName = gs("testGroupName");
+        GlideString consumer = gs("testConsumer");
+        Long minIdleTime = 18L;
+        GlideString[] ids = new GlideString[] {gs("testId")};
+        StreamClaimOptions options =
+                StreamClaimOptions.builder().force().idle(11L).idleUnixTime(12L).retryCount(5L).build();
+        GlideString[] arguments =
+                new GlideString[] {
+                    key,
+                    groupName,
+                    consumer,
+                    gs("18"),
+                    gs("testId"),
+                    gs(IDLE_REDIS_API),
+                    gs("11"),
+                    gs(TIME_REDIS_API),
+                    gs("12"),
+                    gs(RETRY_COUNT_REDIS_API),
+                    gs("5"),
+                    gs(FORCE_REDIS_API),
+                    gs(JUST_ID_REDIS_API)
+                };
+        GlideString[] mockResult = {gs("message"), gs("log")};
+
+        CompletableFuture testResponse = new CompletableFuture<>();
+        testResponse.complete(mockResult);
+
+        // match on protobuf request
+        when(commandManager.submitNewCommand(eq(XClaim), eq(arguments), any()))
+                .thenReturn(testResponse);
+
+        // exercise
+        CompletableFuture response =
+                service.xclaimJustId(key, groupName, consumer, minIdleTime, ids, options);
+        GlideString[] payload = response.get();
+
+        // verify
+        assertEquals(testResponse, response);
+        assertEquals(mockResult, payload);
+    }
+
     @SneakyThrows
     @Test
     public void xack_binary_returns_success() {
@@ -7100,6 +7255,31 @@ public void xpending_returns_success() {
         assertEquals(summary, payload);
     }
 
+    @SneakyThrows
+    @Test
+    public void xpending_binary_returns_success() {
+        // setup
+        GlideString key = gs("testKey");
+        GlideString groupName = gs("testGroupName");
+        GlideString[] arguments = {key, groupName};
+        Object[] summary = new Object[] {1L, "1234-0", "2345-4", new Object[][] {{"consumer", "4"}}};
+
+        CompletableFuture testResponse = new CompletableFuture<>();
+        testResponse.complete(summary);
+
+        // match on protobuf request
+        when(commandManager.submitNewCommand(eq(XPending), eq(arguments), any()))
+                .thenReturn(testResponse);
+
+        // exercise
+        CompletableFuture response = service.xpending(key, groupName);
+        Object[] payload = response.get();
+
+        // verify
+        assertEquals(testResponse, response);
+        assertEquals(summary, payload);
+    }
+
     @SneakyThrows
     @Test
     public void xpending_with_start_end_count_returns_success() {
@@ -7128,6 +7308,36 @@ public void xpending_with_start_end_count_returns_success() {
         assertEquals(extendedForm, payload);
     }
 
+    @SneakyThrows
+    @Test
+    public void xpending_binary_with_start_end_count_returns_success() {
+        // setup
+        GlideString key = gs("testKey");
+        GlideString groupName = gs("testGroupName");
+        GlideString[] arguments = {
+            key, groupName, gs(EXCLUSIVE_RANGE_REDIS_API + "1234-0"), gs("2345-5"), gs("4")
+        };
+        StreamRange start = IdBound.ofExclusive("1234-0");
+        StreamRange end = IdBound.of("2345-5");
+        Long count = 4L;
+        Object[][] extendedForm = new Object[][] {{"1234-0", "consumer", 4L, 1L}};
+
+        CompletableFuture testResponse = new CompletableFuture<>();
+        testResponse.complete(extendedForm);
+
+        // match on protobuf request
+        when(commandManager.submitNewCommand(eq(XPending), eq(arguments), any()))
+                .thenReturn(testResponse);
+
+        // exercise
+        CompletableFuture response = service.xpending(key, groupName, start, end, count);
+        Object[][] payload = response.get();
+
+        // verify
+        assertEquals(testResponse, response);
+        assertEquals(extendedForm, payload);
+    }
+
     @SneakyThrows
     @Test
     public void xpending_with_start_end_count_options_returns_success() {
@@ -7173,6 +7383,51 @@ public void xpending_with_start_end_count_options_returns_success() {
         assertEquals(extendedForm, payload);
     }
 
+    @SneakyThrows
+    @Test
+    public void xpending_binary_with_start_end_count_options_returns_success() {
+        // setup
+        GlideString key = gs("testKey");
+        GlideString groupName = gs("testGroupName");
+        String consumer = "testConsumer";
+        GlideString[] arguments = {
+            key,
+            groupName,
+            gs(IDLE_TIME_REDIS_API),
+            gs("100"),
+            gs(MINIMUM_RANGE_REDIS_API),
+            gs(MAXIMUM_RANGE_REDIS_API),
+            gs("4"),
+            gs(consumer)
+        };
+        StreamRange start = InfRangeBound.MIN;
+        StreamRange end = InfRangeBound.MAX;
+        Long count = 4L;
+        Object[][] extendedForm = new Object[][] {{"1234-0", consumer, 4L, 1L}};
+
+        CompletableFuture testResponse = new CompletableFuture<>();
+        testResponse.complete(extendedForm);
+
+        // match on protobuf request
+        when(commandManager.submitNewCommand(eq(XPending), eq(arguments), any()))
+                .thenReturn(testResponse);
+
+        // exercise
+        CompletableFuture response =
+                service.xpending(
+                        key,
+                        groupName,
+                        start,
+                        end,
+                        count,
+                        StreamPendingOptions.builder().minIdleTime(100L).consumer(consumer).build());
+        Object[][] payload = response.get();
+
+        // verify
+        assertEquals(testResponse, response);
+        assertEquals(extendedForm, payload);
+    }
+
     @SneakyThrows
     @Test
     public void type_returns_success() {
diff --git a/java/integTest/src/test/java/glide/SharedCommandTests.java b/java/integTest/src/test/java/glide/SharedCommandTests.java
index ef2cbf685c..b612a97201 100644
--- a/java/integTest/src/test/java/glide/SharedCommandTests.java
+++ b/java/integTest/src/test/java/glide/SharedCommandTests.java
@@ -5497,6 +5497,195 @@ public void xpending_xclaim(BaseClient client) {
         assertEquals(2, pending_results_extended.length);
     }
 
+    // TODO: uncomment once relevant methods are implemented with binary version
+    //     @SneakyThrows
+    //     @ParameterizedTest(autoCloseArguments = false)
+    //     @MethodSource("getClients")
+    //     public void xpending_xclaim_binary(BaseClient client) {
+
+    //         GlideString key = gs(UUID.randomUUID().toString());
+    //         GlideString groupName = gs("group" + UUID.randomUUID());
+    //         GlideString zeroStreamId = gs("0");
+    //         GlideString consumer1 = gs("consumer-1-" + UUID.randomUUID());
+    //         GlideString consumer2 = gs("consumer-2-" + UUID.randomUUID());
+
+    //         // create group and consumer for the group
+    //         assertEquals(
+    //                 OK,
+    //                 client
+    //                         .xgroupCreate(
+    //                                 key, groupName, zeroStreamId,
+    // StreamGroupOptions.builder().makeStream().build())
+    //                         .get());
+    //         assertTrue(client.xgroupCreateConsumer(key, groupName, consumer1).get());
+    //         assertTrue(client.xgroupCreateConsumer(key, groupName, consumer2).get());
+
+    //         // Add two stream entries for consumer 1
+    //         GlideString streamid_1 = client.xadd(key, Map.of(gs("field1"), gs("value1"))).get();
+    //         assertNotNull(streamid_1);
+    //         GlideString streamid_2 = client.xadd(key, Map.of(gs("field2"), gs("value2"))).get();
+    //         assertNotNull(streamid_2);
+
+    //         // read the entire stream for the consumer and mark messages as pending
+    //         var result_1 = client.xreadgroup(Map.of(key, gs(">")), groupName, consumer1).get();
+    //         assertDeepEquals(
+    //                 Map.of(
+    //                         key,
+    //                         Map.of(
+    //                                 streamid_1, new GlideString[][] {{gs("field1"), gs("value1")}},
+    //                                 streamid_2, new GlideString[][] {{gs("field2"),
+    // gs("value2")}})),
+    //                 result_1);
+
+    //         // Add three stream entries for consumer 2
+    //         String streamid_3 = client.xadd(key, Map.of(gs("field3"), gs("value3"))).get();
+    //         assertNotNull(streamid_3);
+    //         String streamid_4 = client.xadd(key, Map.of(gs("field4"), gs("value4"))).get();
+    //         assertNotNull(streamid_4);
+    //         String streamid_5 = client.xadd(key, Map.of(gs("field5"), gs("value5"))).get();
+    //         assertNotNull(streamid_5);
+
+    //         // read the entire stream for the consumer and mark messages as pending
+    //         var result_2 = client.xreadgroup(Map.of(key, gs(">")), groupName, consumer2).get();
+    //         assertDeepEquals(
+    //                 Map.of(
+    //                         key,
+    //                         Map.of(
+    //                                 streamid_3, new GlideString[][] {{gs("field3"), gs("value3")}},
+    //                                 streamid_4, new GlideString[][] {{gs("field4"), gs("value4")}},
+    //                                 streamid_5, new GlideString[][] {{gs("field5"),
+    // gs("value5")}})),
+    //                 result_2);
+
+    //         Object[] pending_results = client.xpending(key, groupName).get();
+    //         Object[] expectedResult = {
+    //             Long.valueOf(5L), streamid_1, streamid_5, new Object[][] {{consumer1, "2"},
+    // {consumer2, "3"}}
+    //         };
+    //         assertDeepEquals(expectedResult, pending_results);
+
+    //         // ensure idle_time > 0
+    //         Thread.sleep(2000);
+    //         Object[][] pending_results_extended =
+    //                 client.xpending(key, groupName, InfRangeBound.MIN, InfRangeBound.MAX,
+    // 10L).get();
+
+    //         // because of idle time return, we have to remove it from the expected results
+    //         // and check it separately
+    //         assertArrayEquals(
+    //                 new Object[] {streamid_1, consumer1, 1L},
+    //                 ArrayUtils.remove(pending_results_extended[0], 2));
+    //         assertTrue((Long) pending_results_extended[0][2] > 0L);
+
+    //         assertArrayEquals(
+    //                 new Object[] {streamid_2, consumer1, 1L},
+    //                 ArrayUtils.remove(pending_results_extended[1], 2));
+    //         assertTrue((Long) pending_results_extended[1][2] > 0L);
+
+    //         assertArrayEquals(
+    //                 new Object[] {streamid_3, consumer2, 1L},
+    //                 ArrayUtils.remove(pending_results_extended[2], 2));
+    //         assertTrue((Long) pending_results_extended[2][2] >= 0L);
+
+    //         assertArrayEquals(
+    //                 new Object[] {streamid_4, consumer2, 1L},
+    //                 ArrayUtils.remove(pending_results_extended[3], 2));
+    //         assertTrue((Long) pending_results_extended[3][2] >= 0L);
+
+    //         assertArrayEquals(
+    //                 new Object[] {streamid_5, consumer2, 1L},
+    //                 ArrayUtils.remove(pending_results_extended[4], 2));
+    //         assertTrue((Long) pending_results_extended[4][2] >= 0L);
+
+    //         // use claim to claim stream 3 and 5 for consumer 1
+    //         var claimResults =
+    //                 client
+    //                         .xclaim(key, groupName, consumer1, 0L, new GlideString[] {streamid_3,
+    // streamid_5})
+    //                         .get();
+    //         assertDeepEquals(
+    //                 Map.of(
+    //                         streamid_3,
+    //                         new GlideString[][] {{gs("field3"), gs("value3")}},
+    //                         streamid_5,
+    //                         new GlideString[][] {{gs("field5"), gs("value5")}}),
+    //                 claimResults);
+
+    //         var claimResultsJustId =
+    //                 client
+    //                         .xclaimJustId(key, groupName, consumer1, 0L, new String[] {streamid_3,
+    // streamid_5})
+    //                         .get();
+    //         assertArrayEquals(new GlideString[] {streamid_3, streamid_5}, claimResultsJustId);
+
+    //         // add one more stream
+    //         String streamid_6 = client.xadd(key, Map.of(gs("field6"), gs("value6"))).get();
+    //         assertNotNull(streamid_6);
+
+    //         // using force, we can xclaim the message without reading it
+    //         var claimForceResults =
+    //                 client
+    //                         .xclaim(
+    //                                 key,
+    //                                 groupName,
+    //                                 consumer2,
+    //                                 0L,
+    //                                 new GlideString[] {streamid_6},
+    //                                 StreamClaimOptions.builder().force().retryCount(99L).build())
+    //                         .get();
+    //         assertDeepEquals(
+    //                 Map.of(streamid_6, new GlideString[][] {{gs("field6"), gs("value6")}}),
+    // claimForceResults);
+
+    //         Object[][] forcePendingResults =
+    //                 client.xpending(key, groupName, IdBound.of(streamid_6), IdBound.of(streamid_6),
+    // 1L).get();
+    //         assertEquals(streamid_6, forcePendingResults[0][0]);
+    //         assertEquals(consumer2, forcePendingResults[0][1]);
+    //         assertEquals(99L, forcePendingResults[0][3]);
+
+    //         // acknowledge streams 2, 3, 4, and 6 and remove them from the xpending results
+    //         assertEquals(
+    //                 4L,
+    //                 client
+    //                         .xack(
+    //                                 key, groupName, new GlideString[] {streamid_2, streamid_3,
+    // streamid_4, streamid_6})
+    //                         .get());
+
+    //         pending_results_extended =
+    //                 client
+    //                         .xpending(key, groupName, IdBound.ofExclusive(streamid_3),
+    // InfRangeBound.MAX, 10L)
+    //                         .get();
+    //         assertEquals(1, pending_results_extended.length);
+    //         assertEquals(streamid_5, pending_results_extended[0][0]);
+    //         assertEquals(consumer1, pending_results_extended[0][1]);
+
+    //         pending_results_extended =
+    //                 client
+    //                         .xpending(key, groupName, InfRangeBound.MIN,
+    // IdBound.ofExclusive(streamid_5), 10L)
+    //                         .get();
+    //         assertEquals(1, pending_results_extended.length);
+    //         assertEquals(streamid_1, pending_results_extended[0][0]);
+    //         assertEquals(consumer1, pending_results_extended[0][1]);
+
+    //         pending_results_extended =
+    //                 client
+    //                         .xpending(
+    //                                 key,
+    //                                 groupName,
+    //                                 InfRangeBound.MIN,
+    //                                 InfRangeBound.MAX,
+    //                                 10L,
+    //
+    // StreamPendingOptions.builder().minIdleTime(1L).consumer(consumer1).build())
+    //                         .get();
+    //         // note: streams ID 1 and 5 are still pending, all others were acknowledged
+    //         assertEquals(2, pending_results_extended.length);
+    //     }
+
     @SneakyThrows
     @ParameterizedTest(autoCloseArguments = false)
     @MethodSource("getClients")
@@ -5656,6 +5845,179 @@ public void xpending_return_failures(BaseClient client) {
         assertInstanceOf(RequestException.class, executionException.getCause());
     }
 
+    // TODO: uncomment once relevant methods are implemented with binary version
+    //     @SneakyThrows
+    //     @ParameterizedTest(autoCloseArguments = false)
+    //     @MethodSource("getClients")
+    //     public void xpending_binary_return_failures(BaseClient client) {
+
+    //         GlideString key = gs(UUID.randomUUID().toString());
+    //         GlideString stringkey = gs(UUID.randomUUID().toString());
+    //         GlideString groupName = gs("group" + UUID.randomUUID());
+    //         GlideString zeroStreamId = gs("0");
+    //         GlideString consumer1 = gs("consumer-1-" + UUID.randomUUID());
+
+    //         // create group and consumer for the group
+    //         assertEquals(
+    //                 OK,
+    //                 client
+    //                         .xgroupCreate(
+    //                                 key, groupName, zeroStreamId,
+    // StreamGroupOptions.builder().makeStream().build())
+    //                         .get());
+    //         assertTrue(client.xgroupCreateConsumer(key, groupName, consumer1).get());
+
+    //         // Add two stream entries for consumer 1
+    //         GlideString streamid_1 = client.xadd(key, Map.of(gs("field1"), gs("value1"))).get();
+    //         assertNotNull(streamid_1);
+    //         GlideString streamid_2 = client.xadd(key, Map.of(gs("field2"), gs("value2"))).get();
+    //         assertNotNull(streamid_2);
+
+    //         // no pending messages yet...
+    //         var pending_results_summary = client.xpending(key, groupName).get();
+    //         assertArrayEquals(new Object[] {0L, null, null, null}, pending_results_summary);
+
+    //         var pending_results_extended =
+    //                 client.xpending(key, groupName, InfRangeBound.MAX, InfRangeBound.MIN,
+    // 10L).get();
+    //         assertEquals(0, pending_results_extended.length);
+
+    //         // read the entire stream for the consumer and mark messages as pending
+    //         var result_1 = client.xreadgroup(Map.of(key, gs(">")), groupName, consumer1).get();
+    //         assertDeepEquals(
+    //                 Map.of(
+    //                         key,
+    //                         Map.of(
+    //                                 streamid_1, new GlideString[][] {{gs("field1"), gs("value1")}},
+    //                                 streamid_2, new GlideString[][] {{gs("field2"),
+    // gs("value2")}})),
+    //                 result_1);
+
+    //         // sanity check - expect some results:
+    //         pending_results_summary = client.xpending(key, groupName).get();
+    //         assertTrue((Long) pending_results_summary[0] > 0L);
+
+    //         pending_results_extended =
+    //                 client.xpending(key, groupName, InfRangeBound.MIN, InfRangeBound.MAX,
+    // 1L).get();
+    //         assertTrue(pending_results_extended.length > 0);
+
+    //         // returns empty if + before -
+    //         pending_results_extended =
+    //                 client.xpending(key, groupName, InfRangeBound.MAX, InfRangeBound.MIN,
+    // 10L).get();
+    //         assertEquals(0, pending_results_extended.length);
+
+    //         // min idletime of 100 seconds shouldn't produce any results
+    //         pending_results_extended =
+    //                 client
+    //                         .xpending(
+    //                                 key,
+    //                                 groupName,
+    //                                 InfRangeBound.MIN,
+    //                                 InfRangeBound.MAX,
+    //                                 10L,
+    //                                 StreamPendingOptions.builder().minIdleTime(100000L).build())
+    //                         .get();
+    //         assertEquals(0, pending_results_extended.length);
+
+    //         // invalid consumer - no results
+    //         pending_results_extended =
+    //                 client
+    //                         .xpending(
+    //                                 key,
+    //                                 groupName,
+    //                                 InfRangeBound.MIN,
+    //                                 InfRangeBound.MAX,
+    //                                 10L,
+    //
+    // StreamPendingOptions.builder().consumer("invalid_consumer").build())
+    //                         .get();
+    //         assertEquals(0, pending_results_extended.length);
+
+    //         // xpending when range bound is not valid ID throws a RequestError
+    //         Exception executionException =
+    //                 assertThrows(
+    //                         ExecutionException.class,
+    //                         () ->
+    //                                 client
+    //                                         .xpending(
+    //                                                 key,
+    //                                                 groupName,
+    //                                                 IdBound.ofExclusive("not_a_stream_id"),
+    //                                                 InfRangeBound.MAX,
+    //                                                 10L)
+    //                                         .get());
+    //         assertInstanceOf(RequestException.class, executionException.getCause());
+
+    //         executionException =
+    //                 assertThrows(
+    //                         ExecutionException.class,
+    //                         () ->
+    //                                 client
+    //                                         .xpending(
+    //                                                 key,
+    //                                                 groupName,
+    //                                                 InfRangeBound.MIN,
+    //                                                 IdBound.ofExclusive("not_a_stream_id"),
+    //                                                 10L)
+    //                                         .get());
+    //         assertInstanceOf(RequestException.class, executionException.getCause());
+
+    //         // invalid count should return no results
+    //         pending_results_extended =
+    //                 client.xpending(key, groupName, InfRangeBound.MIN, InfRangeBound.MAX,
+    // -10L).get();
+    //         assertEquals(0, pending_results_extended.length);
+
+    //         pending_results_extended =
+    //                 client.xpending(key, groupName, InfRangeBound.MIN, InfRangeBound.MAX,
+    // 0L).get();
+    //         assertEquals(0, pending_results_extended.length);
+
+    //         // invalid group throws a RequestError (NOGROUP)
+    //         executionException =
+    //                 assertThrows(ExecutionException.class, () -> client.xpending(key,
+    // gs("not_a_group")).get());
+    //         assertInstanceOf(RequestException.class, executionException.getCause());
+    //         assertTrue(executionException.getMessage().contains("NOGROUP"));
+
+    //         // non-existent key throws a RequestError (NOGROUP)
+    //         executionException =
+    //                 assertThrows(ExecutionException.class, () -> client.xpending(stringkey,
+    // groupName).get());
+    //         assertInstanceOf(RequestException.class, executionException.getCause());
+    //         assertTrue(executionException.getMessage().contains("NOGROUP"));
+
+    //         executionException =
+    //                 assertThrows(
+    //                         ExecutionException.class,
+    //                         () ->
+    //                                 client
+    //                                         .xpending(stringkey, groupName, InfRangeBound.MIN,
+    // InfRangeBound.MAX, 10L)
+    //                                         .get());
+    //         assertInstanceOf(RequestException.class, executionException.getCause());
+    //         assertTrue(executionException.getMessage().contains("NOGROUP"));
+
+    //         // Key exists, but it is not a stream
+    //         assertEquals(OK, client.set(stringkey, gs("bar")).get());
+    //         executionException =
+    //                 assertThrows(ExecutionException.class, () -> client.xpending(stringkey,
+    // groupName).get());
+    //         assertInstanceOf(RequestException.class, executionException.getCause());
+
+    //         executionException =
+    //                 assertThrows(
+    //                         ExecutionException.class,
+    //                         () ->
+    //                                 client
+    //                                         .xpending(stringkey, groupName, InfRangeBound.MIN,
+    // InfRangeBound.MAX, 10L)
+    //                                         .get());
+    //         assertInstanceOf(RequestException.class, executionException.getCause());
+    //     }
+
     @SneakyThrows
     @ParameterizedTest(autoCloseArguments = false)
     @MethodSource("getClients")
@@ -5799,6 +6161,161 @@ public void xclaim_return_failures(BaseClient client) {
         assertInstanceOf(RequestException.class, executionException.getCause());
     }
 
+    // TODO: uncomment once relevant methods are implemented with binary version
+    //     @SneakyThrows
+    //     @ParameterizedTest(autoCloseArguments = false)
+    //     @MethodSource("getClients")
+    //     public void xclaim_binary_return_failures(BaseClient client) {
+
+    //         GlideString key = gs(UUID.randomUUID().toString());
+    //         GlideString stringkey = gs(UUID.randomUUID().toString());
+    //         GlideString groupName = gs("group" + UUID.randomUUID());
+    //         GlideString zeroStreamId = gs("0");
+    //         GlideString consumer1 = gs("consumer-1-" + UUID.randomUUID());
+    //         GlideString consumer2 = gs("consumer-2-" + UUID.randomUUID());
+
+    //         // create group and consumer for the group
+    //         assertEquals(
+    //                 OK,
+    //                 client
+    //                         .xgroupCreate(
+    //                                 key, groupName, zeroStreamId,
+    // StreamGroupOptions.builder().makeStream().build())
+    //                         .get());
+    //         assertTrue(client.xgroupCreateConsumer(key, groupName, consumer1).get());
+
+    //         // Add stream entry and mark as pending:
+    //         GlideString streamid_1 = client.xadd(key, Map.of(gs("field1"), gs("value1"))).get();
+    //         assertNotNull(streamid_1);
+    //         assertNotNull(client.xreadgroup(Map.of(key, gs(">")), groupName, consumer1).get());
+
+    //         // claim with invalid stream entry IDs
+    //         ExecutionException executionException =
+    //                 assertThrows(
+    //                         ExecutionException.class,
+    //                         () ->
+    //                                 client
+    //                                         .xclaimJustId(key, groupName, consumer1, 1L, new
+    // GlideString[] {gs("invalid")})
+    //                                         .get());
+    //         assertInstanceOf(RequestException.class, executionException.getCause());
+
+    //         // claim with empty stream entry IDs returns no results
+    //         var emptyClaim = client.xclaimJustId(key, groupName, consumer1, 1L, new
+    // GlideString[0]).get();
+    //         assertEquals(0L, emptyClaim.length);
+
+    //         // non-existent key throws a RequestError (NOGROUP)
+    //         executionException =
+    //                 assertThrows(
+    //                         ExecutionException.class,
+    //                         () ->
+    //                                 client
+    //                                         .xclaim(stringkey, groupName, consumer1, 1L, new
+    // GlideString[] {streamid_1})
+    //                                         .get());
+    //         assertInstanceOf(RequestException.class, executionException.getCause());
+    //         assertTrue(executionException.getMessage().contains("NOGROUP"));
+
+    //         final var claimOptions = StreamClaimOptions.builder().idle(1L).build();
+    //         executionException =
+    //                 assertThrows(
+    //                         ExecutionException.class,
+    //                         () ->
+    //                                 client
+    //                                         .xclaim(
+    //                                                 stringkey,
+    //                                                 groupName,
+    //                                                 consumer1,
+    //                                                 1L,
+    //                                                 new GlideString[] {streamid_1},
+    //                                                 claimOptions)
+    //                                         .get());
+    //         assertInstanceOf(RequestException.class, executionException.getCause());
+    //         assertTrue(executionException.getMessage().contains("NOGROUP"));
+
+    //         executionException =
+    //                 assertThrows(
+    //                         ExecutionException.class,
+    //                         () ->
+    //                                 client
+    //                                         .xclaimJustId(
+    //                                                 stringkey, groupName, consumer1, 1L, new
+    // GlideString[] {streamid_1})
+    //                                         .get());
+    //         assertInstanceOf(RequestException.class, executionException.getCause());
+    //         assertTrue(executionException.getMessage().contains("NOGROUP"));
+
+    //         executionException =
+    //                 assertThrows(
+    //                         ExecutionException.class,
+    //                         () ->
+    //                                 client
+    //                                         .xclaimJustId(
+    //                                                 stringkey,
+    //                                                 groupName,
+    //                                                 consumer1,
+    //                                                 1L,
+    //                                                 new GlideString[] {streamid_1},
+    //                                                 claimOptions)
+    //                                         .get());
+    //         assertInstanceOf(RequestException.class, executionException.getCause());
+    //         assertTrue(executionException.getMessage().contains("NOGROUP"));
+
+    //         // Key exists, but it is not a stream
+    //         assertEquals(OK, client.set(stringkey, gs("bar")).get());
+    //         executionException =
+    //                 assertThrows(
+    //                         ExecutionException.class,
+    //                         () ->
+    //                                 client
+    //                                         .xclaim(stringkey, groupName, consumer1, 1L, new
+    // GlideString[] {streamid_1})
+    //                                         .get());
+    //         assertInstanceOf(RequestException.class, executionException.getCause());
+
+    //         executionException =
+    //                 assertThrows(
+    //                         ExecutionException.class,
+    //                         () ->
+    //                                 client
+    //                                         .xclaim(
+    //                                                 stringkey,
+    //                                                 groupName,
+    //                                                 consumer1,
+    //                                                 1L,
+    //                                                 new GlideString[] {streamid_1},
+    //                                                 claimOptions)
+    //                                         .get());
+    //         assertInstanceOf(RequestException.class, executionException.getCause());
+
+    //         executionException =
+    //                 assertThrows(
+    //                         ExecutionException.class,
+    //                         () ->
+    //                                 client
+    //                                         .xclaimJustId(
+    //                                                 stringkey, groupName, consumer1, 1L, new
+    // GlideString[] {streamid_1})
+    //                                         .get());
+    //         assertInstanceOf(RequestException.class, executionException.getCause());
+
+    //         executionException =
+    //                 assertThrows(
+    //                         ExecutionException.class,
+    //                         () ->
+    //                                 client
+    //                                         .xclaimJustId(
+    //                                                 stringkey,
+    //                                                 groupName,
+    //                                                 consumer1,
+    //                                                 1L,
+    //                                                 new GlideString[] {streamid_1},
+    //                                                 claimOptions)
+    //                                         .get());
+    //         assertInstanceOf(RequestException.class, executionException.getCause());
+    //     }
+
     @SneakyThrows
     @ParameterizedTest(autoCloseArguments = false)
     @MethodSource("getClients")

From dc974a20a735e69a591c79dfb4a3f969e731fc0a Mon Sep 17 00:00:00 2001
From: talxsha <160726520+talxsha@users.noreply.github.com>
Date: Thu, 4 Jul 2024 10:46:00 +0300
Subject: [PATCH 08/23] Glide pop commands (#1654)

* binary version for *pop* commands
---
 .../src/main/java/glide/api/BaseClient.java   | 226 +++++++
 .../glide/api/commands/ListBaseCommands.java  | 249 ++++++++
 .../glide/api/commands/SetBaseCommands.java   |  38 ++
 .../api/commands/SortedSetBaseCommands.java   | 278 +++++++-
 .../java/glide/utils/ArrayTransformUtils.java |  17 +
 .../test/java/glide/api/RedisClientTest.java  | 595 ++++++++++++++++++
 .../test/java/glide/SharedCommandTests.java   | 587 +++++++++++++++++
 .../test/java/glide/cluster/CommandTests.java |  33 +
 8 files changed, 2011 insertions(+), 12 deletions(-)

diff --git a/java/client/src/main/java/glide/api/BaseClient.java b/java/client/src/main/java/glide/api/BaseClient.java
index ecd432e970..3cd379cc17 100644
--- a/java/client/src/main/java/glide/api/BaseClient.java
+++ b/java/client/src/main/java/glide/api/BaseClient.java
@@ -12,6 +12,7 @@
 import static glide.utils.ArrayTransformUtils.cast3DArray;
 import static glide.utils.ArrayTransformUtils.castArray;
 import static glide.utils.ArrayTransformUtils.castArrayofArrays;
+import static glide.utils.ArrayTransformUtils.castBinaryStringMapOfArrays;
 import static glide.utils.ArrayTransformUtils.castMapOf2DArray;
 import static glide.utils.ArrayTransformUtils.castMapOfArrays;
 import static glide.utils.ArrayTransformUtils.concatenateArrays;
@@ -602,6 +603,17 @@ protected  Map handleMapOrNullResponse(Response response) throws R
                 Map.class, EnumSet.of(ResponseFlags.IS_NULLABLE, ResponseFlags.ENCODING_UTF8), response);
     }
 
+    /**
+     * @param response A Protobuf response
+     * @return A map of String to V or null
+     * @param  Value type.
+     */
+    @SuppressWarnings("unchecked") // raw Map cast to Map
+    protected  Map handleBinaryStringMapOrNullResponse(Response response)
+            throws RedisException {
+        return handleRedisResponse(Map.class, EnumSet.of(ResponseFlags.IS_NULLABLE), response);
+    }
+
     /**
      * @param response A Protobuf response
      * @return A map of a map of String[][]
@@ -1198,6 +1210,12 @@ public CompletableFuture lpop(@NonNull String key) {
                 LPop, new String[] {key}, this::handleStringOrNullResponse);
     }
 
+    @Override
+    public CompletableFuture lpop(@NonNull GlideString key) {
+        return commandManager.submitNewCommand(
+                LPop, new GlideString[] {key}, this::handleGlideStringOrNullResponse);
+    }
+
     @Override
     public CompletableFuture lpopCount(@NonNull String key, long count) {
         return commandManager.submitNewCommand(
@@ -1206,6 +1224,14 @@ public CompletableFuture lpopCount(@NonNull String key, long count) {
                 response -> castArray(handleArrayResponse(response), String.class));
     }
 
+    @Override
+    public CompletableFuture lpopCount(@NonNull GlideString key, long count) {
+        return commandManager.submitNewCommand(
+                LPop,
+                new GlideString[] {key, gs(Long.toString(count))},
+                response -> castArray(handleArrayResponse(response), GlideString.class));
+    }
+
     @Override
     public CompletableFuture lpos(@NonNull String key, @NonNull String element) {
         return commandManager.submitNewCommand(
@@ -1364,6 +1390,12 @@ public CompletableFuture rpop(@NonNull String key) {
                 RPop, new String[] {key}, this::handleStringOrNullResponse);
     }
 
+    @Override
+    public CompletableFuture rpop(@NonNull GlideString key) {
+        return commandManager.submitNewCommand(
+                RPop, new GlideString[] {key}, this::handleGlideStringOrNullResponse);
+    }
+
     @Override
     public CompletableFuture rpopCount(@NonNull String key, long count) {
         return commandManager.submitNewCommand(
@@ -1372,6 +1404,14 @@ public CompletableFuture rpopCount(@NonNull String key, long count) {
                 response -> castArray(handleArrayOrNullResponse(response), String.class));
     }
 
+    @Override
+    public CompletableFuture rpopCount(@NonNull GlideString key, long count) {
+        return commandManager.submitNewCommand(
+                RPop,
+                new GlideString[] {key, gs(Long.toString(count))},
+                response -> castArray(handleArrayOrNullResponseBinary(response), GlideString.class));
+    }
+
     @Override
     public CompletableFuture sadd(@NonNull String key, @NonNull String[] members) {
         String[] arguments = ArrayUtils.addFirst(members, key);
@@ -1828,34 +1868,74 @@ public CompletableFuture> zpopmin(@NonNull String key, long
                 ZPopMin, new String[] {key, Long.toString(count)}, this::handleMapResponse);
     }
 
+    @Override
+    public CompletableFuture> zpopmin(@NonNull GlideString key, long count) {
+        return commandManager.submitNewCommand(
+                ZPopMin,
+                new GlideString[] {key, gs(Long.toString(count))},
+                this::handleBinaryStringMapResponse);
+    }
+
     @Override
     public CompletableFuture> zpopmin(@NonNull String key) {
         return commandManager.submitNewCommand(ZPopMin, new String[] {key}, this::handleMapResponse);
     }
 
+    @Override
+    public CompletableFuture> zpopmin(@NonNull GlideString key) {
+        return commandManager.submitNewCommand(
+                ZPopMin, new GlideString[] {key}, this::handleBinaryStringMapResponse);
+    }
+
     @Override
     public CompletableFuture bzpopmin(@NonNull String[] keys, double timeout) {
         String[] arguments = ArrayUtils.add(keys, Double.toString(timeout));
         return commandManager.submitNewCommand(BZPopMin, arguments, this::handleArrayOrNullResponse);
     }
 
+    @Override
+    public CompletableFuture bzpopmin(@NonNull GlideString[] keys, double timeout) {
+        GlideString[] arguments = ArrayUtils.add(keys, gs(Double.toString(timeout)));
+        return commandManager.submitNewCommand(BZPopMin, arguments, this::handleArrayOrNullResponse);
+    }
+
     @Override
     public CompletableFuture> zpopmax(@NonNull String key, long count) {
         return commandManager.submitNewCommand(
                 ZPopMax, new String[] {key, Long.toString(count)}, this::handleMapResponse);
     }
 
+    @Override
+    public CompletableFuture> zpopmax(@NonNull GlideString key, long count) {
+        return commandManager.submitNewCommand(
+                ZPopMax,
+                new GlideString[] {key, gs(Long.toString(count))},
+                this::handleBinaryStringMapResponse);
+    }
+
     @Override
     public CompletableFuture> zpopmax(@NonNull String key) {
         return commandManager.submitNewCommand(ZPopMax, new String[] {key}, this::handleMapResponse);
     }
 
+    @Override
+    public CompletableFuture> zpopmax(@NonNull GlideString key) {
+        return commandManager.submitNewCommand(
+                ZPopMax, new GlideString[] {key}, this::handleBinaryStringMapResponse);
+    }
+
     @Override
     public CompletableFuture bzpopmax(@NonNull String[] keys, double timeout) {
         String[] arguments = ArrayUtils.add(keys, Double.toString(timeout));
         return commandManager.submitNewCommand(BZPopMax, arguments, this::handleArrayOrNullResponse);
     }
 
+    @Override
+    public CompletableFuture bzpopmax(@NonNull GlideString[] keys, double timeout) {
+        GlideString[] arguments = ArrayUtils.add(keys, gs(Double.toString(timeout)));
+        return commandManager.submitNewCommand(BZPopMax, arguments, this::handleArrayOrNullResponse);
+    }
+
     @Override
     public CompletableFuture zscore(@NonNull String key, @NonNull String member) {
         return commandManager.submitNewCommand(
@@ -2737,6 +2817,15 @@ public CompletableFuture blpop(@NonNull String[] keys, double timeout)
                 BLPop, arguments, response -> castArray(handleArrayOrNullResponse(response), String.class));
     }
 
+    @Override
+    public CompletableFuture blpop(@NonNull GlideString[] keys, double timeout) {
+        GlideString[] arguments = ArrayUtils.add(keys, gs(Double.toString(timeout)));
+        return commandManager.submitNewCommand(
+                BLPop,
+                arguments,
+                response -> castArray(handleArrayOrNullResponseBinary(response), GlideString.class));
+    }
+
     @Override
     public CompletableFuture brpop(@NonNull String[] keys, double timeout) {
         String[] arguments = ArrayUtils.add(keys, Double.toString(timeout));
@@ -2744,6 +2833,15 @@ public CompletableFuture brpop(@NonNull String[] keys, double timeout)
                 BRPop, arguments, response -> castArray(handleArrayOrNullResponse(response), String.class));
     }
 
+    @Override
+    public CompletableFuture brpop(@NonNull GlideString[] keys, double timeout) {
+        GlideString[] arguments = ArrayUtils.add(keys, gs(Double.toString(timeout)));
+        return commandManager.submitNewCommand(
+                BRPop,
+                arguments,
+                response -> castArray(handleArrayOrNullResponseBinary(response), GlideString.class));
+    }
+
     @Override
     public CompletableFuture rpushx(@NonNull String key, @NonNull String[] elements) {
         String[] arguments = ArrayUtils.addFirst(elements, key);
@@ -2806,6 +2904,17 @@ public CompletableFuture zmpop(@NonNull String[] keys, @NonNull ScoreF
         return commandManager.submitNewCommand(ZMPop, arguments, this::handleArrayOrNullResponse);
     }
 
+    @Override
+    public CompletableFuture zmpop(
+            @NonNull GlideString[] keys, @NonNull ScoreFilter modifier) {
+        GlideString[] arguments =
+                concatenateArrays(
+                        new GlideString[] {gs(Integer.toString(keys.length))},
+                        keys,
+                        new GlideString[] {gs(modifier.toString())});
+        return commandManager.submitNewCommand(ZMPop, arguments, this::handleArrayOrNullResponse);
+    }
+
     @Override
     public CompletableFuture zmpop(
             @NonNull String[] keys, @NonNull ScoreFilter modifier, long count) {
@@ -2817,6 +2926,19 @@ public CompletableFuture zmpop(
         return commandManager.submitNewCommand(ZMPop, arguments, this::handleArrayOrNullResponse);
     }
 
+    @Override
+    public CompletableFuture zmpop(
+            @NonNull GlideString[] keys, @NonNull ScoreFilter modifier, long count) {
+        GlideString[] arguments =
+                concatenateArrays(
+                        new GlideString[] {gs(Integer.toString(keys.length))},
+                        keys,
+                        new GlideString[] {
+                            gs(modifier.toString()), gs(COUNT_REDIS_API), gs(Long.toString(count))
+                        });
+        return commandManager.submitNewCommand(ZMPop, arguments, this::handleArrayOrNullResponse);
+    }
+
     @Override
     public CompletableFuture bzmpop(
             @NonNull String[] keys, @NonNull ScoreFilter modifier, double timeout) {
@@ -2828,6 +2950,17 @@ public CompletableFuture bzmpop(
         return commandManager.submitNewCommand(BZMPop, arguments, this::handleArrayOrNullResponse);
     }
 
+    @Override
+    public CompletableFuture bzmpop(
+            @NonNull GlideString[] keys, @NonNull ScoreFilter modifier, double timeout) {
+        GlideString[] arguments =
+                concatenateArrays(
+                        new GlideString[] {gs(Double.toString(timeout)), gs(Integer.toString(keys.length))},
+                        keys,
+                        new GlideString[] {gs(modifier.toString())});
+        return commandManager.submitNewCommand(BZMPop, arguments, this::handleArrayOrNullResponse);
+    }
+
     @Override
     public CompletableFuture bzmpop(
             @NonNull String[] keys, @NonNull ScoreFilter modifier, double timeout, long count) {
@@ -2839,6 +2972,19 @@ public CompletableFuture bzmpop(
         return commandManager.submitNewCommand(BZMPop, arguments, this::handleArrayOrNullResponse);
     }
 
+    @Override
+    public CompletableFuture bzmpop(
+            @NonNull GlideString[] keys, @NonNull ScoreFilter modifier, double timeout, long count) {
+        GlideString[] arguments =
+                concatenateArrays(
+                        new GlideString[] {gs(Double.toString(timeout)), gs(Integer.toString(keys.length))},
+                        keys,
+                        new GlideString[] {
+                            gs(modifier.toString()), gs(COUNT_REDIS_API), gs(Long.toString(count))
+                        });
+        return commandManager.submitNewCommand(BZMPop, arguments, this::handleArrayOrNullResponse);
+    }
+
     @Override
     public CompletableFuture pfadd(@NonNull String key, @NonNull String[] elements) {
         String[] arguments = ArrayUtils.addFirst(elements, key);
@@ -3162,6 +3308,24 @@ public CompletableFuture> lmpop(
                 response -> castMapOfArrays(handleMapOrNullResponse(response), String.class));
     }
 
+    @Override
+    public CompletableFuture> lmpop(
+            @NonNull GlideString[] keys, @NonNull ListDirection direction, long count) {
+        GlideString[] arguments =
+                concatenateArrays(
+                        new GlideString[] {gs(Long.toString(keys.length))},
+                        keys,
+                        new GlideString[] {
+                            gs(direction.toString()), gs(COUNT_FOR_LIST_REDIS_API), gs(Long.toString(count))
+                        });
+        return commandManager.submitNewCommand(
+                LMPop,
+                arguments,
+                response ->
+                        castBinaryStringMapOfArrays(
+                                handleBinaryStringMapOrNullResponse(response), GlideString.class));
+    }
+
     @Override
     public CompletableFuture> lmpop(
             @NonNull String[] keys, @NonNull ListDirection direction) {
@@ -3174,6 +3338,22 @@ public CompletableFuture> lmpop(
                 response -> castMapOfArrays(handleMapOrNullResponse(response), String.class));
     }
 
+    @Override
+    public CompletableFuture> lmpop(
+            @NonNull GlideString[] keys, @NonNull ListDirection direction) {
+        GlideString[] arguments =
+                concatenateArrays(
+                        new GlideString[] {gs(Long.toString(keys.length))},
+                        keys,
+                        new GlideString[] {gs(direction.toString())});
+        return commandManager.submitNewCommand(
+                LMPop,
+                arguments,
+                response ->
+                        castBinaryStringMapOfArrays(
+                                handleBinaryStringMapOrNullResponse(response), GlideString.class));
+    }
+
     @Override
     public CompletableFuture> blmpop(
             @NonNull String[] keys, @NonNull ListDirection direction, long count, double timeout) {
@@ -3188,6 +3368,24 @@ public CompletableFuture> blmpop(
                 response -> castMapOfArrays(handleMapOrNullResponse(response), String.class));
     }
 
+    @Override
+    public CompletableFuture> blmpop(
+            @NonNull GlideString[] keys, @NonNull ListDirection direction, long count, double timeout) {
+        GlideString[] arguments =
+                concatenateArrays(
+                        new GlideString[] {gs(Double.toString(timeout)), gs(Long.toString(keys.length))},
+                        keys,
+                        new GlideString[] {
+                            gs(direction.toString()), gs(COUNT_FOR_LIST_REDIS_API), gs(Long.toString(count))
+                        });
+        return commandManager.submitNewCommand(
+                BLMPop,
+                arguments,
+                response ->
+                        castBinaryStringMapOfArrays(
+                                handleBinaryStringMapOrNullResponse(response), GlideString.class));
+    }
+
     @Override
     public CompletableFuture> blmpop(
             @NonNull String[] keys, @NonNull ListDirection direction, double timeout) {
@@ -3202,6 +3400,22 @@ public CompletableFuture> blmpop(
                 response -> castMapOfArrays(handleMapOrNullResponse(response), String.class));
     }
 
+    @Override
+    public CompletableFuture> blmpop(
+            @NonNull GlideString[] keys, @NonNull ListDirection direction, double timeout) {
+        GlideString[] arguments =
+                concatenateArrays(
+                        new GlideString[] {gs(Double.toString(timeout)), gs(Long.toString(keys.length))},
+                        keys,
+                        new GlideString[] {gs(direction.toString())});
+        return commandManager.submitNewCommand(
+                BLMPop,
+                arguments,
+                response ->
+                        castBinaryStringMapOfArrays(
+                                handleBinaryStringMapOrNullResponse(response), GlideString.class));
+    }
+
     @Override
     public CompletableFuture lset(@NonNull String key, long index, @NonNull String element) {
         String[] arguments = new String[] {key, Long.toString(index), element};
@@ -3306,12 +3520,24 @@ public CompletableFuture spop(@NonNull String key) {
         return commandManager.submitNewCommand(SPop, arguments, this::handleStringOrNullResponse);
     }
 
+    @Override
+    public CompletableFuture spop(@NonNull GlideString key) {
+        GlideString[] arguments = new GlideString[] {key};
+        return commandManager.submitNewCommand(SPop, arguments, this::handleGlideStringOrNullResponse);
+    }
+
     @Override
     public CompletableFuture> spopCount(@NonNull String key, long count) {
         String[] arguments = new String[] {key, Long.toString(count)};
         return commandManager.submitNewCommand(SPop, arguments, this::handleSetResponse);
     }
 
+    @Override
+    public CompletableFuture> spopCount(@NonNull GlideString key, long count) {
+        GlideString[] arguments = new GlideString[] {key, gs(Long.toString(count))};
+        return commandManager.submitNewCommand(SPop, arguments, this::handleSetBinaryResponse);
+    }
+
     @Override
     public CompletableFuture bitfield(
             @NonNull String key, @NonNull BitFieldSubCommands[] subCommands) {
diff --git a/java/client/src/main/java/glide/api/commands/ListBaseCommands.java b/java/client/src/main/java/glide/api/commands/ListBaseCommands.java
index fc02355119..e0f314ae2c 100644
--- a/java/client/src/main/java/glide/api/commands/ListBaseCommands.java
+++ b/java/client/src/main/java/glide/api/commands/ListBaseCommands.java
@@ -80,6 +80,25 @@ public interface ListBaseCommands {
      */
     CompletableFuture lpop(String key);
 
+    /**
+     * Removes and returns the first elements of the list stored at key. The command pops
+     * a single element from the beginning of the list.
+     *
+     * @see redis.io for details.
+     * @param key The key of the list.
+     * @return The value of the first element.
+ * If key does not exist, null will be returned. + * @example + *
{@code
+     * GlideString value1 = client.lpop(gs("my_list")).get();
+     * assert value1.equals(gs("value1"));
+     *
+     * GlideString value2 = client.lpop(gs("non_exiting_key")).get();
+     * assert value2.equals(null);
+     * }
+ */ + CompletableFuture lpop(GlideString key); + /** * Returns the index of the first occurrence of element inside the list specified by * key. If no match is found, null is returned. @@ -294,6 +313,26 @@ CompletableFuture lposCount( */ CompletableFuture lpopCount(String key, long count); + /** + * Removes and returns up to count elements of the list stored at key, + * depending on the list's length. + * + * @see redis.io for details. + * @param key The key of the list. + * @param count The count of the elements to pop from the list. + * @return An array of the popped elements will be returned depending on the list's length.
+ * If key does not exist, null will be returned. + * @example + *
{@code
+     * GlideString[] values1 = client.lpopCount(gs("my_list"), 2).get();
+     * assert values1.equals(new GlideString[] {gs("value1"), gs("value2")});
+     *
+     * GlideString[] values2 = client.lpopCount(gs("non_exiting_key") , 7).get();
+     * assert values2.equals(null);
+     * }
+ */ + CompletableFuture lpopCount(GlideString key, long count); + /** * Returns the specified elements of the list stored at key.
* The offsets start and end are zero-based indexes, with 0 @@ -599,6 +638,25 @@ CompletableFuture lposCount( */ CompletableFuture rpop(String key); + /** + * Removes and returns the last elements of the list stored at key.
+ * The command pops a single element from the end of the list. + * + * @see redis.io for details. + * @param key The key of the list. + * @return The value of the last element.
+ * If key does not exist, null will be returned. + * @example + *
{@code
+     * GlideString value1 = client.rpop(gs("my_list")).get();
+     * assert value1.equals(gs("value1"));
+     *
+     * GlideString value2 = client.rpop(gs("non_exiting_key")).get();
+     * assert value2.equals(null);
+     * }
+ */ + CompletableFuture rpop(GlideString key); + /** * Removes and returns up to count elements from the list stored at key, * depending on the list's length. @@ -619,6 +677,26 @@ CompletableFuture lposCount( */ CompletableFuture rpopCount(String key, long count); + /** + * Removes and returns up to count elements from the list stored at key, + * depending on the list's length. + * + * @see redis.io for details. + * @param key The key of the list. + * @param count The count of the elements to pop from the list. + * @return An array of popped elements will be returned depending on the list's length.
+ * If key does not exist, null will be returned. + * @example + *
{@code
+     * GlideString[] values1 = client.rpopCount(gs("my_list"), 2).get();
+     * assert Arrays.equals(values1, new GlideString[] {gs("value1"), gs("value2")});
+     *
+     * GlideString[] values2 = client.rpopCount(gs("non_exiting_key"), 7).get();
+     * assert values2.equals(null);
+     * }
+ */ + CompletableFuture rpopCount(GlideString key, long count); + /** * Inserts element in the list at key either before or after the * pivot. @@ -693,6 +771,36 @@ CompletableFuture linsert( */ CompletableFuture blpop(String[] keys, double timeout); + /** + * Pops an element from the head of the first list that is non-empty, with the given keys + * being checked in the order that they are given.
+ * Blocks the connection when there are no elements to pop from any of the given lists. + * + * @apiNote + *
    + *
  • When in cluster mode, all keys must map to the same hash slot. + *
  • BLPOP is a client blocking command, see Blocking + * Commands for more details and best practices. + *
+ * + * @see redis.io for details. + * @param keys The keys of the lists to pop from. + * @param timeout The number of seconds to wait for a blocking operation to complete. A value of + * 0 will block indefinitely. + * @return A two-element array containing the key from which the element + * was popped and the value of the popped element, formatted as + * [key, value]. If no element could be popped and the timeout expired, returns + * null. + * @example + *
{@code
+     * GlideString[] response = client.blpop([gs("list1"), gs("list2")], 0.5).get();
+     * assert response[0].equals(gs("list1"));
+     * assert response[1].equals(gs("element"));
+     * }
+ */ + CompletableFuture blpop(GlideString[] keys, double timeout); + /** * Pops an element from the tail of the first list that is non-empty, with the given keys * being checked in the order that they are given.
@@ -723,6 +831,36 @@ CompletableFuture linsert( */ CompletableFuture brpop(String[] keys, double timeout); + /** + * Pops an element from the tail of the first list that is non-empty, with the given keys + * being checked in the order that they are given.
+ * Blocks the connection when there are no elements to pop from any of the given lists. + * + * @apiNote + *
    + *
  • When in cluster mode, all keys must map to the same hash slot. + *
  • BRPOP is a client blocking command, see Blocking + * Commands for more details and best practices. + *
+ * + * @see redis.io for details. + * @param keys The keys of the lists to pop from. + * @param timeout The number of seconds to wait for a blocking operation to complete. A value of + * 0 will block indefinitely. + * @return A two-element array containing the key from which the element + * was popped and the value of the popped element, formatted as + * [key, value]. If no element could be popped and the timeout expired, returns + * null. + * @example + *
{@code
+     * GlideString[] response = client.brpop([gs("list1"), gs("list2")], 0.5).get();
+     * assert response[0].equals(gs("list1"));
+     * assert response[1].equals(gs("element"));
+     * }
+ */ + CompletableFuture brpop(GlideString[] keys, double timeout); + /** * Inserts all the specified values at the tail of the list stored at key, only if * key exists and holds a list. If key is not a list, this performs no @@ -814,6 +952,29 @@ CompletableFuture linsert( CompletableFuture> lmpop( String[] keys, ListDirection direction, long count); + /** + * Pops one or more elements from the first non-empty list from the provided keys + * . + * + * @since Redis 7.0 and above. + * @apiNote When in cluster mode, all keys must map to the same hash slot. + * @see valkey.io for details. + * @param keys An array of keys to lists. + * @param direction The direction based on which elements are popped from - see {@link + * ListDirection}. + * @param count The maximum number of popped elements. + * @return A Map of key name mapped array of popped elements. + * @example + *
{@code
+     * client.lpush(gs("testKey"), new GlideString[] {gs("one"), gs("two"), gs("three")}).get();
+     * Map result = client.lmpop(new GlideString[] {gs("testKey")}, PopDirection.LEFT, 1L).get();
+     * GlideString[] resultValue = result.get(gs("testKey"));
+     * assertArrayEquals(new GlideString[] {gs("three")}, resultValue);
+     * }
+ */ + CompletableFuture> lmpop( + GlideString[] keys, ListDirection direction, long count); + /** * Pops one element from the first non-empty list from the provided keys. * @@ -834,6 +995,27 @@ CompletableFuture> lmpop( */ CompletableFuture> lmpop(String[] keys, ListDirection direction); + /** + * Pops one element from the first non-empty list from the provided keys. + * + * @since Redis 7.0 and above. + * @apiNote When in cluster mode, all keys must map to the same hash slot. + * @see valkey.io for details. + * @param keys An array of keys to lists. + * @param direction The direction based on which elements are popped from - see {@link + * ListDirection}. + * @return A Map of key name mapped array of the popped element. + * @example + *
{@code
+     * client.lpush(gs("testKey"), new GlideString[] {gs("one"), gs("two"), gs("three")}).get();
+     * Map result = client.lmpop(new GlideString[] {gs("testKey")}, PopDirection.LEFT).get();
+     * GlideString[] resultValue = result.get(gs("testKey"));
+     * assertArrayEquals(new GlideString[] {gs("three")}, resultValue);
+     * }
+ */ + CompletableFuture> lmpop( + GlideString[] keys, ListDirection direction); + /** * Blocks the connection until it pops one or more elements from the first non-empty list from the * provided keys BLMPOP is the blocking variant of {@link @@ -868,6 +1050,40 @@ CompletableFuture> lmpop( CompletableFuture> blmpop( String[] keys, ListDirection direction, long count, double timeout); + /** + * Blocks the connection until it pops one or more elements from the first non-empty list from the + * provided keys BLMPOP is the blocking variant of {@link + * #lmpop(String[], ListDirection, long)}. + * + * @apiNote + *
    + *
  1. When in cluster mode, all keys must map to the same hash slot. + *
  2. BLMPOP is a client blocking command, see Blocking + * Commands for more details and best practices. + *
+ * + * @since Redis 7.0 and above. + * @see valkey.io for details. + * @param keys An array of keys to lists. + * @param direction The direction based on which elements are popped from - see {@link + * ListDirection}. + * @param count The maximum number of popped elements. + * @param timeout The number of seconds to wait for a blocking operation to complete. A value of + * 0 will block indefinitely. + * @return A Map of key name mapped array of popped elements.
+ * If no member could be popped and the timeout expired, returns null. + * @example + *
{@code
+     * client.lpush(gs("testKey"), new GlideString[] {gs("one"), gs("two"), gs("three")}).get();
+     * Map result = client.blmpop(new GlideString[] {gs("testKey")}, PopDirection.LEFT, 1L, 0.1).get();
+     * GlideString[] resultValue = result.get(gs("testKey"));
+     * assertArrayEquals(new GlideString[] {gs("three")}, resultValue);
+     * }
+ */ + CompletableFuture> blmpop( + GlideString[] keys, ListDirection direction, long count, double timeout); + /** * Blocks the connection until it pops one element from the first non-empty list from the provided * keys BLMPOP is the blocking variant of {@link #lmpop(String[], @@ -901,6 +1117,39 @@ CompletableFuture> blmpop( CompletableFuture> blmpop( String[] keys, ListDirection direction, double timeout); + /** + * Blocks the connection until it pops one element from the first non-empty list from the provided + * keys BLMPOP is the blocking variant of {@link #lmpop(String[], + * ListDirection)}. + * + * @apiNote + *
    + *
  1. When in cluster mode, all keys must map to the same hash slot. + *
  2. BLMPOP is a client blocking command, see Blocking + * Commands for more details and best practices. + *
+ * + * @since Redis 7.0 and above. + * @see valkey.io for details. + * @param keys An array of keys to lists. + * @param direction The direction based on which elements are popped from - see {@link + * ListDirection}. + * @param timeout The number of seconds to wait for a blocking operation to complete. A value of + * 0 will block indefinitely. + * @return A Map of key name mapped array of the popped element.
+ * If no member could be popped and the timeout expired, returns null. + * @example + *
{@code
+     * client.lpush(gs("testKey"), new GlideString[] {gs("one"), gs("two"), gs("three")}).get();
+     * Map result = client.blmpop(new GlideString[] {gs("testKey")}, PopDirection.LEFT, 0.1).get();
+     * GlideString[] resultValue = result.get(gs("testKey"));
+     * assertArrayEquals(new GlideString[] {gs("three")}, resultValue);
+     * }
+ */ + CompletableFuture> blmpop( + GlideString[] keys, ListDirection direction, double timeout); + /** * Sets the list element at index to element.
* The index is zero-based, so 0 means the first element, 1 the second diff --git a/java/client/src/main/java/glide/api/commands/SetBaseCommands.java b/java/client/src/main/java/glide/api/commands/SetBaseCommands.java index 1e560d0ff5..ccebdfb0e5 100644 --- a/java/client/src/main/java/glide/api/commands/SetBaseCommands.java +++ b/java/client/src/main/java/glide/api/commands/SetBaseCommands.java @@ -617,6 +617,24 @@ public interface SetBaseCommands { */ CompletableFuture spop(String key); + /** + * Removes and returns one random member from the set stored at key. + * + * @see redis.io for details. + * @param key The key of the set. + * @return The value of the popped member.
+ * If key does not exist, null will be returned. + * @example + *
{@code
+     * GlideString value1 = client.spop(gs("mySet")).get();
+     * assert value1.equals(gs("value1"));
+     *
+     * GlideString value2 = client.spop(gs("nonExistingSet")).get();
+     * assert value2.equals(null);
+     * }
+ */ + CompletableFuture spop(GlideString key); + /** * Removes and returns up to count random members from the set stored at key * , depending on the set's length. @@ -637,6 +655,26 @@ public interface SetBaseCommands { */ CompletableFuture> spopCount(String key, long count); + /** + * Removes and returns up to count random members from the set stored at key + * , depending on the set's length. + * + * @see redis.io for details. + * @param key The key of the set. + * @param count The count of the elements to pop from the set. + * @return A set of popped elements will be returned depending on the set's length.
+ * If key does not exist, an empty Set will be returned. + * @example + *
{@code
+     * Set values1 = client.spopCount(gs("mySet"), 2).get();
+     * assert values1.equals(new GlideString[] {gs("value1"), gs("value2")});
+     *
+     * Set values2 = client.spopCount(gs("nonExistingSet"), 2).get();
+     * assert values2.size() == 0;
+     * }
+ */ + CompletableFuture> spopCount(GlideString key, long count); + /** * Gets the union of all the given sets. * diff --git a/java/client/src/main/java/glide/api/commands/SortedSetBaseCommands.java b/java/client/src/main/java/glide/api/commands/SortedSetBaseCommands.java index 48965c555d..e673e2ce77 100644 --- a/java/client/src/main/java/glide/api/commands/SortedSetBaseCommands.java +++ b/java/client/src/main/java/glide/api/commands/SortedSetBaseCommands.java @@ -277,11 +277,32 @@ CompletableFuture zaddIncr( * @example *
{@code
      * Map payload = client.zpopmax("mySortedSet", 2).get();
-     * assert payload.equals(Map.of('member3', 7.5 , 'member2', 8.0)); // Indicates that 'member3' with a score of 7.5 and 'member2' with a score of 8.0 have been removed from the sorted set.
+     * assert payload.equals(Map.of("member3", 7.5 , "member2", 8.0)); // Indicates that "member3" with a score of 7.5 and "member2" with a score of 8.0 have been removed from the sorted set.
      * }
*/ CompletableFuture> zpopmin(String key, long count); + /** + * Removes and returns up to count members with the lowest scores from the sorted set + * stored at the specified key. + * + * @see redis.io for more details. + * @param key The key of the sorted set. + * @param count Specifies the quantity of members to pop.
+ * If count is higher than the sorted set's cardinality, returns all members and + * their scores, ordered from lowest to highest. + * @return A map of the removed members and their scores, ordered from the one with the lowest + * score to the one with the highest.
+ * If key doesn't exist, it will be treated as an empty sorted set and the + * command returns an empty Map. + * @example + *
{@code
+     * Map payload = client.zpopmax(gs("mySortedSet"), 2).get();
+     * assert payload.equals(Map.of(gs("member3"), 7.5, gs("member2"), 8.0)); // Indicates that gs("member3") with a score of 7.5 and gs("member2") with a score of 8.0 have been removed from the sorted set.
+     * }
+ */ + CompletableFuture> zpopmin(GlideString key, long count); + /** * Removes and returns the member with the lowest score from the sorted set stored at the * specified key. @@ -294,11 +315,28 @@ CompletableFuture zaddIncr( * @example *
{@code
      * Map payload = client.zpopmin("mySortedSet").get();
-     * assert payload.equals(Map.of('member1', 5.0)); // Indicates that 'member1' with a score of 5.0 has been removed from the sorted set.
+     * assert payload.equals(Map.of("member1", 5.0)); // Indicates that "member1" with a score of 5.0 has been removed from the sorted set.
      * }
*/ CompletableFuture> zpopmin(String key); + /** + * Removes and returns the member with the lowest score from the sorted set stored at the + * specified key. + * + * @see redis.io for more details. + * @param key The key of the sorted set. + * @return A map containing the removed member and its corresponding score.
+ * If key doesn't exist, it will be treated as an empty sorted set and the + * command returns an empty Map. + * @example + *
{@code
+     * Map payload = client.zpopmin(gs("mySortedSet")).get();
+     * assert payload.equals(Map.of(gs("member1"), 5.0)); // Indicates that gs("member1") with a score of 5.0 has been removed from the sorted set.
+     * }
+ */ + CompletableFuture> zpopmin(GlideString key); + /** * Blocks the connection until it removes and returns a member with the lowest score from the * first non-empty sorted set, with the given keys being checked in the order they @@ -329,6 +367,36 @@ CompletableFuture zaddIncr( */ CompletableFuture bzpopmin(String[] keys, double timeout); + /** + * Blocks the connection until it removes and returns a member with the lowest score from the + * first non-empty sorted set, with the given keys being checked in the order they + * are provided.
+ * BZPOPMIN is the blocking variant of {@link #zpopmin(String)}.
+ * + * @apiNote + *
    + *
  • When in cluster mode, all keys must map to the same hash slot. + *
  • BZPOPMIN is a client blocking command, see Blocking + * Commands for more details and best practices. + *
+ * + * @see redis.io for more details. + * @param keys The keys of the sorted sets. + * @param timeout The number of seconds to wait for a blocking operation to complete. A value of + * 0 will block indefinitely. + * @return An array containing the key where the member was popped out, the member + * itself, and the member score.
+ * If no member could be popped and the timeout expired, returns null + * . + * @example + *
{@code
+     * Object[] data = client.bzpopmin(new GlideString[] {gs("zset1"), gs("zset2")}, 0.5).get();
+     * System.out.printf("Popped '%s' with score %d from sorted set '%s'%n", data[1], data[2], data[0]);
+     * }
+ */ + CompletableFuture bzpopmin(GlideString[] keys, double timeout); + /** * Removes and returns up to count members with the highest scores from the sorted * set stored at the specified key. @@ -345,11 +413,32 @@ CompletableFuture zaddIncr( * @example *
{@code
      * Map payload = client.zpopmax("mySortedSet", 2).get();
-     * assert payload.equals(Map.of('member2', 8.0, 'member3', 7.5)); // Indicates that 'member2' with a score of 8.0 and 'member3' with a score of 7.5 have been removed from the sorted set.
+     * assert payload.equals(Map.of("member2", 8.0, "member3", 7.5)); // Indicates that "member2" with a score of 8.0 and "member3" with a score of 7.5 have been removed from the sorted set.
      * }
*/ CompletableFuture> zpopmax(String key, long count); + /** + * Removes and returns up to count members with the highest scores from the sorted + * set stored at the specified key. + * + * @see redis.io for more details. + * @param key The key of the sorted set. + * @param count Specifies the quantity of members to pop.
+ * If count is higher than the sorted set's cardinality, returns all members and + * their scores, ordered from highest to lowest. + * @return A map of the removed members and their scores, ordered from the one with the highest + * score to the one with the lowest.
+ * If key doesn't exist, it will be treated as an empty sorted set and the + * command returns an empty Map. + * @example + *
{@code
+     * Map payload = client.zpopmax(gs("mySortedSet"), 2).get();
+     * assert payload.equals(Map.of(gs("member2"), 8.0, gs("member3"), 7.5)); // Indicates that gs("member2") with a score of 8.0 and gs("member3") with a score of 7.5 have been removed from the sorted set.
+     * }
+ */ + CompletableFuture> zpopmax(GlideString key, long count); + /** * Removes and returns the member with the highest score from the sorted set stored at the * specified key. @@ -362,11 +451,28 @@ CompletableFuture zaddIncr( * @example *
{@code
      * Map payload = client.zpopmax("mySortedSet").get();
-     * assert payload.equals(Map.of('member1', 10.0)); // Indicates that 'member1' with a score of 10.0 has been removed from the sorted set.
+     * assert payload.equals(Map.of("member1", 10.0)); // Indicates that "member1" with a score of 10.0 has been removed from the sorted set.
      * }
*/ CompletableFuture> zpopmax(String key); + /** + * Removes and returns the member with the highest score from the sorted set stored at the + * specified key. + * + * @see redis.io for more details. + * @param key The key of the sorted set. + * @return A map containing the removed member and its corresponding score.
+ * If key doesn't exist, it will be treated as an empty sorted set and the + * command returns an empty Map. + * @example + *
{@code
+     * Map payload = client.zpopmax(gs("mySortedSet")).get();
+     * assert payload.equals(Map.of(gs("member1"), 10.0)); // Indicates that gs("member1") with a score of 10.0 has been removed from the sorted set.
+     * }
+ */ + CompletableFuture> zpopmax(GlideString key); + /** * Blocks the connection until it removes and returns a member with the highest score from the * first non-empty sorted set, with the given keys being checked in the order they @@ -397,6 +503,36 @@ CompletableFuture zaddIncr( */ CompletableFuture bzpopmax(String[] keys, double timeout); + /** + * Blocks the connection until it removes and returns a member with the highest score from the + * first non-empty sorted set, with the given keys being checked in the order they + * are provided.
+ * BZPOPMAX is the blocking variant of {@link #zpopmax(String)}.
+ * + * @apiNote + *
    + *
  • When in cluster mode, all keys must map to the same hash slot. + *
  • BZPOPMAX is a client blocking command, see Blocking + * Commands for more details and best practices. + *
+ * + * @see redis.io for more details. + * @param keys The keys of the sorted sets. + * @param timeout The number of seconds to wait for a blocking operation to complete. A value of + * 0 will block indefinitely. + * @return An array containing the key where the member was popped out, the member + * itself, and the member score.
+ * If no member could be popped and the timeout expired, returns null + * . + * @example + *
{@code
+     * Object[] data = client.bzpopmax(new GlideString[] {gs("zset1"), gs("zset2")}, 0.5).get();
+     * System.out.printf("Popped '%s' with score %d from sorted set '%s'%n", data[1], data[2], data[0]);
+     * }
+ */ + CompletableFuture bzpopmax(GlideString[] keys, double timeout); + /** * Returns the score of member in the sorted set stored at key. * @@ -460,11 +596,11 @@ CompletableFuture zaddIncr( *
{@code
      * RangeByScore query1 = new RangeByScore(new ScoreBoundary(10), new ScoreBoundary(20));
      * String[] payload1 = client.zrange("mySortedSet", query1, true).get(); // Returns members with scores between 10 and 20.
-     * assert payload1.equals(new String[] {'member3', 'member2', 'member1'}); // Returns all members in descending order.
+     * assert payload1.equals(new String[] {"member3", "member2", "member1"}); // Returns all members in descending order.
      *
      * RangeByScore query2 = new RangeByScore(InfScoreBound.NEGATIVE_INFINITY, new ScoreBoundary(3));
      * String[] payload2 = client.zrange("mySortedSet", query2, false).get();
-     * assert payload2.equals(new String[] {'member2', 'member3'}); // Returns members with scores within the range of negative infinity to 3, in ascending order.
+     * assert payload2.equals(new String[] {"member2", "member3"}); // Returns members with scores within the range of negative infinity to 3, in ascending order.
      * }
*/ CompletableFuture zrange(String key, RangeQuery rangeQuery, boolean reverse); @@ -490,11 +626,11 @@ CompletableFuture zaddIncr( *
{@code
      * RangeByIndex query1 = new RangeByIndex(0, -1);
      * String[] payload1 = client.zrange("mySortedSet",query1).get();
-     * assert payload1.equals(new String[] {'member1', 'member2', 'member3'}); // Returns all members in ascending order.
+     * assert payload1.equals(new String[] {"member1", "member2", "member3"}); // Returns all members in ascending order.
      *
      * RangeByScore query2 = new RangeByScore(InfScoreBound.NEGATIVE_INFINITY, new ScoreBoundary(3));
      * String[] payload2 = client.zrange("mySortedSet", query2).get();
-     * assert payload2.equals(new String[] {'member2', 'member3'}); // Returns members with scores within the range of negative infinity to 3, in ascending order.
+     * assert payload2.equals(new String[] {"member2", "member3"}); // Returns members with scores within the range of negative infinity to 3, in ascending order.
      * }
*/ CompletableFuture zrange(String key, RangeQuery rangeQuery); @@ -520,11 +656,11 @@ CompletableFuture zaddIncr( *
{@code
      * RangeByScore query1 = new RangeByScore(new ScoreBoundary(10), new ScoreBoundary(20));
      * Map payload1 = client.zrangeWithScores("mySortedSet", query1, true).get();
-     * assert payload1.equals(Map.of('member2', 15.2, 'member1', 10.5)); // Returns members with scores between 10 and 20 (inclusive) with their scores.
+     * assert payload1.equals(Map.of("member2", 15.2, "member1", 10.5)); // Returns members with scores between 10 and 20 (inclusive) with their scores.
      *
      * RangeByScore query2 = new RangeByScore(InfScoreBound.NEGATIVE_INFINITY, new ScoreBoundary(3));
      * Map payload2 = client.zrangeWithScores("mySortedSet", query2, false).get();
-     * assert payload2.equals(Map.of('member4', -2.0, 'member7', 1.5)); // Returns members with with scores within the range of negative infinity to 3, with their scores.
+     * assert payload2.equals(Map.of("member4", -2.0, "member7", 1.5)); // Returns members with with scores within the range of negative infinity to 3, with their scores.
      * }
*/ CompletableFuture> zrangeWithScores( @@ -549,11 +685,11 @@ CompletableFuture> zrangeWithScores( *
{@code
      * RangeByScore query1 = new RangeByScore(new ScoreBoundary(10), new ScoreBoundary(20));
      * Map payload1 = client.zrangeWithScores("mySortedSet", query1).get();
-     * assert payload1.equals(Map.of('member1', 10.5, 'member2', 15.2)); // Returns members with scores between 10 and 20 (inclusive) with their scores.
+     * assert payload1.equals(Map.of("member1", 10.5, "member2", 15.2)); // Returns members with scores between 10 and 20 (inclusive) with their scores.
      *
      * RangeByScore query2 = new RangeByScore(InfScoreBound.NEGATIVE_INFINITY, new ScoreBoundary(3));
      * Map payload2 = client.zrangeWithScores("mySortedSet", query2).get();
-     * assert payload2.equals(Map.of('member4', -2.0, 'member7', 1.5)); // Returns members with with scores within the range of negative infinity to 3, with their scores.
+     * assert payload2.equals(Map.of("member4", -2.0, "member7", 1.5)); // Returns members with with scores within the range of negative infinity to 3, with their scores.
      * }
*/ CompletableFuture> zrangeWithScores(String key, ScoredRangeQuery rangeQuery); @@ -1141,6 +1277,29 @@ CompletableFuture zinterstore( */ CompletableFuture zmpop(String[] keys, ScoreFilter modifier); + /** + * Pops a member-score pair from the first non-empty sorted set, with the given keys + * being checked in the order they are provided. + * + * @apiNote When in cluster mode, all keys must map to the same hash slot. + * @since Redis 7.0 and above. + * @see redis.io for more details. + * @param keys The keys of the sorted sets. + * @param modifier The element pop criteria - either {@link ScoreFilter#MIN} or {@link + * ScoreFilter#MAX} to pop the member with the lowest/highest score accordingly. + * @return A two-element array containing the key name of the set from which the + * element was popped, and a member-score Map of the popped element.
+ * If no member could be popped, returns null. + * @example + *
{@code
+     * Object[] result = client.zmpop(new GlideString[] { gs("zSet1"), gs("zSet2") }, MAX).get();
+     * Map data = (Map)result[1];
+     * GlideString element = data.keySet().toArray(GlideString[]::new)[0];
+     * System.out.printf("Popped '%s' with score %d from '%s'%n", element, data.get(element), result[0]);
+     * }
+ */ + CompletableFuture zmpop(GlideString[] keys, ScoreFilter modifier); + /** * Pops multiple member-score pairs from the first non-empty sorted set, with the given keys * being checked in the order they are provided. @@ -1166,6 +1325,31 @@ CompletableFuture zinterstore( */ CompletableFuture zmpop(String[] keys, ScoreFilter modifier, long count); + /** + * Pops multiple member-score pairs from the first non-empty sorted set, with the given keys + * being checked in the order they are provided. + * + * @apiNote When in cluster mode, all keys must map to the same hash slot. + * @since Redis 7.0 and above. + * @see redis.io for more details. + * @param keys The keys of the sorted sets. + * @param modifier The element pop criteria - either {@link ScoreFilter#MIN} or {@link + * ScoreFilter#MAX} to pop members with the lowest/highest scores accordingly. + * @param count The number of elements to pop. + * @return A two-element array containing the key name of the set from which elements + * were popped, and a member-score Map of the popped elements.
+ * If no member could be popped, returns null. + * @example + *
{@code
+     * Object[] result = client.zmpop(new GlideString[] { gs("zSet1"), gs("zSet2") }, MAX, 2).get();
+     * Map data = (Map)result[1];
+     * for (Map.Entry entry : data.entrySet()) {
+     *     System.out.printf("Popped '%s' with score %d from '%s'%n", entry.getKey(), entry.getValue(), result[0]);
+     * }
+     * }
+ */ + CompletableFuture zmpop(GlideString[] keys, ScoreFilter modifier, long count); + /** * Blocks the connection until it pops and returns a member-score pair from the first non-empty * sorted set, with the given keys being checked in the order they are provided.
@@ -1199,6 +1383,39 @@ CompletableFuture zinterstore( */ CompletableFuture bzmpop(String[] keys, ScoreFilter modifier, double timeout); + /** + * Blocks the connection until it pops and returns a member-score pair from the first non-empty + * sorted set, with the given keys being checked in the order they are provided.
+ * BZMPOP is the blocking variant of {@link #zmpop(String[], ScoreFilter)}. + * + * @apiNote + *
    + *
  1. When in cluster mode, all keys must map to the same hash slot. + *
  2. BZMPOP is a client blocking command, see Blocking + * Commands for more details and best practices. + *
+ * + * @since Redis 7.0 and above. + * @see redis.io for more details. + * @param keys The keys of the sorted sets. + * @param modifier The element pop criteria - either {@link ScoreFilter#MIN} or {@link + * ScoreFilter#MAX} to pop members with the lowest/highest scores accordingly. + * @param timeout The number of seconds to wait for a blocking operation to complete. A value of + * 0 will block indefinitely. + * @return A two-element array containing the key name of the set from which an + * element was popped, and a member-score Map of the popped elements.
+ * If no member could be popped and the timeout expired, returns null. + * @example + *
{@code
+     * Object[] result = client.bzmpop(new GlideString[] { gs("zSet1"), gs("zSet2") }, MAX, 0.1).get();
+     * Map data = (Map)result[1];
+     * GlideString element = data.keySet().toArray(GlideString[]::new)[0];
+     * System.out.printf("Popped '%s' with score %d from '%s'%n", element, data.get(element), result[0]);
+     * }
+ */ + CompletableFuture bzmpop(GlideString[] keys, ScoreFilter modifier, double timeout); + /** * Blocks the connection until it pops and returns multiple member-score pairs from the first * non-empty sorted set, with the given keys being checked in the order they are @@ -1236,6 +1453,43 @@ CompletableFuture zinterstore( CompletableFuture bzmpop( String[] keys, ScoreFilter modifier, double timeout, long count); + /** + * Blocks the connection until it pops and returns multiple member-score pairs from the first + * non-empty sorted set, with the given keys being checked in the order they are + * provided.
+ * BZMPOP is the blocking variant of {@link #zmpop(String[], ScoreFilter, long)}. + * + * @apiNote + *
    + *
  1. When in cluster mode, all keys must map to the same hash slot. + *
  2. BZMPOP is a client blocking command, see Blocking + * Commands for more details and best practices. + *
+ * + * @since Redis 7.0 and above. + * @see redis.io for more details. + * @param keys The keys of the sorted sets. + * @param modifier The element pop criteria - either {@link ScoreFilter#MIN} or {@link + * ScoreFilter#MAX} to pop members with the lowest/highest scores accordingly. + * @param timeout The number of seconds to wait for a blocking operation to complete. A value of + * 0 will block indefinitely. + * @param count The number of elements to pop. + * @return A two-element array containing the key name of the set from which elements + * were popped, and a member-score Map of the popped elements.
+ * If no members could be popped and the timeout expired, returns null. + * @example + *
{@code
+     * Object[] result = client.bzmpop(new GlideString[] { gs("zSet1"), gs("zSet2") }, MAX, 0.1, 2).get();
+     * Map data = (Map)result[1];
+     * for (Map.Entry entry : data.entrySet()) {
+     *     System.out.printf("Popped '%s' with score %d from '%s'%n", entry.getKey(), entry.getValue(), result[0]);
+     * }
+     * }
+ */ + CompletableFuture bzmpop( + GlideString[] keys, ScoreFilter modifier, double timeout, long count); + /** * Returns the union of members from sorted sets specified by the given keys.
* To get the elements with their scores, see {@link #zunionWithScores}. diff --git a/java/client/src/main/java/glide/utils/ArrayTransformUtils.java b/java/client/src/main/java/glide/utils/ArrayTransformUtils.java index 85431a86b6..bdb7819640 100644 --- a/java/client/src/main/java/glide/utils/ArrayTransformUtils.java +++ b/java/client/src/main/java/glide/utils/ArrayTransformUtils.java @@ -171,6 +171,23 @@ public static Map castMapOfArrays( .collect(Collectors.toMap(Map.Entry::getKey, e -> castArray(e.getValue(), clazz))); } + /** + * Maps a Map of Arrays with value type T[] to value of U[]. + * + * @param mapOfArrays Map of Array values to cast. + * @param clazz The class of the array values to cast to. + * @return A Map of arrays of type U[], containing the key/values from the input Map. + * @param The target type which the elements are cast. + */ + public static Map castBinaryStringMapOfArrays( + Map mapOfArrays, Class clazz) { + if (mapOfArrays == null) { + return null; + } + return mapOfArrays.entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> castArray(e.getValue(), clazz))); + } + /** * Maps a Map of Object[][] with value type T[][] to value of U[][]. * diff --git a/java/client/src/test/java/glide/api/RedisClientTest.java b/java/client/src/test/java/glide/api/RedisClientTest.java index 35a7601ffc..758e11c6cd 100644 --- a/java/client/src/test/java/glide/api/RedisClientTest.java +++ b/java/client/src/test/java/glide/api/RedisClientTest.java @@ -2878,6 +2878,30 @@ public void lpop_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void lpop_binary_returns_success() { + // setup + GlideString key = gs("testKey"); + GlideString[] args = new GlideString[] {key}; + GlideString value = gs("value"); + + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(LPop), eq(args), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.lpop(key); + GlideString payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void lpopCount_returns_success() { @@ -2903,6 +2927,31 @@ public void lpopCount_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void lpopCount_binary_returns_success() { + // setup + GlideString key = gs("testKey"); + long count = 2L; + GlideString[] args = new GlideString[] {key, gs(Long.toString(count))}; + GlideString[] value = new GlideString[] {gs("value1"), gs("value2")}; + + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(LPop), eq(args), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.lpopCount(key, count); + GlideString[] payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void lpos() { @@ -3399,6 +3448,30 @@ public void rpop_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void rpop_binary_returns_success() { + // setup + GlideString key = gs("testKey"); + GlideString value = gs("value"); + GlideString[] args = new GlideString[] {key}; + + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(RPop), eq(args), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.rpop(key); + GlideString payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void rpopCount_returns_success() { @@ -3424,6 +3497,31 @@ public void rpopCount_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void rpopCount_binary_returns_success() { + // setup + GlideString key = gs("testKey"); + long count = 2L; + GlideString[] args = new GlideString[] {key, gs(Long.toString(count))}; + GlideString[] value = new GlideString[] {gs("value1"), gs("value2")}; + + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(RPop), eq(args), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.rpopCount(key, count); + GlideString[] payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void sadd_returns_success() { @@ -4152,6 +4250,31 @@ public void zmpop_returns_success() { assertArrayEquals(value, payload); } + @SneakyThrows + @Test + public void zmpop_binary_returns_success() { + // setup + GlideString[] keys = new GlideString[] {gs("key1"), gs("key2")}; + ScoreFilter modifier = MAX; + GlideString[] arguments = {gs("2"), gs("key1"), gs("key2"), gs("MAX")}; + Object[] value = new Object[] {"key1", "elem"}; + + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(ZMPop), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.zmpop(keys, modifier); + Object[] payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertArrayEquals(value, payload); + } + @SneakyThrows @Test public void zmpop_with_count_returns_success() { @@ -4178,6 +4301,32 @@ public void zmpop_with_count_returns_success() { assertArrayEquals(value, payload); } + @SneakyThrows + @Test + public void zmpop_binary_with_count_returns_success() { + // setup + GlideString[] keys = new GlideString[] {gs("key1"), gs("key2")}; + ScoreFilter modifier = MAX; + long count = 42; + GlideString[] arguments = {gs("2"), gs("key1"), gs("key2"), gs("MAX"), gs("COUNT"), gs("42")}; + Object[] value = new Object[] {"key1", "elem"}; + + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(ZMPop), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.zmpop(keys, modifier, count); + Object[] payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertArrayEquals(value, payload); + } + @SneakyThrows @Test public void bzmpop_returns_success() { @@ -4204,6 +4353,32 @@ public void bzmpop_returns_success() { assertArrayEquals(value, payload); } + @SneakyThrows + @Test + public void bzmpop_binary_returns_success() { + // setup + double timeout = .5; + GlideString[] keys = new GlideString[] {gs("key1"), gs("key2")}; + ScoreFilter modifier = MAX; + GlideString[] arguments = {gs("0.5"), gs("2"), gs("key1"), gs("key2"), gs("MAX")}; + Object[] value = new Object[] {"key1", "elem"}; + + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(BZMPop), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.bzmpop(keys, modifier, timeout); + Object[] payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertArrayEquals(value, payload); + } + @SneakyThrows @Test public void bzmpop_with_count_returns_success() { @@ -4231,6 +4406,35 @@ public void bzmpop_with_count_returns_success() { assertArrayEquals(value, payload); } + @SneakyThrows + @Test + public void bzmpop_binary_with_count_returns_success() { + // setup + double timeout = .5; + GlideString[] keys = new GlideString[] {gs("key1"), gs("key2")}; + ScoreFilter modifier = MAX; + long count = 42; + GlideString[] arguments = { + gs("0.5"), gs("2"), gs("key1"), gs("key2"), gs("MAX"), gs("COUNT"), gs("42") + }; + Object[] value = new Object[] {"key1", "elem"}; + + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(BZMPop), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.bzmpop(keys, modifier, timeout, count); + Object[] payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertArrayEquals(value, payload); + } + @SneakyThrows @Test public void clientId_returns_success() { @@ -4473,6 +4677,31 @@ public void zpopmin_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void zpopmin_binary_returns_success() { + // setup + GlideString key = gs("testKey"); + GlideString[] arguments = new GlideString[] {key}; + Map value = Map.of(gs("member1"), 2.5); + + CompletableFuture> testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.>submitNewCommand( + eq(ZPopMin), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture> response = service.zpopmin(key); + Map payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void zpopmin_with_count_returns_success() { @@ -4498,6 +4727,32 @@ public void zpopmin_with_count_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void zpopmin_with_count_binary_returns_success() { + // setup + GlideString key = gs("testKey"); + long count = 2L; + GlideString[] arguments = new GlideString[] {key, gs(Long.toString(count))}; + Map value = Map.of(gs("member1"), 2.0, gs("member2"), 3.0); + + CompletableFuture> testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.>submitNewCommand( + eq(ZPopMin), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture> response = service.zpopmin(key, count); + Map payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void bzpopmin_returns_success() { @@ -4523,6 +4778,31 @@ public void bzpopmin_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void bzpopmin_binary_returns_success() { + // setup + GlideString[] keys = new GlideString[] {gs("key1"), gs("key2")}; + double timeout = .5; + GlideString[] arguments = new GlideString[] {gs("key1"), gs("key2"), gs("0.5")}; + Object[] value = new Object[] {"key1", "elem", 42.}; + + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(BZPopMin), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.bzpopmin(keys, timeout); + Object[] payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void zpopmax_returns_success() { @@ -4547,6 +4827,31 @@ public void zpopmax_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void zpopmax_binary_returns_success() { + // setup + GlideString key = gs("testKey"); + GlideString[] arguments = new GlideString[] {key}; + Map value = Map.of(gs("member1"), 2.5); + + CompletableFuture> testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.>submitNewCommand( + eq(ZPopMax), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture> response = service.zpopmax(key); + Map payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void bzpopmax_returns_success() { @@ -4572,6 +4877,31 @@ public void bzpopmax_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void bzpopmax_binary_returns_success() { + // setup + GlideString[] keys = new GlideString[] {gs("key1"), gs("key2")}; + double timeout = .5; + GlideString[] arguments = new GlideString[] {gs("key1"), gs("key2"), gs("0.5")}; + Object[] value = new Object[] {"key1", "elem", 42.}; + + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(BZPopMax), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.bzpopmax(keys, timeout); + Object[] payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void zpopmax_with_count_returns_success() { @@ -4597,6 +4927,32 @@ public void zpopmax_with_count_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void zpopmax_with_count_binary_returns_success() { + // setup + GlideString key = gs("testKey"); + long count = 2L; + GlideString[] arguments = new GlideString[] {key, gs(Long.toString(count))}; + Map value = Map.of(gs("member1"), 3.0, gs("member2"), 1.0); + + CompletableFuture> testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.>submitNewCommand( + eq(ZPopMax), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture> response = service.zpopmax(key, count); + Map payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void zscore_returns_success() { @@ -7887,6 +8243,31 @@ public void blpop_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void blpop_binary_returns_success() { + // setup + GlideString key = gs("key"); + double timeout = 0.5; + GlideString[] arguments = new GlideString[] {key, gs("0.5")}; + GlideString[] value = new GlideString[] {gs("key"), gs("value")}; + + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(BLPop), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.blpop(new GlideString[] {key}, timeout); + GlideString[] payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void rpushx_returns_success() { @@ -8012,6 +8393,31 @@ public void brpop_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void brpop_binary_returns_success() { + // setup + GlideString key = gs("key"); + double timeout = 0.5; + GlideString[] arguments = new GlideString[] {key, gs("0.5")}; + GlideString[] value = new GlideString[] {gs("key"), gs("value")}; + + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(BRPop), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.brpop(new GlideString[] {key}, timeout); + GlideString[] payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void pfadd_returns_success() { @@ -9487,6 +9893,39 @@ public void blmpop_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void blmpop_binary_returns_success() { + // setup + GlideString key = gs("testKey"); + GlideString key2 = gs("testKey2"); + GlideString[] keys = {key, key2}; + ListDirection listDirection = ListDirection.LEFT; + double timeout = 0.1; + GlideString[] arguments = + new GlideString[] { + gs(Double.toString(timeout)), gs("2"), key, key2, gs(listDirection.toString()) + }; + Map value = Map.of(key, new GlideString[] {gs("five")}); + + CompletableFuture> testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.>submitNewCommand( + eq(BLMPop), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture> response = + service.blmpop(keys, listDirection, timeout); + Map payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void blmpop_with_count_returns_success() { @@ -9526,6 +9965,46 @@ public void blmpop_with_count_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void blmpop_with_count_binary_returns_success() { + // setup + GlideString key = gs("testKey"); + GlideString key2 = gs("testKey2"); + GlideString[] keys = {key, key2}; + ListDirection listDirection = ListDirection.LEFT; + long count = 1L; + double timeout = 0.1; + GlideString[] arguments = + new GlideString[] { + gs(Double.toString(timeout)), + gs("2"), + key, + key2, + gs(listDirection.toString()), + gs(COUNT_FOR_LIST_REDIS_API), + gs(Long.toString(count)) + }; + Map value = Map.of(key, new GlideString[] {gs("five")}); + + CompletableFuture> testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.>submitNewCommand( + eq(BLMPop), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture> response = + service.blmpop(keys, listDirection, count, timeout); + Map payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void getbit_returns_success() { @@ -9791,6 +10270,35 @@ public void lmpop_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void lmpop_binary_returns_success() { + // setup + GlideString key = gs("testKey"); + GlideString key2 = gs("testKey2"); + GlideString[] keys = {key, key2}; + ListDirection listDirection = ListDirection.LEFT; + GlideString[] arguments = new GlideString[] {gs("2"), key, key2, gs(listDirection.toString())}; + Map value = Map.of(key, new GlideString[] {gs("five")}); + + CompletableFuture> testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.>submitNewCommand( + eq(LMPop), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture> response = + service.lmpop(keys, listDirection); + Map payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void lmpop_with_count_returns_success() { @@ -9822,6 +10330,44 @@ public void lmpop_with_count_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void lmpop_with_count_binary_returns_success() { + // setup + GlideString key = gs("testKey"); + GlideString key2 = gs("testKey2"); + GlideString[] keys = {key, key2}; + ListDirection listDirection = ListDirection.LEFT; + long count = 1L; + GlideString[] arguments = + new GlideString[] { + gs("2"), + key, + key2, + gs(listDirection.toString()), + gs(COUNT_FOR_LIST_REDIS_API), + gs(Long.toString(count)) + }; + Map value = Map.of(key, new GlideString[] {gs("five")}); + + CompletableFuture> testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.>submitNewCommand( + eq(LMPop), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture> response = + service.lmpop(keys, listDirection, count); + Map payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void lmove_returns_success() { @@ -10203,6 +10749,30 @@ public void spop_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void spop_binary_returns_success() { + // setup + GlideString key = gs("testKey"); + GlideString[] arguments = new GlideString[] {key}; + GlideString value = gs("value"); + + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(SPop), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.spop(key); + GlideString payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void spopCount_returns_success() { @@ -10228,6 +10798,31 @@ public void spopCount_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void spopCount_binary_returns_success() { + // setup + GlideString key = gs("testKey"); + long count = 2; + GlideString[] arguments = new GlideString[] {key, gs(Long.toString(count))}; + Set value = Set.of(gs("one"), gs("two")); + + CompletableFuture> testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.>submitNewCommand(eq(SPop), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture> response = service.spopCount(key, count); + Set payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void bitfieldReadOnly_returns_success() { diff --git a/java/integTest/src/test/java/glide/SharedCommandTests.java b/java/integTest/src/test/java/glide/SharedCommandTests.java index b612a97201..30c731bb5d 100644 --- a/java/integTest/src/test/java/glide/SharedCommandTests.java +++ b/java/integTest/src/test/java/glide/SharedCommandTests.java @@ -1502,6 +1502,26 @@ public void lpush_lpop_lrange_existing_non_existing_key(BaseClient client) { assertNull(client.lpop("non_existing_key").get()); } + // TODO: uncomment once client.lrange has binary version + // @SneakyThrows + // @ParameterizedTest(autoCloseArguments = false) + // @MethodSource("getClients") + // public void lpush_lpop_lrange_binary_existing_non_existing_key(BaseClient client) { + // GlideString key = gs(UUID.randomUUID().toString()); + // GlideString[] valueArray = new GlideString[] {gs("value4"), gs("value3"), gs("value2"), + // gs("value1")}; + + // assertEquals(4, client.lpush(key, valueArray).get()); + // assertEquals("value1", client.lpop(key).get()); + // assertArrayEquals(new GlideString[] {gs("value2"), gs("value3"), gs("value4")}, + // client.lrange(key, 0, -1).get()); + // assertArrayEquals(new GlideString[] {gs("value2"), gs("value3")}, client.lpopCount(key, + // 2).get()); + // assertArrayEquals(new GlideString[] {}, client.lrange(gs("non_existing_key"), 0, + // -1).get()); + // assertNull(client.lpop(gs("non_existing_key")).get()); + // } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -1526,6 +1546,33 @@ public void lpush_lpop_lrange_type_error(BaseClient client) { assertTrue(lrangeException.getCause() instanceof RequestException); } + // TODO: uncomment once client.lrange has binary version + // @SneakyThrows + // @ParameterizedTest(autoCloseArguments = false) + // @MethodSource("getClients") + // public void lpush_lpop_lrange_binary_type_error(BaseClient client) { + // GlideString key = gs(UUID.randomUUID().toString()); + + // assertEquals(OK, client.set(key, "foo").get()); + + // Exception lpushException = + // assertThrows(ExecutionException.class, () -> client.lpush(key, new + // GlideString[] {gs("foo")}).get()); + // assertTrue(lpushException.getCause() instanceof RequestException); + + // Exception lpopException = assertThrows(ExecutionException.class, () -> + // client.lpop(key).get()); + // assertTrue(lpopException.getCause() instanceof RequestException); + + // Exception lpopCountException = + // assertThrows(ExecutionException.class, () -> client.lpopCount(key, 2).get()); + // assertTrue(lpopCountException.getCause() instanceof RequestException); + + // Exception lrangeException = + // assertThrows(ExecutionException.class, () -> client.lrange(key, 0, -1).get()); + // assertTrue(lrangeException.getCause() instanceof RequestException); + // } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -1862,6 +1909,22 @@ public void rpush_rpop_existing_non_existing_key(BaseClient client) { assertNull(client.rpop("non_existing_key").get()); } + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void rpush_rpop_binary_existing_non_existing_key(BaseClient client) { + GlideString key = gs(UUID.randomUUID().toString()); + GlideString[] valueArray = + new GlideString[] {gs("value1"), gs("value2"), gs("value3"), gs("value4")}; + + assertEquals(4, client.rpush(key, valueArray).get()); + assertEquals(gs("value4"), client.rpop(key).get()); + + assertArrayEquals( + new GlideString[] {gs("value3"), gs("value2")}, client.rpopCount(key, 2).get()); + assertNull(client.rpop(gs("non_existing_key")).get()); + } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -1878,6 +1941,23 @@ public void rpush_rpop_type_error(BaseClient client) { assertTrue(rpopException.getCause() instanceof RequestException); } + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void rpush_rpop_binary_type_error(BaseClient client) { + GlideString key = gs(UUID.randomUUID().toString()); + + assertEquals(OK, client.set(key, gs("foo")).get()); + + Exception rpushException = + assertThrows( + ExecutionException.class, () -> client.rpush(key, new GlideString[] {gs("foo")}).get()); + assertTrue(rpushException.getCause() instanceof RequestException); + + Exception rpopException = assertThrows(ExecutionException.class, () -> client.rpop(key).get()); + assertTrue(rpopException.getCause() instanceof RequestException); + } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -3194,6 +3274,27 @@ public void zpopmin(BaseClient client) { assertTrue(executionException.getCause() instanceof RequestException); } + // TODO: uncomment once client.zadd has binary version + // @SneakyThrows + // @ParameterizedTest(autoCloseArguments = false) + // @MethodSource("getClients") + // public void zpopmin_binary(BaseClient client) { + // GlideString key = gs(UUID.randomUUID().toString()); + // Map membersScores = Map.of(gs("a"), 1.0, gs("b"), 2.0, gs("c"), + // 3.0); + // assertEquals(3, client.zadd(key, membersScores).get()); + // assertEquals(Map.of(gs("a"), 1.0), client.zpopmin(key).get()); + // assertEquals(Map.of(gs("b"), 2.0, gs("c"), 3.0), client.zpopmin(key, 3).get()); + // assertTrue(client.zpopmin(key).get().isEmpty()); + // assertTrue(client.zpopmin(gs("non_existing_key")).get().isEmpty()); + + // // Key exists, but it is not a set + // assertEquals(OK, client.set(key, gs("value")).get()); + // ExecutionException executionException = + // assertThrows(ExecutionException.class, () -> client.zpopmin(key).get()); + // assertTrue(executionException.getCause() instanceof RequestException); + // } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -3225,6 +3326,42 @@ public void bzpopmin(BaseClient client) { assertInstanceOf(RequestException.class, executionException.getCause()); } + // TODO: uncomment once client.zadd has binary version + // @SneakyThrows + // @ParameterizedTest(autoCloseArguments = false) + // @MethodSource("getClients") + // public void bzpopmin_binary(BaseClient client) { + // GlideString key1 = gs("{test}-1-" + UUID.randomUUID()); + // GlideString key2 = gs("{test}-2-" + UUID.randomUUID()); + // GlideString key3 = gs("{test}-3-" + UUID.randomUUID()); + + // assertEquals(2, client.zadd(key1, Map.of("a", 1.0, "b", 1.5)).get()); + // assertEquals(1, client.zadd(key2, Map.of("c", 2.0)).get()); + // assertArrayEquals( + // new Object[] {key1, "a", 1.0}, client.bzpopmin(new GlideString[] {key1, key2}, + // .5).get()); + + // // nothing popped out - key does not exist + // assertNull( + // client + // .bzpopmin(new GlideString[] {key3}, REDIS_VERSION.isLowerThan("7.0.0") + // ? 1. : 0.001) + // .get()); + + // // pops from the second key + // assertArrayEquals( + // new Object[] {key2, "c", 2.0}, client.bzpopmin(new GlideString[] {key3, key2}, + // .5).get()); + + // // Key exists, but it is not a sorted set + // assertEquals(OK, client.set(key3, gs("value")).get()); + // ExecutionException executionException = + // assertThrows( + // ExecutionException.class, () -> client.bzpopmin(new GlideString[] + // {key3}, .5).get()); + // assertInstanceOf(RequestException.class, executionException.getCause()); + // } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -3247,6 +3384,28 @@ public void bzpopmin_timeout_check(BaseClient client) { } } + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void bzpopmin_binary_timeout_check(BaseClient client) { + GlideString key = gs(UUID.randomUUID().toString()); + // create new client with default request timeout (250 millis) + try (var testClient = + client instanceof RedisClient + ? RedisClient.CreateClient(commonClientConfig().build()).get() + : RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get()) { + + // ensure that commands doesn't time out even if timeout > request timeout + assertNull(testClient.bzpopmin(new GlideString[] {key}, 1).get()); + + // with 0 timeout (no timeout) should never time out, + // but we wrap the test with timeout to avoid test failing or stuck forever + assertThrows( + TimeoutException.class, // <- future timeout, not command timeout + () -> testClient.bzpopmin(new GlideString[] {key}, 0).get(3, TimeUnit.SECONDS)); + } + } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -3266,6 +3425,27 @@ public void zpopmax(BaseClient client) { assertTrue(executionException.getCause() instanceof RequestException); } + // TODO: uncomment once client.zadd has binary version + // @SneakyThrows + // @ParameterizedTest(autoCloseArguments = false) + // @MethodSource("getClients") + // public void zpopmax_binary(BaseClient client) { + // GlideString key = gs(UUID.randomUUID().toString()); + // Map membersScores = Map.of(gs("a"), 1.0, gs("b"), 2.0, gs("c"), + // 3.0); + // assertEquals(3, client.zadd(key, membersScores).get()); + // assertEquals(Map.of(gs("c"), 3.0), client.zpopmax(key).get()); + // assertEquals(Map.of(gs("b"), 2.0, gs("a"), 1.0), client.zpopmax(key, 3).get()); + // assertTrue(client.zpopmax(key).get().isEmpty()); + // assertTrue(client.zpopmax(gs("non_existing_key")).get().isEmpty()); + + // // Key exists, but it is not a set + // assertEquals(OK, client.set(key, gs("value")).get()); + // ExecutionException executionException = + // assertThrows(ExecutionException.class, () -> client.zpopmax(key).get()); + // assertTrue(executionException.getCause() instanceof RequestException); + // } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -3297,6 +3477,42 @@ public void bzpopmax(BaseClient client) { assertInstanceOf(RequestException.class, executionException.getCause()); } + // TODO: uncomment once client.zadd has binary version + // @SneakyThrows + // @ParameterizedTest(autoCloseArguments = false) + // @MethodSource("getClients") + // public void bzpopmax_binary(BaseClient client) { + // GlideString key1 = gs("{test}-1-" + UUID.randomUUID()); + // GlideString key2 = gs("{test}-2-" + UUID.randomUUID()); + // GlideString key3 = gs("{test}-3-" + UUID.randomUUID()); + + // assertEquals(2, client.zadd(key1, Map.of(gs("a"), 1.0, gs("b"), 1.5)).get()); + // assertEquals(1, client.zadd(key2, Map.of(gs("c"), 2.0)).get()); + // assertArrayEquals( + // new Object[] {key1, "b", 1.5}, client.bzpopmax(new GlideString[] {key1, key2}, + // .5).get()); + + // // nothing popped out - key does not exist + // assertNull( + // client + // .bzpopmax(new GlideString[] {key3}, REDIS_VERSION.isLowerThan("7.0.0") + // ? 1. : 0.001) + // .get()); + + // // pops from the second key + // assertArrayEquals( + // new Object[] {key2, "c", 2.0}, client.bzpopmax(new GlideString[] {key3, key2}, + // .5).get()); + + // // Key exists, but it is not a sorted set + // assertEquals(OK, client.set(key3, gs("value")).get()); + // ExecutionException executionException = + // assertThrows( + // ExecutionException.class, () -> client.bzpopmax(new GlideString[] + // {key3}, .5).get()); + // assertInstanceOf(RequestException.class, executionException.getCause()); + // } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -3319,6 +3535,28 @@ public void bzpopmax_timeout_check(BaseClient client) { } } + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void bzpopmax_binary_timeout_check(BaseClient client) { + GlideString key = gs(UUID.randomUUID().toString()); + // create new client with default request timeout (250 millis) + try (var testClient = + client instanceof RedisClient + ? RedisClient.CreateClient(commonClientConfig().build()).get() + : RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get()) { + + // ensure that commands doesn't time out even if timeout > request timeout + assertNull(testClient.bzpopmax(new GlideString[] {key}, 1).get()); + + // with 0 timeout (no timeout) should never time out, + // but we wrap the test with timeout to avoid test failing or stuck forever + assertThrows( + TimeoutException.class, // <- future timeout, not command timeout + () -> testClient.bzpopmax(new GlideString[] {key}, 0).get(3, TimeUnit.SECONDS)); + } + } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -4235,6 +4473,64 @@ public void zmpop(BaseClient client) { assertEquals(entries, client.zmpop(new String[] {key2}, MIN, 10).get()[1]); } + // TODO: uncomment once client.zadd has binary version + // @SneakyThrows + // @ParameterizedTest(autoCloseArguments = false) + // @MethodSource("getClients") + // public void zmpop_binary(BaseClient client) { + // assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0"), "This feature added in redis + // 7"); + // GlideString key1 = gs("{zmpop}-1-" + UUID.randomUUID()); + // GlideString key2 = gs("{zmpop}-2-" + UUID.randomUUID()); + // GlideString key3 = gs("{zmpop}-3-" + UUID.randomUUID()); + + // assertEquals(2, client.zadd(key1, Map.of(gs("a1"), 1., gs("b1"), 2.)).get()); + // assertEquals(2, client.zadd(key2, Map.of(gs("a2"), .1, gs("b2"), .2)).get()); + + // assertArrayEquals( + // new Object[] {key1, Map.of(gs("b1"), 2.)}, client.zmpop(new GlideString[] + // {key1, key2}, MAX).get()); + // assertArrayEquals( + // new Object[] {key2, Map.of(gs("b2"), .2, gs("a2"), .1)}, + // client.zmpop(new GlideString[] {key2, key1}, MAX, 10).get()); + + // // nothing popped out + // assertNull(client.zmpop(new GlideString[] {key3}, MIN).get()); + // assertNull(client.zmpop(new GlideString[] {key3}, MIN, 1).get()); + + // // Key exists, but it is not a sorted set + // assertEquals(OK, client.set(key3, gs("value")).get()); + // ExecutionException executionException = + // assertThrows(ExecutionException.class, () -> client.zmpop(new GlideString[] + // {key3}, MAX).get()); + // assertInstanceOf(RequestException.class, executionException.getCause()); + // executionException = + // assertThrows( + // ExecutionException.class, () -> client.zmpop(new GlideString[] {key3}, + // MAX, 1).get()); + // assertInstanceOf(RequestException.class, executionException.getCause()); + + // // incorrect argument + // executionException = + // assertThrows( + // ExecutionException.class, () -> client.zmpop(new GlideString[] {key1}, + // MAX, 0).get()); + // assertInstanceOf(RequestException.class, executionException.getCause()); + // executionException = + // assertThrows(ExecutionException.class, () -> client.zmpop(new GlideString[0], + // MAX).get()); + // assertInstanceOf(RequestException.class, executionException.getCause()); + + // // check that order of entries in the response is preserved + // var entries = new LinkedHashMap(); + // for (int i = 0; i < 10; i++) { + // // a => 1., b => 2. etc + // entries.put(gs("" + ('a' + i)), (double) i); + // } + // assertEquals(10, client.zadd(key2, entries).get()); + // assertEquals(entries, client.zmpop(new GlideString[] {key2}, MIN, 10).get()[1]); + // } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -4285,6 +4581,61 @@ public void bzmpop(BaseClient client) { assertEquals(entries, client.bzmpop(new String[] {key2}, MIN, .1, 10).get()[1]); } + // TODO: uncomment once client.zadd has binary version + // @SneakyThrows + // @ParameterizedTest(autoCloseArguments = false) + // @MethodSource("getClients") + // public void bzmpop_binary(BaseClient client) { + // assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0"), "This feature added in redis + // 7"); + // GlideString key1 = gs("{bzmpop}-1-" + UUID.randomUUID()); + // GlideString key2 = gs("{bzmpop}-2-" + UUID.randomUUID()); + // GlideString key3 = gs("{bzmpop}-3-" + UUID.randomUUID()); + + // assertEquals(2, client.zadd(key1, Map.of(gs("a1"), 1., gs("b1"), 2.)).get()); + // assertEquals(2, client.zadd(key2, Map.of(gs("a2"), .1, gs("b2"), .2)).get()); + + // assertArrayEquals( + // new Object[] {key1, Map.of(gs("b1"), 2.)}, + // client.bzmpop(new GlideString[] {key1, key2}, MAX, 0.1).get()); + // assertArrayEquals( + // new Object[] {key2, Map.of(gs("b2"), .2, gs("a2"), .1)}, + // client.bzmpop(new GlideString[] {key2, key1}, MAX, 0.1, 10).get()); + + // // nothing popped out + // assertNull(client.bzmpop(new GlideString[] {key3}, MIN, 0.001).get()); + // assertNull(client.bzmpop(new GlideString[] {key3}, MIN, 0.001, 1).get()); + + // // Key exists, but it is not a sorted set + // assertEquals(OK, client.set(key3, gs("value")).get()); + // ExecutionException executionException = + // assertThrows( + // ExecutionException.class, () -> client.bzmpop(new GlideString[] {key3}, + // MAX, .1).get()); + // assertInstanceOf(RequestException.class, executionException.getCause()); + // executionException = + // assertThrows( + // ExecutionException.class, () -> client.bzmpop(new GlideString[] {key3}, + // MAX, .1, 1).get()); + // assertInstanceOf(RequestException.class, executionException.getCause()); + + // // incorrect argument + // executionException = + // assertThrows( + // ExecutionException.class, () -> client.bzmpop(new GlideString[] {key1}, + // MAX, .1, 0).get()); + // assertInstanceOf(RequestException.class, executionException.getCause()); + + // // check that order of entries in the response is preserved + // var entries = new LinkedHashMap(); + // for (int i = 0; i < 10; i++) { + // // a => 1., b => 2. etc + // entries.put(gs("" + ('a' + i)), (double) i); + // } + // assertEquals(10, client.zadd(key2, entries).get()); + // assertEquals(entries, client.bzmpop(new GlideString[] {key2}, MIN, .1, 10).get()[1]); + // } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -4309,6 +4660,29 @@ public void bzmpop_timeout_check(BaseClient client) { } // TODO: add binary version + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void bzmpop_binary_timeout_check(BaseClient client) { + assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0"), "This feature added in redis 7"); + GlideString key = gs(UUID.randomUUID().toString()); + // create new client with default request timeout (250 millis) + try (var testClient = + client instanceof RedisClient + ? RedisClient.CreateClient(commonClientConfig().build()).get() + : RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get()) { + + // ensure that commands doesn't time out even if timeout > request timeout + assertNull(testClient.bzmpop(new GlideString[] {key}, MAX, 1).get()); + + // with 0 timeout (no timeout) should never time out, + // but we wrap the test with timeout to avoid test failing or stuck forever + assertThrows( + TimeoutException.class, // <- future timeout, not command timeout + () -> testClient.bzmpop(new GlideString[] {key}, MAX, 0).get(3, TimeUnit.SECONDS)); + } + } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -6564,6 +6938,34 @@ public void brpop(BaseClient client) { assertTrue(executionException.getCause() instanceof RequestException); } + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void brpop_binary(BaseClient client) { + GlideString listKey1 = gs("{listKey}-1-" + UUID.randomUUID()); + GlideString listKey2 = gs("{listKey}-2-" + UUID.randomUUID()); + GlideString value1 = gs("value1-" + UUID.randomUUID()); + GlideString value2 = gs("value2-" + UUID.randomUUID()); + assertEquals(2, client.lpush(listKey1, new GlideString[] {value1, value2}).get()); + + var response = client.brpop(new GlideString[] {listKey1, listKey2}, 0.5).get(); + assertArrayEquals(new GlideString[] {listKey1, value1}, response); + + // nothing popped out + assertNull( + client + .brpop(new GlideString[] {listKey2}, REDIS_VERSION.isLowerThan("7.0.0") ? 1. : 0.001) + .get()); + + // Key exists, but it is not a list + assertEquals(OK, client.set("foo", "bar").get()); + ExecutionException executionException = + assertThrows( + ExecutionException.class, + () -> client.brpop(new GlideString[] {gs("foo")}, .0001).get()); + assertTrue(executionException.getCause() instanceof RequestException); + } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -6617,6 +7019,34 @@ public void blpop(BaseClient client) { assertTrue(executionException.getCause() instanceof RequestException); } + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void blpop_binary(BaseClient client) { + GlideString listKey1 = gs("{listKey}-1-" + UUID.randomUUID()); + GlideString listKey2 = gs("{listKey}-2-" + UUID.randomUUID()); + GlideString value1 = gs("value1-" + UUID.randomUUID()); + GlideString value2 = gs("value2-" + UUID.randomUUID()); + assertEquals(2, client.lpush(listKey1, new GlideString[] {value1, value2}).get()); + + var response = client.blpop(new GlideString[] {listKey1, listKey2}, 0.5).get(); + assertArrayEquals(new GlideString[] {listKey1, value2}, response); + + // nothing popped out + assertNull( + client + .blpop(new GlideString[] {listKey2}, REDIS_VERSION.isLowerThan("7.0.0") ? 1. : 0.001) + .get()); + + // Key exists, but it is not a list + assertEquals(OK, client.set(gs("foo"), gs("bar")).get()); + ExecutionException executionException = + assertThrows( + ExecutionException.class, + () -> client.blpop(new GlideString[] {gs("foo")}, .0001).get()); + assertTrue(executionException.getCause() instanceof RequestException); + } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -7866,6 +8296,50 @@ public void lmpop(BaseClient client) { assertInstanceOf(RequestException.class, executionException.getCause()); } + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void lmpop_binary(BaseClient client) { + assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0"), "This feature added in redis 7"); + // setup + GlideString key1 = gs("{key}-1" + UUID.randomUUID()); + GlideString key2 = gs("{key}-2" + UUID.randomUUID()); + GlideString nonListKey = gs("{key}-3" + UUID.randomUUID()); + GlideString[] singleKeyArray = {key1}; + GlideString[] multiKeyArray = {key2, key1}; + long count = 1L; + Long arraySize = 5L; + GlideString[] lpushArgs = {gs("one"), gs("two"), gs("three"), gs("four"), gs("five")}; + Map expected = Map.of(key1, new GlideString[] {gs("five")}); + Map expected2 = + Map.of(key2, new GlideString[] {gs("one"), gs("two")}); + + // nothing to be popped + assertNull(client.lmpop(singleKeyArray, ListDirection.LEFT).get()); + assertNull(client.lmpop(singleKeyArray, ListDirection.LEFT, count).get()); + + // pushing to the arrays to be popped + assertEquals(arraySize, client.lpush(key1, lpushArgs).get()); + assertEquals(arraySize, client.lpush(key2, lpushArgs).get()); + + // assert correct result from popping + Map result = client.lmpop(singleKeyArray, ListDirection.LEFT).get(); + assertDeepEquals(result, expected); + + // assert popping multiple elements from the right + Map result2 = + client.lmpop(multiKeyArray, ListDirection.RIGHT, 2L).get(); + assertDeepEquals(result2, expected2); + + // key exists but is not a list type key + assertEquals(OK, client.set(nonListKey, gs("lmpop")).get()); + ExecutionException executionException = + assertThrows( + ExecutionException.class, + () -> client.lmpop(new GlideString[] {nonListKey}, ListDirection.LEFT).get()); + assertInstanceOf(RequestException.class, executionException.getCause()); + } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -7909,6 +8383,51 @@ public void blmpop(BaseClient client) { assertInstanceOf(RequestException.class, executionException.getCause()); } + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void blmpop_binary(BaseClient client) { + assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0"), "This feature added in redis 7"); + // setup + GlideString key1 = gs("{key}-1" + UUID.randomUUID()); + GlideString key2 = gs("{key}-2" + UUID.randomUUID()); + GlideString nonListKey = gs("{key}-3" + UUID.randomUUID()); + GlideString[] singleKeyArray = {key1}; + GlideString[] multiKeyArray = {key2, key1}; + long count = 1L; + Long arraySize = 5L; + GlideString[] lpushArgs = {gs("one"), gs("two"), gs("three"), gs("four"), gs("five")}; + Map expected = Map.of(key1, new GlideString[] {gs("five")}); + Map expected2 = + Map.of(key2, new GlideString[] {gs("one"), gs("two")}); + + // nothing to be popped + assertNull(client.blmpop(singleKeyArray, ListDirection.LEFT, 0.1).get()); + assertNull(client.blmpop(singleKeyArray, ListDirection.LEFT, count, 0.1).get()); + + // pushing to the arrays to be popped + assertEquals(arraySize, client.lpush(key1, lpushArgs).get()); + assertEquals(arraySize, client.lpush(key2, lpushArgs).get()); + + // assert correct result from popping + Map result = + client.blmpop(singleKeyArray, ListDirection.LEFT, 0.1).get(); + assertDeepEquals(result, expected); + + // assert popping multiple elements from the right + Map result2 = + client.blmpop(multiKeyArray, ListDirection.RIGHT, 2L, 0.1).get(); + assertDeepEquals(result2, expected2); + + // key exists but is not a list type key + assertEquals(OK, client.set(nonListKey, gs("blmpop")).get()); + ExecutionException executionException = + assertThrows( + ExecutionException.class, + () -> client.blmpop(new GlideString[] {nonListKey}, ListDirection.LEFT, 0.1).get()); + assertInstanceOf(RequestException.class, executionException.getCause()); + } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -7935,6 +8454,32 @@ public void blmpop_timeout_check(BaseClient client) { } } + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void blmpop_binary_timeout_check(BaseClient client) { + assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0"), "This feature added in redis 7"); + GlideString key = gs(UUID.randomUUID().toString()); + // create new client with default request timeout (250 millis) + try (var testClient = + client instanceof RedisClient + ? RedisClient.CreateClient(commonClientConfig().build()).get() + : RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get()) { + + // ensure that commands doesn't time out even if timeout > request timeout + assertNull(testClient.blmpop(new GlideString[] {key}, ListDirection.LEFT, 1).get()); + + // with 0 timeout (no timeout) should never time out, + // but we wrap the test with timeout to avoid test failing or stuck forever + assertThrows( + TimeoutException.class, // <- future timeout, not command timeout + () -> + testClient + .blmpop(new GlideString[] {key}, ListDirection.LEFT, 0) + .get(3, TimeUnit.SECONDS)); + } + } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -8434,6 +8979,48 @@ public void spop_spopCount(BaseClient client) { assertInstanceOf(RequestException.class, executionException.getCause()); } + // TODO: uncomment once client.sadd has binary version + // @SneakyThrows + // @ParameterizedTest(autoCloseArguments = false) + // @MethodSource("getClients") + // public void spop_spopCount_binary(BaseClient client) { + // GlideString key = gs(UUID.randomUUID().toString()); + // GlideString stringKey = gs(UUID.randomUUID().toString()); + // GlideString nonExistingKey = gs(UUID.randomUUID().toString()); + // GlideString member1 = gs(UUID.randomUUID().toString()); + // GlideString member2 = gs(UUID.randomUUID().toString()); + // GlideString member3 = gs(UUID.randomUUID().toString()); + + // assertEquals(1, client.sadd(key, new GlideString[] {member1}).get()); + // assertEquals(member1, client.spop(key).get()); + + // assertEquals(3, client.sadd(key, new GlideString[] {member1, member2, member3}).get()); + // // Pop with count value greater than the size of the set + // assertEquals(Set.of(member1, member2, member3), client.spopCount(key, 4).get()); + // assertEquals(0, client.scard(key).get()); + + // assertEquals(3, client.sadd(key, new GlideString[] {member1, member2, member3}).get()); + // assertEquals(Set.of(), client.spopCount(key, 0).get()); + + // assertNull(client.spop(nonExistingKey).get()); + // assertEquals(Set.of(), client.spopCount(nonExistingKey, 3).get()); + + // // invalid argument - count must be positive + // ExecutionException executionException = + // assertThrows(ExecutionException.class, () -> client.spopCount(key, -1).get()); + // assertInstanceOf(RequestException.class, executionException.getCause()); + + // // key exists but is not a set + // assertEquals(OK, client.set(stringKey, gs("foo")).get()); + // executionException = assertThrows(ExecutionException.class, () -> + // client.spop(stringKey).get()); + // assertInstanceOf(RequestException.class, executionException.getCause()); + // executionException = + // assertThrows(ExecutionException.class, () -> client.spopCount(stringKey, + // 3).get()); + // assertInstanceOf(RequestException.class, executionException.getCause()); + // } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") diff --git a/java/integTest/src/test/java/glide/cluster/CommandTests.java b/java/integTest/src/test/java/glide/cluster/CommandTests.java index 30a19e6e61..6a9e098ce9 100644 --- a/java/integTest/src/test/java/glide/cluster/CommandTests.java +++ b/java/integTest/src/test/java/glide/cluster/CommandTests.java @@ -813,7 +813,15 @@ public static Stream callCrossSlotCommandsWhichShouldFail() { Arguments.of( "zintercard", "7.0.0", clusterClient.zintercard(new String[] {"abc", "zxy", "lkn"})), Arguments.of("brpop", null, clusterClient.brpop(new String[] {"abc", "zxy", "lkn"}, .1)), + Arguments.of( + "brpop binary", + null, + clusterClient.brpop(new GlideString[] {gs("abc"), gs("zxy"), gs("lkn")}, .1)), Arguments.of("blpop", null, clusterClient.blpop(new String[] {"abc", "zxy", "lkn"}, .1)), + Arguments.of( + "blpop binary", + null, + clusterClient.blpop(new GlideString[] {gs("abc"), gs("zxy"), gs("lkn")}, .1)), Arguments.of("pfcount", null, clusterClient.pfcount(new String[] {"abc", "zxy", "lkn"})), Arguments.of( "pfcount binary", @@ -826,16 +834,36 @@ public static Stream callCrossSlotCommandsWhichShouldFail() { clusterClient.pfmerge(gs("abc"), new GlideString[] {gs("zxy"), gs("lkn")})), Arguments.of( "bzpopmax", "5.0.0", clusterClient.bzpopmax(new String[] {"abc", "zxy", "lkn"}, .1)), + Arguments.of( + "bzpopmax binary", + "5.0.0", + clusterClient.bzpopmax(new GlideString[] {gs("abc"), gs("zxy"), gs("lkn")}, .1)), Arguments.of( "bzpopmin", "5.0.0", clusterClient.bzpopmin(new String[] {"abc", "zxy", "lkn"}, .1)), + Arguments.of( + "bzpopmin binary", + "5.0.0", + clusterClient.bzpopmin(new GlideString[] {gs("abc"), gs("zxy"), gs("lkn")}, .1)), Arguments.of( "zmpop", "7.0.0", clusterClient.zmpop(new String[] {"abc", "zxy", "lkn"}, MAX)), + Arguments.of( + "zmpop binary", + "7.0.0", + clusterClient.zmpop(new GlideString[] {gs("abc"), gs("zxy"), gs("lkn")}, MAX)), Arguments.of( "bzmpop", "7.0.0", clusterClient.bzmpop(new String[] {"abc", "zxy", "lkn"}, MAX, .1)), + Arguments.of( + "bzmpop binary", + "7.0.0", + clusterClient.bzmpop(new GlideString[] {gs("abc"), gs("zxy"), gs("lkn")}, MAX, .1)), Arguments.of( "lmpop", "7.0.0", clusterClient.lmpop(new String[] {"abc", "def"}, ListDirection.LEFT, 1L)), + Arguments.of( + "lmpop binary", + "7.0.0", + clusterClient.lmpop(new GlideString[] {gs("abc"), gs("def")}, ListDirection.LEFT, 1L)), Arguments.of( "bitop", null, @@ -844,6 +872,11 @@ public static Stream callCrossSlotCommandsWhichShouldFail() { "blmpop", "7.0.0", clusterClient.blmpop(new String[] {"abc", "def"}, ListDirection.LEFT, 1L, 0.1)), + Arguments.of( + "blmpop binary", + "7.0.0", + clusterClient.blmpop( + new GlideString[] {gs("abc"), gs("def")}, ListDirection.LEFT, 1L, 0.1)), Arguments.of( "lmove", "6.2.0", From 60e36328a1aa7c9570a53a20d4bcdb03ca0f4076 Mon Sep 17 00:00:00 2001 From: Alon Arenberg <93711356+alon-arenberg@users.noreply.github.com> Date: Thu, 4 Jul 2024 11:04:13 +0300 Subject: [PATCH 09/23] support functionStats with GlideString (#1779) * suuport functionStats with GlideString * fix comments * nit: spotlessApply --- .../src/main/java/glide/api/BaseClient.java | 11 + .../src/main/java/glide/api/RedisClient.java | 8 + .../java/glide/api/RedisClusterClient.java | 35 ++ .../ScriptingAndFunctionsClusterCommands.java | 68 +++ .../ScriptingAndFunctionsCommands.java | 31 ++ .../test/java/glide/api/RedisClientTest.java | 25 ++ .../glide/api/RedisClusterClientTest.java | 52 +++ .../src/test/java/glide/TestUtilities.java | 37 ++ .../test/java/glide/cluster/CommandTests.java | 419 ++++++++++++++++++ .../java/glide/standalone/CommandTests.java | 181 ++++++++ 10 files changed, 867 insertions(+) diff --git a/java/client/src/main/java/glide/api/BaseClient.java b/java/client/src/main/java/glide/api/BaseClient.java index 3cd379cc17..18f7de5e1e 100644 --- a/java/client/src/main/java/glide/api/BaseClient.java +++ b/java/client/src/main/java/glide/api/BaseClient.java @@ -664,6 +664,17 @@ protected Map> handleFunctionStatsResponse( return response; } + /** Process a FUNCTION STATS standalone response. */ + protected Map> handleFunctionStatsBinaryResponse( + Map> response) { + Map runningScriptInfo = response.get(gs("running_script")); + if (runningScriptInfo != null) { + Object[] command = (Object[]) runningScriptInfo.get(gs("command")); + runningScriptInfo.put(gs("command"), castArray(command, GlideString.class)); + } + return response; + } + /** Process a LCS key1 key2 IDX response */ protected Map handleLcsIdxResponse(Map response) throws RedisException { diff --git a/java/client/src/main/java/glide/api/RedisClient.java b/java/client/src/main/java/glide/api/RedisClient.java index 89ada3efce..5f699d39ec 100644 --- a/java/client/src/main/java/glide/api/RedisClient.java +++ b/java/client/src/main/java/glide/api/RedisClient.java @@ -421,6 +421,14 @@ public CompletableFuture>> functionStats() { response -> handleFunctionStatsResponse(handleMapResponse(response))); } + @Override + public CompletableFuture>> functionStatsBinary() { + return commandManager.submitNewCommand( + FunctionStats, + new GlideString[0], + response -> handleFunctionStatsBinaryResponse(handleBinaryStringMapResponse(response))); + } + @Override public CompletableFuture unwatch() { return commandManager.submitNewCommand(UnWatch, new String[0], this::handleStringResponse); diff --git a/java/client/src/main/java/glide/api/RedisClusterClient.java b/java/client/src/main/java/glide/api/RedisClusterClient.java index 800c57045e..fe3814b0db 100644 --- a/java/client/src/main/java/glide/api/RedisClusterClient.java +++ b/java/client/src/main/java/glide/api/RedisClusterClient.java @@ -874,12 +874,37 @@ protected ClusterValue>> handleFunctionStatsResp } } + /** Process a FUNCTION STATS cluster response. */ + protected ClusterValue>> + handleFunctionStatsBinaryResponse(Response response, boolean isSingleValue) { + if (isSingleValue) { + return ClusterValue.ofSingleValue( + handleFunctionStatsBinaryResponse(handleBinaryStringMapResponse(response))); + } else { + Map>> data = + handleBinaryStringMapResponse(response); + for (var nodeInfo : data.entrySet()) { + nodeInfo.setValue(handleFunctionStatsBinaryResponse(nodeInfo.getValue())); + } + return ClusterValue.ofMultiValueBinary(data); + } + } + @Override public CompletableFuture>>> functionStats() { return commandManager.submitNewCommand( FunctionStats, new String[0], response -> handleFunctionStatsResponse(response, false)); } + @Override + public CompletableFuture>>> + functionStatsBinary() { + return commandManager.submitNewCommand( + FunctionStats, + new GlideString[0], + response -> handleFunctionStatsBinaryResponse(response, false)); + } + @Override public CompletableFuture>>> functionStats( @NonNull Route route) { @@ -890,6 +915,16 @@ public CompletableFuture>>> functio response -> handleFunctionStatsResponse(response, route instanceof SingleNodeRoute)); } + @Override + public CompletableFuture>>> + functionStatsBinary(@NonNull Route route) { + return commandManager.submitNewCommand( + FunctionStats, + new GlideString[0], + route, + response -> handleFunctionStatsBinaryResponse(response, route instanceof SingleNodeRoute)); + } + @Override public CompletableFuture unwatch(@NonNull Route route) { return commandManager.submitNewCommand( diff --git a/java/client/src/main/java/glide/api/commands/ScriptingAndFunctionsClusterCommands.java b/java/client/src/main/java/glide/api/commands/ScriptingAndFunctionsClusterCommands.java index ffb1fe3c01..fa80d15dd7 100644 --- a/java/client/src/main/java/glide/api/commands/ScriptingAndFunctionsClusterCommands.java +++ b/java/client/src/main/java/glide/api/commands/ScriptingAndFunctionsClusterCommands.java @@ -814,6 +814,40 @@ CompletableFuture> fcallReadOnly( */ CompletableFuture>>> functionStats(); + /** + * Returns information about the function that's currently running and information about the + * available execution engines.
+ * The command will be routed to all primary nodes. + * + * @since Redis 7.0 and above. + * @see redis.io for details. + * @return A Map with two keys: + *
    + *
  • running_script with information about the running script. + *
  • engines with information about available engines and their stats. + *
+ * See example for more details. + * @example + *
{@code
+     * Map>> response = client.functionStatsBinary().get().getMultiValue();
+     * for (GlideString node : response.keySet()) {
+     *   Map runningScriptInfo = response.get(node).get(gs("running_script"));
+     *   if (runningScriptInfo != null) {
+     *     GlideString[] commandLine = (GlideString[]) runningScriptInfo.get(gs("command"));
+     *     System.out.printf("Node '%s' is currently running function '%s' with command line '%s', which has been running for %d ms%n",
+     *         node, runningScriptInfo.get(gs("name")), String.join(" ", Arrays.toString(commandLine)), (long) runningScriptInfo.get(gs("duration_ms")));
+     *   }
+     *   Map enginesInfo = response.get(node).get(gs("engines"));
+     *   for (String engineName : enginesInfo.keySet()) {
+     *     Map engine = (Map) enginesInfo.get(engineName);
+     *     System.out.printf("Node '%s' supports engine '%s', which has %d libraries and %d functions in total%n",
+     *         node, engineName, engine.get(gs("libraries_count")), engine.get(gs("functions_count")));
+     *   }
+     * }
+     * }
+ */ + CompletableFuture>>> functionStatsBinary(); + /** * Returns information about the function that's currently running and information about the * available execution engines. @@ -846,4 +880,38 @@ CompletableFuture> fcallReadOnly( * }
*/ CompletableFuture>>> functionStats(Route route); + + /** + * Returns information about the function that's currently running and information about the + * available execution engines. + * + * @since Redis 7.0 and above. + * @see redis.io for details. + * @param route Specifies the routing configuration for the command. The client will route the + * command to the nodes defined by route. + * @return A Map with two keys: + *
    + *
  • running_script with information about the running script. + *
  • engines with information about available engines and their stats. + *
+ * See example for more details. + * @example + *
{@code
+     * Map> response = client.functionStats(RANDOM).get().getSingleValue();
+     * Map runningScriptInfo = response.get(gs("running_script"));
+     * if (runningScriptInfo != null) {
+     *   GlideString[] commandLine = (GlideString[]) runningScriptInfo.get(gs("command"));
+     *   System.out.printf("Node is currently running function '%s' with command line '%s', which has been running for %d ms%n",
+     *       runningScriptInfo.get(gs("name")), String.join(" ", Arrays.toString(commandLine)), (long)runningScriptInfo.get(gs("duration_ms")));
+     * }
+     * Map enginesInfo = response.get(gs("engines"));
+     * for (GlideString engineName : enginesInfo.keySet()) {
+     *   Map engine = (Map) enginesInfo.get(engineName);
+     *   System.out.printf("Node supports engine '%s', which has %d libraries and %d functions in total%n",
+     *       engineName, engine.get(gs("libraries_count")), engine.get(gs("functions_count")));
+     * }
+     * }
+ */ + CompletableFuture>>> functionStatsBinary( + Route route); } diff --git a/java/client/src/main/java/glide/api/commands/ScriptingAndFunctionsCommands.java b/java/client/src/main/java/glide/api/commands/ScriptingAndFunctionsCommands.java index 4d31312b13..f753f5ba87 100644 --- a/java/client/src/main/java/glide/api/commands/ScriptingAndFunctionsCommands.java +++ b/java/client/src/main/java/glide/api/commands/ScriptingAndFunctionsCommands.java @@ -319,4 +319,35 @@ public interface ScriptingAndFunctionsCommands { * }
*/ CompletableFuture>> functionStats(); + + /** + * Returns information about the function that's currently running and information about the + * available execution engines. + * + * @since Redis 7.0 and above. + * @see redis.io for details. + * @return A Map with two keys: + *
    + *
  • running_script with information about the running script. + *
  • engines with information about available engines and their stats. + *
+ * See example for more details. + * @example + *
{@code
+     * Map> response = client.functionStats().get();
+     * Map runningScriptInfo = response.get(gs("running_script"));
+     * if (runningScriptInfo != null) {
+     *   GlideString[] commandLine = (GlideString[]) runningScriptInfo.get(gs("command"));
+     *   System.out.printf("Server is currently running function '%s' with command line '%s', which has been running for %d ms%n",
+     *       runningScriptInfo.get(gs("name")), String.join(" ", Arrays.toString(commandLine)), (long)runningScriptInfo.get(gs("duration_ms")));
+     * }
+     * Map enginesInfo = response.get(gs("engines"));
+     * for (GlideString engineName : enginesInfo.keySet()) {
+     *   Map engine = (Map) enginesInfo.get(gs(engineName));
+     *   System.out.printf("Server supports engine '%s', which has %d libraries and %d functions in total%n",
+     *       engineName, engine.get(gs("libraries_count")), engine.get(gs("functions_count")));
+     * }
+     * }
+ */ + CompletableFuture>> functionStatsBinary(); } diff --git a/java/client/src/test/java/glide/api/RedisClientTest.java b/java/client/src/test/java/glide/api/RedisClientTest.java index 758e11c6cd..f981d4be5a 100644 --- a/java/client/src/test/java/glide/api/RedisClientTest.java +++ b/java/client/src/test/java/glide/api/RedisClientTest.java @@ -9615,6 +9615,31 @@ public void functionStats_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void functionStatsBinary_returns_success() { + // setup + GlideString[] args = new GlideString[0]; + Map> value = Map.of(gs("1"), Map.of(gs("2"), 2)); + CompletableFuture>> testResponse = + new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.>>submitNewCommand( + eq(FunctionStats), eq(args), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture>> response = + service.functionStatsBinary(); + Map> payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void functionDump_returns_success() { diff --git a/java/client/src/test/java/glide/api/RedisClusterClientTest.java b/java/client/src/test/java/glide/api/RedisClusterClientTest.java index 0cbc82cf38..d93c6417d3 100644 --- a/java/client/src/test/java/glide/api/RedisClusterClientTest.java +++ b/java/client/src/test/java/glide/api/RedisClusterClientTest.java @@ -2123,6 +2123,32 @@ public void functionStats_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void functionStatsBinary_returns_success() { + // setup + GlideString[] args = new GlideString[0]; + ClusterValue>> value = + ClusterValue.ofSingleValue(Map.of(gs("1"), Map.of(gs("2"), 2))); + CompletableFuture>>> testResponse = + new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.>>>submitNewCommand( + eq(FunctionStats), eq(args), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture>>> response = + service.functionStatsBinary(); + ClusterValue>> payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void fcallReadOnly_without_keys_and_without_args_but_with_route_returns_success() { @@ -2297,6 +2323,32 @@ public void functionStats_with_route_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void functionStatsBinary_with_route_returns_success() { + // setup + GlideString[] args = new GlideString[0]; + ClusterValue>> value = + ClusterValue.ofSingleValue(Map.of(gs("1"), Map.of(gs("2"), 2))); + CompletableFuture>>> testResponse = + new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.>>>submitNewCommand( + eq(FunctionStats), eq(args), eq(RANDOM), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture>>> response = + service.functionStatsBinary(RANDOM); + ClusterValue>> payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void functionDump_returns_success() { diff --git a/java/integTest/src/test/java/glide/TestUtilities.java b/java/integTest/src/test/java/glide/TestUtilities.java index 03d07b1231..a43105f577 100644 --- a/java/integTest/src/test/java/glide/TestUtilities.java +++ b/java/integTest/src/test/java/glide/TestUtilities.java @@ -15,6 +15,7 @@ import glide.api.models.configuration.RedisClientConfiguration; import glide.api.models.configuration.RedisClusterClientConfiguration; import java.security.SecureRandom; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -201,6 +202,42 @@ public static void checkFunctionStatsResponse( assertEquals(expected, response.get("engines")); } + /** + * Validate whether `FUNCTION STATS` response contains required info. + * + * @param response The response from server. + * @param runningFunction Command line of running function expected. Empty, if nothing expected. + * @param libCount Expected libraries count. + * @param functionCount Expected functions count. + */ + public static void checkFunctionStatsBinaryResponse( + Map> response, + GlideString[] runningFunction, + long libCount, + long functionCount) { + Map runningScriptInfo = response.get(gs("running_script")); + if (runningScriptInfo == null && runningFunction.length != 0) { + fail("No running function info"); + } + if (runningScriptInfo != null && runningFunction.length == 0) { + GlideString[] command = (GlideString[]) runningScriptInfo.get(gs("command")); + fail("Unexpected running function info: " + String.join(" ", Arrays.toString(command))); + } + + if (runningScriptInfo != null) { + GlideString[] command = (GlideString[]) runningScriptInfo.get(gs("command")); + assertArrayEquals(runningFunction, command); + // command line format is: + // fcall|fcall_ro * * + assertEquals(runningFunction[1], runningScriptInfo.get(gs("name"))); + } + var expected = + Map.of( + gs("LUA"), + Map.of(gs("libraries_count"), libCount, gs("functions_count"), functionCount)); + assertEquals(expected, response.get(gs("engines"))); + } + /** Generate a String of LUA library code. */ public static String generateLuaLibCode( String libName, Map functions, boolean readonly) { diff --git a/java/integTest/src/test/java/glide/cluster/CommandTests.java b/java/integTest/src/test/java/glide/cluster/CommandTests.java index 6a9e098ce9..be9d29d4cf 100644 --- a/java/integTest/src/test/java/glide/cluster/CommandTests.java +++ b/java/integTest/src/test/java/glide/cluster/CommandTests.java @@ -4,6 +4,7 @@ import static glide.TestConfiguration.REDIS_VERSION; import static glide.TestUtilities.assertDeepEquals; import static glide.TestUtilities.checkFunctionListResponse; +import static glide.TestUtilities.checkFunctionStatsBinaryResponse; import static glide.TestUtilities.checkFunctionStatsResponse; import static glide.TestUtilities.commonClusterClientConfig; import static glide.TestUtilities.createLuaLibWithLongRunningFunction; @@ -1806,6 +1807,86 @@ public void functionStats_and_functionKill_without_route() { assertTrue(error.isEmpty(), "Something went wrong during the test"); } + @Test + @SneakyThrows + public void functionStatsBinary_and_functionKill_without_route() { + assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0"), "This feature added in redis 7"); + + GlideString libName = gs("functionStats_and_functionKill_without_route"); + GlideString funcName = gs("deadlock_without_route"); + GlideString code = + gs(createLuaLibWithLongRunningFunction(libName.toString(), funcName.toString(), 15, true)); + String error = ""; + + assertEquals(OK, clusterClient.functionFlush(SYNC).get()); + + try { + // nothing to kill + var exception = + assertThrows(ExecutionException.class, () -> clusterClient.functionKill().get()); + assertInstanceOf(RequestException.class, exception.getCause()); + assertTrue(exception.getMessage().toLowerCase().contains("notbusy")); + + // load the lib + assertEquals(libName, clusterClient.functionLoad(code, true).get()); + + try (var testClient = + RedisClusterClient.CreateClient(commonClusterClientConfig().requestTimeout(7000).build()) + .get()) { + // call the function without await + // Using a random primary node route, otherwise FCALL can go to a replica. + // FKILL and FSTATS go to primary nodes if no route given, test fails in such case. + Route route = new SlotKeyRoute(UUID.randomUUID().toString(), PRIMARY); + var promise = testClient.fcall(funcName, route); + + int timeout = 5200; // ms + while (timeout > 0) { + var response = clusterClient.functionStatsBinary().get().getMultiValue(); + boolean found = false; + for (var stats : response.values()) { + if (stats.get(gs("running_script")) != null) { + found = true; + checkFunctionStatsBinaryResponse( + stats, new GlideString[] {gs("FCALL"), funcName, gs("0")}, 1, 1); + break; + } + } + if (found) { + break; + } + Thread.sleep(100); + timeout -= 100; + } + if (timeout == 0) { + error += "Can't find a running function."; + } + + assertEquals(OK, clusterClient.functionKill().get()); + Thread.sleep(404); // sometimes kill doesn't happen immediately + + exception = + assertThrows(ExecutionException.class, () -> clusterClient.functionKill().get()); + assertInstanceOf(RequestException.class, exception.getCause()); + assertTrue(exception.getMessage().toLowerCase().contains("notbusy")); + + exception = assertThrows(ExecutionException.class, promise::get); + assertInstanceOf(RequestException.class, exception.getCause()); + assertTrue(exception.getMessage().contains("Script killed by user")); + } + } finally { + // If function wasn't killed, and it didn't time out - it blocks the server and cause rest + // test to fail. + try { + clusterClient.functionKill().get(); + // should throw `notbusy` error, because the function should be killed before + error += "Function should be killed before."; + } catch (Exception ignored) { + } + } + + assertTrue(error.isEmpty(), "Something went wrong during the test"); + } + @ParameterizedTest(name = "single node route = {0}") @ValueSource(booleans = {true, false}) @SneakyThrows @@ -1893,6 +1974,96 @@ public void functionStats_and_functionKill_with_route(boolean singleNodeRoute) { assertTrue(error.isEmpty(), "Something went wrong during the test"); } + @ParameterizedTest(name = "single node route = {0}") + @ValueSource(booleans = {true, false}) + @SneakyThrows + public void functionStatsBinary_and_functionKill_with_route(boolean singleNodeRoute) { + assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0"), "This feature added in redis 7"); + + GlideString libName = gs("functionStats_and_functionKill_with_route_" + singleNodeRoute); + GlideString funcName = gs("deadlock_with_route_" + singleNodeRoute); + GlideString code = + gs(createLuaLibWithLongRunningFunction(libName.toString(), funcName.toString(), 15, true)); + Route route = + singleNodeRoute ? new SlotKeyRoute(UUID.randomUUID().toString(), PRIMARY) : ALL_PRIMARIES; + String error = ""; + + assertEquals(OK, clusterClient.functionFlush(SYNC, route).get()); + + try { + // nothing to kill + var exception = + assertThrows(ExecutionException.class, () -> clusterClient.functionKill(route).get()); + assertInstanceOf(RequestException.class, exception.getCause()); + assertTrue(exception.getMessage().toLowerCase().contains("notbusy")); + + // load the lib + assertEquals(libName, clusterClient.functionLoad(code, true, route).get()); + + try (var testClient = + RedisClusterClient.CreateClient(commonClusterClientConfig().requestTimeout(7000).build()) + .get()) { + // call the function without await + var promise = testClient.fcall(funcName, route); + + int timeout = 5200; // ms + while (timeout > 0) { + var response = clusterClient.functionStatsBinary(route).get(); + if (singleNodeRoute) { + var stats = response.getSingleValue(); + if (stats.get(gs("running_script")) != null) { + checkFunctionStatsBinaryResponse( + stats, new GlideString[] {gs("FCALL"), funcName, gs("0")}, 1, 1); + break; + } + } else { + boolean found = false; + for (var stats : response.getMultiValue().values()) { + if (stats.get(gs("running_script")) != null) { + found = true; + checkFunctionStatsBinaryResponse( + stats, new GlideString[] {gs("FCALL"), funcName, gs("0")}, 1, 1); + break; + } + } + if (found) { + break; + } + } + Thread.sleep(100); + timeout -= 100; + } + if (timeout == 0) { + error += "Can't find a running function."; + } + + // redis kills a function with 5 sec delay + assertEquals(OK, clusterClient.functionKill(route).get()); + Thread.sleep(404); // sometimes kill doesn't happen immediately + + exception = + assertThrows(ExecutionException.class, () -> clusterClient.functionKill(route).get()); + assertInstanceOf(RequestException.class, exception.getCause()); + assertTrue(exception.getMessage().toLowerCase().contains("notbusy")); + + exception = assertThrows(ExecutionException.class, promise::get); + assertInstanceOf(RequestException.class, exception.getCause()); + assertTrue(exception.getMessage().contains("Script killed by user")); + } + } finally { + // If function wasn't killed, and it didn't time out - it blocks the server and cause rest + // test to fail. + try { + clusterClient.functionKill(route).get(); + // should throw `notbusy` error, because the function should be killed before + error += "Function should be killed before."; + } catch (Exception ignored) { + } + } + + assertTrue(error.isEmpty(), "Something went wrong during the test"); + } + @Test @SneakyThrows public void functionStats_and_functionKill_with_key_based_route() { @@ -1964,6 +2135,79 @@ public void functionStats_and_functionKill_with_key_based_route() { assertTrue(error.isEmpty(), "Something went wrong during the test"); } + @Test + @SneakyThrows + public void functionStatsBinary_and_functionKill_with_key_based_route() { + assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0"), "This feature added in redis 7"); + + GlideString libName = gs("functionStats_and_functionKill_with_key_based_route"); + GlideString funcName = gs("deadlock_with_key_based_route"); + GlideString key = libName; + GlideString code = + gs(createLuaLibWithLongRunningFunction(libName.toString(), funcName.toString(), 15, true)); + Route route = new SlotKeyRoute(key.toString(), PRIMARY); + String error = ""; + + assertEquals(OK, clusterClient.functionFlush(SYNC, route).get()); + + try { + // nothing to kill + var exception = + assertThrows(ExecutionException.class, () -> clusterClient.functionKill(route).get()); + assertInstanceOf(RequestException.class, exception.getCause()); + assertTrue(exception.getMessage().toLowerCase().contains("notbusy")); + + // load the lib + assertEquals(libName, clusterClient.functionLoad(code, true, route).get()); + + try (var testClient = + RedisClusterClient.CreateClient(commonClusterClientConfig().requestTimeout(7000).build()) + .get()) { + // call the function without await + var promise = testClient.fcall(funcName, new GlideString[] {key}, new GlideString[0]); + + int timeout = 5200; // ms + while (timeout > 0) { + var stats = clusterClient.functionStatsBinary(route).get().getSingleValue(); + if (stats.get(gs("running_script")) != null) { + checkFunctionStatsBinaryResponse( + stats, new GlideString[] {gs("FCALL"), funcName, gs("1"), key}, 1, 1); + break; + } + Thread.sleep(100); + timeout -= 100; + } + if (timeout == 0) { + error += "Can't find a running function."; + } + + // redis kills a function with 5 sec delay + assertEquals(OK, clusterClient.functionKill(route).get()); + Thread.sleep(404); // sometimes kill doesn't happen immediately + + exception = + assertThrows(ExecutionException.class, () -> clusterClient.functionKill(route).get()); + assertInstanceOf(RequestException.class, exception.getCause()); + assertTrue(exception.getMessage().toLowerCase().contains("notbusy")); + + exception = assertThrows(ExecutionException.class, promise::get); + assertInstanceOf(RequestException.class, exception.getCause()); + assertTrue(exception.getMessage().contains("Script killed by user")); + } + } finally { + // If function wasn't killed, and it didn't time out - it blocks the server and cause rest + // test to fail. + try { + clusterClient.functionKill(route).get(); + // should throw `notbusy` error, because the function should be killed before + error += "Function should be killed before."; + } catch (Exception ignored) { + } + } + + assertTrue(error.isEmpty(), "Something went wrong during the test"); + } + @Test @SneakyThrows public void functionStats_and_functionKill_write_function() { @@ -2035,6 +2279,79 @@ public void functionStats_and_functionKill_write_function() { assertTrue(error.isEmpty(), "Something went wrong during the test"); } + @Test + @SneakyThrows + public void functionStatsBinary_and_functionKill_write_function() { + assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0"), "This feature added in redis 7"); + + GlideString libName = gs("functionStats_and_functionKill_write_function"); + GlideString funcName = gs("deadlock_write_function_with_key_based_route"); + GlideString key = libName; + GlideString code = + gs(createLuaLibWithLongRunningFunction(libName.toString(), funcName.toString(), 6, false)); + Route route = new SlotKeyRoute(key.toString(), PRIMARY); + String error = ""; + + assertEquals(OK, clusterClient.functionFlush(SYNC, route).get()); + + try { + // nothing to kill + var exception = + assertThrows(ExecutionException.class, () -> clusterClient.functionKill(route).get()); + assertInstanceOf(RequestException.class, exception.getCause()); + assertTrue(exception.getMessage().toLowerCase().contains("notbusy")); + + // load the lib + assertEquals(libName, clusterClient.functionLoad(code, true, route).get()); + + try (var testClient = + RedisClusterClient.CreateClient(commonClusterClientConfig().requestTimeout(7000).build()) + .get()) { + // call the function without await + var promise = testClient.fcall(funcName, new GlideString[] {key}, new GlideString[0]); + + int timeout = 5200; // ms + while (timeout > 0) { + var stats = clusterClient.functionStatsBinary(route).get().getSingleValue(); + if (stats.get(gs("running_script")) != null) { + checkFunctionStatsBinaryResponse( + stats, new GlideString[] {gs("FCALL"), funcName, gs("1"), key}, 1, 1); + break; + } + Thread.sleep(100); + timeout -= 100; + } + if (timeout == 0) { + error += "Can't find a running function."; + } + + // redis kills a function with 5 sec delay + exception = + assertThrows(ExecutionException.class, () -> clusterClient.functionKill(route).get()); + assertInstanceOf(RequestException.class, exception.getCause()); + assertTrue(exception.getMessage().toLowerCase().contains("unkillable")); + + assertEquals("Timed out 6 sec", promise.get()); + + exception = + assertThrows(ExecutionException.class, () -> clusterClient.functionKill(route).get()); + assertInstanceOf(RequestException.class, exception.getCause()); + assertTrue(exception.getMessage().toLowerCase().contains("notbusy")); + } + } finally { + // If function wasn't killed, and it didn't time out - it blocks the server and cause rest + // test to fail. + try { + clusterClient.functionKill(route).get(); + // should throw `notbusy` error, because the function should be killed before + error += "Function should finish prior to the test end."; + } catch (Exception ignored) { + } + } + + assertTrue(error.isEmpty(), "Something went wrong during the test"); + } + @Test @SneakyThrows public void functionStats_without_route() { @@ -2073,6 +2390,49 @@ public void functionStats_without_route() { } } + @Test + @SneakyThrows + public void functionStatsBinary_without_route() { + assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0"), "This feature added in redis 7"); + + GlideString libName = gs("functionStats_without_route"); + GlideString funcName = libName; + assertEquals(OK, clusterClient.functionFlush(SYNC).get()); + + // function $funcName returns first argument + GlideString code = + generateLuaLibCodeBinary(libName, Map.of(funcName, gs("return args[1]")), false); + assertEquals(libName, clusterClient.functionLoad(code, true).get()); + + var response = clusterClient.functionStatsBinary().get().getMultiValue(); + for (var nodeResponse : response.values()) { + checkFunctionStatsBinaryResponse(nodeResponse, new GlideString[0], 1, 1); + } + + code = + generateLuaLibCodeBinary( + gs(libName.toString() + "_2"), + Map.of( + gs(funcName.toString() + "_2"), + gs("return 'OK'"), + gs(funcName.toString() + "_3"), + gs("return 42")), + false); + assertEquals(gs(libName.toString() + "_2"), clusterClient.functionLoad(code, true).get()); + + response = clusterClient.functionStatsBinary().get().getMultiValue(); + for (var nodeResponse : response.values()) { + checkFunctionStatsBinaryResponse(nodeResponse, new GlideString[0], 2, 3); + } + + assertEquals(OK, clusterClient.functionFlush(SYNC).get()); + + response = clusterClient.functionStatsBinary().get().getMultiValue(); + for (var nodeResponse : response.values()) { + checkFunctionStatsBinaryResponse(nodeResponse, new GlideString[0], 0, 0); + } + } + @ParameterizedTest(name = "single node route = {0}") @ValueSource(booleans = {true, false}) @SneakyThrows @@ -2126,6 +2486,65 @@ public void functionStats_with_route(boolean singleNodeRoute) { } } + @ParameterizedTest(name = "single node route = {0}") + @ValueSource(booleans = {true, false}) + @SneakyThrows + public void functionStatsBinary_with_route(boolean singleNodeRoute) { + assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0"), "This feature added in redis 7"); + Route route = + singleNodeRoute ? new SlotKeyRoute(UUID.randomUUID().toString(), PRIMARY) : ALL_PRIMARIES; + GlideString libName = gs("functionStats_with_route_" + singleNodeRoute); + GlideString funcName = libName; + + assertEquals(OK, clusterClient.functionFlush(SYNC, route).get()); + + // function $funcName returns first argument + GlideString code = + generateLuaLibCodeBinary(libName, Map.of(funcName, gs("return args[1]")), false); + assertEquals(libName, clusterClient.functionLoad(code, true, route).get()); + + var response = clusterClient.functionStatsBinary(route).get(); + if (singleNodeRoute) { + checkFunctionStatsBinaryResponse(response.getSingleValue(), new GlideString[0], 1, 1); + } else { + for (var nodeResponse : response.getMultiValue().values()) { + checkFunctionStatsBinaryResponse(nodeResponse, new GlideString[0], 1, 1); + } + } + + code = + generateLuaLibCodeBinary( + gs(libName.toString() + "_2"), + Map.of( + gs(funcName.toString() + "_2"), + gs("return 'OK'"), + gs(funcName.toString() + "_3"), + gs("return 42")), + false); + assertEquals( + gs(libName.toString() + "_2"), clusterClient.functionLoad(code, true, route).get()); + + response = clusterClient.functionStatsBinary(route).get(); + if (singleNodeRoute) { + checkFunctionStatsBinaryResponse(response.getSingleValue(), new GlideString[0], 2, 3); + } else { + for (var nodeResponse : response.getMultiValue().values()) { + checkFunctionStatsBinaryResponse(nodeResponse, new GlideString[0], 2, 3); + } + } + + assertEquals(OK, clusterClient.functionFlush(SYNC, route).get()); + + response = clusterClient.functionStatsBinary(route).get(); + if (singleNodeRoute) { + checkFunctionStatsBinaryResponse(response.getSingleValue(), new GlideString[0], 0, 0); + } else { + for (var nodeResponse : response.getMultiValue().values()) { + checkFunctionStatsBinaryResponse(nodeResponse, new GlideString[0], 0, 0); + } + } + } + @Test @SneakyThrows public void function_dump_and_restore() { diff --git a/java/integTest/src/test/java/glide/standalone/CommandTests.java b/java/integTest/src/test/java/glide/standalone/CommandTests.java index c8f4c17b58..a02bfe690b 100644 --- a/java/integTest/src/test/java/glide/standalone/CommandTests.java +++ b/java/integTest/src/test/java/glide/standalone/CommandTests.java @@ -4,6 +4,7 @@ import static glide.TestConfiguration.REDIS_VERSION; import static glide.TestUtilities.assertDeepEquals; import static glide.TestUtilities.checkFunctionListResponse; +import static glide.TestUtilities.checkFunctionStatsBinaryResponse; import static glide.TestUtilities.checkFunctionStatsResponse; import static glide.TestUtilities.commonClientConfig; import static glide.TestUtilities.createLuaLibWithLongRunningFunction; @@ -805,6 +806,78 @@ public void functionStats_and_functionKill() { assertTrue(error.isEmpty(), "Something went wrong during the test"); } + @Test + @SneakyThrows + public void functionStatsBinary_and_functionKill() { + assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0"), "This feature added in redis 7"); + + GlideString libName = gs("functionStats_and_functionKill"); + GlideString funcName = gs("deadlock"); + GlideString code = + gs(createLuaLibWithLongRunningFunction(libName.toString(), funcName.toString(), 15, true)); + String error = ""; + + assertEquals(OK, regularClient.functionFlush(SYNC).get()); + + try { + // nothing to kill + var exception = + assertThrows(ExecutionException.class, () -> regularClient.functionKill().get()); + assertInstanceOf(RequestException.class, exception.getCause()); + assertTrue(exception.getMessage().toLowerCase().contains("notbusy")); + + // load the lib + assertEquals(libName, regularClient.functionLoad(code, true).get()); + + try (var testClient = + RedisClient.CreateClient(commonClientConfig().requestTimeout(7000).build()).get()) { + // call the function without await + var promise = testClient.fcall(funcName); + + int timeout = 5200; // ms + while (timeout > 0) { + var stats = regularClient.functionStatsBinary().get(); + if (stats.get(gs("running_script")) != null) { + checkFunctionStatsBinaryResponse( + stats, new GlideString[] {gs("FCALL"), funcName, gs("0")}, 1, 1); + break; + } + Thread.sleep(100); + timeout -= 100; + } + if (timeout == 0) { + error += "Can't find a running function."; + } + + // redis kills a function with 5 sec delay + assertEquals(OK, regularClient.functionKill().get()); + Thread.sleep(404); // sometimes kill doesn't happen immediately + + exception = + assertThrows(ExecutionException.class, () -> regularClient.functionKill().get()); + assertInstanceOf(RequestException.class, exception.getCause()); + assertTrue(exception.getMessage().toLowerCase().contains("notbusy")); + + exception = assertThrows(ExecutionException.class, promise::get); + assertInstanceOf(RequestException.class, exception.getCause()); + assertTrue(exception.getMessage().contains("Script killed by user")); + } + } finally { + // If function wasn't killed, and it didn't time out - it blocks the server and cause rest + // test to fail. + try { + regularClient.functionKill().get(); + // should throw `notbusy` error, because the function should be killed before + error += "Function should be killed before."; + } catch (Exception ignored) { + } + } + + assertEquals(OK, regularClient.functionDelete(libName).get()); + + assertTrue(error.isEmpty(), "Something went wrong during the test"); + } + @Test @SneakyThrows public void functionStats_and_functionKill_write_function() { @@ -874,6 +947,77 @@ public void functionStats_and_functionKill_write_function() { assertTrue(error.isEmpty(), "Something went wrong during the test"); } + @Test + @SneakyThrows + public void functionStatsBinary_and_functionKill_write_function() { + assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0"), "This feature added in redis 7"); + + GlideString libName = gs("functionStats_and_functionKill_write_function"); + GlideString funcName = gs("deadlock_write_function"); + GlideString key = libName; + GlideString code = + gs(createLuaLibWithLongRunningFunction(libName.toString(), funcName.toString(), 6, false)); + String error = ""; + + assertEquals(OK, regularClient.functionFlush(SYNC).get()); + + try { + // nothing to kill + var exception = + assertThrows(ExecutionException.class, () -> regularClient.functionKill().get()); + assertInstanceOf(RequestException.class, exception.getCause()); + assertTrue(exception.getMessage().toLowerCase().contains("notbusy")); + + // load the lib + assertEquals(libName, regularClient.functionLoad(code, true).get()); + + try (var testClient = + RedisClient.CreateClient(commonClientConfig().requestTimeout(7000).build()).get()) { + // call the function without awai + var promise = testClient.fcall(funcName, new GlideString[] {key}, new GlideString[0]); + + int timeout = 5200; // ms + while (timeout > 0) { + var stats = regularClient.functionStatsBinary().get(); + if (stats.get(gs("running_script")) != null) { + checkFunctionStatsBinaryResponse( + stats, new GlideString[] {gs("FCALL"), funcName, gs("1"), key}, 1, 1); + break; + } + Thread.sleep(100); + timeout -= 100; + } + if (timeout == 0) { + error += "Can't find a running function."; + } + + // can't kill a write function + exception = + assertThrows(ExecutionException.class, () -> regularClient.functionKill().get()); + assertInstanceOf(RequestException.class, exception.getCause()); + assertTrue(exception.getMessage().toLowerCase().contains("unkillable")); + + assertEquals("Timed out 6 sec", promise.get()); + + exception = + assertThrows(ExecutionException.class, () -> regularClient.functionKill().get()); + assertInstanceOf(RequestException.class, exception.getCause()); + assertTrue(exception.getMessage().toLowerCase().contains("notbusy")); + } + } finally { + // If function wasn't killed, and it didn't time out - it blocks the server and cause rest + // test to fail. + try { + regularClient.functionKill().get(); + // should throw `notbusy` error, because the function should be killed before + error += "Function should finish prior to the test end."; + } catch (Exception ignored) { + } + } + + assertTrue(error.isEmpty(), "Something went wrong during the test"); + } + @Test @SneakyThrows public void functionStats() { @@ -906,6 +1050,43 @@ public void functionStats() { checkFunctionStatsResponse(response, new String[0], 0, 0); } + @Test + @SneakyThrows + public void functionStatsBinary() { + assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0"), "This feature added in redis 7"); + + GlideString libName = gs("functionStats"); + GlideString funcName = libName; + assertEquals(OK, regularClient.functionFlush(SYNC).get()); + + // function $funcName returns first argument + GlideString code = + generateLuaLibCodeBinary(libName, Map.of(funcName, gs("return args[1]")), false); + assertEquals(libName, regularClient.functionLoad(code, true).get()); + + var response = regularClient.functionStatsBinary().get(); + checkFunctionStatsBinaryResponse(response, new GlideString[0], 1, 1); + + code = + generateLuaLibCodeBinary( + gs(libName.toString() + "_2"), + Map.of( + gs(funcName.toString() + "_2"), + gs("return 'OK'"), + gs(funcName.toString() + "_3"), + gs("return 42")), + false); + assertEquals(gs(libName.toString() + "_2"), regularClient.functionLoad(code, true).get()); + + response = regularClient.functionStatsBinary().get(); + checkFunctionStatsBinaryResponse(response, new GlideString[0], 2, 3); + + assertEquals(OK, regularClient.functionFlush(SYNC).get()); + + response = regularClient.functionStatsBinary().get(); + checkFunctionStatsBinaryResponse(response, new GlideString[0], 0, 0); + } + @Test @SneakyThrows public void function_dump_and_restore() { From 4b61e9f85abd40462b27e89fcf22c1c8fcde46e7 Mon Sep 17 00:00:00 2001 From: Alon Arenberg <93711356+alon-arenberg@users.noreply.github.com> Date: Thu, 4 Jul 2024 11:04:23 +0300 Subject: [PATCH 10/23] remove using toGlideStringArgs() and use ArgsBuilder instead (#1782) --- .../src/main/java/glide/api/BaseClient.java | 46 ++++++++++--------- .../src/main/java/glide/api/RedisClient.java | 16 +++++-- .../java/glide/api/RedisClusterClient.java | 16 +++++-- .../api/models/commands/ExpireOptions.java | 10 ---- .../api/models/commands/LPosOptions.java | 11 ----- .../glide/api/models/commands/SetOptions.java | 11 ----- .../api/models/commands/SortBaseOptions.java | 11 ----- .../models/commands/SortOptionsBinary.java | 12 +---- .../commands/scan/BaseScanOptionsBinary.java | 12 +---- 9 files changed, 49 insertions(+), 96 deletions(-) diff --git a/java/client/src/main/java/glide/api/BaseClient.java b/java/client/src/main/java/glide/api/BaseClient.java index 18f7de5e1e..d0b71a9c45 100644 --- a/java/client/src/main/java/glide/api/BaseClient.java +++ b/java/client/src/main/java/glide/api/BaseClient.java @@ -745,7 +745,7 @@ public CompletableFuture getex(@NonNull String key, @NonNull GetExOption @Override public CompletableFuture getex( @NonNull GlideString key, @NonNull GetExOptions options) { - GlideString[] arguments = ArrayUtils.addFirst(options.toGlideStringArgs(), key); + GlideString[] arguments = new ArgsBuilder().add(key).add(options.toArgs()).toArray(); return commandManager.submitNewCommand(GetEx, arguments, this::handleGlideStringOrNullResponse); } @@ -771,8 +771,7 @@ public CompletableFuture set( @Override public CompletableFuture set( @NonNull GlideString key, @NonNull GlideString value, @NonNull SetOptions options) { - GlideString[] arguments = - ArrayUtils.addAll(new GlideString[] {key, value}, options.toGlideStringArgs()); + GlideString[] arguments = new ArgsBuilder().add(key).add(value).add(options.toArgs()).toArray(); return commandManager.submitNewCommand(Set, arguments, this::handleStringOrNullResponse); } @@ -1266,7 +1265,7 @@ public CompletableFuture lpos( public CompletableFuture lpos( @NonNull GlideString key, @NonNull GlideString element, @NonNull LPosOptions options) { GlideString[] arguments = - concatenateArrays(new GlideString[] {key, element}, options.toGlideStringArgs()); + new ArgsBuilder().add(key).add(element).add(options.toArgs()).toArray(); return commandManager.submitNewCommand(LPos, arguments, this::handleLongOrNullResponse); } @@ -1306,9 +1305,13 @@ public CompletableFuture lposCount( long count, @NonNull LPosOptions options) { GlideString[] arguments = - concatenateArrays( - new GlideString[] {key, element, gs(COUNT_REDIS_API), gs(Long.toString(count))}, - options.toGlideStringArgs()); + new ArgsBuilder() + .add(key) + .add(element) + .add(COUNT_REDIS_API) + .add(count) + .add(options.toArgs()) + .toArray(); return commandManager.submitNewCommand( LPos, arguments, response -> castArray(handleArrayResponse(response), Long.class)); @@ -1614,8 +1617,8 @@ public CompletableFuture expire( public CompletableFuture expire( @NonNull GlideString key, long seconds, @NonNull ExpireOptions expireOptions) { GlideString[] arguments = - ArrayUtils.addAll( - new GlideString[] {key, gs(Long.toString(seconds))}, expireOptions.toGlideStringArgs()); + new ArgsBuilder().add(key).add(seconds).add(expireOptions.toArgs()).toArray(); + return commandManager.submitNewCommand(Expire, arguments, this::handleBooleanResponse); } @@ -1645,9 +1648,7 @@ public CompletableFuture expireAt( public CompletableFuture expireAt( @NonNull GlideString key, long unixSeconds, @NonNull ExpireOptions expireOptions) { GlideString[] arguments = - ArrayUtils.addAll( - new GlideString[] {key, gs(Long.toString(unixSeconds))}, - expireOptions.toGlideStringArgs()); + new ArgsBuilder().add(key).add(unixSeconds).add(expireOptions.toArgs()).toArray(); return commandManager.submitNewCommand(ExpireAt, arguments, this::handleBooleanResponse); } @@ -1677,9 +1678,7 @@ public CompletableFuture pexpire( public CompletableFuture pexpire( @NonNull GlideString key, long milliseconds, @NonNull ExpireOptions expireOptions) { GlideString[] arguments = - ArrayUtils.addAll( - new GlideString[] {key, gs(Long.toString(milliseconds))}, - expireOptions.toGlideStringArgs()); + new ArgsBuilder().add(key).add(milliseconds).add(expireOptions.toArgs()).toArray(); return commandManager.submitNewCommand(PExpire, arguments, this::handleBooleanResponse); } @@ -1712,9 +1711,8 @@ public CompletableFuture pexpireAt( public CompletableFuture pexpireAt( @NonNull GlideString key, long unixMilliseconds, @NonNull ExpireOptions expireOptions) { GlideString[] arguments = - ArrayUtils.addAll( - new GlideString[] {key, gs(Long.toString(unixMilliseconds))}, - expireOptions.toGlideStringArgs()); + new ArgsBuilder().add(key).add(unixMilliseconds).add(expireOptions.toArgs()).toArray(); + return commandManager.submitNewCommand(PExpireAt, arguments, this::handleBooleanResponse); } @@ -2314,7 +2312,8 @@ public CompletableFuture xtrim(@NonNull String key, @NonNull StreamTrimOpt @Override public CompletableFuture xtrim( @NonNull GlideString key, @NonNull StreamTrimOptions options) { - GlideString[] arguments = ArrayUtils.addFirst(options.toGlideStringArgs(), key); + GlideString[] arguments = new ArgsBuilder().add(key).add(options.toArgs()).toArray(); + return commandManager.submitNewCommand(XTrim, arguments, this::handleLongResponse); } @@ -4161,7 +4160,8 @@ public CompletableFuture sscan( @NonNull GlideString cursor, @NonNull SScanOptionsBinary sScanOptions) { GlideString[] arguments = - concatenateArrays(new GlideString[] {key, cursor}, sScanOptions.toGlideStringArgs()); + new ArgsBuilder().add(key).add(cursor).add(sScanOptions.toArgs()).toArray(); + return commandManager.submitNewCommand(SScan, arguments, this::handleArrayOrNullResponseBinary); } @@ -4190,7 +4190,8 @@ public CompletableFuture zscan( @NonNull GlideString cursor, @NonNull ZScanOptionsBinary zScanOptions) { GlideString[] arguments = - concatenateArrays(new GlideString[] {key, cursor}, zScanOptions.toGlideStringArgs()); + new ArgsBuilder().add(key).add(cursor).add(zScanOptions.toArgs()).toArray(); + return commandManager.submitNewCommand(ZScan, arguments, this::handleArrayOrNullResponseBinary); } @@ -4219,7 +4220,8 @@ public CompletableFuture hscan( @NonNull GlideString cursor, @NonNull HScanOptionsBinary hScanOptions) { GlideString[] arguments = - concatenateArrays(new GlideString[] {key, cursor}, hScanOptions.toGlideStringArgs()); + new ArgsBuilder().add(key).add(cursor).add(hScanOptions.toArgs()).toArray(); + return commandManager.submitNewCommand(HScan, arguments, this::handleArrayOrNullResponseBinary); } diff --git a/java/client/src/main/java/glide/api/RedisClient.java b/java/client/src/main/java/glide/api/RedisClient.java index 5f699d39ec..568af95702 100644 --- a/java/client/src/main/java/glide/api/RedisClient.java +++ b/java/client/src/main/java/glide/api/RedisClient.java @@ -48,6 +48,7 @@ import glide.api.commands.ScriptingAndFunctionsCommands; import glide.api.commands.ServerManagementCommands; import glide.api.commands.TransactionsCommands; +import glide.api.models.ArgsBuilder; import glide.api.models.GlideString; import glide.api.models.Transaction; import glide.api.models.commands.FlushMode; @@ -450,7 +451,7 @@ public CompletableFuture sort(@NonNull String key, @NonNull SortOption @Override public CompletableFuture sort( @NonNull GlideString key, @NonNull SortOptionsBinary sortOptions) { - GlideString[] arguments = ArrayUtils.addFirst(sortOptions.toGlideStringArgs(), key); + GlideString[] arguments = new ArgsBuilder().add(key).add(sortOptions.toArgs()).toArray(); return commandManager.submitNewCommand( Sort, arguments, @@ -470,7 +471,8 @@ public CompletableFuture sortReadOnly( @Override public CompletableFuture sortReadOnly( @NonNull GlideString key, @NonNull SortOptionsBinary sortOptions) { - GlideString[] arguments = ArrayUtils.addFirst(sortOptions.toGlideStringArgs(), key); + GlideString[] arguments = new ArgsBuilder().add(key).add(sortOptions.toArgs()).toArray(); + return commandManager.submitNewCommand( SortReadOnly, arguments, @@ -491,9 +493,15 @@ public CompletableFuture sortStore( @NonNull GlideString key, @NonNull GlideString destination, @NonNull SortOptionsBinary sortOptions) { - GlideString[] storeArguments = new GlideString[] {gs(STORE_COMMAND_STRING), destination}; + GlideString[] arguments = - concatenateArrays(new GlideString[] {key}, sortOptions.toGlideStringArgs(), storeArguments); + new ArgsBuilder() + .add(key) + .add(sortOptions.toArgs()) + .add(STORE_COMMAND_STRING) + .add(destination) + .toArray(); + return commandManager.submitNewCommand(Sort, arguments, this::handleLongResponse); } diff --git a/java/client/src/main/java/glide/api/RedisClusterClient.java b/java/client/src/main/java/glide/api/RedisClusterClient.java index fe3814b0db..89517ec581 100644 --- a/java/client/src/main/java/glide/api/RedisClusterClient.java +++ b/java/client/src/main/java/glide/api/RedisClusterClient.java @@ -51,6 +51,7 @@ import glide.api.commands.ServerManagementClusterCommands; import glide.api.commands.TransactionsClusterCommands; import glide.api.logging.Logger; +import glide.api.models.ArgsBuilder; import glide.api.models.ClusterTransaction; import glide.api.models.ClusterValue; import glide.api.models.GlideString; @@ -987,7 +988,8 @@ public CompletableFuture sort( @Override public CompletableFuture sort( @NonNull GlideString key, @NonNull SortClusterOptions sortClusterOptions) { - GlideString[] arguments = ArrayUtils.addFirst(sortClusterOptions.toGlideStringArgs(), key); + GlideString[] arguments = new ArgsBuilder().add(key).add(sortClusterOptions.toArgs()).toArray(); + return commandManager.submitNewCommand( Sort, arguments, @@ -1007,7 +1009,7 @@ public CompletableFuture sortReadOnly( @Override public CompletableFuture sortReadOnly( @NonNull GlideString key, @NonNull SortClusterOptions sortClusterOptions) { - GlideString[] arguments = ArrayUtils.addFirst(sortClusterOptions.toGlideStringArgs(), key); + GlideString[] arguments = new ArgsBuilder().add(key).add(sortClusterOptions.toArgs()).toArray(); return commandManager.submitNewCommand( SortReadOnly, arguments, @@ -1030,10 +1032,14 @@ public CompletableFuture sortStore( @NonNull GlideString key, @NonNull GlideString destination, @NonNull SortClusterOptions sortClusterOptions) { - GlideString[] storeArguments = new GlideString[] {gs(STORE_COMMAND_STRING), destination}; GlideString[] arguments = - concatenateArrays( - new GlideString[] {key}, sortClusterOptions.toGlideStringArgs(), storeArguments); + new ArgsBuilder() + .add(key) + .add(sortClusterOptions.toArgs()) + .add(STORE_COMMAND_STRING) + .add(destination) + .toArray(); + return commandManager.submitNewCommand(Sort, arguments, this::handleLongResponse); } diff --git a/java/client/src/main/java/glide/api/models/commands/ExpireOptions.java b/java/client/src/main/java/glide/api/models/commands/ExpireOptions.java index fa2ba8942d..418696293f 100644 --- a/java/client/src/main/java/glide/api/models/commands/ExpireOptions.java +++ b/java/client/src/main/java/glide/api/models/commands/ExpireOptions.java @@ -2,7 +2,6 @@ package glide.api.models.commands; import glide.api.commands.GenericBaseCommands; -import glide.api.models.GlideString; import lombok.RequiredArgsConstructor; /** @@ -43,13 +42,4 @@ public enum ExpireOptions { public String[] toArgs() { return new String[] {this.redisApi}; } - - /** - * Converts SetOptions into a GlideString[] to add to a {@link Command} arguments. - * - * @return GlideString[] - */ - public GlideString[] toGlideStringArgs() { - return new GlideString[] {GlideString.gs(redisApi)}; - } } diff --git a/java/client/src/main/java/glide/api/models/commands/LPosOptions.java b/java/client/src/main/java/glide/api/models/commands/LPosOptions.java index f2fd96bd70..9aa02f307e 100644 --- a/java/client/src/main/java/glide/api/models/commands/LPosOptions.java +++ b/java/client/src/main/java/glide/api/models/commands/LPosOptions.java @@ -2,9 +2,7 @@ package glide.api.models.commands; import glide.api.commands.ListBaseCommands; -import glide.api.models.GlideString; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import lombok.Builder; @@ -51,13 +49,4 @@ public String[] toArgs() { return optionArgs.toArray(new String[0]); } - - /** - * Converts LPosOptions into a GlideString[]. - * - * @return GlideString[] - */ - public GlideString[] toGlideStringArgs() { - return Arrays.stream(toArgs()).map(GlideString::gs).toArray(GlideString[]::new); - } } diff --git a/java/client/src/main/java/glide/api/models/commands/SetOptions.java b/java/client/src/main/java/glide/api/models/commands/SetOptions.java index 345e3c7137..306cb2ef1d 100644 --- a/java/client/src/main/java/glide/api/models/commands/SetOptions.java +++ b/java/client/src/main/java/glide/api/models/commands/SetOptions.java @@ -8,9 +8,7 @@ import static glide.api.models.commands.SetOptions.ExpiryType.UNIX_SECONDS; import glide.api.commands.StringBaseCommands; -import glide.api.models.GlideString; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import lombok.Builder; import lombok.Getter; @@ -170,13 +168,4 @@ public String[] toArgs() { return optionArgs.toArray(new String[0]); } - - /** - * Converts SetOptions into a GlideString[] to add to a {@link Command} arguments. - * - * @return GlideString[] - */ - public GlideString[] toGlideStringArgs() { - return Arrays.stream(toArgs()).map(GlideString::gs).toArray(GlideString[]::new); - } } diff --git a/java/client/src/main/java/glide/api/models/commands/SortBaseOptions.java b/java/client/src/main/java/glide/api/models/commands/SortBaseOptions.java index 41c668c543..8140febe5f 100644 --- a/java/client/src/main/java/glide/api/models/commands/SortBaseOptions.java +++ b/java/client/src/main/java/glide/api/models/commands/SortBaseOptions.java @@ -1,9 +1,7 @@ /** Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 */ package glide.api.models.commands; -import glide.api.models.GlideString; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import lombok.RequiredArgsConstructor; import lombok.experimental.SuperBuilder; @@ -108,13 +106,4 @@ public String[] toArgs() { return optionArgs.toArray(new String[0]); } - - /** - * Creates the arguments to be used in SORT and SORT_RO commands. - * - * @return a String array that holds the sub commands and their arguments. - */ - public GlideString[] toGlideStringArgs() { - return Arrays.stream(toArgs()).map(GlideString::gs).toArray(GlideString[]::new); - } } diff --git a/java/client/src/main/java/glide/api/models/commands/SortOptionsBinary.java b/java/client/src/main/java/glide/api/models/commands/SortOptionsBinary.java index 4ccac7df3e..0741f36c0f 100644 --- a/java/client/src/main/java/glide/api/models/commands/SortOptionsBinary.java +++ b/java/client/src/main/java/glide/api/models/commands/SortOptionsBinary.java @@ -6,7 +6,6 @@ import glide.api.commands.GenericCommands; import glide.api.models.GlideString; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import lombok.Singular; import lombok.experimental.SuperBuilder; @@ -64,7 +63,7 @@ public class SortOptionsBinary extends SortBaseOptions { * * @return a String array that holds the sub commands and their arguments. */ - public String[] toStringArgs() { + public String[] toArgs() { List optionArgs = new ArrayList<>(List.of(super.toArgs())); if (byPattern != null) { @@ -81,13 +80,4 @@ public String[] toStringArgs() { return optionArgs.toArray(new String[0]); } - - /** - * Creates the arguments to be used in SORT and SORT_RO commands. - * - * @return a GlideString array that holds the sub commands and their arguments. - */ - public GlideString[] toGlideStringArgs() { - return Arrays.stream(toStringArgs()).map(GlideString::gs).toArray(GlideString[]::new); - } } diff --git a/java/client/src/main/java/glide/api/models/commands/scan/BaseScanOptionsBinary.java b/java/client/src/main/java/glide/api/models/commands/scan/BaseScanOptionsBinary.java index 10bf845e43..98d880e220 100644 --- a/java/client/src/main/java/glide/api/models/commands/scan/BaseScanOptionsBinary.java +++ b/java/client/src/main/java/glide/api/models/commands/scan/BaseScanOptionsBinary.java @@ -5,7 +5,6 @@ import glide.api.models.GlideString; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import lombok.experimental.SuperBuilder; @@ -45,7 +44,7 @@ public abstract class BaseScanOptionsBinary { * * @return a String array that holds the options and their arguments. */ - public String[] toStringArgs() { + public String[] toArgs() { List optionArgs = new ArrayList<>(); if (matchPattern != null) { @@ -60,13 +59,4 @@ public String[] toStringArgs() { return optionArgs.toArray(new String[0]); } - - /** - * Creates the arguments to be used in SCAN commands. - * - * @return a GlideString array that holds the options and their arguments. - */ - public GlideString[] toGlideStringArgs() { - return Arrays.stream(toStringArgs()).map(GlideString::gs).toArray(GlideString[]::new); - } } From b863832df9da2c9f8a411d3c24f01aadb24b43d3 Mon Sep 17 00:00:00 2001 From: Shoham Elias <116083498+shohamazon@users.noreply.github.com> Date: Thu, 4 Jul 2024 11:34:32 +0300 Subject: [PATCH 11/23] Python: renaming tests clients (#1780) --- python/python/tests/conftest.py | 2 +- python/python/tests/test_async_client.py | 4504 ++++++++--------- python/python/tests/test_scan.py | 124 +- python/python/tests/test_transaction.py | 124 +- .../tests/tests_redis_modules/test_json.py | 96 +- 5 files changed, 2425 insertions(+), 2425 deletions(-) diff --git a/python/python/tests/conftest.py b/python/python/tests/conftest.py index 6006280e1d..1f7548b954 100644 --- a/python/python/tests/conftest.py +++ b/python/python/tests/conftest.py @@ -204,7 +204,7 @@ def pytest_collection_modifyitems(config, items): @pytest.fixture() -async def redis_client( +async def glide_client( request, cluster_mode: bool, protocol: ProtocolVersion ) -> AsyncGenerator[TGlideClient, None]: "Get async socket client for tests" diff --git a/python/python/tests/test_async_client.py b/python/python/tests/test_async_client.py index b4a9106b02..cf2c1ae596 100644 --- a/python/python/tests/test_async_client.py +++ b/python/python/tests/test_async_client.py @@ -107,12 +107,12 @@ class TestGlideClients: @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_register_client_name_and_version(self, redis_client: TGlideClient): + async def test_register_client_name_and_version(self, glide_client: TGlideClient): min_version = "7.2.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): # TODO: change it to pytest fixture after we'll implement a sync client return pytest.mark.skip(reason=f"Redis version required >= {min_version}") - info = await redis_client.custom_command(["CLIENT", "INFO"]) + info = await glide_client.custom_command(["CLIENT", "INFO"]) assert isinstance(info, bytes) info_str = info.decode() assert "lib-name=GlidePy" in info_str @@ -121,7 +121,7 @@ async def test_register_client_name_and_version(self, redis_client: TGlideClient @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_send_and_receive_large_values(self, request, cluster_mode, protocol): - redis_client = await create_client( + glide_client = await create_client( request, cluster_mode=cluster_mode, protocol=protocol, timeout=5000 ) length = 2**25 # 33mb @@ -129,23 +129,23 @@ async def test_send_and_receive_large_values(self, request, cluster_mode, protoc value = "0" * length assert len(key) == length assert len(value) == length - await redis_client.set(key, value) - assert await redis_client.get(key) == value.encode() + await glide_client.set(key, value) + assert await glide_client.get(key) == value.encode() @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_send_and_receive_non_ascii_unicode(self, redis_client: TGlideClient): + async def test_send_and_receive_non_ascii_unicode(self, glide_client: TGlideClient): key = "foo" value = "שלום hello 汉字" assert value == "שלום hello 汉字" - await redis_client.set(key, value) - assert await redis_client.get(key) == value.encode() + await glide_client.set(key, value) + assert await glide_client.get(key) == value.encode() @pytest.mark.parametrize("value_size", [100, 2**16]) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_client_handle_concurrent_workload_without_dropping_or_changing_values( - self, redis_client: TGlideClient, value_size + self, glide_client: TGlideClient, value_size ): num_of_concurrent_tasks = 100 running_tasks = set() @@ -154,8 +154,8 @@ async def exec_command(i): range_end = 1 if value_size > 100 else 100 for _ in range(range_end): value = get_random_string(value_size) - assert await redis_client.set(str(i), value) == OK - assert await redis_client.get(str(i)) == value.encode() + assert await glide_client.set(str(i), value) == OK + assert await glide_client.get(str(i)) == value.encode() for i in range(num_of_concurrent_tasks): task = asyncio.create_task(exec_command(i)) @@ -166,13 +166,13 @@ async def exec_command(i): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_can_connect_with_auth_requirepass( - self, redis_client: TGlideClient, request + self, glide_client: TGlideClient, request ): - is_cluster = isinstance(redis_client, GlideClusterClient) + is_cluster = isinstance(glide_client, GlideClusterClient) password = "TEST_AUTH" credentials = RedisCredentials(password) try: - await redis_client.custom_command( + await glide_client.custom_command( ["CONFIG", "SET", "requirepass", password] ) @@ -181,14 +181,14 @@ async def test_can_connect_with_auth_requirepass( await create_client( request, is_cluster, - addresses=redis_client.config.addresses, + addresses=glide_client.config.addresses, ) auth_client = await create_client( request, is_cluster, credentials, - addresses=redis_client.config.addresses, + addresses=glide_client.config.addresses, ) key = get_random_string(10) assert await auth_client.set(key, key) == OK @@ -199,21 +199,21 @@ async def test_can_connect_with_auth_requirepass( request, is_cluster, credentials, - addresses=redis_client.config.addresses, + addresses=glide_client.config.addresses, ) await auth_client.custom_command(["CONFIG", "SET", "requirepass", ""]) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_can_connect_with_auth_acl( - self, redis_client: Union[GlideClient, GlideClusterClient], request + self, glide_client: Union[GlideClient, GlideClusterClient], request ): - is_cluster = isinstance(redis_client, GlideClusterClient) + is_cluster = isinstance(glide_client, GlideClusterClient) username = "testuser" password = "TEST_AUTH" try: assert ( - await redis_client.custom_command( + await glide_client.custom_command( [ "ACL", "SETUSER", @@ -231,14 +231,14 @@ async def test_can_connect_with_auth_acl( == OK ) key = get_random_string(10) - assert await redis_client.set(key, key) == OK + assert await glide_client.set(key, key) == OK credentials = RedisCredentials(password, username) testuser_client = await create_client( request, is_cluster, credentials, - addresses=redis_client.config.addresses, + addresses=glide_client.config.addresses, ) assert await testuser_client.get(key) == key.encode() with pytest.raises(RequestError) as e: @@ -247,34 +247,34 @@ async def test_can_connect_with_auth_acl( assert "NOPERM" in str(e) finally: # Delete this user - await redis_client.custom_command(["ACL", "DELUSER", username]) + await glide_client.custom_command(["ACL", "DELUSER", username]) @pytest.mark.parametrize("cluster_mode", [False]) async def test_select_standalone_database_id(self, request, cluster_mode): - redis_client = await create_client( + glide_client = await create_client( request, cluster_mode=cluster_mode, database_id=4 ) - client_info = await redis_client.custom_command(["CLIENT", "INFO"]) + client_info = await glide_client.custom_command(["CLIENT", "INFO"]) assert b"db=4" in client_info @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_client_name(self, request, cluster_mode, protocol): - redis_client = await create_client( + glide_client = await create_client( request, cluster_mode=cluster_mode, client_name="TEST_CLIENT_NAME", protocol=protocol, ) - client_info = await redis_client.custom_command(["CLIENT", "INFO"]) + client_info = await glide_client.custom_command(["CLIENT", "INFO"]) assert b"name=TEST_CLIENT_NAME" in client_info @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_closed_client_raises_error(self, redis_client: TGlideClient): - await redis_client.close() + async def test_closed_client_raises_error(self, glide_client: TGlideClient): + await glide_client.close() with pytest.raises(ClosingError) as e: - await redis_client.set("foo", "bar") + await glide_client.set("foo", "bar") assert "the client is closed" in str(e) @@ -283,75 +283,75 @@ class TestCommands: @pytest.mark.smoke_test @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_socket_set_get(self, redis_client: TGlideClient): + async def test_socket_set_get(self, glide_client: TGlideClient): key = get_random_string(10) value = datetime.now(timezone.utc).strftime("%m/%d/%Y, %H:%M:%S") - assert await redis_client.set(key, value) == OK - assert await redis_client.get(key) == value.encode() + assert await glide_client.set(key, value) == OK + assert await glide_client.get(key) == value.encode() @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP3]) - async def test_use_resp3_protocol(self, redis_client: TGlideClient): - result = cast(Dict[bytes, bytes], await redis_client.custom_command(["HELLO"])) + async def test_use_resp3_protocol(self, glide_client: TGlideClient): + result = cast(Dict[bytes, bytes], await glide_client.custom_command(["HELLO"])) assert int(result[b"proto"]) == 3 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2]) - async def test_allow_opt_in_to_resp2_protocol(self, redis_client: TGlideClient): - result = cast(Dict[bytes, bytes], await redis_client.custom_command(["HELLO"])) + async def test_allow_opt_in_to_resp2_protocol(self, glide_client: TGlideClient): + result = cast(Dict[bytes, bytes], await glide_client.custom_command(["HELLO"])) assert int(result[b"proto"]) == 2 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_conditional_set(self, redis_client: TGlideClient): + async def test_conditional_set(self, glide_client: TGlideClient): key = get_random_string(10) value = get_random_string(10) - res = await redis_client.set( + res = await glide_client.set( key, value, conditional_set=ConditionalChange.ONLY_IF_EXISTS ) assert res is None - res = await redis_client.set( + res = await glide_client.set( key, value, conditional_set=ConditionalChange.ONLY_IF_DOES_NOT_EXIST ) assert res == OK - assert await redis_client.get(key) == value.encode() - res = await redis_client.set( + assert await glide_client.get(key) == value.encode() + res = await glide_client.set( key, "foobar", conditional_set=ConditionalChange.ONLY_IF_DOES_NOT_EXIST ) assert res is None - assert await redis_client.get(key) == value.encode() + assert await glide_client.get(key) == value.encode() @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_set_return_old_value(self, redis_client: TGlideClient): + async def test_set_return_old_value(self, glide_client: TGlideClient): min_version = "6.2.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): # TODO: change it to pytest fixture after we'll implement a sync client return pytest.mark.skip(reason=f"Redis version required >= {min_version}") key = get_random_string(10) value = get_random_string(10) - res = await redis_client.set(key, value) + res = await glide_client.set(key, value) assert res == OK - assert await redis_client.get(key) == value.encode() + assert await glide_client.get(key) == value.encode() new_value = get_random_string(10) - res = await redis_client.set(key, new_value, return_old_value=True) + res = await glide_client.set(key, new_value, return_old_value=True) assert res == value.encode() - assert await redis_client.get(key) == new_value.encode() + assert await glide_client.get(key) == new_value.encode() @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_custom_command_single_arg(self, redis_client: TGlideClient): + async def test_custom_command_single_arg(self, glide_client: TGlideClient): # Test single arg command - res = await redis_client.custom_command(["PING"]) + res = await glide_client.custom_command(["PING"]) assert res == b"PONG" @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_custom_command_multi_arg(self, redis_client: TGlideClient): + async def test_custom_command_multi_arg(self, glide_client: TGlideClient): # Test multi args command - client_list = await redis_client.custom_command( + client_list = await glide_client.custom_command( ["CLIENT", "LIST", "TYPE", "NORMAL"] ) assert isinstance(client_list, (bytes, list)) @@ -363,10 +363,10 @@ async def test_custom_command_multi_arg(self, redis_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_custom_command_lower_and_upper_case( - self, redis_client: TGlideClient + self, glide_client: TGlideClient ): # Test multi args command - client_list = await redis_client.custom_command( + client_list = await glide_client.custom_command( ["CLIENT", "LIST", "TYPE", "NORMAL"] ) assert isinstance(client_list, (bytes, list)) @@ -377,36 +377,36 @@ async def test_custom_command_lower_and_upper_case( @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_request_error_raises_exception(self, redis_client: TGlideClient): + async def test_request_error_raises_exception(self, glide_client: TGlideClient): key = get_random_string(10) value = get_random_string(10) - await redis_client.set(key, value) + await glide_client.set(key, value) with pytest.raises(RequestError) as e: - await redis_client.custom_command(["HSET", key, "1", "bar"]) + await glide_client.custom_command(["HSET", key, "1", "bar"]) assert "WRONGTYPE" in str(e) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_info_server_replication(self, redis_client: TGlideClient): - info_res = get_first_result(await redis_client.info([InfoSection.SERVER])) + async def test_info_server_replication(self, glide_client: TGlideClient): + info_res = get_first_result(await glide_client.info([InfoSection.SERVER])) info = info_res.decode() assert "# Server" in info cluster_mode = parse_info_response(info_res)["redis_mode"] - expected_cluster_mode = isinstance(redis_client, GlideClusterClient) + expected_cluster_mode = isinstance(glide_client, GlideClusterClient) assert cluster_mode == "cluster" if expected_cluster_mode else "standalone" info = get_first_result( - await redis_client.info([InfoSection.REPLICATION]) + await glide_client.info([InfoSection.REPLICATION]) ).decode() assert "# Replication" in info assert "# Errorstats" not in info @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_info_default(self, redis_client: TGlideClient): - cluster_mode = isinstance(redis_client, GlideClusterClient) - info_result = await redis_client.info() + async def test_info_default(self, glide_client: TGlideClient): + cluster_mode = isinstance(glide_client, GlideClusterClient) + info_result = await glide_client.info() if cluster_mode: - cluster_nodes = await redis_client.custom_command(["CLUSTER", "NODES"]) + cluster_nodes = await glide_client.custom_command(["CLUSTER", "NODES"]) assert isinstance(cluster_nodes, (bytes, list)) cluster_nodes = get_first_result(cluster_nodes) expected_num_of_results = cluster_nodes.count(b"master") @@ -416,233 +416,233 @@ async def test_info_default(self, redis_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_select(self, redis_client: GlideClient): - assert await redis_client.select(0) == OK + async def test_select(self, glide_client: GlideClient): + assert await glide_client.select(0) == OK key = get_random_string(10) value = get_random_string(10) - assert await redis_client.set(key, value) == OK - assert await redis_client.get(key) == value.encode() - assert await redis_client.select(1) == OK - assert await redis_client.get(key) is None - assert await redis_client.select(0) == OK - assert await redis_client.get(key) == value.encode() + assert await glide_client.set(key, value) == OK + assert await glide_client.get(key) == value.encode() + assert await glide_client.select(1) == OK + assert await glide_client.get(key) is None + assert await glide_client.select(0) == OK + assert await glide_client.get(key) == value.encode() @pytest.mark.parametrize("cluster_mode", [False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_move(self, redis_client: GlideClient): + async def test_move(self, glide_client: GlideClient): key = get_random_string(10) value = get_random_string(10) - assert await redis_client.select(0) == OK - assert await redis_client.move(key, 1) is False + assert await glide_client.select(0) == OK + assert await glide_client.move(key, 1) is False - assert await redis_client.set(key, value) == OK - assert await redis_client.get(key) == value.encode() + assert await glide_client.set(key, value) == OK + assert await glide_client.get(key) == value.encode() - assert await redis_client.move(key, 1) is True - assert await redis_client.get(key) is None - assert await redis_client.select(1) == OK - assert await redis_client.get(key) == value.encode() + assert await glide_client.move(key, 1) is True + assert await glide_client.get(key) is None + assert await glide_client.select(1) == OK + assert await glide_client.get(key) == value.encode() with pytest.raises(RequestError) as e: - await redis_client.move(key, -1) + await glide_client.move(key, -1) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_delete(self, redis_client: TGlideClient): + async def test_delete(self, glide_client: TGlideClient): keys = [get_random_string(10), get_random_string(10), get_random_string(10)] value = get_random_string(10) value_encoded = value.encode() - [await redis_client.set(key, value) for key in keys] - assert await redis_client.get(keys[0]) == value_encoded - assert await redis_client.get(keys[1]) == value_encoded - assert await redis_client.get(keys[2]) == value_encoded + [await glide_client.set(key, value) for key in keys] + assert await glide_client.get(keys[0]) == value_encoded + assert await glide_client.get(keys[1]) == value_encoded + assert await glide_client.get(keys[2]) == value_encoded delete_keys = keys + [get_random_string(10)] - assert await redis_client.delete(delete_keys) == 3 - assert await redis_client.delete(keys) == 0 + assert await glide_client.delete(delete_keys) == 3 + assert await glide_client.delete(keys) == 0 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_getdel(self, redis_client: TGlideClient): + async def test_getdel(self, glide_client: TGlideClient): key = get_random_string(10) value = get_random_string(10) non_existing_key = get_random_string(10) list_key = get_random_string(10) - assert await redis_client.set(key, value) == "OK" + assert await glide_client.set(key, value) == "OK" # Retrieve and delete existing key - assert await redis_client.getdel(key) == value.encode() - assert await redis_client.get(key) is None + assert await glide_client.getdel(key) == value.encode() + assert await glide_client.get(key) is None # Try to get and delete a non-existing key - assert await redis_client.getdel(non_existing_key) is None + assert await glide_client.getdel(non_existing_key) is None - assert await redis_client.lpush(list_key, [value]) == 1 + assert await glide_client.lpush(list_key, [value]) == 1 with pytest.raises(RequestError) as e: - await redis_client.getdel(list_key) + await glide_client.getdel(list_key) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_getrange(self, redis_client: TGlideClient): + async def test_getrange(self, glide_client: TGlideClient): key = get_random_string(16) value = get_random_string(10) value_encoded = value.encode() non_string_key = get_random_string(10) - assert await redis_client.set(key, value) == OK - assert await redis_client.getrange(key, 0, 3) == value_encoded[:4] - assert await redis_client.getrange(key, -3, -1) == value_encoded[-3:] - assert await redis_client.getrange(key, 0, -1) == value_encoded + assert await glide_client.set(key, value) == OK + assert await glide_client.getrange(key, 0, 3) == value_encoded[:4] + assert await glide_client.getrange(key, -3, -1) == value_encoded[-3:] + assert await glide_client.getrange(key, 0, -1) == value_encoded # out of range - assert await redis_client.getrange(key, 10, 100) == value_encoded[10:] - assert await redis_client.getrange(key, -200, -3) == value_encoded[-200:-2] - assert await redis_client.getrange(key, 100, 200) == b"" + assert await glide_client.getrange(key, 10, 100) == value_encoded[10:] + assert await glide_client.getrange(key, -200, -3) == value_encoded[-200:-2] + assert await glide_client.getrange(key, 100, 200) == b"" # incorrect range - assert await redis_client.getrange(key, -1, -3) == b"" + assert await glide_client.getrange(key, -1, -3) == b"" # a redis bug, fixed in version 8: https://github.com/redis/redis/issues/13207 - if await check_if_server_version_lt(redis_client, "8.0.0"): - assert await redis_client.getrange(key, -200, -100) == value[0].encode() + if await check_if_server_version_lt(glide_client, "8.0.0"): + assert await glide_client.getrange(key, -200, -100) == value[0].encode() else: - assert await redis_client.getrange(key, -200, -100) == b"" + assert await glide_client.getrange(key, -200, -100) == b"" - if await check_if_server_version_lt(redis_client, "8.0.0"): - assert await redis_client.getrange(non_string_key, 0, -1) == b"" + if await check_if_server_version_lt(glide_client, "8.0.0"): + assert await glide_client.getrange(non_string_key, 0, -1) == b"" # non-string key - assert await redis_client.lpush(non_string_key, ["_"]) == 1 + assert await glide_client.lpush(non_string_key, ["_"]) == 1 with pytest.raises(RequestError): - await redis_client.getrange(non_string_key, 0, -1) + await glide_client.getrange(non_string_key, 0, -1) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_config_reset_stat(self, redis_client: TGlideClient): + async def test_config_reset_stat(self, glide_client: TGlideClient): # we execute set and info so the commandstats will show `cmdstat_set::calls` greater than 1 # after the configResetStat call we initiate an info command and the the commandstats won't contain `cmdstat_set`. - await redis_client.set("foo", "bar") - info_stats = str(await redis_client.info([InfoSection.COMMAND_STATS])) + await glide_client.set("foo", "bar") + info_stats = str(await glide_client.info([InfoSection.COMMAND_STATS])) assert "cmdstat_set" in info_stats - assert await redis_client.config_resetstat() == OK - info_stats = str(await redis_client.info([InfoSection.COMMAND_STATS])) + assert await glide_client.config_resetstat() == OK + info_stats = str(await glide_client.info([InfoSection.COMMAND_STATS])) # 1 stands for the second info command assert "cmdstat_set" not in info_stats @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_config_rewrite(self, redis_client: TGlideClient): + async def test_config_rewrite(self, glide_client: TGlideClient): info_server = parse_info_response( - get_first_result(await redis_client.info([InfoSection.SERVER])) + get_first_result(await glide_client.info([InfoSection.SERVER])) ) if len(info_server["config_file"]) > 0: - assert await redis_client.config_rewrite() == OK + assert await glide_client.config_rewrite() == OK else: # We expect Redis to return an error since the test cluster doesn't use redis.conf file with pytest.raises(RequestError) as e: - await redis_client.config_rewrite() + await glide_client.config_rewrite() assert "The server is running without a config file" in str(e) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_client_id(self, redis_client: TGlideClient): - client_id = await redis_client.client_id() + async def test_client_id(self, glide_client: TGlideClient): + client_id = await glide_client.client_id() assert type(client_id) is int assert client_id > 0 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_incr_commands_existing_key(self, redis_client: TGlideClient): + async def test_incr_commands_existing_key(self, glide_client: TGlideClient): key = get_random_string(10) - assert await redis_client.set(key, "10") == OK - assert await redis_client.incr(key) == 11 - assert await redis_client.get(key) == b"11" - assert await redis_client.incrby(key, 4) == 15 - assert await redis_client.get(key) == b"15" - assert await redis_client.incrbyfloat(key, 5.5) == 20.5 - assert await redis_client.get(key) == b"20.5" + assert await glide_client.set(key, "10") == OK + assert await glide_client.incr(key) == 11 + assert await glide_client.get(key) == b"11" + assert await glide_client.incrby(key, 4) == 15 + assert await glide_client.get(key) == b"15" + assert await glide_client.incrbyfloat(key, 5.5) == 20.5 + assert await glide_client.get(key) == b"20.5" @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_incr_commands_non_existing_key(self, redis_client: TGlideClient): + async def test_incr_commands_non_existing_key(self, glide_client: TGlideClient): key = get_random_string(10) key2 = get_random_string(10) key3 = get_random_string(10) - assert await redis_client.get(key) is None - assert await redis_client.incr(key) == 1 - assert await redis_client.get(key) == b"1" + assert await glide_client.get(key) is None + assert await glide_client.incr(key) == 1 + assert await glide_client.get(key) == b"1" - assert await redis_client.get(key2) is None - assert await redis_client.incrby(key2, 3) == 3 - assert await redis_client.get(key2) == b"3" + assert await glide_client.get(key2) is None + assert await glide_client.incrby(key2, 3) == 3 + assert await glide_client.get(key2) == b"3" - assert await redis_client.get(key3) is None - assert await redis_client.incrbyfloat(key3, 0.5) == 0.5 - assert await redis_client.get(key3) == b"0.5" + assert await glide_client.get(key3) is None + assert await glide_client.incrbyfloat(key3, 0.5) == 0.5 + assert await glide_client.get(key3) == b"0.5" @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_incr_commands_with_str_value(self, redis_client: TGlideClient): + async def test_incr_commands_with_str_value(self, glide_client: TGlideClient): key = get_random_string(10) - assert await redis_client.set(key, "foo") == OK + assert await glide_client.set(key, "foo") == OK with pytest.raises(RequestError) as e: - await redis_client.incr(key) + await glide_client.incr(key) assert "value is not an integer" in str(e) with pytest.raises(RequestError) as e: - await redis_client.incrby(key, 3) + await glide_client.incrby(key, 3) assert "value is not an integer" in str(e) with pytest.raises(RequestError) as e: - await redis_client.incrbyfloat(key, 3.5) + await glide_client.incrbyfloat(key, 3.5) assert "value is not a valid float" in str(e) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_client_getname(self, redis_client: TGlideClient): - assert await redis_client.client_getname() is None + async def test_client_getname(self, glide_client: TGlideClient): + assert await glide_client.client_getname() is None assert ( - await redis_client.custom_command(["CLIENT", "SETNAME", "GlideConnection"]) + await glide_client.custom_command(["CLIENT", "SETNAME", "GlideConnection"]) == OK ) - assert await redis_client.client_getname() == b"GlideConnection" + assert await glide_client.client_getname() == b"GlideConnection" @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_mset_mget(self, redis_client: TGlideClient): + async def test_mset_mget(self, glide_client: TGlideClient): keys = [get_random_string(10), get_random_string(10), get_random_string(10)] non_existing_key = get_random_string(10) key_value_pairs = {key: value for key, value in zip(keys, keys)} - assert await redis_client.mset(key_value_pairs) == OK + assert await glide_client.mset(key_value_pairs) == OK # Add the non-existing key keys.append(non_existing_key) - mget_res = await redis_client.mget(keys) + mget_res = await glide_client.mget(keys) keys[-1] = None assert mget_res == [key.encode() if key is not None else key for key in keys] @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_touch(self, redis_client: TGlideClient): + async def test_touch(self, glide_client: TGlideClient): keys = [get_random_string(10), get_random_string(10)] key_value_pairs = {key: value for key, value in zip(keys, keys)} - assert await redis_client.mset(key_value_pairs) == OK - assert await redis_client.touch(keys) == 2 + assert await glide_client.mset(key_value_pairs) == OK + assert await glide_client.touch(keys) == 2 # 2 existing keys, one non-existing - assert await redis_client.touch([*keys, get_random_string(3)]) == 2 + assert await glide_client.touch([*keys, get_random_string(3)]) == 2 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_msetnx(self, redis_client: TGlideClient): + async def test_msetnx(self, glide_client: TGlideClient): key1 = f"{{key}}-1{get_random_string(5)}" key2 = f"{{key}}-2{get_random_string(5)}" key3 = f"{{key}}-3{get_random_string(5)}" @@ -655,32 +655,32 @@ async def test_msetnx(self, redis_client: TGlideClient): key3: value, } - assert await redis_client.msetnx(key_value_map1) is True - mget_res = await redis_client.mget([key1, key2, non_existing]) + assert await glide_client.msetnx(key_value_map1) is True + mget_res = await glide_client.mget([key1, key2, non_existing]) assert mget_res == [value_encoded, value_encoded, None] - assert await redis_client.msetnx(key_value_map2) is False - assert await redis_client.get(key3) is None - assert await redis_client.get(key2) == value_encoded + assert await glide_client.msetnx(key_value_map2) is False + assert await glide_client.get(key3) is None + assert await glide_client.get(key2) == value_encoded @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_ping(self, redis_client: TGlideClient): - assert await redis_client.ping() == b"PONG" - assert await redis_client.ping("HELLO") == b"HELLO" + async def test_ping(self, glide_client: TGlideClient): + assert await glide_client.ping() == b"PONG" + assert await glide_client.ping("HELLO") == b"HELLO" @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_config_get_set(self, redis_client: TGlideClient): - previous_timeout = await redis_client.config_get(["timeout"]) - assert await redis_client.config_set({"timeout": "1000"}) == OK - assert await redis_client.config_get(["timeout"]) == {b"timeout": b"1000"} + async def test_config_get_set(self, glide_client: TGlideClient): + previous_timeout = await glide_client.config_get(["timeout"]) + assert await glide_client.config_set({"timeout": "1000"}) == OK + assert await glide_client.config_get(["timeout"]) == {b"timeout": b"1000"} # revert changes to previous timeout previous_timeout_decoded = convert_bytes_to_string_object(previous_timeout) assert isinstance(previous_timeout_decoded, dict) assert isinstance(previous_timeout_decoded["timeout"], str) assert ( - await redis_client.config_set( + await glide_client.config_set( {"timeout": previous_timeout_decoded["timeout"]} ) == OK @@ -688,317 +688,317 @@ async def test_config_get_set(self, redis_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_decr_decrby_existing_key(self, redis_client: TGlideClient): + async def test_decr_decrby_existing_key(self, glide_client: TGlideClient): key = get_random_string(10) - assert await redis_client.set(key, "10") == OK - assert await redis_client.decr(key) == 9 - assert await redis_client.get(key) == b"9" - assert await redis_client.decrby(key, 4) == 5 - assert await redis_client.get(key) == b"5" + assert await glide_client.set(key, "10") == OK + assert await glide_client.decr(key) == 9 + assert await glide_client.get(key) == b"9" + assert await glide_client.decrby(key, 4) == 5 + assert await glide_client.get(key) == b"5" @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_decr_decrby_non_existing_key(self, redis_client: TGlideClient): + async def test_decr_decrby_non_existing_key(self, glide_client: TGlideClient): key = get_random_string(10) key2 = get_random_string(10) - assert await redis_client.get(key) is None - assert await redis_client.decr(key) == -1 - assert await redis_client.get(key) == b"-1" + assert await glide_client.get(key) is None + assert await glide_client.decr(key) == -1 + assert await glide_client.get(key) == b"-1" - assert await redis_client.get(key2) is None - assert await redis_client.decrby(key2, 3) == -3 - assert await redis_client.get(key2) == b"-3" + assert await glide_client.get(key2) is None + assert await glide_client.decrby(key2, 3) == -3 + assert await glide_client.get(key2) == b"-3" @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_decr_with_str_value(self, redis_client: TGlideClient): + async def test_decr_with_str_value(self, glide_client: TGlideClient): key = get_random_string(10) - assert await redis_client.set(key, "foo") == OK + assert await glide_client.set(key, "foo") == OK with pytest.raises(RequestError) as e: - await redis_client.decr(key) + await glide_client.decr(key) assert "value is not an integer" in str(e) with pytest.raises(RequestError) as e: - await redis_client.decrby(key, 3) + await glide_client.decrby(key, 3) assert "value is not an integer" in str(e) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_setrange(self, redis_client: TGlideClient): + async def test_setrange(self, glide_client: TGlideClient): key1 = get_random_string(10) key2 = get_random_string(10) # test new key and existing key - assert await redis_client.setrange(key1, 0, "Hello World") == 11 - assert await redis_client.setrange(key1, 6, "GLIDE") == 11 + assert await glide_client.setrange(key1, 0, "Hello World") == 11 + assert await glide_client.setrange(key1, 6, "GLIDE") == 11 # offset > len - assert await redis_client.setrange(key1, 15, "GLIDE") == 20 + assert await glide_client.setrange(key1, 15, "GLIDE") == 20 # negative offset with pytest.raises(RequestError): - assert await redis_client.setrange(key1, -1, "GLIDE") + assert await glide_client.setrange(key1, -1, "GLIDE") # non-string key throws RequestError - assert await redis_client.lpush(key2, ["_"]) == 1 + assert await glide_client.lpush(key2, ["_"]) == 1 with pytest.raises(RequestError): - assert await redis_client.setrange(key2, 0, "_") + assert await glide_client.setrange(key2, 0, "_") @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_hset_hget_hgetall(self, redis_client: TGlideClient): + async def test_hset_hget_hgetall(self, glide_client: TGlideClient): key = get_random_string(10) field = get_random_string(5) field2 = get_random_string(5) field_value_map = {field: "value", field2: "value2"} - assert await redis_client.hset(key, field_value_map) == 2 - assert await redis_client.hget(key, field) == b"value" - assert await redis_client.hget(key, field2) == b"value2" - assert await redis_client.hget(key, "non_existing_field") is None + assert await glide_client.hset(key, field_value_map) == 2 + assert await glide_client.hget(key, field) == b"value" + assert await glide_client.hget(key, field2) == b"value2" + assert await glide_client.hget(key, "non_existing_field") is None - hgetall_map = await redis_client.hgetall(key) + hgetall_map = await glide_client.hgetall(key) expected_map = { field.encode(): b"value", field2.encode(): b"value2", } assert compare_maps(hgetall_map, expected_map) is True - assert await redis_client.hgetall("non_existing_field") == {} + assert await glide_client.hgetall("non_existing_field") == {} @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_hdel(self, redis_client: TGlideClient): + async def test_hdel(self, glide_client: TGlideClient): key = get_random_string(10) field = get_random_string(5) field2 = get_random_string(5) field3 = get_random_string(5) field_value_map = {field: "value", field2: "value2", field3: "value3"} - assert await redis_client.hset(key, field_value_map) == 3 - assert await redis_client.hdel(key, [field, field2]) == 2 - assert await redis_client.hdel(key, ["nonExistingField"]) == 0 - assert await redis_client.hdel("nonExistingKey", [field3]) == 0 + assert await glide_client.hset(key, field_value_map) == 3 + assert await glide_client.hdel(key, [field, field2]) == 2 + assert await glide_client.hdel(key, ["nonExistingField"]) == 0 + assert await glide_client.hdel("nonExistingKey", [field3]) == 0 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_hsetnx(self, redis_client: TGlideClient): + async def test_hsetnx(self, glide_client: TGlideClient): key = get_random_string(10) field = get_random_string(5) - assert await redis_client.hsetnx(key, field, "value") == True - assert await redis_client.hsetnx(key, field, "new value") == False - assert await redis_client.hget(key, field) == b"value" + assert await glide_client.hsetnx(key, field, "value") == True + assert await glide_client.hsetnx(key, field, "new value") == False + assert await glide_client.hget(key, field) == b"value" key = get_random_string(5) - assert await redis_client.set(key, "value") == OK + assert await glide_client.set(key, "value") == OK with pytest.raises(RequestError): - await redis_client.hsetnx(key, field, "value") + await glide_client.hsetnx(key, field, "value") @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_hmget(self, redis_client: TGlideClient): + async def test_hmget(self, glide_client: TGlideClient): key = get_random_string(10) field = get_random_string(5) field2 = get_random_string(5) field_value_map = {field: "value", field2: "value2"} - assert await redis_client.hset(key, field_value_map) == 2 - assert await redis_client.hmget(key, [field, "nonExistingField", field2]) == [ + assert await glide_client.hset(key, field_value_map) == 2 + assert await glide_client.hmget(key, [field, "nonExistingField", field2]) == [ b"value", None, b"value2", ] - assert await redis_client.hmget("nonExistingKey", [field, field2]) == [ + assert await glide_client.hmget("nonExistingKey", [field, field2]) == [ None, None, ] @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_hset_without_data(self, redis_client: TGlideClient): + async def test_hset_without_data(self, glide_client: TGlideClient): with pytest.raises(RequestError) as e: - await redis_client.hset("key", {}) + await glide_client.hset("key", {}) assert "wrong number of arguments" in str(e) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_hincrby_hincrbyfloat(self, redis_client: TGlideClient): + async def test_hincrby_hincrbyfloat(self, glide_client: TGlideClient): key = get_random_string(10) field = get_random_string(5) field_value_map = {field: "10"} - assert await redis_client.hset(key, field_value_map) == 1 - assert await redis_client.hincrby(key, field, 1) == 11 - assert await redis_client.hincrby(key, field, 4) == 15 - assert await redis_client.hincrbyfloat(key, field, 1.5) == 16.5 + assert await glide_client.hset(key, field_value_map) == 1 + assert await glide_client.hincrby(key, field, 1) == 11 + assert await glide_client.hincrby(key, field, 4) == 15 + assert await glide_client.hincrbyfloat(key, field, 1.5) == 16.5 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_hincrby_non_existing_key_field(self, redis_client: TGlideClient): + async def test_hincrby_non_existing_key_field(self, glide_client: TGlideClient): key = get_random_string(10) key2 = get_random_string(10) field = get_random_string(5) field_value_map = {field: "10"} - assert await redis_client.hincrby("nonExistingKey", field, 1) == 1 - assert await redis_client.hset(key, field_value_map) == 1 - assert await redis_client.hincrby(key, "nonExistingField", 2) == 2 - assert await redis_client.hset(key2, field_value_map) == 1 - assert await redis_client.hincrbyfloat(key2, "nonExistingField", -0.5) == -0.5 + assert await glide_client.hincrby("nonExistingKey", field, 1) == 1 + assert await glide_client.hset(key, field_value_map) == 1 + assert await glide_client.hincrby(key, "nonExistingField", 2) == 2 + assert await glide_client.hset(key2, field_value_map) == 1 + assert await glide_client.hincrbyfloat(key2, "nonExistingField", -0.5) == -0.5 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_hincrby_invalid_value(self, redis_client: TGlideClient): + async def test_hincrby_invalid_value(self, glide_client: TGlideClient): key = get_random_string(10) field = get_random_string(5) field_value_map = {field: "value"} - assert await redis_client.hset(key, field_value_map) == 1 + assert await glide_client.hset(key, field_value_map) == 1 with pytest.raises(RequestError) as e: - await redis_client.hincrby(key, field, 2) + await glide_client.hincrby(key, field, 2) assert "hash value is not an integer" in str(e) with pytest.raises(RequestError) as e: - await redis_client.hincrbyfloat(key, field, 1.5) + await glide_client.hincrbyfloat(key, field, 1.5) assert "hash value is not a float" in str(e) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_hexist(self, redis_client: TGlideClient): + async def test_hexist(self, glide_client: TGlideClient): key = get_random_string(10) field = get_random_string(5) field2 = get_random_string(5) field_value_map = {field: "value", field2: "value2"} - assert await redis_client.hset(key, field_value_map) == 2 - assert await redis_client.hexists(key, field) - assert not await redis_client.hexists(key, "nonExistingField") - assert not await redis_client.hexists("nonExistingKey", field2) + assert await glide_client.hset(key, field_value_map) == 2 + assert await glide_client.hexists(key, field) + assert not await glide_client.hexists(key, "nonExistingField") + assert not await glide_client.hexists("nonExistingKey", field2) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_hlen(self, redis_client: TGlideClient): + async def test_hlen(self, glide_client: TGlideClient): key = get_random_string(10) key2 = get_random_string(5) field = get_random_string(5) field2 = get_random_string(5) field_value_map = {field: "value", field2: "value2"} - assert await redis_client.hset(key, field_value_map) == 2 - assert await redis_client.hlen(key) == 2 - assert await redis_client.hdel(key, [field]) == 1 - assert await redis_client.hlen(key) == 1 - assert await redis_client.hlen("non_existing_hash") == 0 + assert await glide_client.hset(key, field_value_map) == 2 + assert await glide_client.hlen(key) == 2 + assert await glide_client.hdel(key, [field]) == 1 + assert await glide_client.hlen(key) == 1 + assert await glide_client.hlen("non_existing_hash") == 0 - assert await redis_client.set(key2, "value") == OK + assert await glide_client.set(key2, "value") == OK with pytest.raises(RequestError): - await redis_client.hlen(key2) + await glide_client.hlen(key2) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_hvals(self, redis_client: TGlideClient): + async def test_hvals(self, glide_client: TGlideClient): key = get_random_string(10) key2 = get_random_string(5) field = get_random_string(5) field2 = get_random_string(5) field_value_map = {field: "value", field2: "value2"} - assert await redis_client.hset(key, field_value_map) == 2 - assert await redis_client.hvals(key) == [b"value", b"value2"] - assert await redis_client.hdel(key, [field]) == 1 - assert await redis_client.hvals(key) == [b"value2"] - assert await redis_client.hvals("non_existing_key") == [] + assert await glide_client.hset(key, field_value_map) == 2 + assert await glide_client.hvals(key) == [b"value", b"value2"] + assert await glide_client.hdel(key, [field]) == 1 + assert await glide_client.hvals(key) == [b"value2"] + assert await glide_client.hvals("non_existing_key") == [] - assert await redis_client.set(key2, "value") == OK + assert await glide_client.set(key2, "value") == OK with pytest.raises(RequestError): - await redis_client.hvals(key2) + await glide_client.hvals(key2) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_hkeys(self, redis_client: TGlideClient): + async def test_hkeys(self, glide_client: TGlideClient): key = get_random_string(10) key2 = get_random_string(5) field = get_random_string(5) field2 = get_random_string(5) field_value_map = {field: "value", field2: "value2"} - assert await redis_client.hset(key, field_value_map) == 2 - assert await redis_client.hkeys(key) == [ + assert await glide_client.hset(key, field_value_map) == 2 + assert await glide_client.hkeys(key) == [ field.encode(), field2.encode(), ] - assert await redis_client.hdel(key, [field]) == 1 - assert await redis_client.hkeys(key) == [field2.encode()] - assert await redis_client.hkeys("non_existing_key") == [] + assert await glide_client.hdel(key, [field]) == 1 + assert await glide_client.hkeys(key) == [field2.encode()] + assert await glide_client.hkeys("non_existing_key") == [] - assert await redis_client.set(key2, "value") == OK + assert await glide_client.set(key2, "value") == OK with pytest.raises(RequestError): - await redis_client.hkeys(key2) + await glide_client.hkeys(key2) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_hrandfield(self, redis_client: TGlideClient): + async def test_hrandfield(self, glide_client: TGlideClient): key = get_random_string(10) key2 = get_random_string(5) field = get_random_string(5) field2 = get_random_string(5) field_value_map = {field: "value", field2: "value2"} - assert await redis_client.hset(key, field_value_map) == 2 - assert await redis_client.hrandfield(key) in [ + assert await glide_client.hset(key, field_value_map) == 2 + assert await glide_client.hrandfield(key) in [ field.encode(), field2.encode(), ] - assert await redis_client.hrandfield("non_existing_key") is None + assert await glide_client.hrandfield("non_existing_key") is None - assert await redis_client.set(key2, "value") == OK + assert await glide_client.set(key2, "value") == OK with pytest.raises(RequestError): - await redis_client.hrandfield(key2) + await glide_client.hrandfield(key2) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_hrandfield_count(self, redis_client: TGlideClient): + async def test_hrandfield_count(self, glide_client: TGlideClient): key = get_random_string(10) key2 = get_random_string(5) field = get_random_string(5) field2 = get_random_string(5) field_value_map = {field: "value", field2: "value2"} - assert await redis_client.hset(key, field_value_map) == 2 + assert await glide_client.hset(key, field_value_map) == 2 # Unique values are expected as count is positive - rand_fields = await redis_client.hrandfield_count(key, 4) + rand_fields = await glide_client.hrandfield_count(key, 4) assert len(rand_fields) == 2 assert set(rand_fields) == {field.encode(), field2.encode()} # Duplicate values are expected as count is negative - rand_fields = await redis_client.hrandfield_count(key, -4) + rand_fields = await glide_client.hrandfield_count(key, -4) assert len(rand_fields) == 4 for rand_field in rand_fields: assert rand_field in [field.encode(), field2.encode()] - assert await redis_client.hrandfield_count(key, 0) == [] - assert await redis_client.hrandfield_count("non_existing_key", 4) == [] + assert await glide_client.hrandfield_count(key, 0) == [] + assert await glide_client.hrandfield_count("non_existing_key", 4) == [] - assert await redis_client.set(key2, "value") == OK + assert await glide_client.set(key2, "value") == OK with pytest.raises(RequestError): - await redis_client.hrandfield_count(key2, 5) + await glide_client.hrandfield_count(key2, 5) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_hrandfield_withvalues(self, redis_client: TGlideClient): + async def test_hrandfield_withvalues(self, glide_client: TGlideClient): key = get_random_string(10) key2 = get_random_string(5) field = get_random_string(5) field2 = get_random_string(5) field_value_map = {field: "value", field2: "value2"} - assert await redis_client.hset(key, field_value_map) == 2 + assert await glide_client.hset(key, field_value_map) == 2 # Unique values are expected as count is positive - rand_fields_with_values = await redis_client.hrandfield_withvalues(key, 4) + rand_fields_with_values = await glide_client.hrandfield_withvalues(key, 4) assert len(rand_fields_with_values) == 2 for field_with_value in rand_fields_with_values: assert field_with_value in [ @@ -1007,7 +1007,7 @@ async def test_hrandfield_withvalues(self, redis_client: TGlideClient): ] # Duplicate values are expected as count is negative - rand_fields_with_values = await redis_client.hrandfield_withvalues(key, -4) + rand_fields_with_values = await glide_client.hrandfield_withvalues(key, -4) assert len(rand_fields_with_values) == 4 for field_with_value in rand_fields_with_values: assert field_with_value in [ @@ -1015,111 +1015,111 @@ async def test_hrandfield_withvalues(self, redis_client: TGlideClient): [field2.encode(), b"value2"], ] - assert await redis_client.hrandfield_withvalues(key, 0) == [] - assert await redis_client.hrandfield_withvalues("non_existing_key", 4) == [] + assert await glide_client.hrandfield_withvalues(key, 0) == [] + assert await glide_client.hrandfield_withvalues("non_existing_key", 4) == [] - assert await redis_client.set(key2, "value") == OK + assert await glide_client.set(key2, "value") == OK with pytest.raises(RequestError): - await redis_client.hrandfield_withvalues(key2, 5) + await glide_client.hrandfield_withvalues(key2, 5) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_hstrlen(self, redis_client: TGlideClient): + async def test_hstrlen(self, glide_client: TGlideClient): key = get_random_string(10) - assert await redis_client.hstrlen(key, "field") == 0 - assert await redis_client.hset(key, {"field": "value"}) == 1 - assert await redis_client.hstrlen(key, "field") == 5 + assert await glide_client.hstrlen(key, "field") == 0 + assert await glide_client.hset(key, {"field": "value"}) == 1 + assert await glide_client.hstrlen(key, "field") == 5 - assert await redis_client.hstrlen(key, "field2") == 0 + assert await glide_client.hstrlen(key, "field2") == 0 - await redis_client.set(key, "value") + await glide_client.set(key, "value") with pytest.raises(RequestError): - await redis_client.hstrlen(key, "field") + await glide_client.hstrlen(key, "field") @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_lpush_lpop_lrange(self, redis_client: TGlideClient): + async def test_lpush_lpop_lrange(self, glide_client: TGlideClient): key = get_random_string(10) value_list: List[TEncodable] = ["value4", "value3", "value2", "value1"] - assert await redis_client.lpush(key, value_list) == 4 - assert await redis_client.lpop(key) == cast(str, value_list[-1]).encode() - assert await redis_client.lrange(key, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lpush(key, value_list) == 4 + assert await glide_client.lpop(key) == cast(str, value_list[-1]).encode() + assert await glide_client.lrange(key, 0, -1) == convert_string_to_bytes_object( value_list[-2::-1] ) - assert await redis_client.lpop_count(key, 2) == convert_string_to_bytes_object( + assert await glide_client.lpop_count(key, 2) == convert_string_to_bytes_object( value_list[-2:0:-1] ) - assert await redis_client.lrange("non_existing_key", 0, -1) == [] - assert await redis_client.lpop("non_existing_key") is None + assert await glide_client.lrange("non_existing_key", 0, -1) == [] + assert await glide_client.lpop("non_existing_key") is None @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_lpush_lpop_lrange_wrong_type_raise_error( - self, redis_client: TGlideClient + self, glide_client: TGlideClient ): key = get_random_string(10) - assert await redis_client.set(key, "foo") == OK + assert await glide_client.set(key, "foo") == OK with pytest.raises(RequestError) as e: - await redis_client.lpush(key, ["bar"]) + await glide_client.lpush(key, ["bar"]) assert "Operation against a key holding the wrong kind of value" in str(e) with pytest.raises(RequestError) as e: - await redis_client.lpop(key) + await glide_client.lpop(key) assert "Operation against a key holding the wrong kind of value" in str(e) with pytest.raises(RequestError) as e: - await redis_client.lrange(key, 0, -1) + await glide_client.lrange(key, 0, -1) assert "Operation against a key holding the wrong kind of value" in str(e) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_lpushx(self, redis_client: TGlideClient): + async def test_lpushx(self, glide_client: TGlideClient): key1 = get_random_string(10) key2 = get_random_string(10) # new key - assert await redis_client.lpushx(key1, ["1"]) == 0 - assert await redis_client.lrange(key1, 0, -1) == [] + assert await glide_client.lpushx(key1, ["1"]) == 0 + assert await glide_client.lrange(key1, 0, -1) == [] # existing key - assert await redis_client.lpush(key1, ["0"]) == 1 - assert await redis_client.lpushx(key1, ["1", "2", "3"]) == 4 - assert await redis_client.lrange(key1, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lpush(key1, ["0"]) == 1 + assert await glide_client.lpushx(key1, ["1", "2", "3"]) == 4 + assert await glide_client.lrange(key1, 0, -1) == convert_string_to_bytes_object( ["3", "2", "1", "0"] ) # key exists, but not a list - assert await redis_client.set(key2, "bar") == OK + assert await glide_client.set(key2, "bar") == OK with pytest.raises(RequestError) as e: - await redis_client.lpushx(key2, ["_"]) + await glide_client.lpushx(key2, ["_"]) # incorrect arguments with pytest.raises(RequestError): - await redis_client.lpushx(key1, []) + await glide_client.lpushx(key1, []) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_blpop(self, redis_client: TGlideClient): + async def test_blpop(self, glide_client: TGlideClient): key1 = f"{{test}}-1-f{get_random_string(10)}" key2 = f"{{test}}-2-f{get_random_string(10)}" value1 = "value1" value2 = "value2" value_list: List[TEncodable] = [value1, value2] - assert await redis_client.lpush(key1, value_list) == 2 - assert await redis_client.blpop( + assert await glide_client.lpush(key1, value_list) == 2 + assert await glide_client.blpop( [key1, key2], 0.5 ) == convert_string_to_bytes_object([key1, value2]) # ensure that command doesn't time out even if timeout > request timeout (250ms by default) - assert await redis_client.blpop(["non_existent_key"], 0.5) is None + assert await glide_client.blpop(["non_existent_key"], 0.5) is None # key exists, but not a list - assert await redis_client.set("foo", "bar") + assert await glide_client.set("foo", "bar") with pytest.raises(RequestError): - await redis_client.blpop(["foo"], 0.001) + await glide_client.blpop(["foo"], 0.001) async def endless_blpop_call(): - await redis_client.blpop(["non_existent_key"], 0) + await glide_client.blpop(["non_existent_key"], 0) # blpop is called against a non-existing key with no timeout, but we wrap the call in an asyncio timeout to # avoid having the test block forever @@ -1128,9 +1128,9 @@ async def endless_blpop_call(): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_lmpop(self, redis_client: TGlideClient): + async def test_lmpop(self, glide_client: TGlideClient): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") key1 = f"{{test}}-1-f{get_random_string(10)}" @@ -1138,38 +1138,38 @@ async def test_lmpop(self, redis_client: TGlideClient): key3 = f"{{test}}-3-f{get_random_string(10)}" # Initialize the lists - assert await redis_client.lpush(key1, ["3", "2", "1"]) == 3 - assert await redis_client.lpush(key2, ["6", "5", "4"]) == 3 + assert await glide_client.lpush(key1, ["3", "2", "1"]) == 3 + assert await glide_client.lpush(key2, ["6", "5", "4"]) == 3 # Pop from LEFT - result = await redis_client.lmpop([key1, key2], ListDirection.LEFT, 2) + result = await glide_client.lmpop([key1, key2], ListDirection.LEFT, 2) expected_result = {key1: ["1", "2"]} assert compare_maps(result, expected_result) is True # Pop from RIGHT - result = await redis_client.lmpop([key2, key1], ListDirection.RIGHT, 2) + result = await glide_client.lmpop([key2, key1], ListDirection.RIGHT, 2) expected_result = {key2: ["6", "5"]} assert compare_maps(result, expected_result) is True # Pop without count (default is 1) - result = await redis_client.lmpop([key1, key2], ListDirection.LEFT) + result = await glide_client.lmpop([key1, key2], ListDirection.LEFT) expected_result = {key1: ["3"]} assert compare_maps(result, expected_result) is True # Non-existing key - result = await redis_client.lmpop([key3], ListDirection.LEFT, 1) + result = await glide_client.lmpop([key3], ListDirection.LEFT, 1) assert result is None # Non-list key - assert await redis_client.set(key3, "value") == OK + assert await glide_client.set(key3, "value") == OK with pytest.raises(RequestError): - await redis_client.lmpop([key3], ListDirection.LEFT, 1) + await glide_client.lmpop([key3], ListDirection.LEFT, 1) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_blmpop(self, redis_client: TGlideClient): + async def test_blmpop(self, glide_client: TGlideClient): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") key1 = f"{{test}}-1-f{get_random_string(10)}" @@ -1178,127 +1178,127 @@ async def test_blmpop(self, redis_client: TGlideClient): key4 = f"{{test}}-4-f{get_random_string(10)}" # Initialize the lists - assert await redis_client.lpush(key1, ["3", "2", "1"]) == 3 - assert await redis_client.lpush(key2, ["6", "5", "4"]) == 3 + assert await glide_client.lpush(key1, ["3", "2", "1"]) == 3 + assert await glide_client.lpush(key2, ["6", "5", "4"]) == 3 # Pop from LEFT with blocking - result = await redis_client.blmpop([key1, key2], ListDirection.LEFT, 0.1, 2) + result = await glide_client.blmpop([key1, key2], ListDirection.LEFT, 0.1, 2) expected_result = {key1: ["1", "2"]} assert compare_maps(result, expected_result) is True # Pop from RIGHT with blocking - result = await redis_client.blmpop([key2, key1], ListDirection.RIGHT, 0.1, 2) + result = await glide_client.blmpop([key2, key1], ListDirection.RIGHT, 0.1, 2) expected_result = {key2: ["6", "5"]} assert compare_maps(result, expected_result) is True # Pop without count (default is 1) - result = await redis_client.blmpop([key1, key2], ListDirection.LEFT, 0.1) + result = await glide_client.blmpop([key1, key2], ListDirection.LEFT, 0.1) expected_result = {key1: ["3"]} assert compare_maps(result, expected_result) is True # Non-existing key with blocking - result = await redis_client.blmpop([key3], ListDirection.LEFT, 0.1, 1) + result = await glide_client.blmpop([key3], ListDirection.LEFT, 0.1, 1) assert result is None # Non-list key with blocking - assert await redis_client.set(key4, "value") == OK + assert await glide_client.set(key4, "value") == OK with pytest.raises(RequestError): - await redis_client.blmpop([key4], ListDirection.LEFT, 0.1, 1) + await glide_client.blmpop([key4], ListDirection.LEFT, 0.1, 1) # BLMPOP is called against a non-existing key with no timeout, but we wrap the call in an asyncio timeout to # avoid having the test block forever async def endless_blmpop_call(): - await redis_client.blmpop([key3], ListDirection.LEFT, 0, 1) + await glide_client.blmpop([key3], ListDirection.LEFT, 0, 1) with pytest.raises(asyncio.TimeoutError): await asyncio.wait_for(endless_blmpop_call(), timeout=3) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_lindex(self, redis_client: TGlideClient): + async def test_lindex(self, glide_client: TGlideClient): key = get_random_string(10) value_list = [get_random_string(5), get_random_string(5)] - assert await redis_client.lpush(key, value_list) == 2 - assert await redis_client.lindex(key, 0) == value_list[1].encode() - assert await redis_client.lindex(key, 1) == value_list[0].encode() - assert await redis_client.lindex(key, 3) is None - assert await redis_client.lindex("non_existing_key", 0) is None + assert await glide_client.lpush(key, value_list) == 2 + assert await glide_client.lindex(key, 0) == value_list[1].encode() + assert await glide_client.lindex(key, 1) == value_list[0].encode() + assert await glide_client.lindex(key, 3) is None + assert await glide_client.lindex("non_existing_key", 0) is None @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_rpush_rpop(self, redis_client: TGlideClient): + async def test_rpush_rpop(self, glide_client: TGlideClient): key = get_random_string(10) value_list: List[TEncodable] = ["value4", "value3", "value2", "value1"] - assert await redis_client.rpush(key, value_list) == 4 - assert await redis_client.rpop(key) == cast(str, value_list[-1]).encode() + assert await glide_client.rpush(key, value_list) == 4 + assert await glide_client.rpop(key) == cast(str, value_list[-1]).encode() - assert await redis_client.rpop_count(key, 2) == convert_string_to_bytes_object( + assert await glide_client.rpop_count(key, 2) == convert_string_to_bytes_object( value_list[-2:0:-1] ) - assert await redis_client.rpop("non_existing_key") is None + assert await glide_client.rpop("non_existing_key") is None @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_rpush_rpop_wrong_type_raise_error(self, redis_client: TGlideClient): + async def test_rpush_rpop_wrong_type_raise_error(self, glide_client: TGlideClient): key = get_random_string(10) - assert await redis_client.set(key, "foo") == OK + assert await glide_client.set(key, "foo") == OK with pytest.raises(RequestError) as e: - await redis_client.rpush(key, ["bar"]) + await glide_client.rpush(key, ["bar"]) assert "Operation against a key holding the wrong kind of value" in str(e) with pytest.raises(RequestError) as e: - await redis_client.rpop(key) + await glide_client.rpop(key) assert "Operation against a key holding the wrong kind of value" in str(e) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_rpushx(self, redis_client: TGlideClient): + async def test_rpushx(self, glide_client: TGlideClient): key1 = get_random_string(10) key2 = get_random_string(10) # new key - assert await redis_client.rpushx(key1, ["1"]) == 0 - assert await redis_client.lrange(key1, 0, -1) == [] + assert await glide_client.rpushx(key1, ["1"]) == 0 + assert await glide_client.lrange(key1, 0, -1) == [] # existing key - assert await redis_client.rpush(key1, ["0"]) == 1 - assert await redis_client.rpushx(key1, ["1", "2", "3"]) == 4 - assert await redis_client.lrange(key1, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.rpush(key1, ["0"]) == 1 + assert await glide_client.rpushx(key1, ["1", "2", "3"]) == 4 + assert await glide_client.lrange(key1, 0, -1) == convert_string_to_bytes_object( ["0", "1", "2", "3"] ) # key existing, but it is not a list - assert await redis_client.set(key2, "bar") == OK + assert await glide_client.set(key2, "bar") == OK with pytest.raises(RequestError) as e: - await redis_client.rpushx(key2, ["_"]) + await glide_client.rpushx(key2, ["_"]) # incorrect arguments with pytest.raises(RequestError): - await redis_client.rpushx(key2, []) + await glide_client.rpushx(key2, []) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_brpop(self, redis_client: TGlideClient): + async def test_brpop(self, glide_client: TGlideClient): key1 = f"{{test}}-1-f{get_random_string(10)}" key2 = f"{{test}}-2-f{get_random_string(10)}" value1 = "value1" value2 = "value2" value_list: List[TEncodable] = [value1, value2] - assert await redis_client.lpush(key1, value_list) == 2 + assert await glide_client.lpush(key1, value_list) == 2 # ensure that command doesn't time out even if timeout > request timeout (250ms by default) - assert await redis_client.brpop( + assert await glide_client.brpop( [key1, key2], 0.5 ) == convert_string_to_bytes_object([key1, value1]) - assert await redis_client.brpop(["non_existent_key"], 0.5) is None + assert await glide_client.brpop(["non_existent_key"], 0.5) is None # key exists, but not a list - assert await redis_client.set("foo", "bar") + assert await glide_client.set("foo", "bar") with pytest.raises(RequestError): - await redis_client.brpop(["foo"], 0.001) + await glide_client.brpop(["foo"], 0.001) async def endless_brpop_call(): - await redis_client.brpop(["non_existent_key"], 0) + await glide_client.brpop(["non_existent_key"], 0) # brpop is called against a non-existing key with no timeout, but we wrap the call in an asyncio timeout to # avoid having the test block forever @@ -1307,14 +1307,14 @@ async def endless_brpop_call(): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_linsert(self, redis_client: TGlideClient): + async def test_linsert(self, glide_client: TGlideClient): key1 = get_random_string(10) key2 = get_random_string(10) - assert await redis_client.lpush(key1, ["4", "3", "2", "1"]) == 4 - assert await redis_client.linsert(key1, InsertPosition.BEFORE, "2", "1.5") == 5 - assert await redis_client.linsert(key1, InsertPosition.AFTER, "3", "3.5") == 6 - assert await redis_client.lrange(key1, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lpush(key1, ["4", "3", "2", "1"]) == 4 + assert await glide_client.linsert(key1, InsertPosition.BEFORE, "2", "1.5") == 5 + assert await glide_client.linsert(key1, InsertPosition.AFTER, "3", "3.5") == 6 + assert await glide_client.lrange(key1, 0, -1) == convert_string_to_bytes_object( [ "1", "1.5", @@ -1326,83 +1326,83 @@ async def test_linsert(self, redis_client: TGlideClient): ) assert ( - await redis_client.linsert( + await glide_client.linsert( "non_existing_key", InsertPosition.BEFORE, "pivot", "elem" ) == 0 ) - assert await redis_client.linsert(key1, InsertPosition.AFTER, "5", "6") == -1 + assert await glide_client.linsert(key1, InsertPosition.AFTER, "5", "6") == -1 # key exists, but it is not a list - assert await redis_client.set(key2, "value") == OK + assert await glide_client.set(key2, "value") == OK with pytest.raises(RequestError): - await redis_client.linsert(key2, InsertPosition.AFTER, "p", "e") + await glide_client.linsert(key2, InsertPosition.AFTER, "p", "e") @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_lmove(self, redis_client: TGlideClient): + async def test_lmove(self, glide_client: TGlideClient): key1 = "{SameSlot}" + get_random_string(10) key2 = "{SameSlot}" + get_random_string(10) # Initialize the lists - assert await redis_client.lpush(key1, ["2", "1"]) == 2 - assert await redis_client.lpush(key2, ["4", "3"]) == 2 + assert await glide_client.lpush(key1, ["2", "1"]) == 2 + assert await glide_client.lpush(key2, ["4", "3"]) == 2 # Move from LEFT to LEFT assert ( - await redis_client.lmove(key1, key2, ListDirection.LEFT, ListDirection.LEFT) + await glide_client.lmove(key1, key2, ListDirection.LEFT, ListDirection.LEFT) == b"1" ) - assert await redis_client.lrange(key1, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lrange(key1, 0, -1) == convert_string_to_bytes_object( ["2"] ) - assert await redis_client.lrange(key2, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lrange(key2, 0, -1) == convert_string_to_bytes_object( ["1", "3", "4"] ) # Move from LEFT to RIGHT assert ( - await redis_client.lmove( + await glide_client.lmove( key1, key2, ListDirection.LEFT, ListDirection.RIGHT ) == b"2" ) - assert await redis_client.lrange(key1, 0, -1) == [] - assert await redis_client.lrange(key2, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lrange(key1, 0, -1) == [] + assert await glide_client.lrange(key2, 0, -1) == convert_string_to_bytes_object( ["1", "3", "4", "2"] ) # Move from RIGHT to LEFT - non-existing destination key assert ( - await redis_client.lmove( + await glide_client.lmove( key2, key1, ListDirection.RIGHT, ListDirection.LEFT ) == b"2" ) - assert await redis_client.lrange(key2, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lrange(key2, 0, -1) == convert_string_to_bytes_object( ["1", "3", "4"] ) - assert await redis_client.lrange(key1, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lrange(key1, 0, -1) == convert_string_to_bytes_object( ["2"] ) # Move from RIGHT to RIGHT assert ( - await redis_client.lmove( + await glide_client.lmove( key2, key1, ListDirection.RIGHT, ListDirection.RIGHT ) == b"4" ) - assert await redis_client.lrange(key2, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lrange(key2, 0, -1) == convert_string_to_bytes_object( ["1", "3"] ) - assert await redis_client.lrange(key1, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lrange(key1, 0, -1) == convert_string_to_bytes_object( ["2", "4"] ) # Non-existing source key assert ( - await redis_client.lmove( + await glide_client.lmove( "{SameSlot}non_existing_key", key1, ListDirection.LEFT, @@ -1413,81 +1413,81 @@ async def test_lmove(self, redis_client: TGlideClient): # Non-list source key key3 = get_random_string(10) - assert await redis_client.set(key3, "value") == OK + assert await glide_client.set(key3, "value") == OK with pytest.raises(RequestError): - await redis_client.lmove(key3, key1, ListDirection.LEFT, ListDirection.LEFT) + await glide_client.lmove(key3, key1, ListDirection.LEFT, ListDirection.LEFT) # Non-list destination key with pytest.raises(RequestError): - await redis_client.lmove(key1, key3, ListDirection.LEFT, ListDirection.LEFT) + await glide_client.lmove(key1, key3, ListDirection.LEFT, ListDirection.LEFT) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_blmove(self, redis_client: TGlideClient): + async def test_blmove(self, glide_client: TGlideClient): key1 = "{SameSlot}" + get_random_string(10) key2 = "{SameSlot}" + get_random_string(10) # Initialize the lists - assert await redis_client.lpush(key1, ["2", "1"]) == 2 - assert await redis_client.lpush(key2, ["4", "3"]) == 2 + assert await glide_client.lpush(key1, ["2", "1"]) == 2 + assert await glide_client.lpush(key2, ["4", "3"]) == 2 # Move from LEFT to LEFT with blocking assert ( - await redis_client.blmove( + await glide_client.blmove( key1, key2, ListDirection.LEFT, ListDirection.LEFT, 0.1 ) == b"1" ) - assert await redis_client.lrange(key1, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lrange(key1, 0, -1) == convert_string_to_bytes_object( ["2"] ) - assert await redis_client.lrange(key2, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lrange(key2, 0, -1) == convert_string_to_bytes_object( ["1", "3", "4"] ) # Move from LEFT to RIGHT with blocking assert ( - await redis_client.blmove( + await glide_client.blmove( key1, key2, ListDirection.LEFT, ListDirection.RIGHT, 0.1 ) == b"2" ) - assert await redis_client.lrange(key1, 0, -1) == [] - assert await redis_client.lrange(key2, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lrange(key1, 0, -1) == [] + assert await glide_client.lrange(key2, 0, -1) == convert_string_to_bytes_object( ["1", "3", "4", "2"] ) # Move from RIGHT to LEFT non-existing destination with blocking assert ( - await redis_client.blmove( + await glide_client.blmove( key2, key1, ListDirection.RIGHT, ListDirection.LEFT, 0.1 ) == b"2" ) - assert await redis_client.lrange(key2, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lrange(key2, 0, -1) == convert_string_to_bytes_object( ["1", "3", "4"] ) - assert await redis_client.lrange(key1, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lrange(key1, 0, -1) == convert_string_to_bytes_object( ["2"] ) # Move from RIGHT to RIGHT with blocking assert ( - await redis_client.blmove( + await glide_client.blmove( key2, key1, ListDirection.RIGHT, ListDirection.RIGHT, 0.1 ) == b"4" ) - assert await redis_client.lrange(key2, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lrange(key2, 0, -1) == convert_string_to_bytes_object( ["1", "3"] ) - assert await redis_client.lrange(key1, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lrange(key1, 0, -1) == convert_string_to_bytes_object( ["2", "4"] ) # Non-existing source key with blocking assert ( - await redis_client.blmove( + await glide_client.blmove( "{SameSlot}non_existing_key", key1, ListDirection.LEFT, @@ -1499,22 +1499,22 @@ async def test_blmove(self, redis_client: TGlideClient): # Non-list source key with blocking key3 = get_random_string(10) - assert await redis_client.set(key3, "value") == OK + assert await glide_client.set(key3, "value") == OK with pytest.raises(RequestError): - await redis_client.blmove( + await glide_client.blmove( key3, key1, ListDirection.LEFT, ListDirection.LEFT, 0.1 ) # Non-list destination key with blocking with pytest.raises(RequestError): - await redis_client.blmove( + await glide_client.blmove( key1, key3, ListDirection.LEFT, ListDirection.LEFT, 0.1 ) # BLMOVE is called against a non-existing key with no timeout, but we wrap the call in an asyncio timeout to # avoid having the test block forever async def endless_blmove_call(): - await redis_client.blmove( + await glide_client.blmove( "{SameSlot}non_existing_key", key2, ListDirection.LEFT, @@ -1527,204 +1527,204 @@ async def endless_blmove_call(): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_lset(self, redis_client: TGlideClient): + async def test_lset(self, glide_client: TGlideClient): key = get_random_string(10) element = get_random_string(5) values = [get_random_string(5) for _ in range(4)] # key does not exist with pytest.raises(RequestError): - await redis_client.lset("non_existing_key", 0, element) + await glide_client.lset("non_existing_key", 0, element) # pushing elements to list - await redis_client.lpush(key, values) == 4 + await glide_client.lpush(key, values) == 4 # index out of range with pytest.raises(RequestError): - await redis_client.lset(key, 10, element) + await glide_client.lset(key, 10, element) # assert lset result - assert await redis_client.lset(key, 0, element) == OK + assert await glide_client.lset(key, 0, element) == OK values = [element] + values[:-1][::-1] - assert await redis_client.lrange(key, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lrange(key, 0, -1) == convert_string_to_bytes_object( values ) # assert lset with a negative index for the last element in the list - assert await redis_client.lset(key, -1, element) == OK + assert await glide_client.lset(key, -1, element) == OK values[-1] = element - assert await redis_client.lrange(key, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lrange(key, 0, -1) == convert_string_to_bytes_object( values ) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_sadd_srem_smembers_scard(self, redis_client: TGlideClient): + async def test_sadd_srem_smembers_scard(self, glide_client: TGlideClient): key = get_random_string(10) value_list: List[TEncodable] = ["member1", "member2", "member3", "member4"] - assert await redis_client.sadd(key, value_list) == 4 - assert await redis_client.srem(key, ["member4", "nonExistingMember"]) == 1 + assert await glide_client.sadd(key, value_list) == 4 + assert await glide_client.srem(key, ["member4", "nonExistingMember"]) == 1 - assert set(await redis_client.smembers(key)) == set( + assert set(await glide_client.smembers(key)) == set( cast(list, convert_string_to_bytes_object(value_list[:3])) ) - assert await redis_client.srem(key, ["member1"]) == 1 - assert await redis_client.scard(key) == 2 + assert await glide_client.srem(key, ["member1"]) == 1 + assert await glide_client.scard(key) == 2 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_sadd_srem_smembers_scard_non_existing_key( - self, redis_client: TGlideClient + self, glide_client: TGlideClient ): non_existing_key = get_random_string(10) - assert await redis_client.srem(non_existing_key, ["member"]) == 0 - assert await redis_client.scard(non_existing_key) == 0 - assert await redis_client.smembers(non_existing_key) == set() + assert await glide_client.srem(non_existing_key, ["member"]) == 0 + assert await glide_client.scard(non_existing_key) == 0 + assert await glide_client.smembers(non_existing_key) == set() @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_sadd_srem_smembers_scard_wrong_type_raise_error( - self, redis_client: TGlideClient + self, glide_client: TGlideClient ): key = get_random_string(10) - assert await redis_client.set(key, "foo") == OK + assert await glide_client.set(key, "foo") == OK with pytest.raises(RequestError) as e: - await redis_client.sadd(key, ["bar"]) + await glide_client.sadd(key, ["bar"]) assert "Operation against a key holding the wrong kind of value" in str(e) with pytest.raises(RequestError) as e: - await redis_client.srem(key, ["bar"]) + await glide_client.srem(key, ["bar"]) assert "Operation against a key holding the wrong kind of value" in str(e) with pytest.raises(RequestError) as e: - await redis_client.scard(key) + await glide_client.scard(key) assert "Operation against a key holding the wrong kind of value" in str(e) with pytest.raises(RequestError) as e: - await redis_client.smembers(key) + await glide_client.smembers(key) assert "Operation against a key holding the wrong kind of value" in str(e) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_sismember(self, redis_client: TGlideClient): + async def test_sismember(self, glide_client: TGlideClient): key = get_random_string(10) member = get_random_string(5) - assert await redis_client.sadd(key, [member]) == 1 - assert await redis_client.sismember(key, member) - assert not await redis_client.sismember(key, get_random_string(5)) - assert not await redis_client.sismember("non_existing_key", member) + assert await glide_client.sadd(key, [member]) == 1 + assert await glide_client.sismember(key, member) + assert not await glide_client.sismember(key, get_random_string(5)) + assert not await glide_client.sismember("non_existing_key", member) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_spop(self, redis_client: TGlideClient): + async def test_spop(self, glide_client: TGlideClient): key = get_random_string(10) member = get_random_string(5) - assert await redis_client.sadd(key, [member]) == 1 - assert await redis_client.spop(key) == member.encode() + assert await glide_client.sadd(key, [member]) == 1 + assert await glide_client.spop(key) == member.encode() member2 = get_random_string(5) member3 = get_random_string(5) - assert await redis_client.sadd(key, [member, member2, member3]) == 3 - assert await redis_client.spop_count(key, 4) == convert_string_to_bytes_object( + assert await glide_client.sadd(key, [member, member2, member3]) == 3 + assert await glide_client.spop_count(key, 4) == convert_string_to_bytes_object( {member, member2, member3} ) - assert await redis_client.scard(key) == 0 + assert await glide_client.scard(key) == 0 - assert await redis_client.spop("non_existing_key") == None - assert await redis_client.spop_count("non_existing_key", 3) == set() + assert await glide_client.spop("non_existing_key") == None + assert await glide_client.spop_count("non_existing_key", 3) == set() @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_smove(self, redis_client: TGlideClient): + async def test_smove(self, glide_client: TGlideClient): key1 = f"{{testKey}}:1-{get_random_string(10)}" key2 = f"{{testKey}}:2-{get_random_string(10)}" key3 = f"{{testKey}}:3-{get_random_string(10)}" string_key = f"{{testKey}}:4-{get_random_string(10)}" non_existing_key = f"{{testKey}}:5-{get_random_string(10)}" - assert await redis_client.sadd(key1, ["1", "2", "3"]) == 3 - assert await redis_client.sadd(key2, ["2", "3"]) == 2 + assert await glide_client.sadd(key1, ["1", "2", "3"]) == 3 + assert await glide_client.sadd(key2, ["2", "3"]) == 2 # move an element - assert await redis_client.smove(key1, key2, "1") is True - assert await redis_client.smembers(key1) == convert_string_to_bytes_object( + assert await glide_client.smove(key1, key2, "1") is True + assert await glide_client.smembers(key1) == convert_string_to_bytes_object( {"2", "3"} ) - assert await redis_client.smembers(key2) == convert_string_to_bytes_object( + assert await glide_client.smembers(key2) == convert_string_to_bytes_object( {"1", "2", "3"} ) # moved element already exists in the destination set - assert await redis_client.smove(key2, key1, "2") is True - assert await redis_client.smembers(key1) == convert_string_to_bytes_object( + assert await glide_client.smove(key2, key1, "2") is True + assert await glide_client.smembers(key1) == convert_string_to_bytes_object( {"2", "3"} ) - assert await redis_client.smembers(key2) == convert_string_to_bytes_object( + assert await glide_client.smembers(key2) == convert_string_to_bytes_object( {"1", "3"} ) # attempt to move from a non-existing key - assert await redis_client.smove(non_existing_key, key1, "4") is False - assert await redis_client.smembers(key1) == convert_string_to_bytes_object( + assert await glide_client.smove(non_existing_key, key1, "4") is False + assert await glide_client.smembers(key1) == convert_string_to_bytes_object( {"2", "3"} ) # move to a new set - assert await redis_client.smove(key1, key3, "2") - assert await redis_client.smembers(key1) == {b"3"} - assert await redis_client.smembers(key3) == {b"2"} + assert await glide_client.smove(key1, key3, "2") + assert await glide_client.smembers(key1) == {b"3"} + assert await glide_client.smembers(key3) == {b"2"} # attempt to move a missing element - assert await redis_client.smove(key1, key3, "42") is False - assert await redis_client.smembers(key1) == {b"3"} - assert await redis_client.smembers(key3) == {b"2"} + assert await glide_client.smove(key1, key3, "42") is False + assert await glide_client.smembers(key1) == {b"3"} + assert await glide_client.smembers(key3) == {b"2"} # move missing element to missing key - assert await redis_client.smove(key1, non_existing_key, "42") is False - assert await redis_client.smembers(key1) == {b"3"} - assert await redis_client.type(non_existing_key) == b"none" + assert await glide_client.smove(key1, non_existing_key, "42") is False + assert await glide_client.smembers(key1) == {b"3"} + assert await glide_client.type(non_existing_key) == b"none" # key exists, but it is not a set - assert await redis_client.set(string_key, "value") == OK + assert await glide_client.set(string_key, "value") == OK with pytest.raises(RequestError): - await redis_client.smove(string_key, key1, "_") + await glide_client.smove(string_key, key1, "_") @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_sunion(self, redis_client: TGlideClient): + async def test_sunion(self, glide_client: TGlideClient): key1 = f"{{testKey}}:{get_random_string(10)}" key2 = f"{{testKey}}:{get_random_string(10)}" non_existing_key = f"{{testKey}}:non_existing_key" member1_list: List[TEncodable] = ["a", "b", "c"] member2_list: List[TEncodable] = ["b", "c", "d", "e"] - assert await redis_client.sadd(key1, member1_list) == 3 - assert await redis_client.sadd(key2, member2_list) == 4 - assert await redis_client.sunion([key1, key2]) == {b"a", b"b", b"c", b"d", b"e"} + assert await glide_client.sadd(key1, member1_list) == 3 + assert await glide_client.sadd(key2, member2_list) == 4 + assert await glide_client.sunion([key1, key2]) == {b"a", b"b", b"c", b"d", b"e"} # invalid argument - key list must not be empty with pytest.raises(RequestError): - await redis_client.sunion([]) + await glide_client.sunion([]) # non-existing key returns the set of existing keys - assert await redis_client.sunion( + assert await glide_client.sunion( [key1, non_existing_key] ) == convert_string_to_bytes_object(set(cast(List[str], member1_list))) # non-set key - assert await redis_client.set(key2, "value") == OK + assert await glide_client.set(key2, "value") == OK with pytest.raises(RequestError) as e: - await redis_client.sunion([key2]) + await glide_client.sunion([key2]) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_sunionstore(self, redis_client: TGlideClient): + async def test_sunionstore(self, glide_client: TGlideClient): key1 = f"{{testKey}}:1-{get_random_string(10)}" key2 = f"{{testKey}}:2-{get_random_string(10)}" key3 = f"{{testKey}}:3-{get_random_string(10)}" @@ -1732,40 +1732,40 @@ async def test_sunionstore(self, redis_client: TGlideClient): string_key = f"{{testKey}}:4-{get_random_string(10)}" non_existing_key = f"{{testKey}}:5-{get_random_string(10)}" - assert await redis_client.sadd(key1, ["a", "b", "c"]) == 3 - assert await redis_client.sadd(key2, ["c", "d", "e"]) == 3 - assert await redis_client.sadd(key3, ["e", "f", "g"]) == 3 + assert await glide_client.sadd(key1, ["a", "b", "c"]) == 3 + assert await glide_client.sadd(key2, ["c", "d", "e"]) == 3 + assert await glide_client.sadd(key3, ["e", "f", "g"]) == 3 # store union in new key - assert await redis_client.sunionstore(key4, [key1, key2]) == 5 - assert await redis_client.smembers(key4) == convert_string_to_bytes_object( + assert await glide_client.sunionstore(key4, [key1, key2]) == 5 + assert await glide_client.smembers(key4) == convert_string_to_bytes_object( {"a", "b", "c", "d", "e"} ) # overwrite existing set - assert await redis_client.sunionstore(key1, [key4, key2]) == 5 - assert await redis_client.smembers(key1) == convert_string_to_bytes_object( + assert await glide_client.sunionstore(key1, [key4, key2]) == 5 + assert await glide_client.smembers(key1) == convert_string_to_bytes_object( {"a", "b", "c", "d", "e"} ) # overwrite one of the source keys - assert await redis_client.sunionstore(key2, [key4, key2]) == 5 - assert await redis_client.smembers(key1) == convert_string_to_bytes_object( + assert await glide_client.sunionstore(key2, [key4, key2]) == 5 + assert await glide_client.smembers(key1) == convert_string_to_bytes_object( {"a", "b", "c", "d", "e"} ) # union with a non existing key - assert await redis_client.sunionstore(key2, [non_existing_key]) == 0 - assert await redis_client.smembers(key2) == set() + assert await glide_client.sunionstore(key2, [non_existing_key]) == 0 + assert await glide_client.smembers(key2) == set() # key exists, but it is not a sorted set - assert await redis_client.set(string_key, "value") == OK + assert await glide_client.set(string_key, "value") == OK with pytest.raises(RequestError): - await redis_client.sunionstore(key4, [string_key, key1]) + await glide_client.sunionstore(key4, [string_key, key1]) # overwrite destination when destination is not a set - assert await redis_client.sunionstore(string_key, [key1, key3]) == 7 - assert await redis_client.smembers( + assert await glide_client.sunionstore(string_key, [key1, key3]) == 7 + assert await glide_client.smembers( string_key ) == convert_string_to_bytes_object( { @@ -1781,7 +1781,7 @@ async def test_sunionstore(self, redis_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_sinter(self, redis_client: TGlideClient): + async def test_sinter(self, glide_client: TGlideClient): key1 = f"{{testKey}}:{get_random_string(10)}" key2 = f"{{testKey}}:{get_random_string(10)}" non_existing_key = f"{{testKey}}:non_existing_key" @@ -1789,26 +1789,26 @@ async def test_sinter(self, redis_client: TGlideClient): member2_list: List[TEncodable] = ["c", "d", "e"] # positive test case - assert await redis_client.sadd(key1, member1_list) == 3 - assert await redis_client.sadd(key2, member2_list) == 3 - assert await redis_client.sinter([key1, key2]) == {b"c"} + assert await glide_client.sadd(key1, member1_list) == 3 + assert await glide_client.sadd(key2, member2_list) == 3 + assert await glide_client.sinter([key1, key2]) == {b"c"} # invalid argument - key list must not be empty with pytest.raises(RequestError): - await redis_client.sinter([]) + await glide_client.sinter([]) # non-existing key returns empty set - assert await redis_client.sinter([key1, non_existing_key]) == set() + assert await glide_client.sinter([key1, non_existing_key]) == set() # non-set key - assert await redis_client.set(key2, "value") == OK + assert await glide_client.set(key2, "value") == OK with pytest.raises(RequestError) as e: - await redis_client.sinter([key2]) + await glide_client.sinter([key2]) assert "Operation against a key holding the wrong kind of value" in str(e) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_sinterstore(self, redis_client: TGlideClient): + async def test_sinterstore(self, glide_client: TGlideClient): key1 = f"{{testKey}}:{get_random_string(10)}" key2 = f"{{testKey}}:{get_random_string(10)}" key3 = f"{{testKey}}:{get_random_string(10)}" @@ -1817,43 +1817,43 @@ async def test_sinterstore(self, redis_client: TGlideClient): member1_list: List[TEncodable] = ["a", "b", "c"] member2_list: List[TEncodable] = ["c", "d", "e"] - assert await redis_client.sadd(key1, member1_list) == 3 - assert await redis_client.sadd(key2, member2_list) == 3 + assert await glide_client.sadd(key1, member1_list) == 3 + assert await glide_client.sadd(key2, member2_list) == 3 # store in new key - assert await redis_client.sinterstore(key3, [key1, key2]) == 1 - assert await redis_client.smembers(key3) == {b"c"} + assert await glide_client.sinterstore(key3, [key1, key2]) == 1 + assert await glide_client.smembers(key3) == {b"c"} # overwrite existing set, which is also a source set - assert await redis_client.sinterstore(key2, [key2, key3]) == 1 - assert await redis_client.smembers(key2) == {b"c"} + assert await glide_client.sinterstore(key2, [key2, key3]) == 1 + assert await glide_client.smembers(key2) == {b"c"} # source set is the same as the existing set - assert await redis_client.sinterstore(key2, [key2]) == 1 - assert await redis_client.smembers(key2) == {b"c"} + assert await glide_client.sinterstore(key2, [key2]) == 1 + assert await glide_client.smembers(key2) == {b"c"} # intersection with non-existing key - assert await redis_client.sinterstore(key1, [key2, non_existing_key]) == 0 - assert await redis_client.smembers(key1) == set() + assert await glide_client.sinterstore(key1, [key2, non_existing_key]) == 0 + assert await glide_client.smembers(key1) == set() # invalid argument - key list must not be empty with pytest.raises(RequestError): - await redis_client.sinterstore(key3, []) + await glide_client.sinterstore(key3, []) # non-set key - assert await redis_client.set(string_key, "value") == OK + assert await glide_client.set(string_key, "value") == OK with pytest.raises(RequestError) as e: - await redis_client.sinterstore(key3, [string_key]) + await glide_client.sinterstore(key3, [string_key]) # overwrite non-set key - assert await redis_client.sinterstore(string_key, [key2]) == 1 - assert await redis_client.smembers(string_key) == {b"c"} + assert await glide_client.sinterstore(string_key, [key2]) == 1 + assert await glide_client.smembers(string_key) == {b"c"} @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_sintercard(self, redis_client: TGlideClient): + async def test_sintercard(self, glide_client: TGlideClient): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") key1 = f"{{testKey}}:{get_random_string(10)}" @@ -1865,168 +1865,168 @@ async def test_sintercard(self, redis_client: TGlideClient): member2_list: List[TEncodable] = ["b", "c", "d", "e"] member3_list: List[TEncodable] = ["b", "c", "f", "g"] - assert await redis_client.sadd(key1, member1_list) == 3 - assert await redis_client.sadd(key2, member2_list) == 4 - assert await redis_client.sadd(key3, member3_list) == 4 + assert await glide_client.sadd(key1, member1_list) == 3 + assert await glide_client.sadd(key2, member2_list) == 4 + assert await glide_client.sadd(key3, member3_list) == 4 # Basic intersection assert ( - await redis_client.sintercard([key1, key2]) == 2 + await glide_client.sintercard([key1, key2]) == 2 ) # Intersection of key1 and key2 is {"b", "c"} # Intersection with non-existing key assert ( - await redis_client.sintercard([key1, non_existing_key]) == 0 + await glide_client.sintercard([key1, non_existing_key]) == 0 ) # No common elements # Intersection with a single key - assert await redis_client.sintercard([key1]) == 3 # All elements in key1 + assert await glide_client.sintercard([key1]) == 3 # All elements in key1 # Intersection with limit assert ( - await redis_client.sintercard([key1, key2, key3], limit=1) == 1 + await glide_client.sintercard([key1, key2, key3], limit=1) == 1 ) # Stops early at limit # Invalid argument - key list must not be empty with pytest.raises(RequestError): - await redis_client.sintercard([]) + await glide_client.sintercard([]) # Non-set key - assert await redis_client.set(string_key, "value") == "OK" + assert await glide_client.set(string_key, "value") == "OK" with pytest.raises(RequestError): - await redis_client.sintercard([string_key]) + await glide_client.sintercard([string_key]) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_sdiff(self, redis_client: TGlideClient): + async def test_sdiff(self, glide_client: TGlideClient): key1 = f"{{testKey}}:1-{get_random_string(10)}" key2 = f"{{testKey}}:2-{get_random_string(10)}" string_key = f"{{testKey}}:4-{get_random_string(10)}" non_existing_key = f"{{testKey}}:5-{get_random_string(10)}" - assert await redis_client.sadd(key1, ["a", "b", "c"]) == 3 - assert await redis_client.sadd(key2, ["c", "d", "e"]) == 3 + assert await glide_client.sadd(key1, ["a", "b", "c"]) == 3 + assert await glide_client.sadd(key2, ["c", "d", "e"]) == 3 - assert await redis_client.sdiff([key1, key2]) == convert_string_to_bytes_object( + assert await glide_client.sdiff([key1, key2]) == convert_string_to_bytes_object( {"a", "b"} ) - assert await redis_client.sdiff([key2, key1]) == convert_string_to_bytes_object( + assert await glide_client.sdiff([key2, key1]) == convert_string_to_bytes_object( {"d", "e"} ) - assert await redis_client.sdiff( + assert await glide_client.sdiff( [key1, non_existing_key] ) == convert_string_to_bytes_object({"a", "b", "c"}) - assert await redis_client.sdiff([non_existing_key, key1]) == set() + assert await glide_client.sdiff([non_existing_key, key1]) == set() # invalid argument - key list must not be empty with pytest.raises(RequestError): - await redis_client.sdiff([]) + await glide_client.sdiff([]) # key exists, but it is not a set - assert await redis_client.set(string_key, "value") == OK + assert await glide_client.set(string_key, "value") == OK with pytest.raises(RequestError): - await redis_client.sdiff([string_key]) + await glide_client.sdiff([string_key]) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_sdiffstore(self, redis_client: TGlideClient): + async def test_sdiffstore(self, glide_client: TGlideClient): key1 = f"{{testKey}}:1-{get_random_string(10)}" key2 = f"{{testKey}}:2-{get_random_string(10)}" key3 = f"{{testKey}}:3-{get_random_string(10)}" string_key = f"{{testKey}}:4-{get_random_string(10)}" non_existing_key = f"{{testKey}}:5-{get_random_string(10)}" - assert await redis_client.sadd(key1, ["a", "b", "c"]) == 3 - assert await redis_client.sadd(key2, ["c", "d", "e"]) == 3 + assert await glide_client.sadd(key1, ["a", "b", "c"]) == 3 + assert await glide_client.sadd(key2, ["c", "d", "e"]) == 3 # Store diff in new key - assert await redis_client.sdiffstore(key3, [key1, key2]) == 2 - assert await redis_client.smembers(key3) == convert_string_to_bytes_object( + assert await glide_client.sdiffstore(key3, [key1, key2]) == 2 + assert await glide_client.smembers(key3) == convert_string_to_bytes_object( {"a", "b"} ) # Overwrite existing set - assert await redis_client.sdiffstore(key3, [key2, key1]) == 2 - assert await redis_client.smembers(key3) == convert_string_to_bytes_object( + assert await glide_client.sdiffstore(key3, [key2, key1]) == 2 + assert await glide_client.smembers(key3) == convert_string_to_bytes_object( {"d", "e"} ) # Overwrite one of the source sets - assert await redis_client.sdiffstore(key3, [key2, key3]) == 1 - assert await redis_client.smembers(key3) == {b"c"} + assert await glide_client.sdiffstore(key3, [key2, key3]) == 1 + assert await glide_client.smembers(key3) == {b"c"} # Diff between non-empty set and empty set - assert await redis_client.sdiffstore(key3, [key1, non_existing_key]) == 3 - assert await redis_client.smembers(key3) == convert_string_to_bytes_object( + assert await glide_client.sdiffstore(key3, [key1, non_existing_key]) == 3 + assert await glide_client.smembers(key3) == convert_string_to_bytes_object( {"a", "b", "c"} ) # Diff between empty set and non-empty set - assert await redis_client.sdiffstore(key3, [non_existing_key, key1]) == 0 - assert await redis_client.smembers(key3) == set() + assert await glide_client.sdiffstore(key3, [non_existing_key, key1]) == 0 + assert await glide_client.smembers(key3) == set() # invalid argument - key list must not be empty with pytest.raises(RequestError): - await redis_client.sdiffstore(key3, []) + await glide_client.sdiffstore(key3, []) # source key exists, but it is not a set - assert await redis_client.set(string_key, "value") == OK + assert await glide_client.set(string_key, "value") == OK with pytest.raises(RequestError): - await redis_client.sdiffstore(key3, [string_key]) + await glide_client.sdiffstore(key3, [string_key]) # Overwrite a key holding a non-set value - assert await redis_client.sdiffstore(string_key, [key1, key2]) == 2 - assert await redis_client.smembers( + assert await glide_client.sdiffstore(string_key, [key1, key2]) == 2 + assert await glide_client.smembers( string_key ) == convert_string_to_bytes_object({"a", "b"}) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_smismember(self, redis_client: TGlideClient): + async def test_smismember(self, glide_client: TGlideClient): key1 = get_random_string(10) string_key = get_random_string(10) non_existing_key = get_random_string(10) - assert await redis_client.sadd(key1, ["one", "two"]) == 2 - assert await redis_client.smismember(key1, ["two", "three"]) == [True, False] + assert await glide_client.sadd(key1, ["one", "two"]) == 2 + assert await glide_client.smismember(key1, ["two", "three"]) == [True, False] - assert await redis_client.smismember(non_existing_key, ["two"]) == [False] + assert await glide_client.smismember(non_existing_key, ["two"]) == [False] # invalid argument - member list must not be empty with pytest.raises(RequestError): - await redis_client.smismember(key1, []) + await glide_client.smismember(key1, []) # source key exists, but it is not a set - assert await redis_client.set(string_key, "value") == OK + assert await glide_client.set(string_key, "value") == OK with pytest.raises(RequestError): - await redis_client.smismember(string_key, ["two"]) + await glide_client.smismember(string_key, ["two"]) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_ltrim(self, redis_client: TGlideClient): + async def test_ltrim(self, glide_client: TGlideClient): key = get_random_string(10) value_list: List[TEncodable] = ["value4", "value3", "value2", "value1"] - assert await redis_client.lpush(key, value_list) == 4 - assert await redis_client.ltrim(key, 0, 1) == OK - assert await redis_client.lrange(key, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lpush(key, value_list) == 4 + assert await glide_client.ltrim(key, 0, 1) == OK + assert await glide_client.lrange(key, 0, -1) == convert_string_to_bytes_object( ["value1", "value2"] ) - assert await redis_client.ltrim(key, 4, 2) == OK - assert await redis_client.lrange(key, 0, -1) == [] + assert await glide_client.ltrim(key, 4, 2) == OK + assert await glide_client.lrange(key, 0, -1) == [] - assert await redis_client.ltrim("non_existing_key", 0, 1) == OK + assert await glide_client.ltrim("non_existing_key", 0, 1) == OK - assert await redis_client.set(key, "foo") == OK + assert await glide_client.set(key, "foo") == OK with pytest.raises(RequestError) as e: - await redis_client.ltrim(key, 0, 1) + await glide_client.ltrim(key, 0, 1) assert "Operation against a key holding the wrong kind of value" in str(e) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_lrem(self, redis_client: TGlideClient): + async def test_lrem(self, glide_client: TGlideClient): key = get_random_string(10) value_list: List[TEncodable] = [ "value1", @@ -2036,71 +2036,71 @@ async def test_lrem(self, redis_client: TGlideClient): "value2", ] - assert await redis_client.lpush(key, value_list) == 5 + assert await glide_client.lpush(key, value_list) == 5 - assert await redis_client.lrem(key, 2, "value1") == 2 - assert await redis_client.lrange(key, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lrem(key, 2, "value1") == 2 + assert await glide_client.lrange(key, 0, -1) == convert_string_to_bytes_object( ["value2", "value2", "value1"] ) - assert await redis_client.lrem(key, -1, "value2") == 1 - assert await redis_client.lrange(key, 0, -1) == convert_string_to_bytes_object( + assert await glide_client.lrem(key, -1, "value2") == 1 + assert await glide_client.lrange(key, 0, -1) == convert_string_to_bytes_object( ["value2", "value1"] ) - assert await redis_client.lrem(key, 0, "value2") == 1 - assert await redis_client.lrange(key, 0, -1) == [b"value1"] + assert await glide_client.lrem(key, 0, "value2") == 1 + assert await glide_client.lrange(key, 0, -1) == [b"value1"] - assert await redis_client.lrem("non_existing_key", 2, "value") == 0 + assert await glide_client.lrem("non_existing_key", 2, "value") == 0 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_llen(self, redis_client: TGlideClient): + async def test_llen(self, glide_client: TGlideClient): key1 = get_random_string(10) key2 = get_random_string(10) value_list: List[TEncodable] = ["value4", "value3", "value2", "value1"] - assert await redis_client.lpush(key1, value_list) == 4 - assert await redis_client.llen(key1) == 4 + assert await glide_client.lpush(key1, value_list) == 4 + assert await glide_client.llen(key1) == 4 - assert await redis_client.llen("non_existing_key") == 0 + assert await glide_client.llen("non_existing_key") == 0 - assert await redis_client.set(key2, "foo") == OK + assert await glide_client.set(key2, "foo") == OK with pytest.raises(RequestError) as e: - await redis_client.llen(key2) + await glide_client.llen(key2) assert "Operation against a key holding the wrong kind of value" in str(e) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_strlen(self, redis_client: TGlideClient): + async def test_strlen(self, glide_client: TGlideClient): key1 = get_random_string(10) key2 = get_random_string(10) value_list: List[TEncodable] = ["value4", "value3", "value2", "value1"] - assert await redis_client.set(key1, "foo") == OK - assert await redis_client.strlen(key1) == 3 - assert await redis_client.strlen("non_existing_key") == 0 + assert await glide_client.set(key1, "foo") == OK + assert await glide_client.strlen(key1) == 3 + assert await glide_client.strlen("non_existing_key") == 0 - assert await redis_client.lpush(key2, value_list) == 4 + assert await glide_client.lpush(key2, value_list) == 4 with pytest.raises(RequestError): - assert await redis_client.strlen(key2) + assert await glide_client.strlen(key2) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_rename(self, redis_client: TGlideClient): + async def test_rename(self, glide_client: TGlideClient): key1 = "{" + get_random_string(10) + "}" - assert await redis_client.set(key1, "foo") == OK - assert await redis_client.rename(key1, key1 + "_rename") == OK - assert await redis_client.exists([key1 + "_rename"]) == 1 + assert await glide_client.set(key1, "foo") == OK + assert await glide_client.rename(key1, key1 + "_rename") == OK + assert await glide_client.exists([key1 + "_rename"]) == 1 with pytest.raises(RequestError): - assert await redis_client.rename( + assert await glide_client.rename( "{same_slot}" + "non_existing_key", "{same_slot}" + "_rename" ) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_renamenx(self, redis_client: TGlideClient): + async def test_renamenx(self, glide_client: TGlideClient): key1 = f"{{testKey}}:1-{get_random_string(10)}" key2 = f"{{testKey}}:2-{get_random_string(10)}" key3 = f"{{testKey}}:3-{get_random_string(10)}" @@ -2108,204 +2108,204 @@ async def test_renamenx(self, redis_client: TGlideClient): # Verify that attempting to rename a non-existing key throws an error with pytest.raises(RequestError): - assert await redis_client.renamenx(non_existing_key, key1) + assert await glide_client.renamenx(non_existing_key, key1) # Test RENAMENX with string values - assert await redis_client.set(key1, "key1") == OK - assert await redis_client.set(key3, "key3") == OK + assert await glide_client.set(key1, "key1") == OK + assert await glide_client.set(key3, "key3") == OK # Test that RENAMENX can rename key1 to key2 (where key2 does not yet exist) - assert await redis_client.renamenx(key1, key2) is True + assert await glide_client.renamenx(key1, key2) is True # Verify that key2 now holds the value that was in key1 - assert await redis_client.get(key2) == b"key1" + assert await glide_client.get(key2) == b"key1" # Verify that RENAMENX doesn't rename key2 to key3, since key3 already exists - assert await redis_client.renamenx(key2, key3) is False + assert await glide_client.renamenx(key2, key3) is False # Verify that key3 remains unchanged - assert await redis_client.get(key3) == b"key3" + assert await glide_client.get(key3) == b"key3" @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_exists(self, redis_client: TGlideClient): + async def test_exists(self, glide_client: TGlideClient): keys = [get_random_string(10), get_random_string(10)] - assert await redis_client.set(keys[0], "value") == OK - assert await redis_client.exists(keys) == 1 + assert await glide_client.set(keys[0], "value") == OK + assert await glide_client.exists(keys) == 1 - assert await redis_client.set(keys[1], "value") == OK - assert await redis_client.exists(keys) == 2 + assert await glide_client.set(keys[1], "value") == OK + assert await glide_client.exists(keys) == 2 keys.append("non_existing_key") - assert await redis_client.exists(keys) == 2 + assert await glide_client.exists(keys) == 2 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_unlink(self, redis_client: TGlideClient): + async def test_unlink(self, glide_client: TGlideClient): key1 = get_random_string(10) key2 = get_random_string(10) key3 = get_random_string(10) - assert await redis_client.set(key1, "value") == OK - assert await redis_client.set(key2, "value") == OK - assert await redis_client.set(key3, "value") == OK - assert await redis_client.unlink([key1, key2, "non_existing_key", key3]) == 3 + assert await glide_client.set(key1, "value") == OK + assert await glide_client.set(key2, "value") == OK + assert await glide_client.set(key3, "value") == OK + assert await glide_client.unlink([key1, key2, "non_existing_key", key3]) == 3 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_expire_pexpire_ttl_expiretime_pexpiretime_with_positive_timeout( - self, redis_client: TGlideClient + self, glide_client: TGlideClient ): key = get_random_string(10) - assert await redis_client.set(key, "foo") == OK - assert await redis_client.ttl(key) == -1 + assert await glide_client.set(key, "foo") == OK + assert await glide_client.ttl(key) == -1 - if not await check_if_server_version_lt(redis_client, "7.0.0"): - assert await redis_client.expiretime(key) == -1 - assert await redis_client.pexpiretime(key) == -1 + if not await check_if_server_version_lt(glide_client, "7.0.0"): + assert await glide_client.expiretime(key) == -1 + assert await glide_client.pexpiretime(key) == -1 - assert await redis_client.expire(key, 10) == 1 - assert await redis_client.ttl(key) in range(11) + assert await glide_client.expire(key, 10) == 1 + assert await glide_client.ttl(key) in range(11) # set command clears the timeout. - assert await redis_client.set(key, "bar") == OK - if await check_if_server_version_lt(redis_client, "7.0.0"): - assert await redis_client.pexpire(key, 10000) + assert await glide_client.set(key, "bar") == OK + if await check_if_server_version_lt(glide_client, "7.0.0"): + assert await glide_client.pexpire(key, 10000) else: - assert await redis_client.pexpire(key, 10000, ExpireOptions.HasNoExpiry) - assert await redis_client.ttl(key) in range(11) + assert await glide_client.pexpire(key, 10000, ExpireOptions.HasNoExpiry) + assert await glide_client.ttl(key) in range(11) - if await check_if_server_version_lt(redis_client, "7.0.0"): - assert await redis_client.expire(key, 15) + if await check_if_server_version_lt(glide_client, "7.0.0"): + assert await glide_client.expire(key, 15) else: - assert await redis_client.expire(key, 15, ExpireOptions.HasExistingExpiry) - assert await redis_client.expiretime(key) > int(time.time()) - assert await redis_client.pexpiretime(key) > (int(time.time()) * 1000) - assert await redis_client.ttl(key) in range(16) + assert await glide_client.expire(key, 15, ExpireOptions.HasExistingExpiry) + assert await glide_client.expiretime(key) > int(time.time()) + assert await glide_client.pexpiretime(key) > (int(time.time()) * 1000) + assert await glide_client.ttl(key) in range(16) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_expireat_pexpireat_ttl_with_positive_timeout( - self, redis_client: TGlideClient + self, glide_client: TGlideClient ): key = get_random_string(10) - assert await redis_client.set(key, "foo") == OK + assert await glide_client.set(key, "foo") == OK current_time = int(time.time()) - assert await redis_client.expireat(key, current_time + 10) == 1 - assert await redis_client.ttl(key) in range(11) - if await check_if_server_version_lt(redis_client, "7.0.0"): - assert await redis_client.expireat(key, current_time + 50) == 1 + assert await glide_client.expireat(key, current_time + 10) == 1 + assert await glide_client.ttl(key) in range(11) + if await check_if_server_version_lt(glide_client, "7.0.0"): + assert await glide_client.expireat(key, current_time + 50) == 1 else: assert ( - await redis_client.expireat( + await glide_client.expireat( key, current_time + 50, ExpireOptions.NewExpiryGreaterThanCurrent ) == 1 ) - assert await redis_client.ttl(key) in range(51) + assert await glide_client.ttl(key) in range(51) # set command clears the timeout. - assert await redis_client.set(key, "bar") == OK + assert await glide_client.set(key, "bar") == OK current_time_ms = int(time.time() * 1000) - if not await check_if_server_version_lt(redis_client, "7.0.0"): - assert not await redis_client.pexpireat( + if not await check_if_server_version_lt(glide_client, "7.0.0"): + assert not await glide_client.pexpireat( key, current_time_ms + 50000, ExpireOptions.HasExistingExpiry ) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_expire_pexpire_expireat_pexpireat_expiretime_pexpiretime_past_or_negative_timeout( - self, redis_client: TGlideClient + self, glide_client: TGlideClient ): key = get_random_string(10) - assert await redis_client.set(key, "foo") == OK - assert await redis_client.ttl(key) == -1 - - if not await check_if_server_version_lt(redis_client, "7.0.0"): - assert await redis_client.expiretime(key) == -1 - assert await redis_client.pexpiretime(key) == -1 - - assert await redis_client.expire(key, -10) is True - assert await redis_client.ttl(key) == -2 - if not await check_if_server_version_lt(redis_client, "7.0.0"): - assert await redis_client.expiretime(key) == -2 - assert await redis_client.pexpiretime(key) == -2 - - assert await redis_client.set(key, "foo") == OK - assert await redis_client.pexpire(key, -10000) - assert await redis_client.ttl(key) == -2 - if not await check_if_server_version_lt(redis_client, "7.0.0"): - assert await redis_client.expiretime(key) == -2 - assert await redis_client.pexpiretime(key) == -2 - - assert await redis_client.set(key, "foo") == OK - assert await redis_client.expireat(key, int(time.time()) - 50) == 1 - assert await redis_client.ttl(key) == -2 - if not await check_if_server_version_lt(redis_client, "7.0.0"): - assert await redis_client.expiretime(key) == -2 - assert await redis_client.pexpiretime(key) == -2 - - assert await redis_client.set(key, "foo") == OK - assert await redis_client.pexpireat(key, int(time.time() * 1000) - 50000) - assert await redis_client.ttl(key) == -2 - if not await check_if_server_version_lt(redis_client, "7.0.0"): - assert await redis_client.expiretime(key) == -2 - assert await redis_client.pexpiretime(key) == -2 + assert await glide_client.set(key, "foo") == OK + assert await glide_client.ttl(key) == -1 + + if not await check_if_server_version_lt(glide_client, "7.0.0"): + assert await glide_client.expiretime(key) == -1 + assert await glide_client.pexpiretime(key) == -1 + + assert await glide_client.expire(key, -10) is True + assert await glide_client.ttl(key) == -2 + if not await check_if_server_version_lt(glide_client, "7.0.0"): + assert await glide_client.expiretime(key) == -2 + assert await glide_client.pexpiretime(key) == -2 + + assert await glide_client.set(key, "foo") == OK + assert await glide_client.pexpire(key, -10000) + assert await glide_client.ttl(key) == -2 + if not await check_if_server_version_lt(glide_client, "7.0.0"): + assert await glide_client.expiretime(key) == -2 + assert await glide_client.pexpiretime(key) == -2 + + assert await glide_client.set(key, "foo") == OK + assert await glide_client.expireat(key, int(time.time()) - 50) == 1 + assert await glide_client.ttl(key) == -2 + if not await check_if_server_version_lt(glide_client, "7.0.0"): + assert await glide_client.expiretime(key) == -2 + assert await glide_client.pexpiretime(key) == -2 + + assert await glide_client.set(key, "foo") == OK + assert await glide_client.pexpireat(key, int(time.time() * 1000) - 50000) + assert await glide_client.ttl(key) == -2 + if not await check_if_server_version_lt(glide_client, "7.0.0"): + assert await glide_client.expiretime(key) == -2 + assert await glide_client.pexpiretime(key) == -2 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_expire_pexpire_expireAt_pexpireAt_ttl_expiretime_pexpiretime_non_existing_key( - self, redis_client: TGlideClient + self, glide_client: TGlideClient ): key = get_random_string(10) - assert await redis_client.expire(key, 10) == 0 - assert not await redis_client.pexpire(key, 10000) - assert await redis_client.expireat(key, int(time.time()) + 50) == 0 - assert not await redis_client.pexpireat(key, int(time.time() * 1000) + 50000) - assert await redis_client.ttl(key) == -2 - if not await check_if_server_version_lt(redis_client, "7.0.0"): - assert await redis_client.expiretime(key) == -2 - assert await redis_client.pexpiretime(key) == -2 + assert await glide_client.expire(key, 10) == 0 + assert not await glide_client.pexpire(key, 10000) + assert await glide_client.expireat(key, int(time.time()) + 50) == 0 + assert not await glide_client.pexpireat(key, int(time.time() * 1000) + 50000) + assert await glide_client.ttl(key) == -2 + if not await check_if_server_version_lt(glide_client, "7.0.0"): + assert await glide_client.expiretime(key) == -2 + assert await glide_client.pexpiretime(key) == -2 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_pttl(self, redis_client: TGlideClient): + async def test_pttl(self, glide_client: TGlideClient): key = get_random_string(10) - assert await redis_client.pttl(key) == -2 + assert await glide_client.pttl(key) == -2 current_time = int(time.time()) - assert await redis_client.set(key, "value") == OK - assert await redis_client.pttl(key) == -1 + assert await glide_client.set(key, "value") == OK + assert await glide_client.pttl(key) == -1 - assert await redis_client.expire(key, 10) - assert 0 < await redis_client.pttl(key) <= 10000 + assert await glide_client.expire(key, 10) + assert 0 < await glide_client.pttl(key) <= 10000 - assert await redis_client.expireat(key, current_time + 20) - assert 0 < await redis_client.pttl(key) <= 20000 + assert await glide_client.expireat(key, current_time + 20) + assert 0 < await glide_client.pttl(key) <= 20000 - assert await redis_client.pexpireat(key, current_time * 1000 + 30000) - assert 0 < await redis_client.pttl(key) <= 30000 + assert await glide_client.pexpireat(key, current_time * 1000 + 30000) + assert 0 < await glide_client.pttl(key) <= 30000 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_persist(self, redis_client: TGlideClient): + async def test_persist(self, glide_client: TGlideClient): key = get_random_string(10) - assert await redis_client.set(key, "value") == OK - assert not await redis_client.persist(key) + assert await glide_client.set(key, "value") == OK + assert not await glide_client.persist(key) - assert await redis_client.expire(key, 10) - assert await redis_client.persist(key) + assert await glide_client.expire(key, 10) + assert await glide_client.persist(key) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_geoadd(self, redis_client: TGlideClient): + async def test_geoadd(self, glide_client: TGlideClient): key, key2 = get_random_string(10), get_random_string(10) members_coordinates: Dict[str | bytes, GeospatialData] = { "Palermo": GeospatialData(13.361389, 38.115556), "Catania": GeospatialData(15.087269, 37.502669), } - assert await redis_client.geoadd(key, members_coordinates) == 2 + assert await glide_client.geoadd(key, members_coordinates) == 2 members_coordinates["Catania"].latitude = 39 assert ( - await redis_client.geoadd( + await glide_client.geoadd( key, members_coordinates, existing_options=ConditionalChange.ONLY_IF_DOES_NOT_EXIST, @@ -2313,7 +2313,7 @@ async def test_geoadd(self, redis_client: TGlideClient): == 0 ) assert ( - await redis_client.geoadd( + await glide_client.geoadd( key, members_coordinates, existing_options=ConditionalChange.ONLY_IF_EXISTS, @@ -2323,7 +2323,7 @@ async def test_geoadd(self, redis_client: TGlideClient): members_coordinates["Catania"].latitude = 40 members_coordinates.update({"Tel-Aviv": GeospatialData(32.0853, 34.7818)}) assert ( - await redis_client.geoadd( + await glide_client.geoadd( key, members_coordinates, changed=True, @@ -2331,33 +2331,33 @@ async def test_geoadd(self, redis_client: TGlideClient): == 2 ) - assert await redis_client.set(key2, "value") == OK + assert await glide_client.set(key2, "value") == OK with pytest.raises(RequestError): - await redis_client.geoadd(key2, members_coordinates) + await glide_client.geoadd(key2, members_coordinates) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_geoadd_invalid_args(self, redis_client: TGlideClient): + async def test_geoadd_invalid_args(self, glide_client: TGlideClient): key = get_random_string(10) with pytest.raises(RequestError): - await redis_client.geoadd(key, {}) + await glide_client.geoadd(key, {}) with pytest.raises(RequestError): - await redis_client.geoadd(key, {"Place": GeospatialData(-181, 0)}) + await glide_client.geoadd(key, {"Place": GeospatialData(-181, 0)}) with pytest.raises(RequestError): - await redis_client.geoadd(key, {"Place": GeospatialData(181, 0)}) + await glide_client.geoadd(key, {"Place": GeospatialData(181, 0)}) with pytest.raises(RequestError): - await redis_client.geoadd(key, {"Place": GeospatialData(0, 86)}) + await glide_client.geoadd(key, {"Place": GeospatialData(0, 86)}) with pytest.raises(RequestError): - await redis_client.geoadd(key, {"Place": GeospatialData(0, -86)}) + await glide_client.geoadd(key, {"Place": GeospatialData(0, -86)}) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_geosearch_by_box(self, redis_client: TGlideClient): + async def test_geosearch_by_box(self, glide_client: TGlideClient): key = get_random_string(10) members = ["Catania", "Palermo", "edge2", "edge1"] members_coordinates: Mapping[TEncodable, GeospatialData] = { @@ -2384,17 +2384,17 @@ async def test_geosearch_by_box(self, redis_client: TGlideClient): [279.7405, 3479273021651468, [12.75848776102066, 38.78813451624225]], ], ] - assert await redis_client.geoadd(key, members_coordinates) == 4 + assert await glide_client.geoadd(key, members_coordinates) == 4 # Test search by box, unit: kilometers, from a geospatial data - assert await redis_client.geosearch( + assert await glide_client.geosearch( key, GeospatialData(15, 37), GeoSearchByBox(400, 400, GeoUnit.KILOMETERS), OrderBy.ASC, ) == convert_string_to_bytes_object(members) - assert await redis_client.geosearch( + assert await glide_client.geosearch( key, GeospatialData(15, 37), GeoSearchByBox(400, 400, GeoUnit.KILOMETERS), @@ -2404,7 +2404,7 @@ async def test_geosearch_by_box(self, redis_client: TGlideClient): with_hash=True, ) == convert_string_to_bytes_object(result[::-1]) - assert await redis_client.geosearch( + assert await glide_client.geosearch( key, GeospatialData(15, 37), GeoSearchByBox(400, 400, GeoUnit.KILOMETERS), @@ -2416,7 +2416,7 @@ async def test_geosearch_by_box(self, redis_client: TGlideClient): # Test search by box, unit: meters, from a member, with distance meters = 400 * 1000 - assert await redis_client.geosearch( + assert await glide_client.geosearch( key, "Catania", GeoSearchByBox(meters, meters, GeoUnit.METERS), @@ -2428,7 +2428,7 @@ async def test_geosearch_by_box(self, redis_client: TGlideClient): # Test search by box, unit: feet, from a member, with limited count to 2, with hash feet = 400 * 3280.8399 - assert await redis_client.geosearch( + assert await glide_client.geosearch( key, "Palermo", GeoSearchByBox(feet, feet, GeoUnit.FEET), @@ -2439,7 +2439,7 @@ async def test_geosearch_by_box(self, redis_client: TGlideClient): # Test search by box, unit: miles, from a geospatial data, with limited ANY count to 1 assert ( - await redis_client.geosearch( + await glide_client.geosearch( key, GeospatialData(15, 37), GeoSearchByBox(250, 250, GeoUnit.MILES), @@ -2450,7 +2450,7 @@ async def test_geosearch_by_box(self, redis_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_geosearch_by_radius(self, redis_client: TGlideClient): + async def test_geosearch_by_radius(self, glide_client: TGlideClient): key = get_random_string(10) members_coordinates: Mapping[TEncodable, GeospatialData] = { "Palermo": GeospatialData(13.361389, 38.115556), @@ -2469,11 +2469,11 @@ async def test_geosearch_by_radius(self, redis_client: TGlideClient): ], ] members = ["Catania", "Palermo", "edge2", "edge1"] - assert await redis_client.geoadd(key, members_coordinates) == 4 + assert await glide_client.geoadd(key, members_coordinates) == 4 # Test search by radius, units: feet, from a member feet = 200 * 3280.8399 - assert await redis_client.geosearch( + assert await glide_client.geosearch( key, "Catania", GeoSearchByRadius(feet, GeoUnit.FEET), @@ -2482,7 +2482,7 @@ async def test_geosearch_by_radius(self, redis_client: TGlideClient): # Test search by radius, units: meters, from a member meters = 200 * 1000 - assert await redis_client.geosearch( + assert await glide_client.geosearch( key, "Catania", GeoSearchByRadius(meters, GeoUnit.METERS), @@ -2490,7 +2490,7 @@ async def test_geosearch_by_radius(self, redis_client: TGlideClient): ) == convert_string_to_bytes_object(members[:2][::-1]) # Test search by radius, unit: miles, from a geospatial data - assert await redis_client.geosearch( + assert await glide_client.geosearch( key, GeospatialData(15, 37), GeoSearchByRadius(175, GeoUnit.MILES), @@ -2498,7 +2498,7 @@ async def test_geosearch_by_radius(self, redis_client: TGlideClient): ) == convert_string_to_bytes_object(members[::-1]) # Test search by radius, unit: kilometers, from a geospatial data, with limited count to 2 - assert await redis_client.geosearch( + assert await glide_client.geosearch( key, GeospatialData(15, 37), GeoSearchByRadius(200, GeoUnit.KILOMETERS), @@ -2511,7 +2511,7 @@ async def test_geosearch_by_radius(self, redis_client: TGlideClient): # Test search by radius, unit: kilometers, from a geospatial data, with limited ANY count to 1 assert ( - await redis_client.geosearch( + await glide_client.geosearch( key, GeospatialData(15, 37), GeoSearchByRadius(200, GeoUnit.KILOMETERS), @@ -2525,7 +2525,7 @@ async def test_geosearch_by_radius(self, redis_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_geosearch_no_result(self, redis_client: TGlideClient): + async def test_geosearch_no_result(self, glide_client: TGlideClient): key = get_random_string(10) members_coordinates: Mapping[TEncodable, GeospatialData] = { "Palermo": GeospatialData(13.361389, 38.115556), @@ -2533,11 +2533,11 @@ async def test_geosearch_no_result(self, redis_client: TGlideClient): "edge1": GeospatialData(12.758489, 38.788135), "edge2": GeospatialData(17.241510, 38.788135), } - assert await redis_client.geoadd(key, members_coordinates) == 4 + assert await glide_client.geoadd(key, members_coordinates) == 4 # No membes within the aea assert ( - await redis_client.geosearch( + await glide_client.geosearch( key, GeospatialData(15, 37), GeoSearchByBox(50, 50, GeoUnit.METERS), @@ -2547,7 +2547,7 @@ async def test_geosearch_no_result(self, redis_client: TGlideClient): ) assert ( - await redis_client.geosearch( + await glide_client.geosearch( key, GeospatialData(15, 37), GeoSearchByRadius(10, GeoUnit.METERS), @@ -2557,13 +2557,13 @@ async def test_geosearch_no_result(self, redis_client: TGlideClient): ) # No members in the area (apart from the member we seach fom itself) - assert await redis_client.geosearch( + assert await glide_client.geosearch( key, "Catania", GeoSearchByBox(10, 10, GeoUnit.KILOMETERS), ) == [b"Catania"] - assert await redis_client.geosearch( + assert await glide_client.geosearch( key, "Catania", GeoSearchByRadius(10, GeoUnit.METERS), @@ -2571,15 +2571,15 @@ async def test_geosearch_no_result(self, redis_client: TGlideClient): # Search from non exiting memeber with pytest.raises(RequestError): - await redis_client.geosearch( + await glide_client.geosearch( key, "non_existing_member", GeoSearchByBox(10, 10, GeoUnit.MILES), ) - assert await redis_client.set(key, "foo") == OK + assert await glide_client.set(key, "foo") == OK with pytest.raises(RequestError): - await redis_client.geosearch( + await glide_client.geosearch( key, "Catania", GeoSearchByBox(10, 10, GeoUnit.MILES), @@ -2587,7 +2587,7 @@ async def test_geosearch_no_result(self, redis_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_geosearchstore_by_box(self, redis_client: TGlideClient): + async def test_geosearchstore_by_box(self, glide_client: TGlideClient): key = f"{{testKey}}:{get_random_string(10)}" destination_key = f"{{testKey}}:{get_random_string(8)}" members_coordinates: Mapping[TEncodable, GeospatialData] = { @@ -2602,11 +2602,11 @@ async def test_geosearchstore_by_box(self, redis_client: TGlideClient): b"edge2": [279.7403417843143, 3481342659049484.0], b"edge1": [279.7404521356343, 3479273021651468.0], } - assert await redis_client.geoadd(key, members_coordinates) == 4 + assert await glide_client.geoadd(key, members_coordinates) == 4 # Test storing results of a box search, unit: kilometes, from a geospatial data assert ( - await redis_client.geosearchstore( + await glide_client.geosearchstore( destination_key, key, GeospatialData(15, 37), @@ -2615,7 +2615,7 @@ async def test_geosearchstore_by_box(self, redis_client: TGlideClient): ) == 4 # Number of elements stored # Verify the stored results - zrange_map = await redis_client.zrange_withscores( + zrange_map = await glide_client.zrange_withscores( destination_key, RangeByIndex(0, -1) ) expected_map = {member: value[1] for member, value in result.items()} @@ -2624,7 +2624,7 @@ async def test_geosearchstore_by_box(self, redis_client: TGlideClient): # Test storing results of a box search, unit: kilometes, from a geospatial data, with distance assert ( - await redis_client.geosearchstore( + await glide_client.geosearchstore( destination_key, key, GeospatialData(15, 37), @@ -2634,7 +2634,7 @@ async def test_geosearchstore_by_box(self, redis_client: TGlideClient): ) == 4 # Number of elements stored # Verify the stored results - zrange_map = await redis_client.zrange_withscores( + zrange_map = await glide_client.zrange_withscores( destination_key, RangeByIndex(0, -1) ) expected_map = {member: value[0] for member, value in result.items()} @@ -2643,7 +2643,7 @@ async def test_geosearchstore_by_box(self, redis_client: TGlideClient): # Test storing results of a box search, unit: kilometes, from a geospatial data, with count assert ( - await redis_client.geosearchstore( + await glide_client.geosearchstore( destination_key, key, GeospatialData(15, 37), @@ -2653,7 +2653,7 @@ async def test_geosearchstore_by_box(self, redis_client: TGlideClient): ) == 1 # Number of elements stored # Verify the stored results - zrange_map = await redis_client.zrange_withscores( + zrange_map = await glide_client.zrange_withscores( destination_key, RangeByIndex(0, -1) ) assert compare_maps(zrange_map, {b"Catania": 3479447370796909.0}) is True @@ -2661,7 +2661,7 @@ async def test_geosearchstore_by_box(self, redis_client: TGlideClient): # Test storing results of a box search, unit: meters, from a member, with distance meters = 400 * 1000 assert ( - await redis_client.geosearchstore( + await glide_client.geosearchstore( destination_key, key, "Catania", @@ -2671,7 +2671,7 @@ async def test_geosearchstore_by_box(self, redis_client: TGlideClient): ) == 3 # Number of elements stored # Verify the stored results with distances - zrange_map = await redis_client.zrange_withscores( + zrange_map = await glide_client.zrange_withscores( destination_key, RangeByIndex(0, -1) ) expected_distances = { @@ -2684,7 +2684,7 @@ async def test_geosearchstore_by_box(self, redis_client: TGlideClient): # Test search by box, unit: feet, from a member, with limited ANY count to 2, with hash feet = 400 * 3280.8399 assert ( - await redis_client.geosearchstore( + await glide_client.geosearchstore( destination_key, key, "Palermo", @@ -2695,7 +2695,7 @@ async def test_geosearchstore_by_box(self, redis_client: TGlideClient): ) # Verify the stored results - zrange_map = await redis_client.zrange_withscores( + zrange_map = await glide_client.zrange_withscores( destination_key, RangeByIndex(0, -1) ) for member in zrange_map: @@ -2703,7 +2703,7 @@ async def test_geosearchstore_by_box(self, redis_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_geosearchstore_by_radius(self, redis_client: TGlideClient): + async def test_geosearchstore_by_radius(self, glide_client: TGlideClient): key = f"{{testKey}}:{get_random_string(10)}" destination_key = f"{{testKey}}:{get_random_string(8)}" members_coordinates: Mapping[TEncodable, GeospatialData] = { @@ -2716,12 +2716,12 @@ async def test_geosearchstore_by_radius(self, redis_client: TGlideClient): b"Catania": [56.4412578701582, 3479447370796909.0], b"Palermo": [190.44242984775784, 3479099956230698.0], } - assert await redis_client.geoadd(key, members_coordinates) == 4 + assert await glide_client.geoadd(key, members_coordinates) == 4 # Test storing results of a radius search, unit: feet, from a member feet = 200 * 3280.8399 assert ( - await redis_client.geosearchstore( + await glide_client.geosearchstore( destination_key, key, "Catania", @@ -2731,7 +2731,7 @@ async def test_geosearchstore_by_radius(self, redis_client: TGlideClient): ) # Verify the stored results - zrange_map = await redis_client.zrange_withscores( + zrange_map = await glide_client.zrange_withscores( destination_key, RangeByIndex(0, -1) ) expected_map = {member: value[1] for member, value in result.items()} @@ -2741,7 +2741,7 @@ async def test_geosearchstore_by_radius(self, redis_client: TGlideClient): # Test search by radius, units: meters, from a member meters = 200 * 1000 assert ( - await redis_client.geosearchstore( + await glide_client.geosearchstore( destination_key, key, "Catania", @@ -2752,7 +2752,7 @@ async def test_geosearchstore_by_radius(self, redis_client: TGlideClient): ) # Verify the stored results - zrange_map = await redis_client.zrange_withscores( + zrange_map = await glide_client.zrange_withscores( destination_key, RangeByIndex(0, -1) ) expected_distances = { @@ -2763,7 +2763,7 @@ async def test_geosearchstore_by_radius(self, redis_client: TGlideClient): # Test search by radius, unit: miles, from a geospatial data assert ( - await redis_client.geosearchstore( + await glide_client.geosearchstore( destination_key, key, GeospatialData(15, 37), @@ -2775,7 +2775,7 @@ async def test_geosearchstore_by_radius(self, redis_client: TGlideClient): # Test storing results of a radius search, unit: kilometers, from a geospatial data, with limited count to 2 kilometers = 200 assert ( - await redis_client.geosearchstore( + await glide_client.geosearchstore( destination_key, key, GeospatialData(15, 37), @@ -2787,7 +2787,7 @@ async def test_geosearchstore_by_radius(self, redis_client: TGlideClient): ) # Verify the stored results - zrange_map = await redis_client.zrange_withscores( + zrange_map = await glide_client.zrange_withscores( destination_key, RangeByIndex(0, -1) ) expected_map = {member: value[0] for member, value in result.items()} @@ -2796,7 +2796,7 @@ async def test_geosearchstore_by_radius(self, redis_client: TGlideClient): # Test storing results of a radius search, unit: kilometers, from a geospatial data, with limited ANY count to 1 assert ( - await redis_client.geosearchstore( + await glide_client.geosearchstore( destination_key, key, GeospatialData(15, 37), @@ -2807,7 +2807,7 @@ async def test_geosearchstore_by_radius(self, redis_client: TGlideClient): ) # Verify the stored results - zrange_map = await redis_client.zrange_withscores( + zrange_map = await glide_client.zrange_withscores( destination_key, RangeByIndex(0, -1) ) @@ -2816,7 +2816,7 @@ async def test_geosearchstore_by_radius(self, redis_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_geosearchstore_no_result(self, redis_client: TGlideClient): + async def test_geosearchstore_no_result(self, glide_client: TGlideClient): key = f"{{testKey}}:{get_random_string(10)}" destination_key = f"{{testKey}}:{get_random_string(8)}" members_coordinates: Mapping[TEncodable, GeospatialData] = { @@ -2825,11 +2825,11 @@ async def test_geosearchstore_no_result(self, redis_client: TGlideClient): "edge1": GeospatialData(12.758489, 38.788135), "edge2": GeospatialData(17.241510, 38.788135), } - assert await redis_client.geoadd(key, members_coordinates) == 4 + assert await glide_client.geoadd(key, members_coordinates) == 4 # No members within the area assert ( - await redis_client.geosearchstore( + await glide_client.geosearchstore( destination_key, key, GeospatialData(15, 37), @@ -2839,7 +2839,7 @@ async def test_geosearchstore_no_result(self, redis_client: TGlideClient): ) assert ( - await redis_client.geosearchstore( + await glide_client.geosearchstore( destination_key, key, GeospatialData(15, 37), @@ -2850,7 +2850,7 @@ async def test_geosearchstore_no_result(self, redis_client: TGlideClient): # No members in the area (apart from the member we search from itself) assert ( - await redis_client.geosearchstore( + await glide_client.geosearchstore( destination_key, key, "Catania", @@ -2860,7 +2860,7 @@ async def test_geosearchstore_no_result(self, redis_client: TGlideClient): ) assert ( - await redis_client.geosearchstore( + await glide_client.geosearchstore( destination_key, key, "Catania", @@ -2871,16 +2871,16 @@ async def test_geosearchstore_no_result(self, redis_client: TGlideClient): # Search from non-existing member with pytest.raises(RequestError): - await redis_client.geosearchstore( + await glide_client.geosearchstore( destination_key, key, "non_existing_member", GeoSearchByBox(10, 10, GeoUnit.MILES), ) - assert await redis_client.set(key, "foo") == OK + assert await glide_client.set(key, "foo") == OK with pytest.raises(RequestError): - await redis_client.geosearchstore( + await glide_client.geosearchstore( destination_key, key, "Catania", @@ -2889,14 +2889,14 @@ async def test_geosearchstore_no_result(self, redis_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_geohash(self, redis_client: TGlideClient): + async def test_geohash(self, glide_client: TGlideClient): key = get_random_string(10) members_coordinates: Mapping[TEncodable, GeospatialData] = { "Palermo": GeospatialData(13.361389, 38.115556), "Catania": GeospatialData(15.087269, 37.502669), } - assert await redis_client.geoadd(key, members_coordinates) == 2 - assert await redis_client.geohash( + assert await glide_client.geoadd(key, members_coordinates) == 2 + assert await glide_client.geohash( key, ["Palermo", "Catania", "Place"] ) == convert_string_to_bytes_object( [ @@ -2907,7 +2907,7 @@ async def test_geohash(self, redis_client: TGlideClient): ) assert ( - await redis_client.geohash( + await glide_client.geohash( "non_existing_key", ["Palermo", "Catania", "Place"] ) == [None] * 3 @@ -2916,52 +2916,52 @@ async def test_geohash(self, redis_client: TGlideClient): # Neccessary to check since we are enforcing the user to pass a list of members while redis don't # But when running the command with key only (and no members) the returned value will always be an empty list # So in case of any changes, this test will fail and inform us that we should allow not passing any members. - assert await redis_client.geohash(key, []) == [] + assert await glide_client.geohash(key, []) == [] - assert await redis_client.set(key, "value") == OK + assert await glide_client.set(key, "value") == OK with pytest.raises(RequestError): - await redis_client.geohash(key, ["Palermo", "Catania"]) + await glide_client.geohash(key, ["Palermo", "Catania"]) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_geodist(self, redis_client: TGlideClient): + async def test_geodist(self, glide_client: TGlideClient): key, key2 = get_random_string(10), get_random_string(10) members_coordinates: Mapping[TEncodable, GeospatialData] = { "Palermo": GeospatialData(13.361389, 38.115556), "Catania": GeospatialData(15.087269, 37.502669), } - assert await redis_client.geoadd(key, members_coordinates) == 2 + assert await glide_client.geoadd(key, members_coordinates) == 2 - assert await redis_client.geodist(key, "Palermo", "Catania") == 166274.1516 + assert await glide_client.geodist(key, "Palermo", "Catania") == 166274.1516 assert ( - await redis_client.geodist(key, "Palermo", "Catania", GeoUnit.KILOMETERS) + await glide_client.geodist(key, "Palermo", "Catania", GeoUnit.KILOMETERS) == 166.2742 ) - assert await redis_client.geodist(key, "Palermo", "Palermo", GeoUnit.MILES) == 0 + assert await glide_client.geodist(key, "Palermo", "Palermo", GeoUnit.MILES) == 0 assert ( - await redis_client.geodist( + await glide_client.geodist( key, "Palermo", "non-existing-member", GeoUnit.FEET ) == None ) - assert await redis_client.set(key2, "value") == OK + assert await glide_client.set(key2, "value") == OK with pytest.raises(RequestError): - await redis_client.geodist(key2, "Palmero", "Catania") + await glide_client.geodist(key2, "Palmero", "Catania") @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_geopos(self, redis_client: TGlideClient): + async def test_geopos(self, glide_client: TGlideClient): key = get_random_string(10) members_coordinates: Mapping[TEncodable, GeospatialData] = { "Palermo": GeospatialData(13.361389, 38.115556), "Catania": GeospatialData(15.087269, 37.502669), } - assert await redis_client.geoadd(key, members_coordinates) == 2 + assert await glide_client.geoadd(key, members_coordinates) == 2 # The comparison allows for a small tolerance level due to potential precision errors in floating-point calculations # No worries, Python can handle it, therefore, this shouldn't fail - positions = await redis_client.geopos(key, ["Palermo", "Catania", "Place"]) + positions = await glide_client.geopos(key, ["Palermo", "Catania", "Place"]) expected_positions = [ [13.36138933897018433, 38.11555639549629859], [15.08726745843887329, 37.50266842333162032], @@ -2978,7 +2978,7 @@ async def test_geopos(self, redis_client: TGlideClient): ) assert ( - await redis_client.geopos( + await glide_client.geopos( "non_existing_key", ["Palermo", "Catania", "Place"] ) == [None] * 3 @@ -2987,27 +2987,27 @@ async def test_geopos(self, redis_client: TGlideClient): # Neccessary to check since we are enforcing the user to pass a list of members while redis don't # But when running the command with key only (and no members) the returned value will always be an empty list # So in case of any changes, this test will fail and inform us that we should allow not passing any members. - assert await redis_client.geohash(key, []) == [] + assert await glide_client.geohash(key, []) == [] - assert await redis_client.set(key, "value") == OK + assert await glide_client.set(key, "value") == OK with pytest.raises(RequestError): - await redis_client.geopos(key, ["Palermo", "Catania"]) + await glide_client.geopos(key, ["Palermo", "Catania"]) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zadd_zaddincr(self, redis_client: TGlideClient): + async def test_zadd_zaddincr(self, glide_client: TGlideClient): key = get_random_string(10) members_scores: Mapping[TEncodable, float] = {"one": 1, "two": 2, "three": 3} - assert await redis_client.zadd(key, members_scores=members_scores) == 3 - assert await redis_client.zadd_incr(key, member="one", increment=2) == 3.0 + assert await glide_client.zadd(key, members_scores=members_scores) == 3 + assert await glide_client.zadd_incr(key, member="one", increment=2) == 3.0 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zadd_nx_xx(self, redis_client: TGlideClient): + async def test_zadd_nx_xx(self, glide_client: TGlideClient): key = get_random_string(10) members_scores: Mapping[TEncodable, float] = {"one": 1, "two": 2, "three": 3} assert ( - await redis_client.zadd( + await glide_client.zadd( key, members_scores=members_scores, existing_options=ConditionalChange.ONLY_IF_EXISTS, @@ -3015,7 +3015,7 @@ async def test_zadd_nx_xx(self, redis_client: TGlideClient): == 0 ) assert ( - await redis_client.zadd( + await glide_client.zadd( key, members_scores=members_scores, existing_options=ConditionalChange.ONLY_IF_DOES_NOT_EXIST, @@ -3024,7 +3024,7 @@ async def test_zadd_nx_xx(self, redis_client: TGlideClient): ) assert ( - await redis_client.zadd_incr( + await glide_client.zadd_incr( key, member="one", increment=5.0, @@ -3034,7 +3034,7 @@ async def test_zadd_nx_xx(self, redis_client: TGlideClient): ) assert ( - await redis_client.zadd_incr( + await glide_client.zadd_incr( key, member="one", increment=5.0, @@ -3045,13 +3045,13 @@ async def test_zadd_nx_xx(self, redis_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zadd_gt_lt(self, redis_client: TGlideClient): + async def test_zadd_gt_lt(self, glide_client: TGlideClient): key = get_random_string(10) members_scores: Dict[TEncodable, float] = {"one": -3, "two": 2, "three": 3} - assert await redis_client.zadd(key, members_scores=members_scores) == 3 + assert await glide_client.zadd(key, members_scores=members_scores) == 3 members_scores["one"] = 10 assert ( - await redis_client.zadd( + await glide_client.zadd( key, members_scores=members_scores, update_condition=UpdateOptions.GREATER_THAN, @@ -3061,7 +3061,7 @@ async def test_zadd_gt_lt(self, redis_client: TGlideClient): ) assert ( - await redis_client.zadd( + await glide_client.zadd( key, members_scores=members_scores, update_condition=UpdateOptions.LESS_THAN, @@ -3071,7 +3071,7 @@ async def test_zadd_gt_lt(self, redis_client: TGlideClient): ) assert ( - await redis_client.zadd_incr( + await glide_client.zadd_incr( key, member="one", increment=-3.0, @@ -3081,7 +3081,7 @@ async def test_zadd_gt_lt(self, redis_client: TGlideClient): ) assert ( - await redis_client.zadd_incr( + await glide_client.zadd_incr( key, member="one", increment=-3.0, @@ -3092,7 +3092,7 @@ async def test_zadd_gt_lt(self, redis_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zincrby(self, redis_client: TGlideClient): + async def test_zincrby(self, glide_client: TGlideClient): key, member, member2 = ( get_random_string(10), get_random_string(5), @@ -3100,110 +3100,110 @@ async def test_zincrby(self, redis_client: TGlideClient): ) # key does not exist - assert await redis_client.zincrby(key, 2.5, member) == 2.5 - assert await redis_client.zscore(key, member) == 2.5 + assert await glide_client.zincrby(key, 2.5, member) == 2.5 + assert await glide_client.zscore(key, member) == 2.5 # key exists, but value doesn't - assert await redis_client.zincrby(key, -3.3, member2) == -3.3 - assert await redis_client.zscore(key, member2) == -3.3 + assert await glide_client.zincrby(key, -3.3, member2) == -3.3 + assert await glide_client.zscore(key, member2) == -3.3 # updating existing value in existing key - assert await redis_client.zincrby(key, 1.0, member) == 3.5 - assert await redis_client.zscore(key, member) == 3.5 + assert await glide_client.zincrby(key, 1.0, member) == 3.5 + assert await glide_client.zscore(key, member) == 3.5 # Key exists, but it is not a sorted set - assert await redis_client.set(key, "_") == OK + assert await glide_client.set(key, "_") == OK with pytest.raises(RequestError): - await redis_client.zincrby(key, 0.5, "_") + await glide_client.zincrby(key, 0.5, "_") @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zrem(self, redis_client: TGlideClient): + async def test_zrem(self, glide_client: TGlideClient): key = get_random_string(10) members_scores: Mapping[TEncodable, float] = {"one": 1, "two": 2, "three": 3} - assert await redis_client.zadd(key, members_scores=members_scores) == 3 + assert await glide_client.zadd(key, members_scores=members_scores) == 3 - assert await redis_client.zrem(key, ["one"]) == 1 - assert await redis_client.zrem(key, ["one", "two", "three"]) == 2 + assert await glide_client.zrem(key, ["one"]) == 1 + assert await glide_client.zrem(key, ["one", "two", "three"]) == 2 - assert await redis_client.zrem("non_existing_set", ["member"]) == 0 + assert await glide_client.zrem("non_existing_set", ["member"]) == 0 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zremrangebyscore(self, redis_client: TGlideClient): + async def test_zremrangebyscore(self, glide_client: TGlideClient): key = get_random_string(10) members_scores: Mapping[TEncodable, float] = {"one": 1, "two": 2, "three": 3} - assert await redis_client.zadd(key, members_scores) == 3 + assert await glide_client.zadd(key, members_scores) == 3 assert ( - await redis_client.zremrangebyscore( + await glide_client.zremrangebyscore( key, ScoreBoundary(1, False), ScoreBoundary(2) ) == 1 ) assert ( - await redis_client.zremrangebyscore(key, ScoreBoundary(1), InfBound.NEG_INF) + await glide_client.zremrangebyscore(key, ScoreBoundary(1), InfBound.NEG_INF) == 0 ) assert ( - await redis_client.zremrangebyscore( + await glide_client.zremrangebyscore( "non_existing_set", InfBound.NEG_INF, InfBound.POS_INF ) == 0 ) - assert await redis_client.set(key, "value") == OK + assert await glide_client.set(key, "value") == OK with pytest.raises(RequestError): - await redis_client.zremrangebyscore(key, InfBound.NEG_INF, InfBound.POS_INF) + await glide_client.zremrangebyscore(key, InfBound.NEG_INF, InfBound.POS_INF) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zremrangebylex(self, redis_client: TGlideClient): + async def test_zremrangebylex(self, glide_client: TGlideClient): key1 = get_random_string(10) key2 = get_random_string(10) range = RangeByIndex(0, -1) members_scores: Mapping[TEncodable, float] = {"a": 1, "b": 2, "c": 3, "d": 4} - assert await redis_client.zadd(key1, members_scores) == 4 + assert await glide_client.zadd(key1, members_scores) == 4 assert ( - await redis_client.zremrangebylex( + await glide_client.zremrangebylex( key1, LexBoundary("a", False), LexBoundary("c") ) == 2 ) - zremrangebylex_res = await redis_client.zrange_withscores(key1, range) + zremrangebylex_res = await glide_client.zrange_withscores(key1, range) assert compare_maps(zremrangebylex_res, {"a": 1.0, "d": 4.0}) is True assert ( - await redis_client.zremrangebylex(key1, LexBoundary("d"), InfBound.POS_INF) + await glide_client.zremrangebylex(key1, LexBoundary("d"), InfBound.POS_INF) == 1 ) - assert await redis_client.zrange_withscores(key1, range) == {b"a": 1.0} + assert await glide_client.zrange_withscores(key1, range) == {b"a": 1.0} # min_lex > max_lex assert ( - await redis_client.zremrangebylex(key1, LexBoundary("a"), InfBound.NEG_INF) + await glide_client.zremrangebylex(key1, LexBoundary("a"), InfBound.NEG_INF) == 0 ) - assert await redis_client.zrange_withscores(key1, range) == {b"a": 1.0} + assert await glide_client.zrange_withscores(key1, range) == {b"a": 1.0} assert ( - await redis_client.zremrangebylex( + await glide_client.zremrangebylex( "non_existing_key", InfBound.NEG_INF, InfBound.POS_INF ) == 0 ) # key exists, but it is not a sorted set - assert await redis_client.set(key2, "value") == OK + assert await glide_client.set(key2, "value") == OK with pytest.raises(RequestError): - await redis_client.zremrangebylex( + await glide_client.zremrangebylex( key2, LexBoundary("a", False), LexBoundary("c") ) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zremrangebyrank(self, redis_client: TGlideClient): + async def test_zremrangebyrank(self, glide_client: TGlideClient): key1 = get_random_string(10) key2 = get_random_string(10) range = RangeByIndex(0, -1) @@ -3214,41 +3214,41 @@ async def test_zremrangebyrank(self, redis_client: TGlideClient): "d": 4, "e": 5, } - assert await redis_client.zadd(key1, members_scores) == 5 + assert await glide_client.zadd(key1, members_scores) == 5 # Test start exceeding end - assert await redis_client.zremrangebyrank(key1, 2, 1) == 0 + assert await glide_client.zremrangebyrank(key1, 2, 1) == 0 # Test removing elements by rank - assert await redis_client.zremrangebyrank(key1, 0, 2) == 3 - zremrangebyrank_res = await redis_client.zrange_withscores(key1, range) + assert await glide_client.zremrangebyrank(key1, 0, 2) == 3 + zremrangebyrank_res = await glide_client.zrange_withscores(key1, range) assert compare_maps(zremrangebyrank_res, {"d": 4.0, "e": 5.0}) is True # Test removing elements beyond the existing range - assert await redis_client.zremrangebyrank(key1, 0, 10) == 2 - assert await redis_client.zrange_withscores(key1, range) == {} + assert await glide_client.zremrangebyrank(key1, 0, 10) == 2 + assert await glide_client.zrange_withscores(key1, range) == {} # Test with non-existing key - assert await redis_client.zremrangebyrank("non_existing_key", 0, 1) == 0 + assert await glide_client.zremrangebyrank("non_existing_key", 0, 1) == 0 # Key exists, but it is not a sorted set - assert await redis_client.set(key2, "value") == OK + assert await glide_client.set(key2, "value") == OK with pytest.raises(RequestError): - await redis_client.zremrangebyrank(key2, 0, 1) + await glide_client.zremrangebyrank(key2, 0, 1) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zlexcount(self, redis_client: TGlideClient): + async def test_zlexcount(self, glide_client: TGlideClient): key1 = get_random_string(10) key2 = get_random_string(10) members_scores: Mapping[TEncodable, float] = {"a": 1.0, "b": 2.0, "c": 3.0} - assert await redis_client.zadd(key1, members_scores) == 3 + assert await glide_client.zadd(key1, members_scores) == 3 assert ( - await redis_client.zlexcount(key1, InfBound.NEG_INF, InfBound.POS_INF) == 3 + await glide_client.zlexcount(key1, InfBound.NEG_INF, InfBound.POS_INF) == 3 ) assert ( - await redis_client.zlexcount( + await glide_client.zlexcount( key1, LexBoundary("a", is_inclusive=False), LexBoundary("c", is_inclusive=True), @@ -3256,52 +3256,52 @@ async def test_zlexcount(self, redis_client: TGlideClient): == 2 ) assert ( - await redis_client.zlexcount( + await glide_client.zlexcount( key1, InfBound.NEG_INF, LexBoundary("c", is_inclusive=True) ) == 3 ) # Incorrect range; start > end assert ( - await redis_client.zlexcount( + await glide_client.zlexcount( key1, InfBound.POS_INF, LexBoundary("c", is_inclusive=True) ) == 0 ) assert ( - await redis_client.zlexcount( + await glide_client.zlexcount( "non_existing_key", InfBound.NEG_INF, InfBound.POS_INF ) == 0 ) # key exists, but it is not a sorted set - assert await redis_client.set(key2, "value") == OK + assert await glide_client.set(key2, "value") == OK with pytest.raises(RequestError): - await redis_client.zlexcount(key2, InfBound.NEG_INF, InfBound.POS_INF) + await glide_client.zlexcount(key2, InfBound.NEG_INF, InfBound.POS_INF) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zcard(self, redis_client: TGlideClient): + async def test_zcard(self, glide_client: TGlideClient): key = get_random_string(10) members_scores: Mapping[TEncodable, float] = {"one": 1, "two": 2, "three": 3} - assert await redis_client.zadd(key, members_scores=members_scores) == 3 - assert await redis_client.zcard(key) == 3 + assert await glide_client.zadd(key, members_scores=members_scores) == 3 + assert await glide_client.zcard(key) == 3 - assert await redis_client.zrem(key, ["one"]) == 1 - assert await redis_client.zcard(key) == 2 - assert await redis_client.zcard("non_existing_key") == 0 + assert await glide_client.zrem(key, ["one"]) == 1 + assert await glide_client.zcard(key) == 2 + assert await glide_client.zcard("non_existing_key") == 0 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zcount(self, redis_client: TGlideClient): + async def test_zcount(self, glide_client: TGlideClient): key = get_random_string(10) members_scores: Mapping[TEncodable, float] = {"one": 1, "two": 2, "three": 3} - assert await redis_client.zadd(key, members_scores=members_scores) == 3 + assert await glide_client.zadd(key, members_scores=members_scores) == 3 - assert await redis_client.zcount(key, InfBound.NEG_INF, InfBound.POS_INF) == 3 + assert await glide_client.zcount(key, InfBound.NEG_INF, InfBound.POS_INF) == 3 assert ( - await redis_client.zcount( + await glide_client.zcount( key, ScoreBoundary(1, is_inclusive=False), ScoreBoundary(3, is_inclusive=False), @@ -3309,7 +3309,7 @@ async def test_zcount(self, redis_client: TGlideClient): == 1 ) assert ( - await redis_client.zcount( + await glide_client.zcount( key, ScoreBoundary(1, is_inclusive=False), ScoreBoundary(3, is_inclusive=True), @@ -3317,19 +3317,19 @@ async def test_zcount(self, redis_client: TGlideClient): == 2 ) assert ( - await redis_client.zcount( + await glide_client.zcount( key, InfBound.NEG_INF, ScoreBoundary(3, is_inclusive=True) ) == 3 ) assert ( - await redis_client.zcount( + await glide_client.zcount( key, InfBound.POS_INF, ScoreBoundary(3, is_inclusive=True) ) == 0 ) assert ( - await redis_client.zcount( + await glide_client.zcount( "non_existing_key", InfBound.NEG_INF, InfBound.POS_INF ) == 0 @@ -3337,42 +3337,42 @@ async def test_zcount(self, redis_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zscore(self, redis_client: TGlideClient): + async def test_zscore(self, glide_client: TGlideClient): key = get_random_string(10) members_scores: Mapping[TEncodable, float] = {"one": 1, "two": 2, "three": 3} - assert await redis_client.zadd(key, members_scores=members_scores) == 3 - assert await redis_client.zscore(key, "one") == 1.0 + assert await glide_client.zadd(key, members_scores=members_scores) == 3 + assert await glide_client.zscore(key, "one") == 1.0 - assert await redis_client.zscore(key, "non_existing_member") is None + assert await glide_client.zscore(key, "non_existing_member") is None assert ( - await redis_client.zscore("non_existing_key", "non_existing_member") is None + await glide_client.zscore("non_existing_key", "non_existing_member") is None ) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zmscore(self, redis_client: TGlideClient): + async def test_zmscore(self, glide_client: TGlideClient): key1 = get_random_string(10) key2 = get_random_string(10) members_scores: Mapping[TEncodable, float] = {"one": 1, "two": 2, "three": 3} - assert await redis_client.zadd(key1, members_scores=members_scores) == 3 - assert await redis_client.zmscore(key1, ["one", "two", "three"]) == [ + assert await glide_client.zadd(key1, members_scores=members_scores) == 3 + assert await glide_client.zmscore(key1, ["one", "two", "three"]) == [ 1.0, 2.0, 3.0, ] - assert await redis_client.zmscore( + assert await glide_client.zmscore( key1, ["one", "non_existing_member", "non_existing_member", "three"] ) == [1.0, None, None, 3.0] - assert await redis_client.zmscore("non_existing_key", ["one"]) == [None] + assert await glide_client.zmscore("non_existing_key", ["one"]) == [None] - assert await redis_client.set(key2, "value") == OK + assert await glide_client.set(key2, "value") == OK with pytest.raises(RequestError): - await redis_client.zmscore(key2, ["one"]) + await glide_client.zmscore(key2, ["one"]) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zinter_commands(self, redis_client: TGlideClient): + async def test_zinter_commands(self, glide_client: TGlideClient): key1 = "{testKey}:1-" + get_random_string(10) key2 = "{testKey}:2-" + get_random_string(10) key3 = "{testKey}:3-" + get_random_string(10) @@ -3384,17 +3384,17 @@ async def test_zinter_commands(self, redis_client: TGlideClient): "three": 3.5, } - assert await redis_client.zadd(key1, members_scores1) == 2 - assert await redis_client.zadd(key2, members_scores2) == 3 + assert await glide_client.zadd(key1, members_scores1) == 2 + assert await glide_client.zadd(key2, members_scores2) == 3 # zinter tests - zinter_map = await redis_client.zinter([key1, key2]) + zinter_map = await glide_client.zinter([key1, key2]) expected_zinter_map = [b"one", b"two"] assert zinter_map == expected_zinter_map # zinterstore tests - assert await redis_client.zinterstore(key3, [key1, key2]) == 2 - zinterstore_map = await redis_client.zrange_withscores(key3, range) + assert await glide_client.zinterstore(key3, [key1, key2]) == 2 + zinterstore_map = await glide_client.zrange_withscores(key3, range) expected_zinter_map_withscores = { b"one": 2.5, b"two": 4.5, @@ -3402,51 +3402,51 @@ async def test_zinter_commands(self, redis_client: TGlideClient): assert compare_maps(zinterstore_map, expected_zinter_map_withscores) is True # zinter_withscores tests - zinter_withscores_map = await redis_client.zinter_withscores([key1, key2]) + zinter_withscores_map = await glide_client.zinter_withscores([key1, key2]) assert ( compare_maps(zinter_withscores_map, expected_zinter_map_withscores) is True ) # MAX aggregation tests assert ( - await redis_client.zinterstore(key3, [key1, key2], AggregationType.MAX) == 2 + await glide_client.zinterstore(key3, [key1, key2], AggregationType.MAX) == 2 ) - zinterstore_map_max = await redis_client.zrange_withscores(key3, range) + zinterstore_map_max = await glide_client.zrange_withscores(key3, range) expected_zinter_map_max = { b"one": 1.5, b"two": 2.5, } assert compare_maps(zinterstore_map_max, expected_zinter_map_max) is True - zinter_withscores_map_max = await redis_client.zinter_withscores( + zinter_withscores_map_max = await glide_client.zinter_withscores( [key1, key2], AggregationType.MAX ) assert compare_maps(zinter_withscores_map_max, expected_zinter_map_max) is True # MIN aggregation tests assert ( - await redis_client.zinterstore(key3, [key1, key2], AggregationType.MIN) == 2 + await glide_client.zinterstore(key3, [key1, key2], AggregationType.MIN) == 2 ) - zinterstore_map_min = await redis_client.zrange_withscores(key3, range) + zinterstore_map_min = await glide_client.zrange_withscores(key3, range) expected_zinter_map_min = { b"one": 1.0, b"two": 2.0, } assert compare_maps(zinterstore_map_min, expected_zinter_map_min) is True - zinter_withscores_map_min = await redis_client.zinter_withscores( + zinter_withscores_map_min = await glide_client.zinter_withscores( [key1, key2], AggregationType.MIN ) assert compare_maps(zinter_withscores_map_min, expected_zinter_map_min) is True # SUM aggregation tests assert ( - await redis_client.zinterstore(key3, [key1, key2], AggregationType.SUM) == 2 + await glide_client.zinterstore(key3, [key1, key2], AggregationType.SUM) == 2 ) - zinterstore_map_sum = await redis_client.zrange_withscores(key3, range) + zinterstore_map_sum = await glide_client.zrange_withscores(key3, range) assert compare_maps(zinterstore_map_sum, expected_zinter_map_withscores) is True - zinter_withscores_map_sum = await redis_client.zinter_withscores( + zinter_withscores_map_sum = await glide_client.zinter_withscores( [key1, key2], AggregationType.SUM ) assert ( @@ -3456,12 +3456,12 @@ async def test_zinter_commands(self, redis_client: TGlideClient): # Multiplying scores during aggregation tests assert ( - await redis_client.zinterstore( + await glide_client.zinterstore( key3, [(key1, 2.0), (key2, 2.0)], AggregationType.SUM ) == 2 ) - zinterstore_map_multiplied = await redis_client.zrange_withscores(key3, range) + zinterstore_map_multiplied = await glide_client.zrange_withscores(key3, range) expected_zinter_map_multiplied = { b"one": 5.0, b"two": 9.0, @@ -3471,7 +3471,7 @@ async def test_zinter_commands(self, redis_client: TGlideClient): is True ) - zinter_withscores_map_multiplied = await redis_client.zinter_withscores( + zinter_withscores_map_multiplied = await glide_client.zinter_withscores( [(key1, 2.0), (key2, 2.0)], AggregationType.SUM ) assert ( @@ -3483,32 +3483,32 @@ async def test_zinter_commands(self, redis_client: TGlideClient): # Non-existing key test assert ( - await redis_client.zinterstore(key3, [key1, "{testKey}-non_existing_key"]) + await glide_client.zinterstore(key3, [key1, "{testKey}-non_existing_key"]) == 0 ) - zinter_withscores_non_existing = await redis_client.zinter_withscores( + zinter_withscores_non_existing = await glide_client.zinter_withscores( [key1, "{testKey}-non_existing_key"] ) assert zinter_withscores_non_existing == {} # Empty list check with pytest.raises(RequestError) as e: - await redis_client.zinterstore( + await glide_client.zinterstore( "{xyz}", cast(List[TEncodable], cast(List[TEncodable], [])) ) assert "wrong number of arguments" in str(e) with pytest.raises(RequestError) as e: - await redis_client.zinter([]) + await glide_client.zinter([]) assert "wrong number of arguments" in str(e) with pytest.raises(RequestError) as e: - await redis_client.zinter_withscores(cast(List[TEncodable], [])) + await glide_client.zinter_withscores(cast(List[TEncodable], [])) assert "at least 1 input key is needed" in str(e) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zunion_commands(self, redis_client: TGlideClient): + async def test_zunion_commands(self, glide_client: TGlideClient): key1 = "{testKey}:1-" + get_random_string(10) key2 = "{testKey}:2-" + get_random_string(10) key3 = "{testKey}:3-" + get_random_string(10) @@ -3520,17 +3520,17 @@ async def test_zunion_commands(self, redis_client: TGlideClient): "three": 3.5, } - assert await redis_client.zadd(key1, members_scores1) == 2 - assert await redis_client.zadd(key2, members_scores2) == 3 + assert await glide_client.zadd(key1, members_scores1) == 2 + assert await glide_client.zadd(key2, members_scores2) == 3 # zunion tests - zunion_map = await redis_client.zunion([key1, key2]) + zunion_map = await glide_client.zunion([key1, key2]) expected_zunion_map = [b"one", b"three", b"two"] assert zunion_map == expected_zunion_map # zunionstore tests - assert await redis_client.zunionstore(key3, [key1, key2]) == 3 - zunionstore_map = await redis_client.zrange_withscores(key3, range) + assert await glide_client.zunionstore(key3, [key1, key2]) == 3 + zunionstore_map = await glide_client.zrange_withscores(key3, range) expected_zunion_map_withscores = { b"one": 2.5, b"three": 3.5, @@ -3539,16 +3539,16 @@ async def test_zunion_commands(self, redis_client: TGlideClient): assert compare_maps(zunionstore_map, expected_zunion_map_withscores) is True # zunion_withscores tests - zunion_withscores_map = await redis_client.zunion_withscores([key1, key2]) + zunion_withscores_map = await glide_client.zunion_withscores([key1, key2]) assert ( compare_maps(zunion_withscores_map, expected_zunion_map_withscores) is True ) # MAX aggregation tests assert ( - await redis_client.zunionstore(key3, [key1, key2], AggregationType.MAX) == 3 + await glide_client.zunionstore(key3, [key1, key2], AggregationType.MAX) == 3 ) - zunionstore_map_max = await redis_client.zrange_withscores(key3, range) + zunionstore_map_max = await glide_client.zrange_withscores(key3, range) expected_zunion_map_max = { b"one": 1.5, b"two": 2.5, @@ -3556,16 +3556,16 @@ async def test_zunion_commands(self, redis_client: TGlideClient): } assert compare_maps(zunionstore_map_max, expected_zunion_map_max) is True - zunion_withscores_map_max = await redis_client.zunion_withscores( + zunion_withscores_map_max = await glide_client.zunion_withscores( [key1, key2], AggregationType.MAX ) assert compare_maps(zunion_withscores_map_max, expected_zunion_map_max) is True # MIN aggregation tests assert ( - await redis_client.zunionstore(key3, [key1, key2], AggregationType.MIN) == 3 + await glide_client.zunionstore(key3, [key1, key2], AggregationType.MIN) == 3 ) - zunionstore_map_min = await redis_client.zrange_withscores(key3, range) + zunionstore_map_min = await glide_client.zrange_withscores(key3, range) expected_zunion_map_min = { b"one": 1.0, b"two": 2.0, @@ -3573,19 +3573,19 @@ async def test_zunion_commands(self, redis_client: TGlideClient): } assert compare_maps(zunionstore_map_min, expected_zunion_map_min) is True - zunion_withscores_map_min = await redis_client.zunion_withscores( + zunion_withscores_map_min = await glide_client.zunion_withscores( [key1, key2], AggregationType.MIN ) assert compare_maps(zunion_withscores_map_min, expected_zunion_map_min) is True # SUM aggregation tests assert ( - await redis_client.zunionstore(key3, [key1, key2], AggregationType.SUM) == 3 + await glide_client.zunionstore(key3, [key1, key2], AggregationType.SUM) == 3 ) - zunionstore_map_sum = await redis_client.zrange_withscores(key3, range) + zunionstore_map_sum = await glide_client.zrange_withscores(key3, range) assert compare_maps(zunionstore_map_sum, expected_zunion_map_withscores) is True - zunion_withscores_map_sum = await redis_client.zunion_withscores( + zunion_withscores_map_sum = await glide_client.zunion_withscores( [key1, key2], AggregationType.SUM ) assert ( @@ -3595,12 +3595,12 @@ async def test_zunion_commands(self, redis_client: TGlideClient): # Multiplying scores during aggregation tests assert ( - await redis_client.zunionstore( + await glide_client.zunionstore( key3, [(key1, 2.0), (key2, 2.0)], AggregationType.SUM ) == 3 ) - zunionstore_map_multiplied = await redis_client.zrange_withscores(key3, range) + zunionstore_map_multiplied = await glide_client.zrange_withscores(key3, range) expected_zunion_map_multiplied = { b"one": 5.0, b"three": 7.0, @@ -3611,7 +3611,7 @@ async def test_zunion_commands(self, redis_client: TGlideClient): is True ) - zunion_withscores_map_multiplied = await redis_client.zunion_withscores( + zunion_withscores_map_multiplied = await glide_client.zunion_withscores( [(key1, 2.0), (key2, 2.0)], AggregationType.SUM ) assert ( @@ -3623,10 +3623,10 @@ async def test_zunion_commands(self, redis_client: TGlideClient): # Non-existing key test assert ( - await redis_client.zunionstore(key3, [key1, "{testKey}-non_existing_key"]) + await glide_client.zunionstore(key3, [key1, "{testKey}-non_existing_key"]) == 2 ) - zunionstore_map_nonexistingkey = await redis_client.zrange_withscores( + zunionstore_map_nonexistingkey = await glide_client.zrange_withscores( key3, range ) expected_zunion_map_nonexistingkey = { @@ -3640,7 +3640,7 @@ async def test_zunion_commands(self, redis_client: TGlideClient): is True ) - zunion_withscores_non_existing = await redis_client.zunion_withscores( + zunion_withscores_non_existing = await glide_client.zunion_withscores( [key1, "{testKey}-non_existing_key"] ) assert ( @@ -3652,49 +3652,49 @@ async def test_zunion_commands(self, redis_client: TGlideClient): # Empty list check with pytest.raises(RequestError) as e: - await redis_client.zunionstore("{xyz}", cast(List[TEncodable], [])) + await glide_client.zunionstore("{xyz}", cast(List[TEncodable], [])) assert "wrong number of arguments" in str(e) with pytest.raises(RequestError) as e: - await redis_client.zunion([]) + await glide_client.zunion([]) assert "wrong number of arguments" in str(e) with pytest.raises(RequestError) as e: - await redis_client.zunion_withscores(cast(List[TEncodable], [])) + await glide_client.zunion_withscores(cast(List[TEncodable], [])) assert "at least 1 input key is needed" in str(e) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zpopmin(self, redis_client: TGlideClient): + async def test_zpopmin(self, glide_client: TGlideClient): key = get_random_string(10) members_scores: Mapping[TEncodable, float] = {"a": 1.0, "b": 2.0, "c": 3.0} - assert await redis_client.zadd(key, members_scores=members_scores) == 3 - assert await redis_client.zpopmin(key) == {b"a": 1.0} + assert await glide_client.zadd(key, members_scores=members_scores) == 3 + assert await glide_client.zpopmin(key) == {b"a": 1.0} - zpopmin_map = await redis_client.zpopmin(key, 3) + zpopmin_map = await glide_client.zpopmin(key, 3) expected_map = {b"b": 2.0, b"c": 3.0} assert compare_maps(zpopmin_map, expected_map) is True - assert await redis_client.zpopmin(key) == {} - assert await redis_client.set(key, "value") == OK + assert await glide_client.zpopmin(key) == {} + assert await glide_client.set(key, "value") == OK with pytest.raises(RequestError): - await redis_client.zpopmin(key) + await glide_client.zpopmin(key) - assert await redis_client.zpopmin("non_exisitng_key") == {} + assert await glide_client.zpopmin("non_exisitng_key") == {} @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_bzpopmin(self, redis_client: TGlideClient): + async def test_bzpopmin(self, glide_client: TGlideClient): key1 = f"{{testKey}}:{get_random_string(10)}" key2 = f"{{testKey}}:{get_random_string(10)}" non_existing_key = f"{{testKey}}:non_existing_key" - assert await redis_client.zadd(key1, {"a": 1.0, "b": 1.5}) == 2 - assert await redis_client.zadd(key2, {"c": 2.0}) == 1 - assert await redis_client.bzpopmin( + assert await glide_client.zadd(key1, {"a": 1.0, "b": 1.5}) == 2 + assert await glide_client.zadd(key2, {"c": 2.0}) == 1 + assert await glide_client.bzpopmin( [key1, key2], 0.5 ) == convert_string_to_bytes_object([key1, "a", 1.0]) - assert await redis_client.bzpopmin( + assert await glide_client.bzpopmin( [non_existing_key, key2], 0.5 ) == convert_string_to_bytes_object( [ @@ -3703,19 +3703,19 @@ async def test_bzpopmin(self, redis_client: TGlideClient): 2.0, ] ) - assert await redis_client.bzpopmin(["non_existing_key"], 0.5) is None + assert await glide_client.bzpopmin(["non_existing_key"], 0.5) is None # invalid argument - key list must not be empty with pytest.raises(RequestError): - await redis_client.bzpopmin([], 0.5) + await glide_client.bzpopmin([], 0.5) # key exists, but it is not a sorted set - assert await redis_client.set("foo", "value") == OK + assert await glide_client.set("foo", "value") == OK with pytest.raises(RequestError): - await redis_client.bzpopmin(["foo"], 0.5) + await glide_client.bzpopmin(["foo"], 0.5) async def endless_bzpopmin_call(): - await redis_client.bzpopmin(["non_existent_key"], 0) + await glide_client.bzpopmin(["non_existent_key"], 0) # bzpopmin is called against a non-existing key with no timeout, but we wrap the call in an asyncio timeout to # avoid having the test block forever @@ -3724,36 +3724,36 @@ async def endless_bzpopmin_call(): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zpopmax(self, redis_client: TGlideClient): + async def test_zpopmax(self, glide_client: TGlideClient): key = get_random_string(10) members_scores: Mapping[TEncodable, float] = {"a": 1.0, "b": 2.0, "c": 3.0} - assert await redis_client.zadd(key, members_scores) == 3 - assert await redis_client.zpopmax(key) == {b"c": 3.0} + assert await glide_client.zadd(key, members_scores) == 3 + assert await glide_client.zpopmax(key) == {b"c": 3.0} - zpopmax_map = await redis_client.zpopmax(key, 3) + zpopmax_map = await glide_client.zpopmax(key, 3) expected_map = {"b": 2.0, "a": 1.0} assert compare_maps(zpopmax_map, expected_map) is True - assert await redis_client.zpopmax(key) == {} - assert await redis_client.set(key, "value") == OK + assert await glide_client.zpopmax(key) == {} + assert await glide_client.set(key, "value") == OK with pytest.raises(RequestError): - await redis_client.zpopmax(key) + await glide_client.zpopmax(key) - assert await redis_client.zpopmax("non_exisitng_key") == {} + assert await glide_client.zpopmax("non_exisitng_key") == {} @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_bzpopmax(self, redis_client: TGlideClient): + async def test_bzpopmax(self, glide_client: TGlideClient): key1 = f"{{testKey}}:{get_random_string(10)}" key2 = f"{{testKey}}:{get_random_string(10)}" non_existing_key = f"{{testKey}}:non_existing_key" - assert await redis_client.zadd(key1, {"a": 1.0, "b": 1.5}) == 2 - assert await redis_client.zadd(key2, {"c": 2.0}) == 1 - assert await redis_client.bzpopmax( + assert await glide_client.zadd(key1, {"a": 1.0, "b": 1.5}) == 2 + assert await glide_client.zadd(key2, {"c": 2.0}) == 1 + assert await glide_client.bzpopmax( [key1, key2], 0.5 ) == convert_string_to_bytes_object([key1, "b", 1.5]) - assert await redis_client.bzpopmax( + assert await glide_client.bzpopmax( [non_existing_key, key2], 0.5 ) == convert_string_to_bytes_object( [ @@ -3762,19 +3762,19 @@ async def test_bzpopmax(self, redis_client: TGlideClient): 2.0, ] ) - assert await redis_client.bzpopmax(["non_existing_key"], 0.5) is None + assert await glide_client.bzpopmax(["non_existing_key"], 0.5) is None # invalid argument - key list must not be empty with pytest.raises(RequestError): - await redis_client.bzpopmax([], 0.5) + await glide_client.bzpopmax([], 0.5) # key exists, but it is not a sorted set - assert await redis_client.set("foo", "value") == OK + assert await glide_client.set("foo", "value") == OK with pytest.raises(RequestError): - await redis_client.bzpopmax(["foo"], 0.5) + await glide_client.bzpopmax(["foo"], 0.5) async def endless_bzpopmax_call(): - await redis_client.bzpopmax(["non_existent_key"], 0) + await glide_client.bzpopmax(["non_existent_key"], 0) # bzpopmax is called against a non-existing key with no timeout, but we wrap the call in an asyncio timeout to # avoid having the test block forever @@ -3783,57 +3783,57 @@ async def endless_bzpopmax_call(): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zrange_by_index(self, redis_client: TGlideClient): + async def test_zrange_by_index(self, glide_client: TGlideClient): key = get_random_string(10) members_scores: Mapping[TEncodable, float] = {"one": 1, "two": 2, "three": 3} - assert await redis_client.zadd(key, members_scores=members_scores) == 3 + assert await glide_client.zadd(key, members_scores=members_scores) == 3 - assert await redis_client.zrange(key, RangeByIndex(start=0, stop=1)) == [ + assert await glide_client.zrange(key, RangeByIndex(start=0, stop=1)) == [ b"one", b"two", ] - zrange_map = await redis_client.zrange_withscores( + zrange_map = await glide_client.zrange_withscores( key, RangeByIndex(start=0, stop=-1) ) expected_map = {b"one": 1.0, b"two": 2.0, b"three": 3.0} assert compare_maps(zrange_map, expected_map) is True - assert await redis_client.zrange( + assert await glide_client.zrange( key, RangeByIndex(start=0, stop=1), reverse=True ) == [ b"three", b"two", ] - assert await redis_client.zrange(key, RangeByIndex(start=3, stop=1)) == [] + assert await glide_client.zrange(key, RangeByIndex(start=3, stop=1)) == [] assert ( - await redis_client.zrange_withscores(key, RangeByIndex(start=3, stop=1)) + await glide_client.zrange_withscores(key, RangeByIndex(start=3, stop=1)) == {} ) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zrange_byscore(self, redis_client: TGlideClient): + async def test_zrange_byscore(self, glide_client: TGlideClient): key = get_random_string(10) members_scores: Mapping[TEncodable, float] = {"one": 1, "two": 2, "three": 3} - assert await redis_client.zadd(key, members_scores=members_scores) == 3 + assert await glide_client.zadd(key, members_scores=members_scores) == 3 - assert await redis_client.zrange( + assert await glide_client.zrange( key, RangeByScore( start=InfBound.NEG_INF, stop=ScoreBoundary(3, is_inclusive=False) ), ) == [b"one", b"two"] - zrange_map = await redis_client.zrange_withscores( + zrange_map = await glide_client.zrange_withscores( key, RangeByScore(start=InfBound.NEG_INF, stop=InfBound.POS_INF), ) expected_map = {b"one": 1.0, b"two": 2.0, b"three": 3.0} assert compare_maps(zrange_map, expected_map) is True - assert await redis_client.zrange( + assert await glide_client.zrange( key, RangeByScore( start=ScoreBoundary(3, is_inclusive=False), stop=InfBound.NEG_INF @@ -3842,7 +3842,7 @@ async def test_zrange_byscore(self, redis_client: TGlideClient): ) == [b"two", b"one"] assert ( - await redis_client.zrange( + await glide_client.zrange( key, RangeByScore( start=InfBound.NEG_INF, @@ -3853,7 +3853,7 @@ async def test_zrange_byscore(self, redis_client: TGlideClient): ) == [b"two", b"three"] assert ( - await redis_client.zrange( + await glide_client.zrange( key, RangeByScore( start=InfBound.NEG_INF, stop=ScoreBoundary(3, is_inclusive=False) @@ -3864,7 +3864,7 @@ async def test_zrange_byscore(self, redis_client: TGlideClient): ) # stop is greater than start with reverse set to True assert ( - await redis_client.zrange( + await glide_client.zrange( key, RangeByScore( start=InfBound.POS_INF, stop=ScoreBoundary(3, is_inclusive=False) @@ -3874,7 +3874,7 @@ async def test_zrange_byscore(self, redis_client: TGlideClient): ) # start is greater than stop assert ( - await redis_client.zrange_withscores( + await glide_client.zrange_withscores( key, RangeByScore( start=InfBound.POS_INF, stop=ScoreBoundary(3, is_inclusive=False) @@ -3884,7 +3884,7 @@ async def test_zrange_byscore(self, redis_client: TGlideClient): ) # start is greater than stop assert ( - await redis_client.zrange_withscores( + await glide_client.zrange_withscores( key, RangeByScore( start=InfBound.NEG_INF, stop=ScoreBoundary(3, is_inclusive=False) @@ -3896,12 +3896,12 @@ async def test_zrange_byscore(self, redis_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zrange_bylex(self, redis_client: TGlideClient): + async def test_zrange_bylex(self, glide_client: TGlideClient): key = get_random_string(10) members_scores: Mapping[TEncodable, float] = {"a": 1, "b": 2, "c": 3} - assert await redis_client.zadd(key, members_scores=members_scores) == 3 + assert await glide_client.zadd(key, members_scores=members_scores) == 3 - assert await redis_client.zrange( + assert await glide_client.zrange( key, RangeByLex( start=InfBound.NEG_INF, stop=LexBoundary("c", is_inclusive=False) @@ -3909,7 +3909,7 @@ async def test_zrange_bylex(self, redis_client: TGlideClient): ) == [b"a", b"b"] assert ( - await redis_client.zrange( + await glide_client.zrange( key, RangeByLex( start=InfBound.NEG_INF, @@ -3919,7 +3919,7 @@ async def test_zrange_bylex(self, redis_client: TGlideClient): ) ) == [b"b", b"c"] - assert await redis_client.zrange( + assert await glide_client.zrange( key, RangeByLex( start=LexBoundary("c", is_inclusive=False), stop=InfBound.NEG_INF @@ -3928,7 +3928,7 @@ async def test_zrange_bylex(self, redis_client: TGlideClient): ) == [b"b", b"a"] assert ( - await redis_client.zrange( + await glide_client.zrange( key, RangeByLex( start=InfBound.NEG_INF, stop=LexBoundary("c", is_inclusive=False) @@ -3939,7 +3939,7 @@ async def test_zrange_bylex(self, redis_client: TGlideClient): ) # stop is greater than start with reverse set to True assert ( - await redis_client.zrange( + await glide_client.zrange( key, RangeByLex( start=InfBound.POS_INF, stop=LexBoundary("c", is_inclusive=False) @@ -3950,30 +3950,30 @@ async def test_zrange_bylex(self, redis_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zrange_different_types_of_keys(self, redis_client: TGlideClient): + async def test_zrange_different_types_of_keys(self, glide_client: TGlideClient): key = get_random_string(10) assert ( - await redis_client.zrange("non_existing_key", RangeByIndex(start=0, stop=1)) + await glide_client.zrange("non_existing_key", RangeByIndex(start=0, stop=1)) == [] ) assert ( - await redis_client.zrange_withscores( + await glide_client.zrange_withscores( "non_existing_key", RangeByIndex(start=0, stop=-1) ) ) == {} - assert await redis_client.set(key, "value") == OK + assert await glide_client.set(key, "value") == OK with pytest.raises(RequestError): - await redis_client.zrange(key, RangeByIndex(start=0, stop=1)) + await glide_client.zrange(key, RangeByIndex(start=0, stop=1)) with pytest.raises(RequestError): - await redis_client.zrange_withscores(key, RangeByIndex(start=0, stop=1)) + await glide_client.zrange_withscores(key, RangeByIndex(start=0, stop=1)) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zrangestore_by_index(self, redis_client: TGlideClient): + async def test_zrangestore_by_index(self, glide_client: TGlideClient): destination = f"{{testKey}}:{get_random_string(10)}" source = f"{{testKey}}:{get_random_string(10)}" string_key = f"{{testKey}}:{get_random_string(10)}" @@ -3984,58 +3984,58 @@ async def test_zrangestore_by_index(self, redis_client: TGlideClient): "two": 2.0, "three": 3.0, } - assert await redis_client.zadd(source, member_scores) == 3 + assert await glide_client.zadd(source, member_scores) == 3 # full range assert ( - await redis_client.zrangestore(destination, source, RangeByIndex(0, -1)) + await glide_client.zrangestore(destination, source, RangeByIndex(0, -1)) == 3 ) - zrange_res = await redis_client.zrange_withscores( + zrange_res = await glide_client.zrange_withscores( destination, RangeByIndex(0, -1) ) assert compare_maps(zrange_res, {"one": 1.0, "two": 2.0, "three": 3.0}) is True # range from rank 0 to 1, from highest to lowest score assert ( - await redis_client.zrangestore( + await glide_client.zrangestore( destination, source, RangeByIndex(0, 1), True ) == 2 ) - zrange_res = await redis_client.zrange_withscores( + zrange_res = await glide_client.zrange_withscores( destination, RangeByIndex(0, -1) ) assert compare_maps(zrange_res, {"two": 2.0, "three": 3.0}) is True # incorrect range, as start > stop assert ( - await redis_client.zrangestore(destination, source, RangeByIndex(3, 1)) == 0 + await glide_client.zrangestore(destination, source, RangeByIndex(3, 1)) == 0 ) assert ( - await redis_client.zrange_withscores(destination, RangeByIndex(0, -1)) == {} + await glide_client.zrange_withscores(destination, RangeByIndex(0, -1)) == {} ) # non-existing source assert ( - await redis_client.zrangestore( + await glide_client.zrangestore( destination, non_existing_key, RangeByIndex(0, -1) ) == 0 ) assert ( - await redis_client.zrange_withscores(destination, RangeByIndex(0, -1)) == {} + await glide_client.zrange_withscores(destination, RangeByIndex(0, -1)) == {} ) # key exists, but it is not a set - assert await redis_client.set(string_key, "value") == OK + assert await glide_client.set(string_key, "value") == OK with pytest.raises(RequestError): - await redis_client.zrangestore(destination, string_key, RangeByIndex(0, -1)) + await glide_client.zrangestore(destination, string_key, RangeByIndex(0, -1)) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zrangestore_by_score(self, redis_client: TGlideClient): + async def test_zrangestore_by_score(self, glide_client: TGlideClient): destination = f"{{testKey}}:{get_random_string(10)}" source = f"{{testKey}}:{get_random_string(10)}" string_key = f"{{testKey}}:{get_random_string(10)}" @@ -4046,11 +4046,11 @@ async def test_zrangestore_by_score(self, redis_client: TGlideClient): "two": 2.0, "three": 3.0, } - assert await redis_client.zadd(source, member_scores) == 3 + assert await glide_client.zadd(source, member_scores) == 3 # range from negative infinity to 3 (exclusive) assert ( - await redis_client.zrangestore( + await glide_client.zrangestore( destination, source, RangeByScore(InfBound.NEG_INF, ScoreBoundary(3, False)), @@ -4058,40 +4058,40 @@ async def test_zrangestore_by_score(self, redis_client: TGlideClient): == 2 ) - zrange_res = await redis_client.zrange_withscores( + zrange_res = await glide_client.zrange_withscores( destination, RangeByIndex(0, -1) ) assert compare_maps(zrange_res, {"one": 1.0, "two": 2.0}) is True # range from 1 (inclusive) to positive infinity assert ( - await redis_client.zrangestore( + await glide_client.zrangestore( destination, source, RangeByScore(ScoreBoundary(1), InfBound.POS_INF) ) == 3 ) - zrange_res = await redis_client.zrange_withscores( + zrange_res = await glide_client.zrange_withscores( destination, RangeByIndex(0, -1) ) assert compare_maps(zrange_res, {"one": 1.0, "two": 2.0, "three": 3.0}) is True # range from negative to positive infinity, limited to ranks 1 to 2 assert ( - await redis_client.zrangestore( + await glide_client.zrangestore( destination, source, RangeByScore(InfBound.NEG_INF, InfBound.POS_INF, Limit(1, 2)), ) == 2 ) - zrange_res = await redis_client.zrange_withscores( + zrange_res = await glide_client.zrange_withscores( destination, RangeByIndex(0, -1) ) assert compare_maps(zrange_res, {"two": 2.0, "three": 3.0}) is True # range from positive to negative infinity reversed, limited to ranks 1 to 2 assert ( - await redis_client.zrangestore( + await glide_client.zrangestore( destination, source, RangeByScore(InfBound.POS_INF, InfBound.NEG_INF, Limit(1, 2)), @@ -4100,14 +4100,14 @@ async def test_zrangestore_by_score(self, redis_client: TGlideClient): == 2 ) - zrange_res = await redis_client.zrange_withscores( + zrange_res = await glide_client.zrange_withscores( destination, RangeByIndex(0, -1) ) assert compare_maps(zrange_res, {"one": 1.0, "two": 2.0}) is True # incorrect range as start > stop assert ( - await redis_client.zrangestore( + await glide_client.zrangestore( destination, source, RangeByScore(ScoreBoundary(3, False), InfBound.NEG_INF), @@ -4115,12 +4115,12 @@ async def test_zrangestore_by_score(self, redis_client: TGlideClient): == 0 ) assert ( - await redis_client.zrange_withscores(destination, RangeByIndex(0, -1)) == {} + await glide_client.zrange_withscores(destination, RangeByIndex(0, -1)) == {} ) # non-existing source assert ( - await redis_client.zrangestore( + await glide_client.zrangestore( destination, non_existing_key, RangeByScore(InfBound.NEG_INF, ScoreBoundary(3, False)), @@ -4128,13 +4128,13 @@ async def test_zrangestore_by_score(self, redis_client: TGlideClient): == 0 ) assert ( - await redis_client.zrange_withscores(destination, RangeByIndex(0, -1)) == {} + await glide_client.zrange_withscores(destination, RangeByIndex(0, -1)) == {} ) # key exists, but it is not a set - assert await redis_client.set(string_key, "value") == OK + assert await glide_client.set(string_key, "value") == OK with pytest.raises(RequestError): - await redis_client.zrangestore( + await glide_client.zrangestore( destination, string_key, RangeByScore(ScoreBoundary(0), ScoreBoundary(3)), @@ -4142,18 +4142,18 @@ async def test_zrangestore_by_score(self, redis_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zrangestore_by_lex(self, redis_client: TGlideClient): + async def test_zrangestore_by_lex(self, glide_client: TGlideClient): destination = f"{{testKey}}:{get_random_string(10)}" source = f"{{testKey}}:{get_random_string(10)}" string_key = f"{{testKey}}:4-{get_random_string(10)}" non_existing_key = f"{{testKey}}:5-{get_random_string(10)}" member_scores: Mapping[TEncodable, float] = {"a": 1.0, "b": 2.0, "c": 3.0} - assert await redis_client.zadd(source, member_scores) == 3 + assert await glide_client.zadd(source, member_scores) == 3 # range from negative infinity to "c" (exclusive) assert ( - await redis_client.zrangestore( + await glide_client.zrangestore( destination, source, RangeByLex(InfBound.NEG_INF, LexBoundary("c", False)), @@ -4161,27 +4161,27 @@ async def test_zrangestore_by_lex(self, redis_client: TGlideClient): == 2 ) - zrange_res = await redis_client.zrange_withscores( + zrange_res = await glide_client.zrange_withscores( destination, RangeByIndex(0, -1) ) assert compare_maps(zrange_res, {"a": 1.0, "b": 2.0}) is True # range from "a" (inclusive) to positive infinity assert ( - await redis_client.zrangestore( + await glide_client.zrangestore( destination, source, RangeByLex(LexBoundary("a"), InfBound.POS_INF) ) == 3 ) - zrange_res = await redis_client.zrange_withscores( + zrange_res = await glide_client.zrange_withscores( destination, RangeByIndex(0, -1) ) assert compare_maps(zrange_res, {"a": 1.0, "b": 2.0, "c": 3.0}) is True # range from negative to positive infinity, limited to ranks 1 to 2 assert ( - await redis_client.zrangestore( + await glide_client.zrangestore( destination, source, RangeByLex(InfBound.NEG_INF, InfBound.POS_INF, Limit(1, 2)), @@ -4189,14 +4189,14 @@ async def test_zrangestore_by_lex(self, redis_client: TGlideClient): == 2 ) - zrange_res = await redis_client.zrange_withscores( + zrange_res = await glide_client.zrange_withscores( destination, RangeByIndex(0, -1) ) assert compare_maps(zrange_res, {"b": 2.0, "c": 3.0}) is True # range from positive to negative infinity reversed, limited to ranks 1 to 2 assert ( - await redis_client.zrangestore( + await glide_client.zrangestore( destination, source, RangeByLex(InfBound.POS_INF, InfBound.NEG_INF, Limit(1, 2)), @@ -4205,14 +4205,14 @@ async def test_zrangestore_by_lex(self, redis_client: TGlideClient): == 2 ) - zrange_res = await redis_client.zrange_withscores( + zrange_res = await glide_client.zrange_withscores( destination, RangeByIndex(0, -1) ) assert compare_maps(zrange_res, {"a": 1.0, "b": 2.0}) is True # incorrect range as start > stop assert ( - await redis_client.zrangestore( + await glide_client.zrangestore( destination, source, RangeByLex(LexBoundary("c", False), InfBound.NEG_INF), @@ -4220,12 +4220,12 @@ async def test_zrangestore_by_lex(self, redis_client: TGlideClient): == 0 ) assert ( - await redis_client.zrange_withscores(destination, RangeByIndex(0, -1)) == {} + await glide_client.zrange_withscores(destination, RangeByIndex(0, -1)) == {} ) # non-existing source assert ( - await redis_client.zrangestore( + await glide_client.zrangestore( destination, non_existing_key, RangeByLex(InfBound.NEG_INF, InfBound.POS_INF), @@ -4233,40 +4233,40 @@ async def test_zrangestore_by_lex(self, redis_client: TGlideClient): == 0 ) assert ( - await redis_client.zrange_withscores(destination, RangeByIndex(0, -1)) == {} + await glide_client.zrange_withscores(destination, RangeByIndex(0, -1)) == {} ) # key exists, but it is not a set - assert await redis_client.set(string_key, "value") == OK + assert await glide_client.set(string_key, "value") == OK with pytest.raises(RequestError): - await redis_client.zrangestore( + await glide_client.zrangestore( destination, string_key, RangeByLex(InfBound.NEG_INF, InfBound.POS_INF) ) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zrank(self, redis_client: TGlideClient): + async def test_zrank(self, glide_client: TGlideClient): key = get_random_string(10) members_scores: Mapping[TEncodable, float] = {"one": 1.5, "two": 2, "three": 3} - assert await redis_client.zadd(key, members_scores) == 3 - assert await redis_client.zrank(key, "one") == 0 - if not await check_if_server_version_lt(redis_client, "7.2.0"): - assert await redis_client.zrank_withscore(key, "one") == [0, 1.5] - assert await redis_client.zrank_withscore(key, "non_existing_field") is None + assert await glide_client.zadd(key, members_scores) == 3 + assert await glide_client.zrank(key, "one") == 0 + if not await check_if_server_version_lt(glide_client, "7.2.0"): + assert await glide_client.zrank_withscore(key, "one") == [0, 1.5] + assert await glide_client.zrank_withscore(key, "non_existing_field") is None assert ( - await redis_client.zrank_withscore("non_existing_key", "field") is None + await glide_client.zrank_withscore("non_existing_key", "field") is None ) - assert await redis_client.zrank(key, "non_existing_field") is None - assert await redis_client.zrank("non_existing_key", "field") is None + assert await glide_client.zrank(key, "non_existing_field") is None + assert await glide_client.zrank("non_existing_key", "field") is None - assert await redis_client.set(key, "value") == OK + assert await glide_client.set(key, "value") == OK with pytest.raises(RequestError): - await redis_client.zrank(key, "one") + await glide_client.zrank(key, "one") @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zrevrank(self, redis_client: TGlideClient): + async def test_zrevrank(self, glide_client: TGlideClient): key = get_random_string(10) non_existing_key = get_random_string(10) string_key = get_random_string(10) @@ -4276,36 +4276,36 @@ async def test_zrevrank(self, redis_client: TGlideClient): "three": 3.0, } - assert await redis_client.zadd(key, member_scores) == 3 - assert await redis_client.zrevrank(key, "three") == 0 - assert await redis_client.zrevrank(key, "non_existing_member") is None + assert await glide_client.zadd(key, member_scores) == 3 + assert await glide_client.zrevrank(key, "three") == 0 + assert await glide_client.zrevrank(key, "non_existing_member") is None assert ( - await redis_client.zrevrank(non_existing_key, "non_existing_member") is None + await glide_client.zrevrank(non_existing_key, "non_existing_member") is None ) - if not await check_if_server_version_lt(redis_client, "7.2.0"): - assert await redis_client.zrevrank_withscore(key, "one") == [2, 1.0] + if not await check_if_server_version_lt(glide_client, "7.2.0"): + assert await glide_client.zrevrank_withscore(key, "one") == [2, 1.0] assert ( - await redis_client.zrevrank_withscore(key, "non_existing_member") + await glide_client.zrevrank_withscore(key, "non_existing_member") is None ) assert ( - await redis_client.zrevrank_withscore( + await glide_client.zrevrank_withscore( non_existing_key, "non_existing_member" ) is None ) # key exists, but it is not a sorted set - assert await redis_client.set(string_key, "foo") == OK + assert await glide_client.set(string_key, "foo") == OK with pytest.raises(RequestError): - await redis_client.zrevrank(string_key, "member") + await glide_client.zrevrank(string_key, "member") with pytest.raises(RequestError): - await redis_client.zrevrank_withscore(string_key, "member") + await glide_client.zrevrank_withscore(string_key, "member") @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zdiff(self, redis_client: TGlideClient): + async def test_zdiff(self, glide_client: TGlideClient): key1 = f"{{testKey}}:1-{get_random_string(10)}" key2 = f"{{testKey}}:2-{get_random_string(10)}" key3 = f"{{testKey}}:3-{get_random_string(10)}" @@ -4325,46 +4325,46 @@ async def test_zdiff(self, redis_client: TGlideClient): "four": 4.0, } - assert await redis_client.zadd(key1, member_scores1) == 3 - assert await redis_client.zadd(key2, member_scores2) == 1 - assert await redis_client.zadd(key3, member_scores3) == 4 + assert await glide_client.zadd(key1, member_scores1) == 3 + assert await glide_client.zadd(key2, member_scores2) == 1 + assert await glide_client.zadd(key3, member_scores3) == 4 - assert await redis_client.zdiff([key1, key2]) == [b"one", b"three"] - assert await redis_client.zdiff([key1, key3]) == [] - assert await redis_client.zdiff([non_existing_key, key3]) == [] + assert await glide_client.zdiff([key1, key2]) == [b"one", b"three"] + assert await glide_client.zdiff([key1, key3]) == [] + assert await glide_client.zdiff([non_existing_key, key3]) == [] - zdiff_map = await redis_client.zdiff_withscores([key1, key2]) + zdiff_map = await glide_client.zdiff_withscores([key1, key2]) expected_map = { b"one": 1.0, b"three": 3.0, } assert compare_maps(zdiff_map, expected_map) is True assert ( - compare_maps(await redis_client.zdiff_withscores([key1, key3]), {}) is True # type: ignore + compare_maps(await glide_client.zdiff_withscores([key1, key3]), {}) is True # type: ignore ) - non_exist_res = await redis_client.zdiff_withscores([non_existing_key, key3]) + non_exist_res = await glide_client.zdiff_withscores([non_existing_key, key3]) assert non_exist_res == {} # invalid argument - key list must not be empty with pytest.raises(RequestError): - await redis_client.zdiff([]) + await glide_client.zdiff([]) # invalid argument - key list must not be empty with pytest.raises(RequestError): - await redis_client.zdiff_withscores([]) + await glide_client.zdiff_withscores([]) # key exists, but it is not a sorted set - assert await redis_client.set(string_key, "foo") == OK + assert await glide_client.set(string_key, "foo") == OK with pytest.raises(RequestError): - await redis_client.zdiff([string_key, key2]) + await glide_client.zdiff([string_key, key2]) - assert await redis_client.set(string_key, "foo") == OK + assert await glide_client.set(string_key, "foo") == OK with pytest.raises(RequestError): - await redis_client.zdiff_withscores([string_key, key2]) + await glide_client.zdiff_withscores([string_key, key2]) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zdiffstore(self, redis_client: TGlideClient): + async def test_zdiffstore(self, glide_client: TGlideClient): key1 = f"{{testKey}}:1-{get_random_string(10)}" key2 = f"{{testKey}}:2-{get_random_string(10)}" key3 = f"{{testKey}}:3-{get_random_string(10)}" @@ -4385,36 +4385,36 @@ async def test_zdiffstore(self, redis_client: TGlideClient): "four": 4.0, } - assert await redis_client.zadd(key1, member_scores1) == 3 - assert await redis_client.zadd(key2, member_scores2) == 1 - assert await redis_client.zadd(key3, member_scores3) == 4 + assert await glide_client.zadd(key1, member_scores1) == 3 + assert await glide_client.zadd(key2, member_scores2) == 1 + assert await glide_client.zadd(key3, member_scores3) == 4 - assert await redis_client.zdiffstore(key4, [key1, key2]) == 2 + assert await glide_client.zdiffstore(key4, [key1, key2]) == 2 - zrange_res = await redis_client.zrange_withscores(key4, RangeByIndex(0, -1)) + zrange_res = await glide_client.zrange_withscores(key4, RangeByIndex(0, -1)) assert compare_maps(zrange_res, {"one": 1.0, "three": 3.0}) is True - assert await redis_client.zdiffstore(key4, [key3, key2, key1]) == 1 - assert await redis_client.zrange_withscores(key4, RangeByIndex(0, -1)) == { + assert await glide_client.zdiffstore(key4, [key3, key2, key1]) == 1 + assert await glide_client.zrange_withscores(key4, RangeByIndex(0, -1)) == { b"four": 4.0 } - assert await redis_client.zdiffstore(key4, [key1, key3]) == 0 - assert await redis_client.zrange_withscores(key4, RangeByIndex(0, -1)) == {} + assert await glide_client.zdiffstore(key4, [key1, key3]) == 0 + assert await glide_client.zrange_withscores(key4, RangeByIndex(0, -1)) == {} - assert await redis_client.zdiffstore(key4, [non_existing_key, key1]) == 0 - assert await redis_client.zrange_withscores(key4, RangeByIndex(0, -1)) == {} + assert await glide_client.zdiffstore(key4, [non_existing_key, key1]) == 0 + assert await glide_client.zrange_withscores(key4, RangeByIndex(0, -1)) == {} # key exists, but it is not a sorted set - assert await redis_client.set(string_key, "value") == OK + assert await glide_client.set(string_key, "value") == OK with pytest.raises(RequestError): - await redis_client.zdiffstore(key4, [string_key, key1]) + await glide_client.zdiffstore(key4, [string_key, key1]) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_bzmpop(self, redis_client: TGlideClient): + async def test_bzmpop(self, glide_client: TGlideClient): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") key1 = f"{{test}}-1-f{get_random_string(10)}" @@ -4423,64 +4423,64 @@ async def test_bzmpop(self, redis_client: TGlideClient): string_key = f"{{test}}-3-f{get_random_string(10)}" assert ( - await redis_client.zadd( + await glide_client.zadd( key1, cast(Mapping[TEncodable, float], {"a1": 1, "b1": 2}) ) == 2 ) assert ( - await redis_client.zadd( + await glide_client.zadd( key2, cast(Mapping[TEncodable, float], {"a2": 0.1, "b2": 0.2}) ) == 2 ) - assert await redis_client.bzmpop([key1, key2], ScoreFilter.MAX, 0.1) == [ + assert await glide_client.bzmpop([key1, key2], ScoreFilter.MAX, 0.1) == [ key1.encode(), {b"b1": 2}, ] - assert await redis_client.bzmpop([key2, key1], ScoreFilter.MAX, 0.1, 10) == [ + assert await glide_client.bzmpop([key2, key1], ScoreFilter.MAX, 0.1, 10) == [ key2.encode(), {b"b2": 0.2, b"a2": 0.1}, ] # ensure that command doesn't time out even if timeout > request timeout (250ms by default) assert ( - await redis_client.bzmpop([non_existing_key], ScoreFilter.MIN, 0.5) is None + await glide_client.bzmpop([non_existing_key], ScoreFilter.MIN, 0.5) is None ) assert ( - await redis_client.bzmpop([non_existing_key], ScoreFilter.MIN, 0.55, 1) + await glide_client.bzmpop([non_existing_key], ScoreFilter.MIN, 0.55, 1) is None ) # key exists, but it is not a sorted set - assert await redis_client.set(string_key, "value") == OK + assert await glide_client.set(string_key, "value") == OK with pytest.raises(RequestError): - await redis_client.bzmpop([string_key], ScoreFilter.MAX, 0.1) + await glide_client.bzmpop([string_key], ScoreFilter.MAX, 0.1) with pytest.raises(RequestError): - await redis_client.bzmpop([string_key], ScoreFilter.MAX, 0.1, 1) + await glide_client.bzmpop([string_key], ScoreFilter.MAX, 0.1, 1) # incorrect argument: key list should not be empty with pytest.raises(RequestError): - assert await redis_client.bzmpop([], ScoreFilter.MAX, 0.1, 1) + assert await glide_client.bzmpop([], ScoreFilter.MAX, 0.1, 1) # incorrect argument: count should be greater than 0 with pytest.raises(RequestError): - assert await redis_client.bzmpop([key1], ScoreFilter.MAX, 0.1, 0) + assert await glide_client.bzmpop([key1], ScoreFilter.MAX, 0.1, 0) # check that order of entries in the response is preserved entries: Dict[TEncodable, float] = {} for i in range(0, 10): entries.update({f"a{i}": float(i)}) - assert await redis_client.zadd(key2, entries) == 10 - result = await redis_client.bzmpop([key2], ScoreFilter.MIN, 0.1, 10) + assert await glide_client.zadd(key2, entries) == 10 + result = await glide_client.bzmpop([key2], ScoreFilter.MIN, 0.1, 10) assert result is not None result_map = cast(Mapping[bytes, float], result[1]) assert compare_maps(entries, result_map) is True # type: ignore async def endless_bzmpop_call(): - await redis_client.bzmpop(["non_existent_key"], ScoreFilter.MAX, 0) + await glide_client.bzmpop(["non_existent_key"], ScoreFilter.MAX, 0) # bzmpop is called against a non-existing key with no timeout, but we wrap the call in an asyncio timeout to # avoid having the test block forever @@ -4489,62 +4489,62 @@ async def endless_bzmpop_call(): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zrandmember(self, redis_client: TGlideClient): + async def test_zrandmember(self, glide_client: TGlideClient): key = get_random_string(10) string_key = get_random_string(10) scores: Mapping[TEncodable, float] = {"one": 1, "two": 2} - assert await redis_client.zadd(key, scores) == 2 + assert await glide_client.zadd(key, scores) == 2 - member = await redis_client.zrandmember(key) + member = await glide_client.zrandmember(key) # TODO: remove when functions API is fixed assert isinstance(member, bytes) assert member.decode() in scores - assert await redis_client.zrandmember("non_existing_key") is None + assert await glide_client.zrandmember("non_existing_key") is None # key exists, but it is not a set - assert await redis_client.set(string_key, "value") == OK + assert await glide_client.set(string_key, "value") == OK with pytest.raises(RequestError): - await redis_client.zrandmember(string_key) + await glide_client.zrandmember(string_key) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zrandmember_count(self, redis_client: TGlideClient): + async def test_zrandmember_count(self, glide_client: TGlideClient): key = get_random_string(10) string_key = get_random_string(10) scores: Mapping[TEncodable, float] = {"one": 1, "two": 2} - assert await redis_client.zadd(key, scores) == 2 + assert await glide_client.zadd(key, scores) == 2 # unique values are expected as count is positive - members = await redis_client.zrandmember_count(key, 4) + members = await glide_client.zrandmember_count(key, 4) assert len(members) == 2 assert set(members) == {b"one", b"two"} # duplicate values are expected as count is negative - members = await redis_client.zrandmember_count(key, -4) + members = await glide_client.zrandmember_count(key, -4) assert len(members) == 4 for member in members: # TODO: remove when functions API is fixed assert isinstance(member, bytes) assert member.decode() in scores - assert await redis_client.zrandmember_count(key, 0) == [] - assert await redis_client.zrandmember_count("non_existing_key", 0) == [] + assert await glide_client.zrandmember_count(key, 0) == [] + assert await glide_client.zrandmember_count("non_existing_key", 0) == [] # key exists, but it is not a set - assert await redis_client.set(string_key, "value") == OK + assert await glide_client.set(string_key, "value") == OK with pytest.raises(RequestError): - await redis_client.zrandmember_count(string_key, 5) + await glide_client.zrandmember_count(string_key, 5) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zrandmember_withscores(self, redis_client: TGlideClient): + async def test_zrandmember_withscores(self, glide_client: TGlideClient): key = get_random_string(10) string_key = get_random_string(10) scores: Mapping[TEncodable, float] = {"one": 1, "two": 2} - assert await redis_client.zadd(key, scores) == 2 + assert await glide_client.zadd(key, scores) == 2 # unique values are expected as count is positive - elements = await redis_client.zrandmember_withscores(key, 4) + elements = await glide_client.zrandmember_withscores(key, 4) assert len(elements) == 2 for member, score in elements: @@ -4553,26 +4553,26 @@ async def test_zrandmember_withscores(self, redis_client: TGlideClient): assert scores[(member).decode()] == score # duplicate values are expected as count is negative - elements = await redis_client.zrandmember_withscores(key, -4) + elements = await glide_client.zrandmember_withscores(key, -4) assert len(elements) == 4 for member, score in elements: # TODO: remove when functions API is fixed assert isinstance(member, bytes) assert scores[(member).decode()] == score - assert await redis_client.zrandmember_withscores(key, 0) == [] - assert await redis_client.zrandmember_withscores("non_existing_key", 0) == [] + assert await glide_client.zrandmember_withscores(key, 0) == [] + assert await glide_client.zrandmember_withscores("non_existing_key", 0) == [] # key exists, but it is not a set - assert await redis_client.set(string_key, "value") == OK + assert await glide_client.set(string_key, "value") == OK with pytest.raises(RequestError): - await redis_client.zrandmember_withscores(string_key, 5) + await glide_client.zrandmember_withscores(string_key, 5) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zintercard(self, redis_client: TGlideClient): + async def test_zintercard(self, glide_client: TGlideClient): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") key1 = f"{{testKey}}:1-{get_random_string(10)}" @@ -4591,30 +4591,30 @@ async def test_zintercard(self, redis_client: TGlideClient): "four": 4.0, } - assert await redis_client.zadd(key1, member_scores1) == 3 - assert await redis_client.zadd(key2, member_scores2) == 3 + assert await glide_client.zadd(key1, member_scores1) == 3 + assert await glide_client.zadd(key2, member_scores2) == 3 - assert await redis_client.zintercard([key1, key2]) == 2 - assert await redis_client.zintercard([key1, non_existing_key]) == 0 + assert await glide_client.zintercard([key1, key2]) == 2 + assert await glide_client.zintercard([key1, non_existing_key]) == 0 - assert await redis_client.zintercard([key1, key2], 0) == 2 - assert await redis_client.zintercard([key1, key2], 1) == 1 - assert await redis_client.zintercard([key1, key2], 3) == 2 + assert await glide_client.zintercard([key1, key2], 0) == 2 + assert await glide_client.zintercard([key1, key2], 1) == 1 + assert await glide_client.zintercard([key1, key2], 3) == 2 # invalid argument - key list must not be empty with pytest.raises(RequestError): - await redis_client.zintercard([]) + await glide_client.zintercard([]) # key exists, but it is not a sorted set - assert await redis_client.set(string_key, "value") == OK + assert await glide_client.set(string_key, "value") == OK with pytest.raises(RequestError): - await redis_client.zintercard([string_key]) + await glide_client.zintercard([string_key]) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zmpop(self, redis_client: TGlideClient): + async def test_zmpop(self, glide_client: TGlideClient): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") key1 = f"{{test}}-1-f{get_random_string(10)}" @@ -4622,81 +4622,81 @@ async def test_zmpop(self, redis_client: TGlideClient): non_existing_key = f"{{test}}-non_existing_key" string_key = f"{{test}}-3-f{get_random_string(10)}" - assert await redis_client.zadd(key1, {"a1": 1, "b1": 2}) == 2 - assert await redis_client.zadd(key2, {"a2": 0.1, "b2": 0.2}) == 2 + assert await glide_client.zadd(key1, {"a1": 1, "b1": 2}) == 2 + assert await glide_client.zadd(key2, {"a2": 0.1, "b2": 0.2}) == 2 - assert await redis_client.zmpop([key1, key2], ScoreFilter.MAX) == [ + assert await glide_client.zmpop([key1, key2], ScoreFilter.MAX) == [ key1.encode(), {b"b1": 2}, ] - assert await redis_client.zmpop([key2, key1], ScoreFilter.MAX, 10) == [ + assert await glide_client.zmpop([key2, key1], ScoreFilter.MAX, 10) == [ key2.encode(), {b"b2": 0.2, b"a2": 0.1}, ] - assert await redis_client.zmpop([non_existing_key], ScoreFilter.MIN) is None - assert await redis_client.zmpop([non_existing_key], ScoreFilter.MIN, 1) is None + assert await glide_client.zmpop([non_existing_key], ScoreFilter.MIN) is None + assert await glide_client.zmpop([non_existing_key], ScoreFilter.MIN, 1) is None # key exists, but it is not a sorted set - assert await redis_client.set(string_key, "value") == OK + assert await glide_client.set(string_key, "value") == OK with pytest.raises(RequestError): - await redis_client.zmpop([string_key], ScoreFilter.MAX) + await glide_client.zmpop([string_key], ScoreFilter.MAX) with pytest.raises(RequestError): - await redis_client.zmpop([string_key], ScoreFilter.MAX, 1) + await glide_client.zmpop([string_key], ScoreFilter.MAX, 1) # incorrect argument: key list should not be empty with pytest.raises(RequestError): - assert await redis_client.zmpop([], ScoreFilter.MAX, 1) + assert await glide_client.zmpop([], ScoreFilter.MAX, 1) # incorrect argument: count should be greater than 0 with pytest.raises(RequestError): - assert await redis_client.zmpop([key1], ScoreFilter.MAX, 0) + assert await glide_client.zmpop([key1], ScoreFilter.MAX, 0) # check that order of entries in the response is preserved entries: Dict[TEncodable, float] = {} for i in range(0, 10): entries[f"a{i}"] = float(i) - assert await redis_client.zadd(key2, entries) == 10 - result = await redis_client.zmpop([key2], ScoreFilter.MIN, 10) + assert await glide_client.zadd(key2, entries) == 10 + result = await glide_client.zmpop([key2], ScoreFilter.MIN, 10) assert result is not None result_map = cast(Mapping[bytes, float], result[1]) assert compare_maps(entries, result_map) is True # type: ignore @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_type(self, redis_client: TGlideClient): + async def test_type(self, glide_client: TGlideClient): key = get_random_string(10) - assert await redis_client.set(key, "value") == OK - assert (await redis_client.type(key)).lower() == b"string" - assert await redis_client.delete([key]) == 1 + assert await glide_client.set(key, "value") == OK + assert (await glide_client.type(key)).lower() == b"string" + assert await glide_client.delete([key]) == 1 - assert await redis_client.lpush(key, ["value"]) == 1 - assert (await redis_client.type(key)).lower() == b"list" - assert await redis_client.delete([key]) == 1 + assert await glide_client.lpush(key, ["value"]) == 1 + assert (await glide_client.type(key)).lower() == b"list" + assert await glide_client.delete([key]) == 1 - assert await redis_client.sadd(key, ["value"]) == 1 - assert (await redis_client.type(key)).lower() == b"set" - assert await redis_client.delete([key]) == 1 + assert await glide_client.sadd(key, ["value"]) == 1 + assert (await glide_client.type(key)).lower() == b"set" + assert await glide_client.delete([key]) == 1 - assert await redis_client.zadd(key, {"member": 1.0}) == 1 - assert (await redis_client.type(key)).lower() == b"zset" - assert await redis_client.delete([key]) == 1 + assert await glide_client.zadd(key, {"member": 1.0}) == 1 + assert (await glide_client.type(key)).lower() == b"zset" + assert await glide_client.delete([key]) == 1 - assert await redis_client.hset(key, {"field": "value"}) == 1 - assert (await redis_client.type(key)).lower() == b"hash" - assert await redis_client.delete([key]) == 1 + assert await glide_client.hset(key, {"field": "value"}) == 1 + assert (await glide_client.type(key)).lower() == b"hash" + assert await glide_client.delete([key]) == 1 - await redis_client.xadd(key, [("field", "value")]) - assert await redis_client.type(key) == b"stream" - assert await redis_client.delete([key]) == 1 + await glide_client.xadd(key, [("field", "value")]) + assert await glide_client.type(key) == b"stream" + assert await glide_client.delete([key]) == 1 - assert (await redis_client.type(key)).lower() == b"none" + assert (await glide_client.type(key)).lower() == b"none" @pytest.mark.parametrize("cluster_mode", [False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_sort_and_sort_store_with_get_or_by_args( - self, redis_client: GlideClient + self, glide_client: GlideClient ): key = "{SameSlotKey}" + get_random_string(10) store = "{SameSlotKey}" + get_random_string(10) @@ -4709,16 +4709,16 @@ async def test_sort_and_sort_store_with_get_or_by_args( ) # Prepare some data - assert await redis_client.hset(user_key1, {"name": "Alice", "age": "30"}) == 2 - assert await redis_client.hset(user_key2, {"name": "Bob", "age": "25"}) == 2 - assert await redis_client.hset(user_key3, {"name": "Charlie", "age": "35"}) == 2 - assert await redis_client.hset(user_key4, {"name": "Dave", "age": "20"}) == 2 - assert await redis_client.hset(user_key5, {"name": "Eve", "age": "40"}) == 2 - assert await redis_client.lpush("user_ids", ["5", "4", "3", "2", "1"]) == 5 + assert await glide_client.hset(user_key1, {"name": "Alice", "age": "30"}) == 2 + assert await glide_client.hset(user_key2, {"name": "Bob", "age": "25"}) == 2 + assert await glide_client.hset(user_key3, {"name": "Charlie", "age": "35"}) == 2 + assert await glide_client.hset(user_key4, {"name": "Dave", "age": "20"}) == 2 + assert await glide_client.hset(user_key5, {"name": "Eve", "age": "40"}) == 2 + assert await glide_client.lpush("user_ids", ["5", "4", "3", "2", "1"]) == 5 # Test sort with all arguments - assert await redis_client.lpush(key, ["3", "1", "2"]) == 3 - result = await redis_client.sort( + assert await glide_client.lpush(key, ["3", "1", "2"]) == 3 + result = await glide_client.sort( key, limit=Limit(0, 2), get_patterns=["user:*->name"], @@ -4728,7 +4728,7 @@ async def test_sort_and_sort_store_with_get_or_by_args( assert result == [b"Alice", b"Bob"] # Test sort_store with all arguments - sort_store_result = await redis_client.sort_store( + sort_store_result = await glide_client.sort_store( key, store, limit=Limit(0, 2), @@ -4737,11 +4737,11 @@ async def test_sort_and_sort_store_with_get_or_by_args( alpha=True, ) assert sort_store_result == 2 - sorted_list = await redis_client.lrange(store, 0, -1) + sorted_list = await glide_client.lrange(store, 0, -1) assert sorted_list == [b"Alice", b"Bob"] # Test sort with `by` argument - result = await redis_client.sort( + result = await glide_client.sort( "user_ids", by_pattern="user:*->age", get_patterns=["user:*->name"], @@ -4752,8 +4752,8 @@ async def test_sort_and_sort_store_with_get_or_by_args( ) # Test sort with `by` argument with missing keys to sort by - assert await redis_client.lpush("user_ids", ["a"]) == 6 - result = await redis_client.sort( + assert await glide_client.lpush("user_ids", ["a"]) == 6 + result = await glide_client.sort( "user_ids", by_pattern="user:*->age", get_patterns=["user:*->name"], @@ -4764,7 +4764,7 @@ async def test_sort_and_sort_store_with_get_or_by_args( ) # Test sort with `by` argument with missing keys to sort by - result = await redis_client.sort( + result = await glide_client.sort( "user_ids", by_pattern="user:*->name", get_patterns=["user:*->age"], @@ -4775,7 +4775,7 @@ async def test_sort_and_sort_store_with_get_or_by_args( ) # Test Limit with count 0 - result = await redis_client.sort( + result = await glide_client.sort( "user_ids", limit=Limit(0, 0), alpha=True, @@ -4785,97 +4785,97 @@ async def test_sort_and_sort_store_with_get_or_by_args( @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_sort_and_sort_store_without_get_or_by_args( - self, redis_client: TGlideClient + self, glide_client: TGlideClient ): key = "{SameSlotKey}" + get_random_string(10) store = "{SameSlotKey}" + get_random_string(10) # Test sort with non-existing key - result = await redis_client.sort("non_existing_key") + result = await glide_client.sort("non_existing_key") assert result == [] # Test sort_store with non-existing key - sort_store_result = await redis_client.sort_store( + sort_store_result = await glide_client.sort_store( "{SameSlotKey}:non_existing_key", store ) assert sort_store_result == 0 # Test each argument separately - assert await redis_client.lpush(key, ["5", "2", "4", "1", "3"]) == 5 + assert await glide_client.lpush(key, ["5", "2", "4", "1", "3"]) == 5 # Test w/o flags - result = await redis_client.sort(key) + result = await glide_client.sort(key) assert result == [b"1", b"2", b"3", b"4", b"5"] # limit argument - result = await redis_client.sort(key, limit=Limit(1, 3)) + result = await glide_client.sort(key, limit=Limit(1, 3)) assert result == [b"2", b"3", b"4"] # order argument - result = await redis_client.sort(key, order=OrderBy.DESC) + result = await glide_client.sort(key, order=OrderBy.DESC) assert result == [b"5", b"4", b"3", b"2", b"1"] - assert await redis_client.lpush(key, ["a"]) == 6 + assert await glide_client.lpush(key, ["a"]) == 6 with pytest.raises(RequestError) as e: - await redis_client.sort(key) + await glide_client.sort(key) assert "can't be converted into double" in str(e).lower() # alpha argument - result = await redis_client.sort(key, alpha=True) + result = await glide_client.sort(key, alpha=True) assert result == [b"1", b"2", b"3", b"4", b"5", b"a"] # Combining multiple arguments - result = await redis_client.sort( + result = await glide_client.sort( key, limit=Limit(1, 3), order=OrderBy.DESC, alpha=True ) assert result == [b"5", b"4", b"3"] # Test sort_store with combined arguments - sort_store_result = await redis_client.sort_store( + sort_store_result = await glide_client.sort_store( key, store, limit=Limit(1, 3), order=OrderBy.DESC, alpha=True ) assert sort_store_result == 3 - sorted_list = await redis_client.lrange(store, 0, -1) + sorted_list = await glide_client.lrange(store, 0, -1) assert sorted_list == [b"5", b"4", b"3"] @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_echo(self, redis_client: TGlideClient): + async def test_echo(self, glide_client: TGlideClient): message = get_random_string(5) - assert await redis_client.echo(message) == message.encode() - if isinstance(redis_client, GlideClusterClient): - echo_dict = await redis_client.echo(message, AllNodes()) + assert await glide_client.echo(message) == message.encode() + if isinstance(glide_client, GlideClusterClient): + echo_dict = await glide_client.echo(message, AllNodes()) assert isinstance(echo_dict, dict) for value in echo_dict.values(): assert value == message.encode() @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_dbsize(self, redis_client: TGlideClient): - assert await redis_client.custom_command(["FLUSHALL"]) == OK + async def test_dbsize(self, glide_client: TGlideClient): + assert await glide_client.custom_command(["FLUSHALL"]) == OK - assert await redis_client.dbsize() == 0 + assert await glide_client.dbsize() == 0 key_value_pairs = [(get_random_string(10), "foo") for _ in range(10)] for key, value in key_value_pairs: - assert await redis_client.set(key, value) == OK - assert await redis_client.dbsize() == 10 + assert await glide_client.set(key, value) == OK + assert await glide_client.dbsize() == 10 - if isinstance(redis_client, GlideClusterClient): - assert await redis_client.custom_command(["FLUSHALL"]) == OK + if isinstance(glide_client, GlideClusterClient): + assert await glide_client.custom_command(["FLUSHALL"]) == OK key = get_random_string(5) - assert await redis_client.set(key, value) == OK - assert await redis_client.dbsize(SlotKeyRoute(SlotType.PRIMARY, key)) == 1 + assert await glide_client.set(key, value) == OK + assert await glide_client.dbsize(SlotKeyRoute(SlotType.PRIMARY, key)) == 1 else: - assert await redis_client.select(1) == OK - assert await redis_client.dbsize() == 0 + assert await glide_client.select(1) == OK + assert await glide_client.dbsize() == 0 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_time(self, redis_client: TGlideClient): + async def test_time(self, glide_client: TGlideClient): current_time = int(time.time()) - 1 - result = await redis_client.time() + result = await glide_client.time() assert len(result) == 2 assert isinstance(result, list) assert int(result[0]) > current_time @@ -4883,45 +4883,45 @@ async def test_time(self, redis_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_lastsave(self, redis_client: TGlideClient): + async def test_lastsave(self, glide_client: TGlideClient): yesterday = date.today() - timedelta(1) yesterday_unix_time = time.mktime(yesterday.timetuple()) - result = await redis_client.lastsave() + result = await glide_client.lastsave() assert isinstance(result, int) assert result > yesterday_unix_time - if isinstance(redis_client, GlideClusterClient): + if isinstance(glide_client, GlideClusterClient): # test with single-node route - result = await redis_client.lastsave(RandomNode()) + result = await glide_client.lastsave(RandomNode()) assert isinstance(result, int) assert result > yesterday_unix_time # test with multi-node route - result = await redis_client.lastsave(AllNodes()) + result = await glide_client.lastsave(AllNodes()) assert isinstance(result, dict) for lastsave_time in result.values(): assert lastsave_time > yesterday_unix_time @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_append(self, redis_client: TGlideClient): + async def test_append(self, glide_client: TGlideClient): key, value = get_random_string(10), get_random_string(5) - assert await redis_client.append(key, value) == 5 + assert await glide_client.append(key, value) == 5 - assert await redis_client.append(key, value) == 10 - assert await redis_client.get(key) == (value * 2).encode() + assert await glide_client.append(key, value) == 10 + assert await glide_client.get(key) == (value * 2).encode() @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_xadd_xtrim_xlen(self, redis_client: TGlideClient): + async def test_xadd_xtrim_xlen(self, glide_client: TGlideClient): key = get_random_string(10) string_key = get_random_string(10) non_existing_key = get_random_string(10) field, field2 = get_random_string(10), get_random_string(10) assert ( - await redis_client.xadd( + await glide_client.xadd( key, [(field, "foo"), (field2, "bar")], StreamAddOptions(make_stream=False), @@ -4930,19 +4930,19 @@ async def test_xadd_xtrim_xlen(self, redis_client: TGlideClient): ) assert ( - await redis_client.xadd( + await glide_client.xadd( key, [(field, "foo1"), (field2, "bar1")], StreamAddOptions(id="0-1") ) == b"0-1" ) assert ( - await redis_client.xadd(key, [(field, "foo2"), (field2, "bar2")]) + await glide_client.xadd(key, [(field, "foo2"), (field2, "bar2")]) ) is not None - assert await redis_client.xlen(key) == 2 + assert await glide_client.xlen(key) == 2 # This will trim the first entry. - id = await redis_client.xadd( + id = await glide_client.xadd( key, [(field, "foo3"), (field2, "bar3")], StreamAddOptions(trim=TrimByMaxLen(exact=True, threshold=2)), @@ -4951,45 +4951,45 @@ async def test_xadd_xtrim_xlen(self, redis_client: TGlideClient): assert id is not None # TODO: remove when functions API is fixed assert isinstance(id, bytes) - assert await redis_client.xlen(key) == 2 + assert await glide_client.xlen(key) == 2 # This will trim the 2nd entry. assert ( - await redis_client.xadd( + await glide_client.xadd( key, [(field, "foo4"), (field2, "bar4")], StreamAddOptions(trim=TrimByMinId(exact=True, threshold=id.decode())), ) is not None ) - assert await redis_client.xlen(key) == 2 + assert await glide_client.xlen(key) == 2 - assert await redis_client.xtrim(key, TrimByMaxLen(threshold=1, exact=True)) == 1 - assert await redis_client.xlen(key) == 1 + assert await glide_client.xtrim(key, TrimByMaxLen(threshold=1, exact=True)) == 1 + assert await glide_client.xlen(key) == 1 - assert await redis_client.xtrim(key, TrimByMaxLen(threshold=0, exact=True)) == 1 + assert await glide_client.xtrim(key, TrimByMaxLen(threshold=0, exact=True)) == 1 # Unlike other Redis collection types, stream keys still exist even after removing all entries - assert await redis_client.exists([key]) == 1 - assert await redis_client.xlen(key) == 0 + assert await glide_client.exists([key]) == 1 + assert await glide_client.xlen(key) == 0 assert ( - await redis_client.xtrim( + await glide_client.xtrim( non_existing_key, TrimByMaxLen(threshold=1, exact=True) ) == 0 ) - assert await redis_client.xlen(non_existing_key) == 0 + assert await glide_client.xlen(non_existing_key) == 0 # key exists, but it is not a stream - assert await redis_client.set(string_key, "foo") + assert await glide_client.set(string_key, "foo") with pytest.raises(RequestError): - await redis_client.xtrim(string_key, TrimByMaxLen(threshold=1, exact=True)) + await glide_client.xtrim(string_key, TrimByMaxLen(threshold=1, exact=True)) with pytest.raises(RequestError): - await redis_client.xlen(string_key) + await glide_client.xlen(string_key) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_xdel(self, redis_client: TGlideClient): + async def test_xdel(self, glide_client: TGlideClient): key1 = get_random_string(10) string_key = get_random_string(10) non_existing_key = get_random_string(10) @@ -4998,35 +4998,35 @@ async def test_xdel(self, redis_client: TGlideClient): stream_id3 = "0-3" assert ( - await redis_client.xadd( + await glide_client.xadd( key1, [("f1", "foo1"), ("f2", "foo2")], StreamAddOptions(stream_id1) ) == stream_id1.encode() ) assert ( - await redis_client.xadd( + await glide_client.xadd( key1, [("f1", "foo1"), ("f2", "foo2")], StreamAddOptions(stream_id2) ) == stream_id2.encode() ) - assert await redis_client.xlen(key1) == 2 + assert await glide_client.xlen(key1) == 2 # deletes one stream id, and ignores anything invalid - assert await redis_client.xdel(key1, [stream_id1, stream_id3]) == 1 - assert await redis_client.xdel(non_existing_key, [stream_id3]) == 0 + assert await glide_client.xdel(key1, [stream_id1, stream_id3]) == 1 + assert await glide_client.xdel(non_existing_key, [stream_id3]) == 0 # invalid argument - id list should not be empty with pytest.raises(RequestError): - await redis_client.xdel(key1, []) + await glide_client.xdel(key1, []) # key exists, but it is not a stream - assert await redis_client.set(string_key, "foo") == OK + assert await glide_client.set(string_key, "foo") == OK with pytest.raises(RequestError): - await redis_client.xdel(string_key, [stream_id3]) + await glide_client.xdel(string_key, [stream_id3]) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_xrange_and_xrevrange(self, redis_client: TGlideClient): + async def test_xrange_and_xrevrange(self, glide_client: TGlideClient): key = get_random_string(10) non_existing_key = get_random_string(10) string_key = get_random_string(10) @@ -5035,90 +5035,90 @@ async def test_xrange_and_xrevrange(self, redis_client: TGlideClient): stream_id3 = "0-3" assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f1", "v1")], StreamAddOptions(id=stream_id1) ) == stream_id1.encode() ) assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f2", "v2")], StreamAddOptions(id=stream_id2) ) == stream_id2.encode() ) - assert await redis_client.xlen(key) == 2 + assert await glide_client.xlen(key) == 2 # get everything from the stream - result = await redis_client.xrange(key, MinId(), MaxId()) + result = await glide_client.xrange(key, MinId(), MaxId()) assert convert_bytes_to_string_object(result) == { stream_id1: [["f1", "v1"]], stream_id2: [["f2", "v2"]], } - result = await redis_client.xrevrange(key, MaxId(), MinId()) + result = await glide_client.xrevrange(key, MaxId(), MinId()) assert convert_bytes_to_string_object(result) == { stream_id2: [["f2", "v2"]], stream_id1: [["f1", "v1"]], } # returns empty mapping if + before - - assert await redis_client.xrange(key, MaxId(), MinId()) == {} + assert await glide_client.xrange(key, MaxId(), MinId()) == {} # rev search returns empty mapping if - before + - assert await redis_client.xrevrange(key, MinId(), MaxId()) == {} + assert await glide_client.xrevrange(key, MinId(), MaxId()) == {} assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f3", "v3")], StreamAddOptions(id=stream_id3) ) == stream_id3.encode() ) # get the newest entry - result = await redis_client.xrange( + result = await glide_client.xrange( key, ExclusiveIdBound(stream_id2), ExclusiveIdBound.from_timestamp(5), 1 ) assert convert_bytes_to_string_object(result) == {stream_id3: [["f3", "v3"]]} - result = await redis_client.xrevrange( + result = await glide_client.xrevrange( key, ExclusiveIdBound.from_timestamp(5), ExclusiveIdBound(stream_id2), 1 ) assert convert_bytes_to_string_object(result) == {stream_id3: [["f3", "v3"]]} # xrange/xrevrange against an emptied stream - assert await redis_client.xdel(key, [stream_id1, stream_id2, stream_id3]) == 3 - assert await redis_client.xrange(key, MinId(), MaxId(), 10) == {} - assert await redis_client.xrevrange(key, MaxId(), MinId(), 10) == {} + assert await glide_client.xdel(key, [stream_id1, stream_id2, stream_id3]) == 3 + assert await glide_client.xrange(key, MinId(), MaxId(), 10) == {} + assert await glide_client.xrevrange(key, MaxId(), MinId(), 10) == {} - assert await redis_client.xrange(non_existing_key, MinId(), MaxId()) == {} - assert await redis_client.xrevrange(non_existing_key, MaxId(), MinId()) == {} + assert await glide_client.xrange(non_existing_key, MinId(), MaxId()) == {} + assert await glide_client.xrevrange(non_existing_key, MaxId(), MinId()) == {} # count value < 1 returns None - assert await redis_client.xrange(key, MinId(), MaxId(), 0) is None - assert await redis_client.xrange(key, MinId(), MaxId(), -1) is None - assert await redis_client.xrevrange(key, MaxId(), MinId(), 0) is None - assert await redis_client.xrevrange(key, MaxId(), MinId(), -1) is None + assert await glide_client.xrange(key, MinId(), MaxId(), 0) is None + assert await glide_client.xrange(key, MinId(), MaxId(), -1) is None + assert await glide_client.xrevrange(key, MaxId(), MinId(), 0) is None + assert await glide_client.xrevrange(key, MaxId(), MinId(), -1) is None # key exists, but it is not a stream - assert await redis_client.set(string_key, "foo") + assert await glide_client.set(string_key, "foo") with pytest.raises(RequestError): - await redis_client.xrange(string_key, MinId(), MaxId()) + await glide_client.xrange(string_key, MinId(), MaxId()) with pytest.raises(RequestError): - await redis_client.xrevrange(string_key, MaxId(), MinId()) + await glide_client.xrevrange(string_key, MaxId(), MinId()) # invalid start bound with pytest.raises(RequestError): - await redis_client.xrange(key, IdBound("not_a_stream_id"), MaxId()) + await glide_client.xrange(key, IdBound("not_a_stream_id"), MaxId()) with pytest.raises(RequestError): - await redis_client.xrevrange(key, MaxId(), IdBound("not_a_stream_id")) + await glide_client.xrevrange(key, MaxId(), IdBound("not_a_stream_id")) # invalid end bound with pytest.raises(RequestError): - await redis_client.xrange(key, MinId(), IdBound("not_a_stream_id")) + await glide_client.xrange(key, MinId(), IdBound("not_a_stream_id")) with pytest.raises(RequestError): - await redis_client.xrevrange(key, IdBound("not_a_stream_id"), MinId()) + await glide_client.xrevrange(key, IdBound("not_a_stream_id"), MinId()) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_xread( - self, redis_client: TGlideClient, cluster_mode, protocol, request + self, glide_client: TGlideClient, cluster_mode, protocol, request ): key1 = f"{{testKey}}:1-{get_random_string(10)}" key2 = f"{{testKey}}:2-{get_random_string(10)}" @@ -5133,13 +5133,13 @@ async def test_xread( # setup first entries in streams key1 and key2 assert ( - await redis_client.xadd( + await glide_client.xadd( key1, [("f1_1", "v1_1")], StreamAddOptions(id=stream_id1_1) ) == stream_id1_1.encode() ) assert ( - await redis_client.xadd( + await glide_client.xadd( key2, [("f2_1", "v2_1")], StreamAddOptions(id=stream_id2_1) ) == stream_id2_1.encode() @@ -5147,13 +5147,13 @@ async def test_xread( # setup second entries in streams key1 and key2 assert ( - await redis_client.xadd( + await glide_client.xadd( key1, [("f1_2", "v1_2")], StreamAddOptions(id=stream_id1_2) ) == stream_id1_2.encode() ) assert ( - await redis_client.xadd( + await glide_client.xadd( key2, [("f2_2", "v2_2")], StreamAddOptions(id=stream_id2_2) ) == stream_id2_2.encode() @@ -5161,19 +5161,19 @@ async def test_xread( # setup third entries in streams key1 and key2 assert ( - await redis_client.xadd( + await glide_client.xadd( key1, [("f1_3", "v1_3")], StreamAddOptions(id=stream_id1_3) ) == stream_id1_3.encode() ) assert ( - await redis_client.xadd( + await glide_client.xadd( key2, [("f2_3", "v2_3")], StreamAddOptions(id=stream_id2_3) ) == stream_id2_3.encode() ) - assert await redis_client.xread({key1: stream_id1_1, key2: stream_id2_1}) == { + assert await glide_client.xread({key1: stream_id1_1, key2: stream_id2_1}) == { key1.encode(): { stream_id1_2.encode(): [[b"f1_2", b"v1_2"]], stream_id1_3.encode(): [[b"f1_3", b"v1_3"]], @@ -5184,25 +5184,25 @@ async def test_xread( }, } - assert await redis_client.xread({non_existing_key: stream_id1_1}) is None - assert await redis_client.xread({key1: non_existing_id}) is None + assert await glide_client.xread({non_existing_key: stream_id1_1}) is None + assert await glide_client.xread({key1: non_existing_id}) is None # passing an empty read options argument has no effect - assert await redis_client.xread({key1: stream_id1_1}, StreamReadOptions()) == { + assert await glide_client.xread({key1: stream_id1_1}, StreamReadOptions()) == { key1.encode(): { stream_id1_2.encode(): [[b"f1_2", b"v1_2"]], stream_id1_3.encode(): [[b"f1_3", b"v1_3"]], }, } - assert await redis_client.xread( + assert await glide_client.xread( {key1: stream_id1_1}, StreamReadOptions(count=1) ) == { key1.encode(): { stream_id1_2.encode(): [[b"f1_2", b"v1_2"]], }, } - assert await redis_client.xread( + assert await glide_client.xread( {key1: stream_id1_1}, StreamReadOptions(count=1, block_ms=1000) ) == { key1.encode(): { @@ -5213,7 +5213,7 @@ async def test_xread( @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_xread_edge_cases_and_failures( - self, redis_client: TGlideClient, cluster_mode, protocol, request + self, glide_client: TGlideClient, cluster_mode, protocol, request ): key1 = f"{{testKey}}:1-{get_random_string(10)}" string_key = f"{{testKey}}:2-{get_random_string(10)}" @@ -5222,13 +5222,13 @@ async def test_xread_edge_cases_and_failures( stream_id2 = "1-2" assert ( - await redis_client.xadd( + await glide_client.xadd( key1, [("f1", "v1")], StreamAddOptions(id=stream_id1) ) == stream_id1.encode() ) assert ( - await redis_client.xadd( + await glide_client.xadd( key1, [("f2", "v2")], StreamAddOptions(id=stream_id2) ) == stream_id2.encode() @@ -5254,7 +5254,7 @@ async def endless_xread_call(): await asyncio.wait_for(endless_xread_call(), timeout=3) # if count is non-positive, it is ignored - assert await redis_client.xread( + assert await glide_client.xread( {key1: stream_id0}, StreamReadOptions(count=0) ) == { key1.encode(): { @@ -5262,7 +5262,7 @@ async def endless_xread_call(): stream_id2.encode(): [[b"f2", b"v2"]], }, } - assert await redis_client.xread( + assert await glide_client.xread( {key1: stream_id0}, StreamReadOptions(count=-1) ) == { key1.encode(): { @@ -5273,27 +5273,27 @@ async def endless_xread_call(): # invalid stream ID with pytest.raises(RequestError): - await redis_client.xread({key1: "invalid_stream_id"}) + await glide_client.xread({key1: "invalid_stream_id"}) # invalid argument - block cannot be negative with pytest.raises(RequestError): - await redis_client.xread({key1: stream_id1}, StreamReadOptions(block_ms=-1)) + await glide_client.xread({key1: stream_id1}, StreamReadOptions(block_ms=-1)) # invalid argument - keys_and_ids must not be empty with pytest.raises(RequestError): - await redis_client.xread({}) + await glide_client.xread({}) # key exists, but it is not a stream - assert await redis_client.set(string_key, "foo") + assert await glide_client.set(string_key, "foo") with pytest.raises(RequestError): - await redis_client.xread({string_key: stream_id1, key1: stream_id1}) + await glide_client.xread({string_key: stream_id1, key1: stream_id1}) with pytest.raises(RequestError): - await redis_client.xread({key1: stream_id1, string_key: stream_id1}) + await glide_client.xread({key1: stream_id1, string_key: stream_id1}) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_xgroup_create_xgroup_destroy( - self, redis_client: TGlideClient, cluster_mode, protocol, request + self, glide_client: TGlideClient, cluster_mode, protocol, request ): key = get_random_string(10) non_existing_key = get_random_string(10) @@ -5304,11 +5304,11 @@ async def test_xgroup_create_xgroup_destroy( # trying to create a consumer group for a non-existing stream without the "MKSTREAM" arg results in error with pytest.raises(RequestError): - await redis_client.xgroup_create(non_existing_key, group_name1, stream_id) + await glide_client.xgroup_create(non_existing_key, group_name1, stream_id) # calling with the "MKSTREAM" arg should create the new stream automatically assert ( - await redis_client.xgroup_create( + await glide_client.xgroup_create( key, group_name1, stream_id, StreamGroupOptions(make_stream=True) ) == OK @@ -5316,26 +5316,26 @@ async def test_xgroup_create_xgroup_destroy( # invalid arg - group names must be unique, but group_name1 already exists with pytest.raises(RequestError): - await redis_client.xgroup_create(key, group_name1, stream_id) + await glide_client.xgroup_create(key, group_name1, stream_id) # invalid stream ID format with pytest.raises(RequestError): - await redis_client.xgroup_create( + await glide_client.xgroup_create( key, group_name2, "invalid_stream_id_format" ) - assert await redis_client.xgroup_destroy(key, group_name1) is True + assert await glide_client.xgroup_destroy(key, group_name1) is True # calling xgroup_destroy again returns False because the group was already destroyed above - assert await redis_client.xgroup_destroy(key, group_name1) is False + assert await glide_client.xgroup_destroy(key, group_name1) is False # attempting to destroy a group for a non-existing key should raise an error with pytest.raises(RequestError): - await redis_client.xgroup_destroy(non_existing_key, group_name1) + await glide_client.xgroup_destroy(non_existing_key, group_name1) # "ENTRIESREAD" option was added in Redis 7.0.0 - if await check_if_server_version_lt(redis_client, "7.0.0"): + if await check_if_server_version_lt(glide_client, "7.0.0"): with pytest.raises(RequestError): - await redis_client.xgroup_create( + await glide_client.xgroup_create( key, group_name1, stream_id, @@ -5343,7 +5343,7 @@ async def test_xgroup_create_xgroup_destroy( ) else: assert ( - await redis_client.xgroup_create( + await glide_client.xgroup_create( key, group_name1, stream_id, @@ -5353,18 +5353,18 @@ async def test_xgroup_create_xgroup_destroy( ) # key exists, but it is not a stream - assert await redis_client.set(string_key, "foo") == OK + assert await glide_client.set(string_key, "foo") == OK with pytest.raises(RequestError): - await redis_client.xgroup_create( + await glide_client.xgroup_create( string_key, group_name1, stream_id, StreamGroupOptions(make_stream=True) ) with pytest.raises(RequestError): - await redis_client.xgroup_destroy(string_key, group_name1) + await glide_client.xgroup_destroy(string_key, group_name1) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_xgroup_create_consumer_xreadgroup_xgroup_del_consumer( - self, redis_client: TGlideClient, cluster_mode, protocol, request + self, glide_client: TGlideClient, cluster_mode, protocol, request ): key = f"{{testKey}}:{get_random_string(10)}" non_existing_key = f"{{testKey}}:{get_random_string(10)}" @@ -5379,35 +5379,35 @@ async def test_xgroup_create_consumer_xreadgroup_xgroup_del_consumer( # create group and consumer for the group assert ( - await redis_client.xgroup_create( + await glide_client.xgroup_create( key, group_name, stream_id0, StreamGroupOptions(make_stream=True) ) == OK ) assert ( - await redis_client.xgroup_create_consumer(key, group_name, consumer_name) + await glide_client.xgroup_create_consumer(key, group_name, consumer_name) is True ) # attempting to create/delete a consumer for a group that does not exist results in a NOGROUP request error with pytest.raises(RequestError): - await redis_client.xgroup_create_consumer( + await glide_client.xgroup_create_consumer( key, "non_existing_group", consumer_name ) with pytest.raises(RequestError): - await redis_client.xgroup_del_consumer( + await glide_client.xgroup_del_consumer( key, "non_existing_group", consumer_name ) # attempt to create consumer for group again assert ( - await redis_client.xgroup_create_consumer(key, group_name, consumer_name) + await glide_client.xgroup_create_consumer(key, group_name, consumer_name) is False ) # attempting to delete a consumer that has not been created yet returns 0 assert ( - await redis_client.xgroup_del_consumer( + await glide_client.xgroup_del_consumer( key, group_name, "non_existing_consumer" ) == 0 @@ -5415,20 +5415,20 @@ async def test_xgroup_create_consumer_xreadgroup_xgroup_del_consumer( # add two stream entries assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f1_0", "v1_0")], StreamAddOptions(stream_id1_0) ) == stream_id1_0.encode() ) assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f1_1", "v1_1")], StreamAddOptions(stream_id1_1) ) == stream_id1_1.encode() ) # read the entire stream for the consumer and mark messages as pending - assert await redis_client.xreadgroup( + assert await glide_client.xreadgroup( {key: ">"}, group_name, consumer_name, @@ -5441,10 +5441,10 @@ async def test_xgroup_create_consumer_xreadgroup_xgroup_del_consumer( } # delete one of the stream entries - assert await redis_client.xdel(key, [stream_id1_0]) == 1 + assert await glide_client.xdel(key, [stream_id1_0]) == 1 # now xreadgroup yields one empty stream entry and one non-empty stream entry - assert await redis_client.xreadgroup({key: "0"}, group_name, consumer_name) == { + assert await glide_client.xreadgroup({key: "0"}, group_name, consumer_name) == { key.encode(): { stream_id1_0.encode(): None, stream_id1_1.encode(): [[b"f1_1", b"v1_1"]], @@ -5452,7 +5452,7 @@ async def test_xgroup_create_consumer_xreadgroup_xgroup_del_consumer( } assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f1_2", "v1_2")], StreamAddOptions(stream_id1_2) ) == stream_id1_2.encode() @@ -5460,11 +5460,11 @@ async def test_xgroup_create_consumer_xreadgroup_xgroup_del_consumer( # delete the consumer group and expect 2 pending messages assert ( - await redis_client.xgroup_del_consumer(key, group_name, consumer_name) == 2 + await glide_client.xgroup_del_consumer(key, group_name, consumer_name) == 2 ) # consume the last message with the previously deleted consumer (create the consumer anew) - assert await redis_client.xreadgroup( + assert await glide_client.xreadgroup( {key: ">"}, group_name, consumer_name, @@ -5473,25 +5473,25 @@ async def test_xgroup_create_consumer_xreadgroup_xgroup_del_consumer( # delete the consumer group and expect the pending message assert ( - await redis_client.xgroup_del_consumer(key, group_name, consumer_name) == 1 + await glide_client.xgroup_del_consumer(key, group_name, consumer_name) == 1 ) # test NOACK option assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f1_3", "v1_3")], StreamAddOptions(stream_id1_3) ) == stream_id1_3.encode() ) # since NOACK is passed, stream entry will be consumed without being added to the pending entries - assert await redis_client.xreadgroup( + assert await glide_client.xreadgroup( {key: ">"}, group_name, consumer_name, StreamReadGroupOptions(no_ack=True, count=5, block_ms=1000), ) == {key.encode(): {stream_id1_3.encode(): [[b"f1_3", b"v1_3"]]}} assert ( - await redis_client.xreadgroup( + await glide_client.xreadgroup( {key: ">"}, group_name, consumer_name, @@ -5499,7 +5499,7 @@ async def test_xgroup_create_consumer_xreadgroup_xgroup_del_consumer( ) is None ) - assert await redis_client.xreadgroup( + assert await glide_client.xreadgroup( {key: "0"}, group_name, consumer_name, @@ -5508,29 +5508,29 @@ async def test_xgroup_create_consumer_xreadgroup_xgroup_del_consumer( # attempting to call XGROUP CREATECONSUMER or XGROUP DELCONSUMER with a non-existing key should raise an error with pytest.raises(RequestError): - await redis_client.xgroup_create_consumer( + await glide_client.xgroup_create_consumer( non_existing_key, group_name, consumer_name ) with pytest.raises(RequestError): - await redis_client.xgroup_del_consumer( + await glide_client.xgroup_del_consumer( non_existing_key, group_name, consumer_name ) # key exists, but it is not a stream - assert await redis_client.set(string_key, "foo") == OK + assert await glide_client.set(string_key, "foo") == OK with pytest.raises(RequestError): - await redis_client.xgroup_create_consumer( + await glide_client.xgroup_create_consumer( string_key, group_name, consumer_name ) with pytest.raises(RequestError): - await redis_client.xgroup_del_consumer( + await glide_client.xgroup_del_consumer( string_key, group_name, consumer_name ) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_xreadgroup_edge_cases_and_failures( - self, redis_client: TGlideClient, cluster_mode, protocol, request + self, glide_client: TGlideClient, cluster_mode, protocol, request ): key = f"{{testKey}}:{get_random_string(10)}" non_existing_key = f"{{testKey}}:{get_random_string(10)}" @@ -5543,42 +5543,42 @@ async def test_xreadgroup_edge_cases_and_failures( # attempting to execute against a non-existing key results in an error with pytest.raises(RequestError): - await redis_client.xreadgroup( + await glide_client.xreadgroup( {non_existing_key: stream_id0}, group_name, consumer_name ) # create group and consumer for group - assert await redis_client.xgroup_create( + assert await glide_client.xgroup_create( key, group_name, stream_id0, StreamGroupOptions(make_stream=True) ) assert ( - await redis_client.xgroup_create_consumer(key, group_name, consumer_name) + await glide_client.xgroup_create_consumer(key, group_name, consumer_name) is True ) # read from empty stream assert ( - await redis_client.xreadgroup({key: ">"}, group_name, consumer_name) is None + await glide_client.xreadgroup({key: ">"}, group_name, consumer_name) is None ) - assert await redis_client.xreadgroup({key: "0"}, group_name, consumer_name) == { + assert await glide_client.xreadgroup({key: "0"}, group_name, consumer_name) == { key.encode(): {} } # setup first entry assert ( - await redis_client.xadd(key, [("f1", "v1")], StreamAddOptions(stream_id1_1)) + await glide_client.xadd(key, [("f1", "v1")], StreamAddOptions(stream_id1_1)) == stream_id1_1.encode() ) # if count is non-positive, it is ignored - assert await redis_client.xreadgroup( + assert await glide_client.xreadgroup( {key: ">"}, group_name, consumer_name, StreamReadGroupOptions(count=0) ) == { key.encode(): { stream_id1_1.encode(): [[b"f1", b"v1"]], }, } - assert await redis_client.xreadgroup( + assert await glide_client.xreadgroup( {key: stream_id1_0}, group_name, consumer_name, @@ -5591,13 +5591,13 @@ async def test_xreadgroup_edge_cases_and_failures( # invalid stream ID with pytest.raises(RequestError): - await redis_client.xreadgroup( + await glide_client.xreadgroup( {key: "invalid_stream_id"}, group_name, consumer_name ) # invalid argument - block cannot be negative with pytest.raises(RequestError): - await redis_client.xreadgroup( + await glide_client.xreadgroup( {key: stream_id0}, group_name, consumer_name, @@ -5606,24 +5606,24 @@ async def test_xreadgroup_edge_cases_and_failures( # invalid argument - keys_and_ids must not be empty with pytest.raises(RequestError): - await redis_client.xreadgroup({}, group_name, consumer_name) + await glide_client.xreadgroup({}, group_name, consumer_name) # first key exists, but it is not a stream - assert await redis_client.set(string_key, "foo") == OK + assert await glide_client.set(string_key, "foo") == OK with pytest.raises(RequestError): - await redis_client.xreadgroup( + await glide_client.xreadgroup( {string_key: stream_id1_1, key: stream_id1_1}, group_name, consumer_name ) # second key exists, but it is not a stream with pytest.raises(RequestError): - await redis_client.xreadgroup( + await glide_client.xreadgroup( {key: stream_id1_1, string_key: stream_id1_1}, group_name, consumer_name ) # attempting to execute command with a non-existing group results in an error with pytest.raises(RequestError): - await redis_client.xreadgroup( + await glide_client.xreadgroup( {key: stream_id1_1}, "non_existing_group", consumer_name ) @@ -5695,7 +5695,7 @@ async def endless_xreadgroup_call(): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_xack( - self, redis_client: TGlideClient, cluster_mode, protocol, request + self, glide_client: TGlideClient, cluster_mode, protocol, request ): key = f"{{testKey}}:{get_random_string(10)}" non_existing_key = f"{{testKey}}:{get_random_string(10)}" @@ -5709,15 +5709,15 @@ async def test_xack( # setup: add 2 entries to the stream, create consumer group, read to mark them as pending assert ( - await redis_client.xadd(key, [("f0", "v0")], StreamAddOptions(stream_id1_0)) + await glide_client.xadd(key, [("f0", "v0")], StreamAddOptions(stream_id1_0)) == stream_id1_0.encode() ) assert ( - await redis_client.xadd(key, [("f1", "v1")], StreamAddOptions(stream_id1_1)) + await glide_client.xadd(key, [("f1", "v1")], StreamAddOptions(stream_id1_1)) == stream_id1_1.encode() ) - assert await redis_client.xgroup_create(key, group_name, stream_id0) == OK - assert await redis_client.xreadgroup({key: ">"}, group_name, consumer_name) == { + assert await glide_client.xgroup_create(key, group_name, stream_id0) == OK + assert await glide_client.xreadgroup({key: ">"}, group_name, consumer_name) == { key.encode(): { stream_id1_0.encode(): [[b"f0", b"v0"]], stream_id1_1.encode(): [[b"f1", b"v1"]], @@ -5726,52 +5726,52 @@ async def test_xack( # add one more entry assert ( - await redis_client.xadd(key, [("f2", "v2")], StreamAddOptions(stream_id1_2)) + await glide_client.xadd(key, [("f2", "v2")], StreamAddOptions(stream_id1_2)) == stream_id1_2.encode() ) # acknowledge the first 2 entries assert ( - await redis_client.xack(key, group_name, [stream_id1_0, stream_id1_1]) == 2 + await glide_client.xack(key, group_name, [stream_id1_0, stream_id1_1]) == 2 ) # attempting to acknowledge the first 2 entries again returns 0 since they were already acknowledged assert ( - await redis_client.xack(key, group_name, [stream_id1_0, stream_id1_1]) == 0 + await glide_client.xack(key, group_name, [stream_id1_0, stream_id1_1]) == 0 ) # read the last, unacknowledged entry - assert await redis_client.xreadgroup({key: ">"}, group_name, consumer_name) == { + assert await glide_client.xreadgroup({key: ">"}, group_name, consumer_name) == { key.encode(): {stream_id1_2.encode(): [[b"f2", b"v2"]]} } # deleting the consumer returns 1 since the last entry still hasn't been acknowledged assert ( - await redis_client.xgroup_del_consumer(key, group_name, consumer_name) == 1 + await glide_client.xgroup_del_consumer(key, group_name, consumer_name) == 1 ) # attempting to acknowledge a non-existing key returns 0 assert ( - await redis_client.xack(non_existing_key, group_name, [stream_id1_0]) == 0 + await glide_client.xack(non_existing_key, group_name, [stream_id1_0]) == 0 ) # attempting to acknowledge a non-existing group returns 0 - assert await redis_client.xack(key, "non_existing_group", [stream_id1_0]) == 0 + assert await glide_client.xack(key, "non_existing_group", [stream_id1_0]) == 0 # attempting to acknowledge a non-existing ID returns 0 - assert await redis_client.xack(key, group_name, ["99-99"]) == 0 + assert await glide_client.xack(key, group_name, ["99-99"]) == 0 # invalid arg - ID list must not be empty with pytest.raises(RequestError): - await redis_client.xack(key, group_name, []) + await glide_client.xack(key, group_name, []) # invalid arg - invalid stream ID format with pytest.raises(RequestError): - await redis_client.xack(key, group_name, ["invalid_ID_format"]) + await glide_client.xack(key, group_name, ["invalid_ID_format"]) # key exists, but it is not a stream - assert await redis_client.set(string_key, "foo") == OK + assert await glide_client.set(string_key, "foo") == OK with pytest.raises(RequestError): - await redis_client.xack(string_key, group_name, [stream_id1_0]) + await glide_client.xack(string_key, group_name, [stream_id1_0]) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_xpending_xclaim(self, redis_client: TGlideClient): + async def test_xpending_xclaim(self, glide_client: TGlideClient): key = get_random_string(10) group_name = get_random_string(10) consumer1 = get_random_string(10) @@ -5786,36 +5786,36 @@ async def test_xpending_xclaim(self, redis_client: TGlideClient): # create group and consumer for group assert ( - await redis_client.xgroup_create( + await glide_client.xgroup_create( key, group_name, stream_id0, StreamGroupOptions(make_stream=True) ) == OK ) assert ( - await redis_client.xgroup_create_consumer(key, group_name, consumer1) + await glide_client.xgroup_create_consumer(key, group_name, consumer1) is True ) assert ( - await redis_client.xgroup_create_consumer(key, group_name, consumer2) + await glide_client.xgroup_create_consumer(key, group_name, consumer2) is True ) # add two stream entries for consumer1 assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f1_0", "v1_0")], StreamAddOptions(stream_id1_0) ) == stream_id1_0.encode() ) assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f1_1", "v1_1")], StreamAddOptions(stream_id1_1) ) == stream_id1_1.encode() ) # read the entire stream with consumer1 and mark messages as pending - assert await redis_client.xreadgroup({key: ">"}, group_name, consumer1) == { + assert await glide_client.xreadgroup({key: ">"}, group_name, consumer1) == { key.encode(): { stream_id1_0.encode(): [[b"f1_0", b"v1_0"]], stream_id1_1.encode(): [[b"f1_1", b"v1_1"]], @@ -5824,26 +5824,26 @@ async def test_xpending_xclaim(self, redis_client: TGlideClient): # add three stream entries for consumer2 assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f1_2", "v1_2")], StreamAddOptions(stream_id1_2) ) == stream_id1_2.encode() ) assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f1_3", "v1_3")], StreamAddOptions(stream_id1_3) ) == stream_id1_3.encode() ) assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f1_4", "v1_4")], StreamAddOptions(stream_id1_4) ) == stream_id1_4.encode() ) # read the entire stream with consumer2 and mark messages as pending - assert await redis_client.xreadgroup({key: ">"}, group_name, consumer2) == { + assert await glide_client.xreadgroup({key: ">"}, group_name, consumer2) == { key.encode(): { stream_id1_2.encode(): [[b"f1_2", b"v1_2"]], stream_id1_3.encode(): [[b"f1_3", b"v1_3"]], @@ -5852,7 +5852,7 @@ async def test_xpending_xclaim(self, redis_client: TGlideClient): } # inner array order is non-deterministic, so we have to assert against it separately from the other info - result = await redis_client.xpending(key, group_name) + result = await glide_client.xpending(key, group_name) consumer_results = cast(List, result[3]) assert [consumer1.encode(), b"2"] in consumer_results assert [consumer2.encode(), b"3"] in consumer_results @@ -5862,7 +5862,7 @@ async def test_xpending_xclaim(self, redis_client: TGlideClient): # to ensure an idle_time > 0 time.sleep(2) - range_result = await redis_client.xpending_range( + range_result = await glide_client.xpending_range( key, group_name, MinId(), MaxId(), 10 ) # the inner lists of the result have format [stream_entry_id, consumer, idle_time, times_delivered] @@ -5893,7 +5893,7 @@ async def test_xpending_xclaim(self, redis_client: TGlideClient): assert range_result[4] == [stream_id1_4.encode(), consumer2.encode(), 1] # use xclaim to claim stream 2 and 4 for consumer 1 - assert await redis_client.xclaim( + assert await glide_client.xclaim( key, group_name, consumer1, 0, [stream_id1_2, stream_id1_4] ) == { stream_id1_2.encode(): [[b"f1_2", b"v1_2"]], @@ -5902,26 +5902,26 @@ async def test_xpending_xclaim(self, redis_client: TGlideClient): # claiming non exists id assert ( - await redis_client.xclaim( + await glide_client.xclaim( key, group_name, consumer1, 0, ["1526569498055-0"] ) == {} ) - assert await redis_client.xclaim_just_id( + assert await glide_client.xclaim_just_id( key, group_name, consumer1, 0, [stream_id1_2, stream_id1_4] ) == [stream_id1_2.encode(), stream_id1_4.encode()] # add one more stream assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f1_5", "v1_5")], StreamAddOptions(stream_id1_5) ) == stream_id1_5.encode() ) # using force, we can xclaim the message without reading it - claim_force_result = await redis_client.xclaim( + claim_force_result = await glide_client.xclaim( key, group_name, consumer2, @@ -5931,7 +5931,7 @@ async def test_xpending_xclaim(self, redis_client: TGlideClient): ) assert claim_force_result == {stream_id1_5.encode(): [[b"f1_5", b"v1_5"]]} - force_pending_result = await redis_client.xpending_range( + force_pending_result = await glide_client.xpending_range( key, group_name, IdBound(stream_id1_5), IdBound(stream_id1_5), 1 ) assert force_pending_result[0][0] == stream_id1_5.encode() @@ -5940,7 +5940,7 @@ async def test_xpending_xclaim(self, redis_client: TGlideClient): # acknowledge streams 1-1, 1-2, 1-3, 1-5 and remove them from the xpending results assert ( - await redis_client.xack( + await glide_client.xack( key, group_name, [stream_id1_1, stream_id1_2, stream_id1_3, stream_id1_5], @@ -5948,14 +5948,14 @@ async def test_xpending_xclaim(self, redis_client: TGlideClient): == 4 ) - range_result = await redis_client.xpending_range( + range_result = await glide_client.xpending_range( key, group_name, IdBound(stream_id1_4), MaxId(), 10 ) assert len(range_result) == 1 assert range_result[0][0] == stream_id1_4.encode() assert range_result[0][1] == consumer1.encode() - range_result = await redis_client.xpending_range( + range_result = await glide_client.xpending_range( key, group_name, MinId(), IdBound(stream_id1_3), 10 ) assert len(range_result) == 1 @@ -5963,14 +5963,14 @@ async def test_xpending_xclaim(self, redis_client: TGlideClient): assert range_result[0][1] == consumer1.encode() # passing an empty StreamPendingOptions object should have no effect - range_result = await redis_client.xpending_range( + range_result = await glide_client.xpending_range( key, group_name, MinId(), IdBound(stream_id1_3), 10, StreamPendingOptions() ) assert len(range_result) == 1 assert range_result[0][0] == stream_id1_0.encode() assert range_result[0][1] == consumer1.encode() - range_result = await redis_client.xpending_range( + range_result = await glide_client.xpending_range( key, group_name, MinId(), @@ -5983,7 +5983,7 @@ async def test_xpending_xclaim(self, redis_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_xpending_edge_cases_and_failures(self, redis_client: TGlideClient): + async def test_xpending_edge_cases_and_failures(self, glide_client: TGlideClient): key = get_random_string(10) non_existing_key = get_random_string(10) string_key = get_random_string(10) @@ -5995,38 +5995,38 @@ async def test_xpending_edge_cases_and_failures(self, redis_client: TGlideClient # create group and consumer for the group assert ( - await redis_client.xgroup_create( + await glide_client.xgroup_create( key, group_name, stream_id0, StreamGroupOptions(make_stream=True) ) == OK ) assert ( - await redis_client.xgroup_create_consumer(key, group_name, consumer) is True + await glide_client.xgroup_create_consumer(key, group_name, consumer) is True ) # add two stream entries for consumer assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f1_0", "v1_0")], StreamAddOptions(stream_id1_0) ) == stream_id1_0.encode() ) assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f1_1", "v1_1")], StreamAddOptions(stream_id1_1) ) == stream_id1_1.encode() ) # no pending messages yet... - assert await redis_client.xpending(key, group_name) == [0, None, None, None] + assert await glide_client.xpending(key, group_name) == [0, None, None, None] assert ( - await redis_client.xpending_range(key, group_name, MinId(), MaxId(), 10) + await glide_client.xpending_range(key, group_name, MinId(), MaxId(), 10) == [] ) # read the entire stream with consumer and mark messages as pending - assert await redis_client.xreadgroup({key: ">"}, group_name, consumer) == { + assert await glide_client.xreadgroup({key: ">"}, group_name, consumer) == { key.encode(): { stream_id1_0.encode(): [[b"f1_0", b"v1_0"]], stream_id1_1.encode(): [[b"f1_1", b"v1_1"]], @@ -6034,24 +6034,24 @@ async def test_xpending_edge_cases_and_failures(self, redis_client: TGlideClient } # sanity check - expect some results - assert await redis_client.xpending(key, group_name) == [ + assert await glide_client.xpending(key, group_name) == [ 2, stream_id1_0.encode(), stream_id1_1.encode(), [[consumer.encode(), b"2"]], ] - result = await redis_client.xpending_range( + result = await glide_client.xpending_range( key, group_name, MinId(), MaxId(), 10 ) assert len(result[0]) > 0 # returns empty if + before - assert ( - await redis_client.xpending_range(key, group_name, MaxId(), MinId(), 10) + await glide_client.xpending_range(key, group_name, MaxId(), MinId(), 10) == [] ) assert ( - await redis_client.xpending_range( + await glide_client.xpending_range( key, group_name, MaxId(), @@ -6064,7 +6064,7 @@ async def test_xpending_edge_cases_and_failures(self, redis_client: TGlideClient # min idle time of 100 seconds shouldn't produce any results assert ( - await redis_client.xpending_range( + await glide_client.xpending_range( key, group_name, MinId(), @@ -6077,7 +6077,7 @@ async def test_xpending_edge_cases_and_failures(self, redis_client: TGlideClient # non-existing consumer: no results assert ( - await redis_client.xpending_range( + await glide_client.xpending_range( key, group_name, MinId(), @@ -6090,26 +6090,26 @@ async def test_xpending_edge_cases_and_failures(self, redis_client: TGlideClient # xpending when range bound is not a valid ID raises a RequestError with pytest.raises(RequestError): - await redis_client.xpending_range( + await glide_client.xpending_range( key, group_name, IdBound("invalid_stream_id_format"), MaxId(), 10 ) with pytest.raises(RequestError): - await redis_client.xpending_range( + await glide_client.xpending_range( key, group_name, MinId(), IdBound("invalid_stream_id_format"), 10 ) # non-positive count returns no results assert ( - await redis_client.xpending_range(key, group_name, MinId(), MaxId(), -10) + await glide_client.xpending_range(key, group_name, MinId(), MaxId(), -10) == [] ) assert ( - await redis_client.xpending_range(key, group_name, MinId(), MaxId(), 0) + await glide_client.xpending_range(key, group_name, MinId(), MaxId(), 0) == [] ) # non-positive min-idle-time values are allowed - result = await redis_client.xpending_range( + result = await glide_client.xpending_range( key, group_name, MinId(), @@ -6118,7 +6118,7 @@ async def test_xpending_edge_cases_and_failures(self, redis_client: TGlideClient StreamPendingOptions(min_idle_time_ms=-100), ) assert len(result[0]) > 0 - result = await redis_client.xpending_range( + result = await glide_client.xpending_range( key, group_name, MinId(), @@ -6130,32 +6130,32 @@ async def test_xpending_edge_cases_and_failures(self, redis_client: TGlideClient # non-existing group name raises a RequestError (NOGROUP) with pytest.raises(RequestError): - await redis_client.xpending(key, "non_existing_group") + await glide_client.xpending(key, "non_existing_group") with pytest.raises(RequestError): - await redis_client.xpending_range( + await glide_client.xpending_range( key, "non_existing_group", MinId(), MaxId(), 10 ) # non-existing key raises a RequestError with pytest.raises(RequestError): - await redis_client.xpending(non_existing_key, group_name) + await glide_client.xpending(non_existing_key, group_name) with pytest.raises(RequestError): - await redis_client.xpending_range( + await glide_client.xpending_range( non_existing_key, group_name, MinId(), MaxId(), 10 ) # key exists but it is not a stream - assert await redis_client.set(string_key, "foo") == OK + assert await glide_client.set(string_key, "foo") == OK with pytest.raises(RequestError): - await redis_client.xpending(string_key, group_name) + await glide_client.xpending(string_key, group_name) with pytest.raises(RequestError): - await redis_client.xpending_range( + await glide_client.xpending_range( string_key, group_name, MinId(), MaxId(), 10 ) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_xclaim_edge_cases_and_failures(self, redis_client: TGlideClient): + async def test_xclaim_edge_cases_and_failures(self, glide_client: TGlideClient): key = get_random_string(10) non_existing_key = get_random_string(10) string_key = get_random_string(10) @@ -6167,34 +6167,34 @@ async def test_xclaim_edge_cases_and_failures(self, redis_client: TGlideClient): # create group and consumer for the group assert ( - await redis_client.xgroup_create( + await glide_client.xgroup_create( key, group_name, stream_id0, StreamGroupOptions(make_stream=True) ) == OK ) assert ( - await redis_client.xgroup_create_consumer(key, group_name, consumer) is True + await glide_client.xgroup_create_consumer(key, group_name, consumer) is True ) # Add stream entry and mark as pending: assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f1_0", "v1_0")], StreamAddOptions(stream_id1_0) ) == stream_id1_0.encode() ) # read the entire stream with consumer and mark messages as pending - assert await redis_client.xreadgroup({key: ">"}, group_name, consumer) == { + assert await glide_client.xreadgroup({key: ">"}, group_name, consumer) == { key.encode(): {stream_id1_0.encode(): [[b"f1_0", b"v1_0"]]} } # claim with invalid stream entry IDs with pytest.raises(RequestError): - await redis_client.xclaim_just_id(key, group_name, consumer, 1, ["invalid"]) + await glide_client.xclaim_just_id(key, group_name, consumer, 1, ["invalid"]) # claim with empty stream entry IDs returns no results - empty_claim = await redis_client.xclaim_just_id( + empty_claim = await glide_client.xclaim_just_id( key, group_name, consumer, 1, [] ) assert len(empty_claim) == 0 @@ -6203,13 +6203,13 @@ async def test_xclaim_edge_cases_and_failures(self, redis_client: TGlideClient): # non-existent key throws a RequestError (NOGROUP) with pytest.raises(RequestError) as e: - await redis_client.xclaim( + await glide_client.xclaim( non_existing_key, group_name, consumer, 1, [stream_id1_0] ) assert "NOGROUP" in str(e) with pytest.raises(RequestError) as e: - await redis_client.xclaim( + await glide_client.xclaim( non_existing_key, group_name, consumer, @@ -6220,13 +6220,13 @@ async def test_xclaim_edge_cases_and_failures(self, redis_client: TGlideClient): assert "NOGROUP" in str(e) with pytest.raises(RequestError) as e: - await redis_client.xclaim_just_id( + await glide_client.xclaim_just_id( non_existing_key, group_name, consumer, 1, [stream_id1_0] ) assert "NOGROUP" in str(e) with pytest.raises(RequestError) as e: - await redis_client.xclaim_just_id( + await glide_client.xclaim_just_id( non_existing_key, group_name, consumer, @@ -6237,32 +6237,32 @@ async def test_xclaim_edge_cases_and_failures(self, redis_client: TGlideClient): assert "NOGROUP" in str(e) # key exists but it is not a stream - assert await redis_client.set(string_key, "foo") == OK + assert await glide_client.set(string_key, "foo") == OK with pytest.raises(RequestError): - await redis_client.xclaim( + await glide_client.xclaim( string_key, group_name, consumer, 1, [stream_id1_0] ) with pytest.raises(RequestError): - await redis_client.xclaim( + await glide_client.xclaim( string_key, group_name, consumer, 1, [stream_id1_0], claim_options ) with pytest.raises(RequestError): - await redis_client.xclaim_just_id( + await glide_client.xclaim_just_id( string_key, group_name, consumer, 1, [stream_id1_0] ) with pytest.raises(RequestError): - await redis_client.xclaim_just_id( + await glide_client.xclaim_just_id( string_key, group_name, consumer, 1, [stream_id1_0], claim_options ) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_xautoclaim(self, redis_client: TGlideClient, protocol): + async def test_xautoclaim(self, glide_client: TGlideClient, protocol): min_version = "6.2.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") - if await check_if_server_version_lt(redis_client, "7.0.0"): + if await check_if_server_version_lt(glide_client, "7.0.0"): version7_or_above = False else: version7_or_above = True @@ -6278,31 +6278,31 @@ async def test_xautoclaim(self, redis_client: TGlideClient, protocol): # setup: add stream entries, create consumer group, add entries to Pending Entries List for group assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f1", "v1"), ("f2", "v2")], StreamAddOptions(stream_id1_0) ) == stream_id1_0.encode() ) assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f1_1", "v1_1")], StreamAddOptions(stream_id1_1) ) == stream_id1_1.encode() ) assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f1_2", "v1_2")], StreamAddOptions(stream_id1_2) ) == stream_id1_2.encode() ) assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f1_3", "v1_3")], StreamAddOptions(stream_id1_3) ) == stream_id1_3.encode() ) - assert await redis_client.xgroup_create(key, group_name, stream_id0_0) == OK - assert await redis_client.xreadgroup({key: ">"}, group_name, consumer) == { + assert await glide_client.xgroup_create(key, group_name, stream_id0_0) == OK + assert await glide_client.xreadgroup({key: ">"}, group_name, consumer) == { key.encode(): { stream_id1_0.encode(): [[b"f1", b"v1"], [b"f2", b"v2"]], stream_id1_1.encode(): [[b"f1_1", b"v1_1"]], @@ -6312,7 +6312,7 @@ async def test_xautoclaim(self, redis_client: TGlideClient, protocol): } # autoclaim the first entry only - result = await redis_client.xautoclaim( + result = await glide_client.xautoclaim( key, group_name, consumer, 0, stream_id0_0, count=1 ) assert result[0] == stream_id1_1.encode() @@ -6323,10 +6323,10 @@ async def test_xautoclaim(self, redis_client: TGlideClient, protocol): assert result[2] == [] # delete entry 1-2 - assert await redis_client.xdel(key, [stream_id1_2]) + assert await glide_client.xdel(key, [stream_id1_2]) # autoclaim the rest of the entries - result = await redis_client.xautoclaim( + result = await glide_client.xautoclaim( key, group_name, consumer, 0, stream_id1_1 ) assert ( @@ -6340,7 +6340,7 @@ async def test_xautoclaim(self, redis_client: TGlideClient, protocol): assert result[2] == [stream_id1_2.encode()] # autoclaim with JUSTID: result at index 1 does not contain fields/values of the claimed entries, only IDs - just_id_result = await redis_client.xautoclaim_just_id( + just_id_result = await glide_client.xautoclaim_just_id( key, group_name, consumer, 0, stream_id0_0 ) assert just_id_result[0] == stream_id0_0.encode() @@ -6364,13 +6364,13 @@ async def test_xautoclaim(self, redis_client: TGlideClient, protocol): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_xautoclaim_edge_cases_and_failures( - self, redis_client: TGlideClient, protocol + self, glide_client: TGlideClient, protocol ): min_version = "6.2.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") - if await check_if_server_version_lt(redis_client, "7.0.0"): + if await check_if_server_version_lt(glide_client, "7.0.0"): version7_or_above = False else: version7_or_above = True @@ -6385,36 +6385,36 @@ async def test_xautoclaim_edge_cases_and_failures( # setup: add entry, create consumer group, add entry to Pending Entries List for group assert ( - await redis_client.xadd(key, [("f1", "v1")], StreamAddOptions(stream_id1_0)) + await glide_client.xadd(key, [("f1", "v1")], StreamAddOptions(stream_id1_0)) == stream_id1_0.encode() ) - assert await redis_client.xgroup_create(key, group_name, stream_id0_0) == OK - assert await redis_client.xreadgroup({key: ">"}, group_name, consumer) == { + assert await glide_client.xgroup_create(key, group_name, stream_id0_0) == OK + assert await glide_client.xreadgroup({key: ">"}, group_name, consumer) == { key.encode(): {stream_id1_0.encode(): [[b"f1", b"v1"]]} } # passing a non-existing key is not allowed and will raise an error with pytest.raises(RequestError): - await redis_client.xautoclaim( + await glide_client.xautoclaim( non_existing_key, group_name, consumer, 0, stream_id0_0 ) with pytest.raises(RequestError): - await redis_client.xautoclaim_just_id( + await glide_client.xautoclaim_just_id( non_existing_key, group_name, consumer, 0, stream_id0_0 ) # passing a non-existing group is not allowed and will raise an error with pytest.raises(RequestError): - await redis_client.xautoclaim( + await glide_client.xautoclaim( key, "non_existing_group", consumer, 0, stream_id0_0 ) with pytest.raises(RequestError): - await redis_client.xautoclaim_just_id( + await glide_client.xautoclaim_just_id( key, "non_existing_group", consumer, 0, stream_id0_0 ) # non-existing consumers are created automatically - result = await redis_client.xautoclaim( + result = await glide_client.xautoclaim( key, group_name, "non_existing_consumer", 0, stream_id0_0 ) assert result[0] == stream_id0_0.encode() @@ -6424,7 +6424,7 @@ async def test_xautoclaim_edge_cases_and_failures( if version7_or_above: assert result[2] == [] - just_id_result = await redis_client.xautoclaim_just_id( + just_id_result = await glide_client.xautoclaim_just_id( key, group_name, "non_existing_consumer", 0, stream_id0_0 ) assert just_id_result[0] == stream_id0_0.encode() @@ -6433,7 +6433,7 @@ async def test_xautoclaim_edge_cases_and_failures( assert just_id_result[2] == [] # negative min_idle_time_ms values are allowed - result = await redis_client.xautoclaim( + result = await glide_client.xautoclaim( key, group_name, consumer, -1, stream_id0_0 ) assert result[0] == stream_id0_0.encode() @@ -6441,7 +6441,7 @@ async def test_xautoclaim_edge_cases_and_failures( if version7_or_above: assert result[2] == [] - just_id_result = await redis_client.xautoclaim_just_id( + just_id_result = await glide_client.xautoclaim_just_id( key, group_name, consumer, -1, stream_id0_0 ) assert just_id_result[0] == stream_id0_0.encode() @@ -6450,22 +6450,22 @@ async def test_xautoclaim_edge_cases_and_failures( assert just_id_result[2] == [] with pytest.raises(RequestError): - await redis_client.xautoclaim( + await glide_client.xautoclaim( key, group_name, consumer, 0, "invalid_stream_id" ) with pytest.raises(RequestError): - await redis_client.xautoclaim_just_id( + await glide_client.xautoclaim_just_id( key, group_name, consumer, 0, "invalid_stream_id" ) # no stream entries to claim above the given start value - result = await redis_client.xautoclaim(key, group_name, consumer, 0, "99-99") + result = await glide_client.xautoclaim(key, group_name, consumer, 0, "99-99") assert result[0] == stream_id0_0.encode() assert result[1] == {} if version7_or_above: assert result[2] == [] - just_id_result = await redis_client.xautoclaim_just_id( + just_id_result = await glide_client.xautoclaim_just_id( key, group_name, consumer, 0, "99-99" ) assert just_id_result[0] == stream_id0_0.encode() @@ -6475,29 +6475,29 @@ async def test_xautoclaim_edge_cases_and_failures( # invalid arg - count must be positive with pytest.raises(RequestError): - await redis_client.xautoclaim( + await glide_client.xautoclaim( key, group_name, consumer, 0, stream_id0_0, count=0 ) with pytest.raises(RequestError): - await redis_client.xautoclaim_just_id( + await glide_client.xautoclaim_just_id( key, group_name, consumer, 0, stream_id0_0, count=0 ) # key exists, but it is not a stream - assert await redis_client.set(string_key, "foo") == OK + assert await glide_client.set(string_key, "foo") == OK with pytest.raises(RequestError): - await redis_client.xautoclaim( + await glide_client.xautoclaim( string_key, group_name, consumer, 0, stream_id0_0 ) with pytest.raises(RequestError): - await redis_client.xautoclaim_just_id( + await glide_client.xautoclaim_just_id( string_key, group_name, consumer, 0, stream_id0_0 ) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_xinfo_groups_xinfo_consumers( - self, redis_client: TGlideClient, protocol + self, glide_client: TGlideClient, protocol ): key = get_random_string(10) group_name1 = get_random_string(10) @@ -6512,33 +6512,33 @@ async def test_xinfo_groups_xinfo_consumers( # setup: add 3 entries to stream, create consumer group and consumer1, read 1 entry from stream with consumer1 assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f1", "v1"), ("f2", "v2")], StreamAddOptions(stream_id1_0) ) == stream_id1_0.encode() ) assert ( - await redis_client.xadd(key, [("f3", "v3")], StreamAddOptions(stream_id1_1)) + await glide_client.xadd(key, [("f3", "v3")], StreamAddOptions(stream_id1_1)) == stream_id1_1.encode() ) assert ( - await redis_client.xadd(key, [("f4", "v4")], StreamAddOptions(stream_id1_2)) + await glide_client.xadd(key, [("f4", "v4")], StreamAddOptions(stream_id1_2)) == stream_id1_2.encode() ) - assert await redis_client.xgroup_create(key, group_name1, stream_id0_0) == OK - assert await redis_client.xreadgroup( + assert await glide_client.xgroup_create(key, group_name1, stream_id0_0) == OK + assert await glide_client.xreadgroup( {key: ">"}, group_name1, consumer1, StreamReadGroupOptions(count=1) ) == {key.encode(): {stream_id1_0.encode(): [[b"f1", b"v1"], [b"f2", b"v2"]]}} # sleep to ensure the idle time value and inactive time value returned by xinfo_consumers is > 0 time.sleep(2) - consumers_result = await redis_client.xinfo_consumers(key, group_name1) + consumers_result = await glide_client.xinfo_consumers(key, group_name1) assert len(consumers_result) == 1 consumer1_info = consumers_result[0] assert consumer1_info.get(b"name") == consumer1.encode() assert consumer1_info.get(b"pending") == 1 assert cast(int, consumer1_info.get(b"idle")) > 0 - if not await check_if_server_version_lt(redis_client, "7.2.0"): + if not await check_if_server_version_lt(glide_client, "7.2.0"): assert ( cast(int, consumer1_info.get(b"inactive")) > 0 # "inactive" was added in Redis 7.2.0 @@ -6546,10 +6546,10 @@ async def test_xinfo_groups_xinfo_consumers( # create consumer2 and read the rest of the entries with it assert ( - await redis_client.xgroup_create_consumer(key, group_name1, consumer2) + await glide_client.xgroup_create_consumer(key, group_name1, consumer2) is True ) - assert await redis_client.xreadgroup({key: ">"}, group_name1, consumer2) == { + assert await glide_client.xreadgroup({key: ">"}, group_name1, consumer2) == { key.encode(): { stream_id1_1.encode(): [[b"f3", b"v3"]], stream_id1_2.encode(): [[b"f4", b"v4"]], @@ -6558,25 +6558,25 @@ async def test_xinfo_groups_xinfo_consumers( # verify that xinfo_consumers contains info for 2 consumers now # test with byte string args - consumers_result = await redis_client.xinfo_consumers( + consumers_result = await glide_client.xinfo_consumers( key.encode(), group_name1.encode() ) assert len(consumers_result) == 2 # add one more entry assert ( - await redis_client.xadd(key, [("f5", "v5")], StreamAddOptions(stream_id1_3)) + await glide_client.xadd(key, [("f5", "v5")], StreamAddOptions(stream_id1_3)) == stream_id1_3.encode() ) - groups = await redis_client.xinfo_groups(key) + groups = await glide_client.xinfo_groups(key) assert len(groups) == 1 group1_info = groups[0] assert group1_info.get(b"name") == group_name1.encode() assert group1_info.get(b"consumers") == 2 assert group1_info.get(b"pending") == 3 assert group1_info.get(b"last-delivered-id") == stream_id1_2.encode() - if not await check_if_server_version_lt(redis_client, "7.0.0"): + if not await check_if_server_version_lt(glide_client, "7.0.0"): assert ( group1_info.get(b"entries-read") == 3 # we have read stream entries 1-0, 1-1, and 1-2 @@ -6587,9 +6587,9 @@ async def test_xinfo_groups_xinfo_consumers( ) # verify xgroup_set_id effects the returned value from xinfo_groups - assert await redis_client.xgroup_set_id(key, group_name1, stream_id1_1) == OK + assert await glide_client.xgroup_set_id(key, group_name1, stream_id1_1) == OK # test with byte string arg - groups = await redis_client.xinfo_groups(key.encode()) + groups = await glide_client.xinfo_groups(key.encode()) assert len(groups) == 1 group1_info = groups[0] assert group1_info.get(b"name") == group_name1.encode() @@ -6597,7 +6597,7 @@ async def test_xinfo_groups_xinfo_consumers( assert group1_info.get(b"pending") == 3 assert group1_info.get(b"last-delivered-id") == stream_id1_1.encode() # entries-read and lag were added to the result in 7.0.0 - if not await check_if_server_version_lt(redis_client, "7.0.0"): + if not await check_if_server_version_lt(glide_client, "7.0.0"): assert ( group1_info.get(b"entries-read") is None # gets set to None when we change the last delivered ID @@ -6607,15 +6607,15 @@ async def test_xinfo_groups_xinfo_consumers( is None # gets set to None when we change the last delivered ID ) - if not await check_if_server_version_lt(redis_client, "7.0.0"): + if not await check_if_server_version_lt(glide_client, "7.0.0"): # verify xgroup_set_id with entries_read effects the returned value from xinfo_groups assert ( - await redis_client.xgroup_set_id( + await glide_client.xgroup_set_id( key, group_name1, stream_id1_1, entries_read=1 ) == OK ) - groups = await redis_client.xinfo_groups(key) + groups = await glide_client.xinfo_groups(key) assert len(groups) == 1 group1_info = groups[0] assert group1_info.get(b"name") == group_name1.encode() @@ -6629,16 +6629,16 @@ async def test_xinfo_groups_xinfo_consumers( ) # add one more consumer group - assert await redis_client.xgroup_create(key, group_name2, stream_id0_0) == OK + assert await glide_client.xgroup_create(key, group_name2, stream_id0_0) == OK # verify that xinfo_groups contains info for 2 consumer groups now - groups = await redis_client.xinfo_groups(key) + groups = await glide_client.xinfo_groups(key) assert len(groups) == 2 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_xinfo_groups_xinfo_consumers_edge_cases_and_failures( - self, redis_client: TGlideClient, protocol + self, glide_client: TGlideClient, protocol ): key = get_random_string(10) string_key = get_random_string(10) @@ -6648,12 +6648,12 @@ async def test_xinfo_groups_xinfo_consumers_edge_cases_and_failures( # passing a non-existing key raises an error with pytest.raises(RequestError): - await redis_client.xinfo_groups(non_existing_key) + await glide_client.xinfo_groups(non_existing_key) with pytest.raises(RequestError): - await redis_client.xinfo_consumers(non_existing_key, group_name) + await glide_client.xinfo_consumers(non_existing_key, group_name) assert ( - await redis_client.xadd( + await glide_client.xadd( key, [("f1", "v1"), ("f2", "v2")], StreamAddOptions(stream_id1_0) ) == stream_id1_0.encode() @@ -6661,26 +6661,26 @@ async def test_xinfo_groups_xinfo_consumers_edge_cases_and_failures( # passing a non-existing group raises an error with pytest.raises(RequestError): - await redis_client.xinfo_consumers(key, "non_existing_group") + await glide_client.xinfo_consumers(key, "non_existing_group") # no groups exist yet - assert await redis_client.xinfo_groups(key) == [] + assert await glide_client.xinfo_groups(key) == [] - assert await redis_client.xgroup_create(key, group_name, stream_id1_0) == OK + assert await glide_client.xgroup_create(key, group_name, stream_id1_0) == OK # no consumers exist yet - assert await redis_client.xinfo_consumers(key, group_name) == [] + assert await glide_client.xinfo_consumers(key, group_name) == [] # key exists, but it is not a stream - assert await redis_client.set(string_key, "foo") == OK + assert await glide_client.set(string_key, "foo") == OK with pytest.raises(RequestError): - await redis_client.xinfo_groups(string_key) + await glide_client.xinfo_groups(string_key) with pytest.raises(RequestError): - await redis_client.xinfo_consumers(string_key, group_name) + await glide_client.xinfo_consumers(string_key, group_name) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_xgroup_set_id( - self, redis_client: TGlideClient, cluster_mode, protocol, request + self, glide_client: TGlideClient, cluster_mode, protocol, request ): key = f"{{testKey}}:{get_random_string(10)}" non_existing_key = f"{{testKey}}:{get_random_string(10)}" @@ -6695,19 +6695,19 @@ async def test_xgroup_set_id( # setup: create stream with 3 entries, create consumer group, read entries to add them to the Pending Entries # List assert ( - await redis_client.xadd(key, [("f0", "v0")], StreamAddOptions(stream_id1_0)) + await glide_client.xadd(key, [("f0", "v0")], StreamAddOptions(stream_id1_0)) == stream_id1_0.encode() ) assert ( - await redis_client.xadd(key, [("f1", "v1")], StreamAddOptions(stream_id1_1)) + await glide_client.xadd(key, [("f1", "v1")], StreamAddOptions(stream_id1_1)) == stream_id1_1.encode() ) assert ( - await redis_client.xadd(key, [("f2", "v2")], StreamAddOptions(stream_id1_2)) + await glide_client.xadd(key, [("f2", "v2")], StreamAddOptions(stream_id1_2)) == stream_id1_2.encode() ) - assert await redis_client.xgroup_create(key, group_name, stream_id0) == OK - assert await redis_client.xreadgroup({key: ">"}, group_name, consumer_name) == { + assert await glide_client.xgroup_create(key, group_name, stream_id0) == OK + assert await glide_client.xreadgroup({key: ">"}, group_name, consumer_name) == { key.encode(): { stream_id1_0.encode(): [[b"f0", b"v0"]], stream_id1_1.encode(): [[b"f1", b"v1"]], @@ -6716,23 +6716,23 @@ async def test_xgroup_set_id( } # sanity check: xreadgroup should not return more entries since they're all already in the Pending Entries List assert ( - await redis_client.xreadgroup({key: ">"}, group_name, consumer_name) is None + await glide_client.xreadgroup({key: ">"}, group_name, consumer_name) is None ) # reset the last delivered ID for the consumer group to "1-1" # ENTRIESREAD is only supported in Redis version 7.0.0 and above - if await check_if_server_version_lt(redis_client, "7.0.0"): - assert await redis_client.xgroup_set_id(key, group_name, stream_id1_1) == OK + if await check_if_server_version_lt(glide_client, "7.0.0"): + assert await glide_client.xgroup_set_id(key, group_name, stream_id1_1) == OK else: assert ( - await redis_client.xgroup_set_id( + await glide_client.xgroup_set_id( key, group_name, stream_id1_1, entries_read=0 ) == OK ) # xreadgroup should only return entry 1-2 since we reset the last delivered ID to 1-1 - assert await redis_client.xreadgroup({key: ">"}, group_name, consumer_name) == { + assert await glide_client.xreadgroup({key: ">"}, group_name, consumer_name) == { key.encode(): { stream_id1_2.encode(): [[b"f2", b"v2"]], } @@ -6740,151 +6740,151 @@ async def test_xgroup_set_id( # an error is raised if XGROUP SETID is called with a non-existing key with pytest.raises(RequestError): - await redis_client.xgroup_set_id(non_existing_key, group_name, stream_id0) + await glide_client.xgroup_set_id(non_existing_key, group_name, stream_id0) # an error is raised if XGROUP SETID is called with a non-existing group with pytest.raises(RequestError): - await redis_client.xgroup_set_id(key, "non_existing_group", stream_id0) + await glide_client.xgroup_set_id(key, "non_existing_group", stream_id0) # setting the ID to a non-existing ID is allowed - assert await redis_client.xgroup_set_id(key, group_name, "99-99") == OK + assert await glide_client.xgroup_set_id(key, group_name, "99-99") == OK # key exists, but it is not a stream - assert await redis_client.set(string_key, "foo") == OK + assert await glide_client.set(string_key, "foo") == OK with pytest.raises(RequestError): - await redis_client.xgroup_set_id(string_key, group_name, stream_id0) + await glide_client.xgroup_set_id(string_key, group_name, stream_id0) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_pfadd(self, redis_client: TGlideClient): + async def test_pfadd(self, glide_client: TGlideClient): key = get_random_string(10) - assert await redis_client.pfadd(key, []) == 1 - assert await redis_client.pfadd(key, ["one", "two"]) == 1 - assert await redis_client.pfadd(key, ["two"]) == 0 - assert await redis_client.pfadd(key, []) == 0 + assert await glide_client.pfadd(key, []) == 1 + assert await glide_client.pfadd(key, ["one", "two"]) == 1 + assert await glide_client.pfadd(key, ["two"]) == 0 + assert await glide_client.pfadd(key, []) == 0 - assert await redis_client.set("foo", "value") == OK + assert await glide_client.set("foo", "value") == OK with pytest.raises(RequestError): - await redis_client.pfadd("foo", []) + await glide_client.pfadd("foo", []) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_pfcount(self, redis_client: TGlideClient): + async def test_pfcount(self, glide_client: TGlideClient): key1 = f"{{testKey}}:1-{get_random_string(10)}" key2 = f"{{testKey}}:2-{get_random_string(10)}" key3 = f"{{testKey}}:3-{get_random_string(10)}" string_key = f"{{testKey}}:4-{get_random_string(10)}" non_existing_key = f"{{testKey}}:5-{get_random_string(10)}" - assert await redis_client.pfadd(key1, ["a", "b", "c"]) == 1 - assert await redis_client.pfadd(key2, ["b", "c", "d"]) == 1 - assert await redis_client.pfcount([key1]) == 3 - assert await redis_client.pfcount([key2]) == 3 - assert await redis_client.pfcount([key1, key2]) == 4 - assert await redis_client.pfcount([key1, key2, non_existing_key]) == 4 + assert await glide_client.pfadd(key1, ["a", "b", "c"]) == 1 + assert await glide_client.pfadd(key2, ["b", "c", "d"]) == 1 + assert await glide_client.pfcount([key1]) == 3 + assert await glide_client.pfcount([key2]) == 3 + assert await glide_client.pfcount([key1, key2]) == 4 + assert await glide_client.pfcount([key1, key2, non_existing_key]) == 4 # empty HyperLogLog data set - assert await redis_client.pfadd(key3, []) == 1 - assert await redis_client.pfcount([key3]) == 0 + assert await glide_client.pfadd(key3, []) == 1 + assert await glide_client.pfcount([key3]) == 0 # incorrect argument - key list cannot be empty with pytest.raises(RequestError): - await redis_client.pfcount([]) + await glide_client.pfcount([]) # key exists, but it is not a HyperLogLog - assert await redis_client.set(string_key, "value") == OK + assert await glide_client.set(string_key, "value") == OK with pytest.raises(RequestError): - await redis_client.pfcount([string_key]) + await glide_client.pfcount([string_key]) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_pfmerge(self, redis_client: TGlideClient): + async def test_pfmerge(self, glide_client: TGlideClient): key1 = f"{{testKey}}:1-{get_random_string(10)}" key2 = f"{{testKey}}:2-{get_random_string(10)}" key3 = f"{{testKey}}:3-{get_random_string(10)}" string_key = f"{{testKey}}:4-{get_random_string(10)}" non_existing_key = f"{{testKey}}:5-{get_random_string(10)}" - assert await redis_client.pfadd(key1, ["a", "b", "c"]) == 1 - assert await redis_client.pfadd(key2, ["b", "c", "d"]) == 1 + assert await glide_client.pfadd(key1, ["a", "b", "c"]) == 1 + assert await glide_client.pfadd(key2, ["b", "c", "d"]) == 1 # merge into new HyperLogLog data set - assert await redis_client.pfmerge(key3, [key1, key2]) == OK - assert await redis_client.pfcount([key3]) == 4 + assert await glide_client.pfmerge(key3, [key1, key2]) == OK + assert await glide_client.pfcount([key3]) == 4 # merge into existing HyperLogLog data set - assert await redis_client.pfmerge(key1, [key2]) == OK - assert await redis_client.pfcount([key1]) == 4 + assert await glide_client.pfmerge(key1, [key2]) == OK + assert await glide_client.pfcount([key1]) == 4 # non-existing source key - assert await redis_client.pfmerge(key2, [key1, non_existing_key]) == OK - assert await redis_client.pfcount([key2]) == 4 + assert await glide_client.pfmerge(key2, [key1, non_existing_key]) == OK + assert await glide_client.pfcount([key2]) == 4 # empty source key list - assert await redis_client.pfmerge(key1, []) == OK - assert await redis_client.pfcount([key1]) == 4 + assert await glide_client.pfmerge(key1, []) == OK + assert await glide_client.pfcount([key1]) == 4 # source key exists, but it is not a HyperLogLog - assert await redis_client.set(string_key, "foo") + assert await glide_client.set(string_key, "foo") with pytest.raises(RequestError): - assert await redis_client.pfmerge(key3, [string_key]) + assert await glide_client.pfmerge(key3, [string_key]) # destination key exists, but it is not a HyperLogLog with pytest.raises(RequestError): - assert await redis_client.pfmerge(string_key, [key3]) + assert await glide_client.pfmerge(string_key, [key3]) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_bitcount(self, redis_client: TGlideClient): + async def test_bitcount(self, glide_client: TGlideClient): key1 = get_random_string(10) set_key = get_random_string(10) non_existing_key = get_random_string(10) value = "foobar" - assert await redis_client.set(key1, value) == OK - assert await redis_client.bitcount(key1) == 26 - assert await redis_client.bitcount(key1, OffsetOptions(1, 1)) == 6 - assert await redis_client.bitcount(key1, OffsetOptions(0, -5)) == 10 - assert await redis_client.bitcount(non_existing_key, OffsetOptions(5, 30)) == 0 - assert await redis_client.bitcount(non_existing_key) == 0 + assert await glide_client.set(key1, value) == OK + assert await glide_client.bitcount(key1) == 26 + assert await glide_client.bitcount(key1, OffsetOptions(1, 1)) == 6 + assert await glide_client.bitcount(key1, OffsetOptions(0, -5)) == 10 + assert await glide_client.bitcount(non_existing_key, OffsetOptions(5, 30)) == 0 + assert await glide_client.bitcount(non_existing_key) == 0 # key exists, but it is not a string - assert await redis_client.sadd(set_key, [value]) == 1 + assert await glide_client.sadd(set_key, [value]) == 1 with pytest.raises(RequestError): - await redis_client.bitcount(set_key) + await glide_client.bitcount(set_key) with pytest.raises(RequestError): - await redis_client.bitcount(set_key, OffsetOptions(1, 1)) + await glide_client.bitcount(set_key, OffsetOptions(1, 1)) - if await check_if_server_version_lt(redis_client, "7.0.0"): + if await check_if_server_version_lt(glide_client, "7.0.0"): # exception thrown because BIT and BYTE options were implemented after 7.0.0 with pytest.raises(RequestError): - await redis_client.bitcount( + await glide_client.bitcount( key1, OffsetOptions(2, 5, BitmapIndexType.BYTE) ) with pytest.raises(RequestError): - await redis_client.bitcount( + await glide_client.bitcount( key1, OffsetOptions(2, 5, BitmapIndexType.BIT) ) else: assert ( - await redis_client.bitcount( + await glide_client.bitcount( key1, OffsetOptions(2, 5, BitmapIndexType.BYTE) ) == 16 ) assert ( - await redis_client.bitcount( + await glide_client.bitcount( key1, OffsetOptions(5, 30, BitmapIndexType.BIT) ) == 17 ) assert ( - await redis_client.bitcount( + await glide_client.bitcount( key1, OffsetOptions(5, -5, BitmapIndexType.BIT) ) == 23 ) assert ( - await redis_client.bitcount( + await glide_client.bitcount( non_existing_key, OffsetOptions(5, 30, BitmapIndexType.BIT) ) == 0 @@ -6892,56 +6892,56 @@ async def test_bitcount(self, redis_client: TGlideClient): # key exists but it is not a string with pytest.raises(RequestError): - await redis_client.bitcount( + await glide_client.bitcount( set_key, OffsetOptions(1, 1, BitmapIndexType.BIT) ) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_setbit(self, redis_client: TGlideClient): + async def test_setbit(self, glide_client: TGlideClient): key = get_random_string(10) set_key = get_random_string(10) - assert await redis_client.setbit(key, 0, 1) == 0 - assert await redis_client.setbit(key, 0, 0) == 1 + assert await glide_client.setbit(key, 0, 1) == 0 + assert await glide_client.setbit(key, 0, 0) == 1 # invalid argument - offset can't be negative with pytest.raises(RequestError): - assert await redis_client.setbit(key, -1, 0) == 1 + assert await glide_client.setbit(key, -1, 0) == 1 # key exists, but it is not a string - assert await redis_client.sadd(set_key, ["foo"]) == 1 + assert await glide_client.sadd(set_key, ["foo"]) == 1 with pytest.raises(RequestError): - await redis_client.setbit(set_key, 0, 0) + await glide_client.setbit(set_key, 0, 0) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_getbit(self, redis_client: TGlideClient): + async def test_getbit(self, glide_client: TGlideClient): key = get_random_string(10) non_existing_key = get_random_string(10) set_key = get_random_string(10) value = "foobar" - assert await redis_client.set(key, value) == OK - assert await redis_client.getbit(key, 1) == 1 + assert await glide_client.set(key, value) == OK + assert await glide_client.getbit(key, 1) == 1 # When offset is beyond the string length, the string is assumed to be a contiguous space with 0 bits. - assert await redis_client.getbit(key, 1000) == 0 + assert await glide_client.getbit(key, 1000) == 0 # When key does not exist it is assumed to be an empty string, so offset is always out of range and the value is # also assumed to be a contiguous space with 0 bits. - assert await redis_client.getbit(non_existing_key, 1) == 0 + assert await glide_client.getbit(non_existing_key, 1) == 0 # invalid argument - offset can't be negative with pytest.raises(RequestError): - assert await redis_client.getbit(key, -1) == 1 + assert await glide_client.getbit(key, -1) == 1 # key exists, but it is not a string - assert await redis_client.sadd(set_key, ["foo"]) == 1 + assert await glide_client.sadd(set_key, ["foo"]) == 1 with pytest.raises(RequestError): - await redis_client.getbit(set_key, 0) + await glide_client.getbit(set_key, 0) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_bitpos_and_bitpos_interval(self, redis_client: TGlideClient): + async def test_bitpos_and_bitpos_interval(self, glide_client: TGlideClient): key = get_random_string(10) non_existing_key = get_random_string(10) set_key = get_random_string(10) @@ -6949,52 +6949,52 @@ async def test_bitpos_and_bitpos_interval(self, redis_client: TGlideClient): "?f0obar" # 00111111 01100110 00110000 01101111 01100010 01100001 01110010 ) - assert await redis_client.set(key, value) == OK - assert await redis_client.bitpos(key, 0) == 0 - assert await redis_client.bitpos(key, 1) == 2 - assert await redis_client.bitpos(key, 1, 1) == 9 - assert await redis_client.bitpos_interval(key, 0, 3, 5) == 24 + assert await glide_client.set(key, value) == OK + assert await glide_client.bitpos(key, 0) == 0 + assert await glide_client.bitpos(key, 1) == 2 + assert await glide_client.bitpos(key, 1, 1) == 9 + assert await glide_client.bitpos_interval(key, 0, 3, 5) == 24 # `BITPOS` returns -1 for non-existing strings - assert await redis_client.bitpos(non_existing_key, 1) == -1 - assert await redis_client.bitpos_interval(non_existing_key, 1, 3, 5) == -1 + assert await glide_client.bitpos(non_existing_key, 1) == -1 + assert await glide_client.bitpos_interval(non_existing_key, 1, 3, 5) == -1 # invalid argument - bit value must be 0 or 1 with pytest.raises(RequestError): - await redis_client.bitpos(key, 2) + await glide_client.bitpos(key, 2) with pytest.raises(RequestError): - await redis_client.bitpos_interval(key, 2, 3, 5) + await glide_client.bitpos_interval(key, 2, 3, 5) # key exists, but it is not a string - assert await redis_client.sadd(set_key, [value]) == 1 + assert await glide_client.sadd(set_key, [value]) == 1 with pytest.raises(RequestError): - await redis_client.bitpos(set_key, 1) + await glide_client.bitpos(set_key, 1) with pytest.raises(RequestError): - await redis_client.bitpos_interval(set_key, 1, 1, -1) + await glide_client.bitpos_interval(set_key, 1, 1, -1) - if await check_if_server_version_lt(redis_client, "7.0.0"): + if await check_if_server_version_lt(glide_client, "7.0.0"): # error thrown because BIT and BYTE options were implemented after 7.0.0 with pytest.raises(RequestError): - await redis_client.bitpos_interval(key, 1, 1, -1, BitmapIndexType.BYTE) + await glide_client.bitpos_interval(key, 1, 1, -1, BitmapIndexType.BYTE) with pytest.raises(RequestError): - await redis_client.bitpos_interval(key, 1, 1, -1, BitmapIndexType.BIT) + await glide_client.bitpos_interval(key, 1, 1, -1, BitmapIndexType.BIT) else: assert ( - await redis_client.bitpos_interval(key, 0, 3, 5, BitmapIndexType.BYTE) + await glide_client.bitpos_interval(key, 0, 3, 5, BitmapIndexType.BYTE) == 24 ) assert ( - await redis_client.bitpos_interval(key, 1, 43, -2, BitmapIndexType.BIT) + await glide_client.bitpos_interval(key, 1, 43, -2, BitmapIndexType.BIT) == 47 ) assert ( - await redis_client.bitpos_interval( + await glide_client.bitpos_interval( non_existing_key, 1, 3, 5, BitmapIndexType.BYTE ) == -1 ) assert ( - await redis_client.bitpos_interval( + await glide_client.bitpos_interval( non_existing_key, 1, 3, 5, BitmapIndexType.BIT ) == -1 @@ -7002,13 +7002,13 @@ async def test_bitpos_and_bitpos_interval(self, redis_client: TGlideClient): # key exists, but it is not a string with pytest.raises(RequestError): - await redis_client.bitpos_interval( + await glide_client.bitpos_interval( set_key, 1, 1, -1, BitmapIndexType.BIT ) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_bitop(self, redis_client: TGlideClient): + async def test_bitop(self, glide_client: TGlideClient): key1 = f"{{testKey}}:1-{get_random_string(10)}" key2 = f"{{testKey}}:2-{get_random_string(10)}" keys: List[TEncodable] = [key1, key2] @@ -7020,80 +7020,80 @@ async def test_bitop(self, redis_client: TGlideClient): value1 = "foobar" value2 = "abcdef" - assert await redis_client.set(key1, value1) == OK - assert await redis_client.set(key2, value2) == OK - assert await redis_client.bitop(BitwiseOperation.AND, destination, keys) == 6 - assert await redis_client.get(destination) == b"`bc`ab" - assert await redis_client.bitop(BitwiseOperation.OR, destination, keys) == 6 - assert await redis_client.get(destination) == b"goofev" + assert await glide_client.set(key1, value1) == OK + assert await glide_client.set(key2, value2) == OK + assert await glide_client.bitop(BitwiseOperation.AND, destination, keys) == 6 + assert await glide_client.get(destination) == b"`bc`ab" + assert await glide_client.bitop(BitwiseOperation.OR, destination, keys) == 6 + assert await glide_client.get(destination) == b"goofev" # reset values for simplicity of results in XOR - assert await redis_client.set(key1, "a") == OK - assert await redis_client.set(key2, "b") == OK - assert await redis_client.bitop(BitwiseOperation.XOR, destination, keys) == 1 - assert await redis_client.get(destination) == "\u0003".encode() + assert await glide_client.set(key1, "a") == OK + assert await glide_client.set(key2, "b") == OK + assert await glide_client.bitop(BitwiseOperation.XOR, destination, keys) == 1 + assert await glide_client.get(destination) == "\u0003".encode() # test single source key - assert await redis_client.bitop(BitwiseOperation.AND, destination, [key1]) == 1 - assert await redis_client.get(destination) == b"a" - assert await redis_client.bitop(BitwiseOperation.OR, destination, [key1]) == 1 - assert await redis_client.get(destination) == b"a" - assert await redis_client.bitop(BitwiseOperation.XOR, destination, [key1]) == 1 - assert await redis_client.get(destination) == b"a" - assert await redis_client.bitop(BitwiseOperation.NOT, destination, [key1]) == 1 + assert await glide_client.bitop(BitwiseOperation.AND, destination, [key1]) == 1 + assert await glide_client.get(destination) == b"a" + assert await glide_client.bitop(BitwiseOperation.OR, destination, [key1]) == 1 + assert await glide_client.get(destination) == b"a" + assert await glide_client.bitop(BitwiseOperation.XOR, destination, [key1]) == 1 + assert await glide_client.get(destination) == b"a" + assert await glide_client.bitop(BitwiseOperation.NOT, destination, [key1]) == 1 # currently, attempting to get the value from destination after the above NOT incorrectly raises an error # TODO: update with a GET call once fix is implemented for https://github.com/aws/glide-for-redis/issues/1447 - assert await redis_client.setbit(key1, 0, 1) == 0 - assert await redis_client.bitop(BitwiseOperation.NOT, destination, [key1]) == 1 - assert await redis_client.get(destination) == "\u001e".encode() + assert await glide_client.setbit(key1, 0, 1) == 0 + assert await glide_client.bitop(BitwiseOperation.NOT, destination, [key1]) == 1 + assert await glide_client.get(destination) == "\u001e".encode() # stores None when all keys hold empty strings assert ( - await redis_client.bitop( + await glide_client.bitop( BitwiseOperation.AND, destination, non_existing_keys ) == 0 ) - assert await redis_client.get(destination) is None + assert await glide_client.get(destination) is None assert ( - await redis_client.bitop( + await glide_client.bitop( BitwiseOperation.OR, destination, non_existing_keys ) == 0 ) - assert await redis_client.get(destination) is None + assert await glide_client.get(destination) is None assert ( - await redis_client.bitop( + await glide_client.bitop( BitwiseOperation.XOR, destination, non_existing_keys ) == 0 ) - assert await redis_client.get(destination) is None + assert await glide_client.get(destination) is None assert ( - await redis_client.bitop( + await glide_client.bitop( BitwiseOperation.NOT, destination, [non_existing_key1] ) == 0 ) - assert await redis_client.get(destination) is None + assert await glide_client.get(destination) is None # invalid argument - source key list cannot be empty with pytest.raises(RequestError): - await redis_client.bitop(BitwiseOperation.OR, destination, []) + await glide_client.bitop(BitwiseOperation.OR, destination, []) # invalid arguments - NOT cannot be passed more than 1 key with pytest.raises(RequestError): - await redis_client.bitop(BitwiseOperation.NOT, destination, [key1, key2]) + await glide_client.bitop(BitwiseOperation.NOT, destination, [key1, key2]) - assert await redis_client.sadd(set_key, [value1]) == 1 + assert await glide_client.sadd(set_key, [value1]) == 1 # invalid argument - source key has the wrong type with pytest.raises(RequestError): - await redis_client.bitop(BitwiseOperation.AND, destination, [set_key]) + await glide_client.bitop(BitwiseOperation.AND, destination, [set_key]) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_bitfield(self, redis_client: TGlideClient): + async def test_bitfield(self, glide_client: TGlideClient): key1 = get_random_string(10) key2 = get_random_string(10) non_existing_key = get_random_string(10) @@ -7111,10 +7111,10 @@ async def test_bitfield(self, redis_client: TGlideClient): overflow_get = BitFieldGet(u2, offset1) # binary value: 01100110 01101111 01101111 01100010 01100001 01110010 - assert await redis_client.set(key1, foobar) == OK + assert await glide_client.set(key1, foobar) == OK # SET tests - assert await redis_client.bitfield( + assert await glide_client.bitfield( key1, [ # binary value becomes: 0(10)00110 01101111 01101111 01100010 01100001 01110010 @@ -7137,7 +7137,7 @@ async def test_bitfield(self, redis_client: TGlideClient): ) == [3, -2, 19, 0, 2, 3, 18, 20] # INCRBY tests - assert await redis_client.bitfield( + assert await glide_client.bitfield( key1, [ # binary value becomes: @@ -7156,7 +7156,7 @@ async def test_bitfield(self, redis_client: TGlideClient): ) == [3, -3, 15, 30] # OVERFLOW WRAP is used by default if no OVERFLOW is specified - assert await redis_client.bitfield( + assert await glide_client.bitfield( key2, [ overflow_set, @@ -7167,7 +7167,7 @@ async def test_bitfield(self, redis_client: TGlideClient): ) == [0, 2, 2] # OVERFLOW affects only SET or INCRBY after OVERFLOW subcommand - assert await redis_client.bitfield( + assert await glide_client.bitfield( key2, [ overflow_set, @@ -7181,49 +7181,49 @@ async def test_bitfield(self, redis_client: TGlideClient): # if the key doesn't exist, the operation is performed as though the missing value was a string with all bits # set to 0. - assert await redis_client.bitfield( + assert await glide_client.bitfield( non_existing_key, [BitFieldSet(UnsignedEncoding(2), BitOffset(3), 2)] ) == [0] # empty subcommands argument returns an empty list - assert await redis_client.bitfield(key1, []) == [] + assert await glide_client.bitfield(key1, []) == [] # invalid argument - offset must be >= 0 with pytest.raises(RequestError): - await redis_client.bitfield( + await glide_client.bitfield( key1, [BitFieldSet(UnsignedEncoding(5), BitOffset(-1), 1)] ) # invalid argument - encoding size must be > 0 with pytest.raises(RequestError): - await redis_client.bitfield( + await glide_client.bitfield( key1, [BitFieldSet(UnsignedEncoding(0), BitOffset(1), 1)] ) # invalid argument - unsigned encoding size must be < 64 with pytest.raises(RequestError): - await redis_client.bitfield( + await glide_client.bitfield( key1, [BitFieldSet(UnsignedEncoding(64), BitOffset(1), 1)] ) # invalid argument - signed encoding size must be < 65 with pytest.raises(RequestError): - await redis_client.bitfield( + await glide_client.bitfield( key1, [BitFieldSet(SignedEncoding(65), BitOffset(1), 1)] ) # key exists, but it is not a string - assert await redis_client.sadd(set_key, [foobar]) == 1 + assert await glide_client.sadd(set_key, [foobar]) == 1 with pytest.raises(RequestError): - await redis_client.bitfield( + await glide_client.bitfield( set_key, [BitFieldSet(SignedEncoding(3), BitOffset(1), 2)] ) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_bitfield_read_only(self, redis_client: TGlideClient): + async def test_bitfield_read_only(self, glide_client: TGlideClient): min_version = "6.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") key = get_random_string(10) @@ -7233,8 +7233,8 @@ async def test_bitfield_read_only(self, redis_client: TGlideClient): unsigned_offset_get = BitFieldGet(UnsignedEncoding(2), BitOffset(1)) # binary value: 01100110 01101111 01101111 01100010 01100001 01110010 - assert await redis_client.set(key, foobar) == OK - assert await redis_client.bitfield_read_only( + assert await glide_client.set(key, foobar) == OK + assert await glide_client.bitfield_read_only( key, [ # Get value in: 0(11)00110 01101111 01101111 01100010 01100001 01110010 00010100 @@ -7249,50 +7249,50 @@ async def test_bitfield_read_only(self, redis_client: TGlideClient): ) == [3, -2, 118, 111] # offset is greater than current length of string: the operation is performed like the missing part all consists # of bits set to 0. - assert await redis_client.bitfield_read_only( + assert await glide_client.bitfield_read_only( key, [BitFieldGet(UnsignedEncoding(3), BitOffset(100))] ) == [0] # similarly, if the key doesn't exist, the operation is performed as though the missing value was a string with # all bits set to 0. - assert await redis_client.bitfield_read_only( + assert await glide_client.bitfield_read_only( non_existing_key, [unsigned_offset_get] ) == [0] # empty subcommands argument returns an empty list - assert await redis_client.bitfield_read_only(key, []) == [] + assert await glide_client.bitfield_read_only(key, []) == [] # invalid argument - offset must be >= 0 with pytest.raises(RequestError): - await redis_client.bitfield_read_only( + await glide_client.bitfield_read_only( key, [BitFieldGet(UnsignedEncoding(5), BitOffset(-1))] ) # invalid argument - encoding size must be > 0 with pytest.raises(RequestError): - await redis_client.bitfield_read_only( + await glide_client.bitfield_read_only( key, [BitFieldGet(UnsignedEncoding(0), BitOffset(1))] ) # invalid argument - unsigned encoding size must be < 64 with pytest.raises(RequestError): - await redis_client.bitfield_read_only( + await glide_client.bitfield_read_only( key, [BitFieldGet(UnsignedEncoding(64), BitOffset(1))] ) # invalid argument - signed encoding size must be < 65 with pytest.raises(RequestError): - await redis_client.bitfield_read_only( + await glide_client.bitfield_read_only( key, [BitFieldGet(SignedEncoding(65), BitOffset(1))] ) # key exists, but it is not a string - assert await redis_client.sadd(set_key, [foobar]) == 1 + assert await glide_client.sadd(set_key, [foobar]) == 1 with pytest.raises(RequestError): - await redis_client.bitfield_read_only(set_key, [unsigned_offset_get]) + await glide_client.bitfield_read_only(set_key, [unsigned_offset_get]) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_object_encoding(self, redis_client: TGlideClient): + async def test_object_encoding(self, glide_client: TGlideClient): string_key = get_random_string(10) list_key = get_random_string(10) hashtable_key = get_random_string(10) @@ -7305,136 +7305,136 @@ async def test_object_encoding(self, redis_client: TGlideClient): stream_key = get_random_string(10) non_existing_key = get_random_string(10) - assert await redis_client.object_encoding(non_existing_key) is None + assert await glide_client.object_encoding(non_existing_key) is None - assert await redis_client.set( + assert await glide_client.set( string_key, "a really loooooooooooooooooooooooooooooooooooooooong value" ) - assert await redis_client.object_encoding(string_key) == "raw".encode() + assert await glide_client.object_encoding(string_key) == "raw".encode() - assert await redis_client.set(string_key, "2") == OK - assert await redis_client.object_encoding(string_key) == "int".encode() + assert await glide_client.set(string_key, "2") == OK + assert await glide_client.object_encoding(string_key) == "int".encode() - assert await redis_client.set(string_key, "value") == OK - assert await redis_client.object_encoding(string_key) == "embstr".encode() + assert await glide_client.set(string_key, "value") == OK + assert await glide_client.object_encoding(string_key) == "embstr".encode() - assert await redis_client.lpush(list_key, ["1"]) == 1 - if await check_if_server_version_lt(redis_client, "7.2.0"): - assert await redis_client.object_encoding(list_key) == "quicklist".encode() + assert await glide_client.lpush(list_key, ["1"]) == 1 + if await check_if_server_version_lt(glide_client, "7.2.0"): + assert await glide_client.object_encoding(list_key) == "quicklist".encode() else: - assert await redis_client.object_encoding(list_key) == "listpack".encode() + assert await glide_client.object_encoding(list_key) == "listpack".encode() # The default value of set-max-intset-entries is 512 for i in range(0, 513): - assert await redis_client.sadd(hashtable_key, [str(i)]) == 1 - assert await redis_client.object_encoding(hashtable_key) == "hashtable".encode() + assert await glide_client.sadd(hashtable_key, [str(i)]) == 1 + assert await glide_client.object_encoding(hashtable_key) == "hashtable".encode() - assert await redis_client.sadd(intset_key, ["1"]) == 1 - assert await redis_client.object_encoding(intset_key) == "intset".encode() + assert await glide_client.sadd(intset_key, ["1"]) == 1 + assert await glide_client.object_encoding(intset_key) == "intset".encode() - assert await redis_client.sadd(set_listpack_key, ["foo"]) == 1 - if await check_if_server_version_lt(redis_client, "7.2.0"): + assert await glide_client.sadd(set_listpack_key, ["foo"]) == 1 + if await check_if_server_version_lt(glide_client, "7.2.0"): assert ( - await redis_client.object_encoding(set_listpack_key) + await glide_client.object_encoding(set_listpack_key) == "hashtable".encode() ) else: assert ( - await redis_client.object_encoding(set_listpack_key) + await glide_client.object_encoding(set_listpack_key) == "listpack".encode() ) # The default value of hash-max-listpack-entries is 512 for i in range(0, 513): - assert await redis_client.hset(hash_hashtable_key, {str(i): "2"}) == 1 + assert await glide_client.hset(hash_hashtable_key, {str(i): "2"}) == 1 assert ( - await redis_client.object_encoding(hash_hashtable_key) + await glide_client.object_encoding(hash_hashtable_key) == "hashtable".encode() ) - assert await redis_client.hset(hash_listpack_key, {"1": "2"}) == 1 - if await check_if_server_version_lt(redis_client, "7.0.0"): + assert await glide_client.hset(hash_listpack_key, {"1": "2"}) == 1 + if await check_if_server_version_lt(glide_client, "7.0.0"): assert ( - await redis_client.object_encoding(hash_listpack_key) + await glide_client.object_encoding(hash_listpack_key) == "ziplist".encode() ) else: assert ( - await redis_client.object_encoding(hash_listpack_key) + await glide_client.object_encoding(hash_listpack_key) == "listpack".encode() ) # The default value of zset-max-listpack-entries is 128 for i in range(0, 129): - assert await redis_client.zadd(skiplist_key, {str(i): 2.0}) == 1 - assert await redis_client.object_encoding(skiplist_key) == "skiplist".encode() + assert await glide_client.zadd(skiplist_key, {str(i): 2.0}) == 1 + assert await glide_client.object_encoding(skiplist_key) == "skiplist".encode() - assert await redis_client.zadd(zset_listpack_key, {"1": 2.0}) == 1 - if await check_if_server_version_lt(redis_client, "7.0.0"): + assert await glide_client.zadd(zset_listpack_key, {"1": 2.0}) == 1 + if await check_if_server_version_lt(glide_client, "7.0.0"): assert ( - await redis_client.object_encoding(zset_listpack_key) + await glide_client.object_encoding(zset_listpack_key) == "ziplist".encode() ) else: assert ( - await redis_client.object_encoding(zset_listpack_key) + await glide_client.object_encoding(zset_listpack_key) == "listpack".encode() ) - assert await redis_client.xadd(stream_key, [("field", "value")]) is not None - assert await redis_client.object_encoding(stream_key) == "stream".encode() + assert await glide_client.xadd(stream_key, [("field", "value")]) is not None + assert await glide_client.object_encoding(stream_key) == "stream".encode() @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_object_freq(self, redis_client: TGlideClient): + async def test_object_freq(self, glide_client: TGlideClient): key = get_random_string(10) non_existing_key = get_random_string(10) maxmemory_policy_key = "maxmemory-policy" - config = await redis_client.config_get([maxmemory_policy_key]) + config = await glide_client.config_get([maxmemory_policy_key]) config_decoded = cast(dict, convert_bytes_to_string_object(config)) assert config_decoded is not None maxmemory_policy = cast(str, config_decoded.get(maxmemory_policy_key)) try: assert ( - await redis_client.config_set({maxmemory_policy_key: "allkeys-lfu"}) + await glide_client.config_set({maxmemory_policy_key: "allkeys-lfu"}) == OK ) - assert await redis_client.object_freq(non_existing_key) is None - assert await redis_client.set(key, "") == OK - freq = await redis_client.object_freq(key) + assert await glide_client.object_freq(non_existing_key) is None + assert await glide_client.set(key, "") == OK + freq = await glide_client.object_freq(key) assert freq is not None and freq >= 0 finally: - await redis_client.config_set({maxmemory_policy_key: maxmemory_policy}) + await glide_client.config_set({maxmemory_policy_key: maxmemory_policy}) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_object_idletime(self, redis_client: TGlideClient): + async def test_object_idletime(self, glide_client: TGlideClient): string_key = get_random_string(10) non_existing_key = get_random_string(10) - assert await redis_client.object_idletime(non_existing_key) is None - assert await redis_client.set(string_key, "foo") == OK + assert await glide_client.object_idletime(non_existing_key) is None + assert await glide_client.set(string_key, "foo") == OK time.sleep(2) - idletime = await redis_client.object_idletime(string_key) + idletime = await glide_client.object_idletime(string_key) assert idletime is not None and idletime > 0 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_object_refcount(self, redis_client: TGlideClient): + async def test_object_refcount(self, glide_client: TGlideClient): string_key = get_random_string(10) non_existing_key = get_random_string(10) - assert await redis_client.object_refcount(non_existing_key) is None - assert await redis_client.set(string_key, "foo") == OK - refcount = await redis_client.object_refcount(string_key) + assert await glide_client.object_refcount(non_existing_key) is None + assert await glide_client.set(string_key, "foo") == OK + refcount = await glide_client.object_refcount(string_key) assert refcount is not None and refcount >= 0 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_function_load(self, redis_client: TGlideClient): + async def test_function_load(self, glide_client: TGlideClient): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") lib_name = f"mylib1C{get_random_string(5)}" @@ -7442,18 +7442,18 @@ async def test_function_load(self, redis_client: TGlideClient): code = generate_lua_lib_code(lib_name, {func_name: "return args[1]"}, True) # verify function does not yet exist - assert await redis_client.function_list(lib_name) == [] + assert await glide_client.function_list(lib_name) == [] - assert await redis_client.function_load(code) == lib_name.encode() + assert await glide_client.function_load(code) == lib_name.encode() - assert await redis_client.fcall(func_name, arguments=["one", "two"]) == b"one" + assert await glide_client.fcall(func_name, arguments=["one", "two"]) == b"one" assert ( - await redis_client.fcall_ro(func_name, arguments=["one", "two"]) == b"one" + await glide_client.fcall_ro(func_name, arguments=["one", "two"]) == b"one" ) # verify with FUNCTION LIST check_function_list_response( - await redis_client.function_list(lib_name, with_code=True), + await glide_client.function_list(lib_name, with_code=True), lib_name, {func_name: None}, {func_name: {b"no-writes"}}, @@ -7462,11 +7462,11 @@ async def test_function_load(self, redis_client: TGlideClient): # re-load library without replace with pytest.raises(RequestError) as e: - await redis_client.function_load(code) + await glide_client.function_load(code) assert "Library '" + lib_name + "' already exists" in str(e) # re-load library with replace - assert await redis_client.function_load(code, True) == lib_name.encode() + assert await glide_client.function_load(code, True) == lib_name.encode() func2_name = f"myfunc2c{get_random_string(5)}" new_code = f"""{code}\n redis.register_function({func2_name}, function(keys, args) return #args end)""" @@ -7474,21 +7474,21 @@ async def test_function_load(self, redis_client: TGlideClient): lib_name, {func_name: "return args[1]", func2_name: "return #args"}, True ) - assert await redis_client.function_load(new_code, True) == lib_name.encode() + assert await glide_client.function_load(new_code, True) == lib_name.encode() - assert await redis_client.fcall(func2_name, arguments=["one", "two"]) == 2 - assert await redis_client.fcall_ro(func2_name, arguments=["one", "two"]) == 2 + assert await glide_client.fcall(func2_name, arguments=["one", "two"]) == 2 + assert await glide_client.fcall_ro(func2_name, arguments=["one", "two"]) == 2 - assert await redis_client.function_flush(FlushMode.SYNC) is OK + assert await glide_client.function_flush(FlushMode.SYNC) is OK @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) @pytest.mark.parametrize("single_route", [True, False]) async def test_function_load_cluster_with_route( - self, redis_client: GlideClusterClient, single_route: bool + self, glide_client: GlideClusterClient, single_route: bool ): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") lib_name = f"mylib1C{get_random_string(5)}" @@ -7497,7 +7497,7 @@ async def test_function_load_cluster_with_route( route = SlotKeyRoute(SlotType.PRIMARY, "1") if single_route else AllPrimaries() # verify function does not yet exist - function_list = await redis_client.function_list(lib_name, False, route) + function_list = await glide_client.function_list(lib_name, False, route) if single_route: assert function_list == [] else: @@ -7505,9 +7505,9 @@ async def test_function_load_cluster_with_route( for functions in function_list.values(): assert functions == [] - assert await redis_client.function_load(code, False, route) == lib_name.encode() + assert await glide_client.function_load(code, False, route) == lib_name.encode() - result = await redis_client.fcall_route( + result = await glide_client.fcall_route( func_name, arguments=["one", "two"], route=route ) @@ -7518,7 +7518,7 @@ async def test_function_load_cluster_with_route( for nodeResponse in result.values(): assert nodeResponse == b"one" - result = await redis_client.fcall_ro_route( + result = await glide_client.fcall_ro_route( func_name, arguments=["one", "two"], route=route ) @@ -7530,7 +7530,7 @@ async def test_function_load_cluster_with_route( assert nodeResponse == b"one" # verify with FUNCTION LIST - function_list = await redis_client.function_list( + function_list = await glide_client.function_list( lib_name, with_code=True, route=route ) if single_route: @@ -7554,11 +7554,11 @@ async def test_function_load_cluster_with_route( # re-load library without replace with pytest.raises(RequestError) as e: - await redis_client.function_load(code, False, route) + await glide_client.function_load(code, False, route) assert "Library '" + lib_name + "' already exists" in str(e) # re-load library with replace - assert await redis_client.function_load(code, True, route) == lib_name.encode() + assert await glide_client.function_load(code, True, route) == lib_name.encode() func2_name = f"myfunc2c{get_random_string(5)}" new_code = f"""{code}\n redis.register_function({func2_name}, function(keys, args) return #args end)""" @@ -7567,10 +7567,10 @@ async def test_function_load_cluster_with_route( ) assert ( - await redis_client.function_load(new_code, True, route) == lib_name.encode() + await glide_client.function_load(new_code, True, route) == lib_name.encode() ) - result = await redis_client.fcall_route( + result = await glide_client.fcall_route( func2_name, arguments=["one", "two"], route=route ) @@ -7581,7 +7581,7 @@ async def test_function_load_cluster_with_route( for nodeResponse in result.values(): assert nodeResponse == 2 - result = await redis_client.fcall_ro_route( + result = await glide_client.fcall_ro_route( func2_name, arguments=["one", "two"], route=route ) @@ -7592,51 +7592,51 @@ async def test_function_load_cluster_with_route( for nodeResponse in result.values(): assert nodeResponse == 2 - assert await redis_client.function_flush(FlushMode.SYNC, route) is OK + assert await glide_client.function_flush(FlushMode.SYNC, route) is OK @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_function_list(self, redis_client: TGlideClient): + async def test_function_list(self, glide_client: TGlideClient): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") - original_functions_count = len(await redis_client.function_list()) + original_functions_count = len(await glide_client.function_list()) lib_name = f"mylib1C{get_random_string(5)}" func_name = f"myfunc1c{get_random_string(5)}" code = generate_lua_lib_code(lib_name, {func_name: "return args[1]"}, True) # Assert function `lib_name` does not yet exist - assert await redis_client.function_list(lib_name) == [] + assert await glide_client.function_list(lib_name) == [] # load library - await redis_client.function_load(code) + await glide_client.function_load(code) check_function_list_response( - await redis_client.function_list(lib_name.encode()), + await glide_client.function_list(lib_name.encode()), lib_name, {func_name: None}, {func_name: {b"no-writes"}}, None, ) check_function_list_response( - await redis_client.function_list(f"{lib_name}*"), + await glide_client.function_list(f"{lib_name}*"), lib_name, {func_name: None}, {func_name: {b"no-writes"}}, None, ) check_function_list_response( - await redis_client.function_list(lib_name, with_code=True), + await glide_client.function_list(lib_name, with_code=True), lib_name, {func_name: None}, {func_name: {b"no-writes"}}, code, ) - no_args_response = await redis_client.function_list() - wildcard_pattern_response = await redis_client.function_list( + no_args_response = await glide_client.function_list() + wildcard_pattern_response = await glide_client.function_list( "*".encode(), False ) assert len(no_args_response) == original_functions_count + 1 @@ -7660,10 +7660,10 @@ async def test_function_list(self, redis_client: TGlideClient): @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) @pytest.mark.parametrize("single_route", [True, False]) async def test_function_list_with_routing( - self, redis_client: GlideClusterClient, single_route: bool + self, glide_client: GlideClusterClient, single_route: bool ): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") route = SlotKeyRoute(SlotType.PRIMARY, "1") if single_route else AllPrimaries() @@ -7673,7 +7673,7 @@ async def test_function_list_with_routing( code = generate_lua_lib_code(lib_name, {func_name: "return args[1]"}, True) # Assert function `lib_name` does not yet exist - result = await redis_client.function_list(lib_name, route=route) + result = await glide_client.function_list(lib_name, route=route) if single_route: assert result == [] else: @@ -7682,9 +7682,9 @@ async def test_function_list_with_routing( assert nodeResponse == [] # load library - await redis_client.function_load(code, route=route) + await glide_client.function_load(code, route=route) - result = await redis_client.function_list(lib_name, route=route) + result = await glide_client.function_list(lib_name, route=route) if single_route: check_function_list_response( result, @@ -7704,7 +7704,7 @@ async def test_function_list_with_routing( None, ) - result = await redis_client.function_list(f"{lib_name}*", route=route) + result = await glide_client.function_list(f"{lib_name}*", route=route) if single_route: check_function_list_response( result, @@ -7724,7 +7724,7 @@ async def test_function_list_with_routing( None, ) - result = await redis_client.function_list(lib_name, with_code=True, route=route) + result = await glide_client.function_list(lib_name, with_code=True, route=route) if single_route: check_function_list_response( result, @@ -7747,14 +7747,14 @@ async def test_function_list_with_routing( @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_function_list_with_multiple_functions( - self, redis_client: TGlideClient + self, glide_client: TGlideClient ): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") - await redis_client.function_flush() - assert len(await redis_client.function_list()) == 0 + await glide_client.function_flush() + assert len(await glide_client.function_list()) == 0 lib_name_1 = f"mylib1C{get_random_string(5)}" func_name_1 = f"myfunc1c{get_random_string(5)}" @@ -7764,16 +7764,16 @@ async def test_function_list_with_multiple_functions( {func_name_1: "return args[1]", func_name_2: "return args[2]"}, False, ) - await redis_client.function_load(code_1) + await glide_client.function_load(code_1) lib_name_2 = f"mylib2C{get_random_string(5)}" func_name_3 = f"myfunc3c{get_random_string(5)}" code_2 = generate_lua_lib_code( lib_name_2, {func_name_3: "return args[3]"}, True ) - await redis_client.function_load(code_2) + await glide_client.function_load(code_2) - no_args_response = await redis_client.function_list() + no_args_response = await glide_client.function_list() assert len(no_args_response) == 2 check_function_list_response( @@ -7793,9 +7793,9 @@ async def test_function_list_with_multiple_functions( @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_function_flush(self, redis_client: TGlideClient): + async def test_function_flush(self, glide_client: TGlideClient): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): pytest.skip(f"Redis version required >= {min_version}") lib_name = f"mylib1C{get_random_string(5)}" @@ -7803,35 +7803,35 @@ async def test_function_flush(self, redis_client: TGlideClient): code = generate_lua_lib_code(lib_name, {func_name: "return args[1]"}, True) # Load the function - assert await redis_client.function_load(code) == lib_name.encode() + assert await glide_client.function_load(code) == lib_name.encode() # verify function exists - assert len(await redis_client.function_list(lib_name)) == 1 + assert len(await glide_client.function_list(lib_name)) == 1 # Flush functions - assert await redis_client.function_flush(FlushMode.SYNC) == OK - assert await redis_client.function_flush(FlushMode.ASYNC) == OK + assert await glide_client.function_flush(FlushMode.SYNC) == OK + assert await glide_client.function_flush(FlushMode.ASYNC) == OK # verify function is removed - assert len(await redis_client.function_list(lib_name)) == 0 + assert len(await glide_client.function_list(lib_name)) == 0 # Attempt to re-load library without overwriting to ensure FLUSH was effective - assert await redis_client.function_load(code) == lib_name.encode() + assert await glide_client.function_load(code) == lib_name.encode() # verify function exists - assert len(await redis_client.function_list(lib_name)) == 1 + assert len(await glide_client.function_list(lib_name)) == 1 # Clean up by flushing functions again - await redis_client.function_flush() + await glide_client.function_flush() @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) @pytest.mark.parametrize("single_route", [True, False]) async def test_function_flush_with_routing( - self, redis_client: GlideClusterClient, single_route: bool + self, glide_client: GlideClusterClient, single_route: bool ): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): pytest.skip(f"Redis version required >= {min_version}") lib_name = f"mylib1C{get_random_string(5)}" @@ -7840,10 +7840,10 @@ async def test_function_flush_with_routing( route = SlotKeyRoute(SlotType.PRIMARY, "1") if single_route else AllPrimaries() # Load the function - assert await redis_client.function_load(code, False, route) == lib_name.encode() + assert await glide_client.function_load(code, False, route) == lib_name.encode() # verify function exists - result = await redis_client.function_list(lib_name, False, route) + result = await glide_client.function_list(lib_name, False, route) if single_route: assert len(result) == 1 else: @@ -7852,11 +7852,11 @@ async def test_function_flush_with_routing( assert len(nodeResponse) == 1 # Flush functions - assert await redis_client.function_flush(FlushMode.SYNC, route) == OK - assert await redis_client.function_flush(FlushMode.ASYNC, route) == OK + assert await glide_client.function_flush(FlushMode.SYNC, route) == OK + assert await glide_client.function_flush(FlushMode.ASYNC, route) == OK # verify function is removed - result = await redis_client.function_list(lib_name, False, route) + result = await glide_client.function_list(lib_name, False, route) if single_route: assert len(result) == 0 else: @@ -7865,10 +7865,10 @@ async def test_function_flush_with_routing( assert len(nodeResponse) == 0 # Attempt to re-load library without overwriting to ensure FLUSH was effective - assert await redis_client.function_load(code, False, route) == lib_name.encode() + assert await glide_client.function_load(code, False, route) == lib_name.encode() # verify function exists - result = await redis_client.function_list(lib_name, False, route) + result = await glide_client.function_list(lib_name, False, route) if single_route: assert len(result) == 1 else: @@ -7877,13 +7877,13 @@ async def test_function_flush_with_routing( assert len(nodeResponse) == 1 # Clean up by flushing functions again - assert await redis_client.function_flush(route=route) == OK + assert await glide_client.function_flush(route=route) == OK @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_function_delete(self, redis_client: TGlideClient): + async def test_function_delete(self, glide_client: TGlideClient): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): pytest.skip(f"Redis version required >= {min_version}") lib_name = f"mylib1C{get_random_string(5)}" @@ -7891,30 +7891,30 @@ async def test_function_delete(self, redis_client: TGlideClient): code = generate_lua_lib_code(lib_name, {func_name: "return args[1]"}, True) # Load the function - assert await redis_client.function_load(code) == lib_name.encode() + assert await glide_client.function_load(code) == lib_name.encode() # verify function exists - assert len(await redis_client.function_list(lib_name)) == 1 + assert len(await glide_client.function_list(lib_name)) == 1 # Delete the function - assert await redis_client.function_delete(lib_name) == OK + assert await glide_client.function_delete(lib_name) == OK # verify function is removed - assert len(await redis_client.function_list(lib_name)) == 0 + assert len(await glide_client.function_list(lib_name)) == 0 # deleting a non-existing library with pytest.raises(RequestError) as e: - await redis_client.function_delete(lib_name) + await glide_client.function_delete(lib_name) assert "Library not found" in str(e) @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) @pytest.mark.parametrize("single_route", [True, False]) async def test_function_delete_with_routing( - self, redis_client: GlideClusterClient, single_route: bool + self, glide_client: GlideClusterClient, single_route: bool ): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): pytest.skip(f"Redis version required >= {min_version}") lib_name = f"mylib1C{get_random_string(5)}" @@ -7923,10 +7923,10 @@ async def test_function_delete_with_routing( route = SlotKeyRoute(SlotType.PRIMARY, "1") if single_route else AllPrimaries() # Load the function - assert await redis_client.function_load(code, False, route) == lib_name.encode() + assert await glide_client.function_load(code, False, route) == lib_name.encode() # verify function exists - result = await redis_client.function_list(lib_name, False, route) + result = await glide_client.function_list(lib_name, False, route) if single_route: assert len(result) == 1 else: @@ -7935,10 +7935,10 @@ async def test_function_delete_with_routing( assert len(nodeResponse) == 1 # Delete the function - assert await redis_client.function_delete(lib_name, route) == OK + assert await glide_client.function_delete(lib_name, route) == OK # verify function is removed - result = await redis_client.function_list(lib_name, False, route) + result = await glide_client.function_list(lib_name, False, route) if single_route: assert len(result) == 0 else: @@ -7948,14 +7948,14 @@ async def test_function_delete_with_routing( # deleting a non-existing library with pytest.raises(RequestError) as e: - await redis_client.function_delete(lib_name) + await glide_client.function_delete(lib_name) assert "Library not found" in str(e) @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_fcall_with_key(self, redis_client: GlideClusterClient): + async def test_fcall_with_key(self, glide_client: GlideClusterClient): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") key1 = f"{{testKey}}:1-{get_random_string(10)}" @@ -7966,16 +7966,16 @@ async def test_fcall_with_key(self, redis_client: GlideClusterClient): func_name = f"myfunc1c{get_random_string(5)}" code = generate_lua_lib_code(lib_name, {func_name: "return keys[1]"}, True) - assert await redis_client.function_flush(FlushMode.SYNC, route) is OK - assert await redis_client.function_load(code, False, route) == lib_name.encode() + assert await glide_client.function_flush(FlushMode.SYNC, route) is OK + assert await glide_client.function_load(code, False, route) == lib_name.encode() assert ( - await redis_client.fcall(func_name, keys=keys, arguments=[]) + await glide_client.fcall(func_name, keys=keys, arguments=[]) == key1.encode() ) assert ( - await redis_client.fcall_ro(func_name, keys=keys, arguments=[]) + await glide_client.fcall_ro(func_name, keys=keys, arguments=[]) == key1.encode() ) @@ -7985,24 +7985,24 @@ async def test_fcall_with_key(self, redis_client: GlideClusterClient): transaction.fcall_ro(func_name, keys=keys, arguments=[]) # check response from a routed transaction request - result = await redis_client.exec(transaction, route) + result = await glide_client.exec(transaction, route) assert result is not None assert result[0] == key1.encode() assert result[1] == key1.encode() # if no route given, GLIDE should detect it automatically - result = await redis_client.exec(transaction) + result = await glide_client.exec(transaction) assert result is not None assert result[0] == key1.encode() assert result[1] == key1.encode() - assert await redis_client.function_flush(FlushMode.SYNC, route) is OK + assert await glide_client.function_flush(FlushMode.SYNC, route) is OK @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_fcall_readonly_function(self, redis_client: GlideClusterClient): + async def test_fcall_readonly_function(self, glide_client: GlideClusterClient): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") lib_name = f"fcall_readonly_function{get_random_string(5)}" @@ -8014,35 +8014,35 @@ async def test_fcall_readonly_function(self, redis_client: GlideClusterClient): # function $funcName returns a magic number code = generate_lua_lib_code(lib_name, {func_name: "return 42"}, False) - assert await redis_client.function_load(code, False) == lib_name.encode() + assert await glide_client.function_load(code, False) == lib_name.encode() # On a replica node should fail, because a function isn't guaranteed to be RO with pytest.raises(RequestError) as e: - assert await redis_client.fcall_route( + assert await glide_client.fcall_route( func_name, arguments=[], route=replicaRoute ) assert "You can't write against a read only replica." in str(e) with pytest.raises(RequestError) as e: - assert await redis_client.fcall_ro_route( + assert await glide_client.fcall_ro_route( func_name, arguments=[], route=replicaRoute ) assert "You can't write against a read only replica." in str(e) # fcall_ro also fails to run it even on primary - another error with pytest.raises(RequestError) as e: - assert await redis_client.fcall_ro_route( + assert await glide_client.fcall_ro_route( func_name, arguments=[], route=primaryRoute ) assert "Can not execute a script with write flag using *_ro command." in str(e) # create the same function, but with RO flag code = generate_lua_lib_code(lib_name, {func_name: "return 42"}, True) - assert await redis_client.function_load(code, True) == lib_name.encode() + assert await glide_client.function_load(code, True) == lib_name.encode() # fcall should succeed now assert ( - await redis_client.fcall_ro_route( + await glide_client.fcall_ro_route( func_name, arguments=[], route=replicaRoute ) == 42 @@ -8050,15 +8050,15 @@ async def test_fcall_readonly_function(self, redis_client: GlideClusterClient): @pytest.mark.parametrize("cluster_mode", [False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_function_dump_restore_standalone(self, redis_client: GlideClient): + async def test_function_dump_restore_standalone(self, glide_client: GlideClient): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") - assert await redis_client.function_flush(FlushMode.SYNC) is OK + assert await glide_client.function_flush(FlushMode.SYNC) is OK # Dump an empty lib - emptyDump = await redis_client.function_dump() + emptyDump = await glide_client.function_dump() assert emptyDump is not None and len(emptyDump) > 0 name1 = f"Foster{get_random_string(5)}" @@ -8068,71 +8068,71 @@ async def test_function_dump_restore_standalone(self, redis_client: GlideClient) code = generate_lua_lib_code( name1, {name1: "return args[1]", name2: "return #args"}, False ) - assert await redis_client.function_load(code, True) == name1.encode() - flist = await redis_client.function_list(with_code=True) + assert await glide_client.function_load(code, True) == name1.encode() + flist = await glide_client.function_list(with_code=True) - dump = await redis_client.function_dump() + dump = await glide_client.function_dump() assert dump is not None # restore without cleaning the lib and/or overwrite option causes an error with pytest.raises(RequestError) as e: - assert await redis_client.function_restore(dump) + assert await glide_client.function_restore(dump) assert "already exists" in str(e) # APPEND policy also fails for the same reason (name collision) with pytest.raises(RequestError) as e: - assert await redis_client.function_restore( + assert await glide_client.function_restore( dump, FunctionRestorePolicy.APPEND ) assert "already exists" in str(e) # REPLACE policy succeed assert ( - await redis_client.function_restore(dump, FunctionRestorePolicy.REPLACE) + await glide_client.function_restore(dump, FunctionRestorePolicy.REPLACE) is OK ) # but nothing changed - all code overwritten - assert await redis_client.function_list(with_code=True) == flist + assert await glide_client.function_list(with_code=True) == flist # create lib with another name, but with the same function names - assert await redis_client.function_flush(FlushMode.SYNC) is OK + assert await glide_client.function_flush(FlushMode.SYNC) is OK code = generate_lua_lib_code( name2, {name1: "return args[1]", name2: "return #args"}, False ) - assert await redis_client.function_load(code, True) == name2.encode() + assert await glide_client.function_load(code, True) == name2.encode() # REPLACE policy now fails due to a name collision with pytest.raises(RequestError) as e: - await redis_client.function_restore(dump, FunctionRestorePolicy.REPLACE) + await glide_client.function_restore(dump, FunctionRestorePolicy.REPLACE) assert "already exists" in str(e) # FLUSH policy succeeds, but deletes the second lib assert ( - await redis_client.function_restore(dump, FunctionRestorePolicy.FLUSH) is OK + await glide_client.function_restore(dump, FunctionRestorePolicy.FLUSH) is OK ) - assert await redis_client.function_list(with_code=True) == flist + assert await glide_client.function_list(with_code=True) == flist # call restored functions assert ( - await redis_client.fcall(name1, arguments=["meow", "woem"]) + await glide_client.fcall(name1, arguments=["meow", "woem"]) == "meow".encode() ) - assert await redis_client.fcall(name2, arguments=["meow", "woem"]) == 2 + assert await glide_client.fcall(name2, arguments=["meow", "woem"]) == 2 @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_function_dump_restore_cluster( - self, redis_client: GlideClusterClient + self, glide_client: GlideClusterClient ): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") - assert await redis_client.function_flush(FlushMode.SYNC) is OK + assert await glide_client.function_flush(FlushMode.SYNC) is OK # Dump an empty lib - emptyDump = await redis_client.function_dump() + emptyDump = await glide_client.function_dump() assert emptyDump is not None and len(emptyDump) > 0 name1 = f"Foster{get_random_string(5)}" @@ -8144,33 +8144,33 @@ async def test_function_dump_restore_cluster( code = generate_lua_lib_code( libname1, {name1: "return args[1]", name2: "return #args"}, True ) - assert await redis_client.function_load(code, True) == libname1.encode() - flist = await redis_client.function_list(with_code=True) - dump = await redis_client.function_dump(RandomNode()) + assert await glide_client.function_load(code, True) == libname1.encode() + flist = await glide_client.function_list(with_code=True) + dump = await glide_client.function_dump(RandomNode()) assert dump is not None and isinstance(dump, bytes) # restore without cleaning the lib and/or overwrite option causes an error with pytest.raises(RequestError) as e: - assert await redis_client.function_restore(dump) + assert await glide_client.function_restore(dump) assert "already exists" in str(e) # APPEND policy also fails for the same reason (name collision) with pytest.raises(RequestError) as e: - assert await redis_client.function_restore( + assert await glide_client.function_restore( dump, FunctionRestorePolicy.APPEND ) assert "already exists" in str(e) # REPLACE policy succeed assert ( - await redis_client.function_restore( + await glide_client.function_restore( dump, FunctionRestorePolicy.REPLACE, route=AllPrimaries() ) is OK ) # but nothing changed - all code overwritten - restoredFunctionList = await redis_client.function_list(with_code=True) + restoredFunctionList = await glide_client.function_list(with_code=True) assert restoredFunctionList is not None assert isinstance(restoredFunctionList, List) and len(restoredFunctionList) == 1 assert restoredFunctionList[0]["library_name".encode()] == libname1.encode() @@ -8179,26 +8179,26 @@ async def test_function_dump_restore_cluster( assert len(restoredFunctionList[0]["functions".encode()]) == 2 # create lib with another name, but with the same function names - assert await redis_client.function_flush(FlushMode.SYNC) is OK + assert await glide_client.function_flush(FlushMode.SYNC) is OK code = generate_lua_lib_code( libname2, {name1: "return args[1]", name2: "return #args"}, True ) - assert await redis_client.function_load(code, True) == libname2.encode() - restoredFunctionList = await redis_client.function_list(with_code=True) + assert await glide_client.function_load(code, True) == libname2.encode() + restoredFunctionList = await glide_client.function_list(with_code=True) assert restoredFunctionList is not None assert isinstance(restoredFunctionList, List) and len(restoredFunctionList) == 1 assert restoredFunctionList[0]["library_name".encode()] == libname2.encode() # REPLACE policy now fails due to a name collision with pytest.raises(RequestError) as e: - await redis_client.function_restore(dump, FunctionRestorePolicy.REPLACE) + await glide_client.function_restore(dump, FunctionRestorePolicy.REPLACE) assert "already exists" in str(e) # FLUSH policy succeeds, but deletes the second lib assert ( - await redis_client.function_restore(dump, FunctionRestorePolicy.FLUSH) is OK + await glide_client.function_restore(dump, FunctionRestorePolicy.FLUSH) is OK ) - restoredFunctionList = await redis_client.function_list(with_code=True) + restoredFunctionList = await glide_client.function_list(with_code=True) assert restoredFunctionList is not None assert isinstance(restoredFunctionList, List) and len(restoredFunctionList) == 1 assert restoredFunctionList[0]["library_name".encode()] == libname1.encode() @@ -8208,45 +8208,45 @@ async def test_function_dump_restore_cluster( # call restored functions assert ( - await redis_client.fcall_ro(name1, arguments=["meow", "woem"]) + await glide_client.fcall_ro(name1, arguments=["meow", "woem"]) == "meow".encode() ) - assert await redis_client.fcall_ro(name2, arguments=["meow", "woem"]) == 2 + assert await glide_client.fcall_ro(name2, arguments=["meow", "woem"]) == 2 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_srandmember(self, redis_client: TGlideClient): + async def test_srandmember(self, glide_client: TGlideClient): key = get_random_string(10) string_key = get_random_string(10) elements: List[TEncodable] = ["one", "two"] - assert await redis_client.sadd(key, elements) == 2 + assert await glide_client.sadd(key, elements) == 2 - member = await redis_client.srandmember(key) + member = await glide_client.srandmember(key) # TODO: remove when function signature is fixed assert isinstance(member, bytes) assert member.decode() in elements - assert await redis_client.srandmember("non_existing_key") is None + assert await glide_client.srandmember("non_existing_key") is None # key exists, but it is not a set - assert await redis_client.set(string_key, "value") == OK + assert await glide_client.set(string_key, "value") == OK with pytest.raises(RequestError): - await redis_client.srandmember(string_key) + await glide_client.srandmember(string_key) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_srandmember_count(self, redis_client: TGlideClient): + async def test_srandmember_count(self, glide_client: TGlideClient): key = get_random_string(10) string_key = get_random_string(10) elements: List[TEncodable] = ["one", "two"] - assert await redis_client.sadd(key, elements) == 2 + assert await glide_client.sadd(key, elements) == 2 # unique values are expected as count is positive - members = await redis_client.srandmember_count(key, 4) + members = await glide_client.srandmember_count(key, 4) assert len(members) == 2 assert set(members) == {b"one", b"two"} # duplicate values are expected as count is negative - members = await redis_client.srandmember_count(key, -4) + members = await glide_client.srandmember_count(key, -4) assert len(members) == 4 for member in members: # TODO: remove when function signature is fixed @@ -8254,77 +8254,77 @@ async def test_srandmember_count(self, redis_client: TGlideClient): assert member.decode() in elements # empty return values for non-existing or empty keys - assert await redis_client.srandmember_count(key, 0) == [] - assert await redis_client.srandmember_count("non_existing_key", 0) == [] + assert await glide_client.srandmember_count(key, 0) == [] + assert await glide_client.srandmember_count("non_existing_key", 0) == [] # key exists, but it is not a set - assert await redis_client.set(string_key, "value") == OK + assert await glide_client.set(string_key, "value") == OK with pytest.raises(RequestError): - await redis_client.srandmember_count(string_key, 8) + await glide_client.srandmember_count(string_key, 8) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_flushall(self, redis_client: TGlideClient): + async def test_flushall(self, glide_client: TGlideClient): min_version = "6.2.0" key = f"{{key}}-1{get_random_string(5)}" value = get_random_string(5) - await redis_client.set(key, value) - assert await redis_client.dbsize() > 0 - assert await redis_client.flushall() == OK - assert await redis_client.flushall(FlushMode.ASYNC) == OK - if not await check_if_server_version_lt(redis_client, min_version): - assert await redis_client.flushall(FlushMode.SYNC) == OK - assert await redis_client.dbsize() == 0 - - if isinstance(redis_client, GlideClusterClient): - await redis_client.set(key, value) - assert await redis_client.flushall(route=AllPrimaries()) == OK - assert await redis_client.flushall(FlushMode.ASYNC, AllPrimaries()) == OK - if not await check_if_server_version_lt(redis_client, min_version): - assert await redis_client.flushall(FlushMode.SYNC, AllPrimaries()) == OK - assert await redis_client.dbsize() == 0 + await glide_client.set(key, value) + assert await glide_client.dbsize() > 0 + assert await glide_client.flushall() == OK + assert await glide_client.flushall(FlushMode.ASYNC) == OK + if not await check_if_server_version_lt(glide_client, min_version): + assert await glide_client.flushall(FlushMode.SYNC) == OK + assert await glide_client.dbsize() == 0 + + if isinstance(glide_client, GlideClusterClient): + await glide_client.set(key, value) + assert await glide_client.flushall(route=AllPrimaries()) == OK + assert await glide_client.flushall(FlushMode.ASYNC, AllPrimaries()) == OK + if not await check_if_server_version_lt(glide_client, min_version): + assert await glide_client.flushall(FlushMode.SYNC, AllPrimaries()) == OK + assert await glide_client.dbsize() == 0 @pytest.mark.parametrize("cluster_mode", [False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_standalone_flushdb(self, redis_client: GlideClient): + async def test_standalone_flushdb(self, glide_client: GlideClient): min_version = "6.2.0" key1 = f"{{key}}-1{get_random_string(5)}" key2 = f"{{key}}-2{get_random_string(5)}" value = get_random_string(5) # fill DB 0 and check size non-empty - assert await redis_client.select(0) == OK - await redis_client.set(key1, value) - assert await redis_client.dbsize() > 0 + assert await glide_client.select(0) == OK + await glide_client.set(key1, value) + assert await glide_client.dbsize() > 0 # fill DB 1 and check size non-empty - assert await redis_client.select(1) == OK - await redis_client.set(key2, value) - assert await redis_client.dbsize() > 0 + assert await glide_client.select(1) == OK + await glide_client.set(key2, value) + assert await glide_client.dbsize() > 0 # flush DB 1 and check again - assert await redis_client.flushdb() == OK - assert await redis_client.dbsize() == 0 + assert await glide_client.flushdb() == OK + assert await glide_client.dbsize() == 0 # swith to DB 0, flush, and check - assert await redis_client.select(0) == OK - assert await redis_client.dbsize() > 0 - assert await redis_client.flushdb(FlushMode.ASYNC) == OK - assert await redis_client.dbsize() == 0 + assert await glide_client.select(0) == OK + assert await glide_client.dbsize() > 0 + assert await glide_client.flushdb(FlushMode.ASYNC) == OK + assert await glide_client.dbsize() == 0 # verify flush SYNC - if not await check_if_server_version_lt(redis_client, min_version): - await redis_client.set(key2, value) - assert await redis_client.dbsize() > 0 - assert await redis_client.flushdb(FlushMode.SYNC) == OK - assert await redis_client.dbsize() == 0 + if not await check_if_server_version_lt(glide_client, min_version): + await glide_client.set(key2, value) + assert await glide_client.dbsize() > 0 + assert await glide_client.flushdb(FlushMode.SYNC) == OK + assert await glide_client.dbsize() == 0 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_getex(self, redis_client: TGlideClient): + async def test_getex(self, glide_client: TGlideClient): min_version = "6.2.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") key1 = get_random_string(10) @@ -8332,35 +8332,35 @@ async def test_getex(self, redis_client: TGlideClient): value = get_random_string(10) value_encoded = value.encode() - assert await redis_client.set(key1, value) == OK - assert await redis_client.getex(non_existing_key) is None - assert await redis_client.getex(key1) == value_encoded - assert await redis_client.ttl(key1) == -1 + assert await glide_client.set(key1, value) == OK + assert await glide_client.getex(non_existing_key) is None + assert await glide_client.getex(key1) == value_encoded + assert await glide_client.ttl(key1) == -1 # setting expiration timer assert ( - await redis_client.getex(key1, ExpiryGetEx(ExpiryTypeGetEx.MILLSEC, 50)) + await glide_client.getex(key1, ExpiryGetEx(ExpiryTypeGetEx.MILLSEC, 50)) == value_encoded ) - assert await redis_client.ttl(key1) != -1 + assert await glide_client.ttl(key1) != -1 # setting and clearing expiration timer - assert await redis_client.set(key1, value) == OK + assert await glide_client.set(key1, value) == OK assert ( - await redis_client.getex(key1, ExpiryGetEx(ExpiryTypeGetEx.SEC, 10)) + await glide_client.getex(key1, ExpiryGetEx(ExpiryTypeGetEx.SEC, 10)) == value_encoded ) assert ( - await redis_client.getex(key1, ExpiryGetEx(ExpiryTypeGetEx.PERSIST, None)) + await glide_client.getex(key1, ExpiryGetEx(ExpiryTypeGetEx.PERSIST, None)) == value_encoded ) - assert await redis_client.ttl(key1) == -1 + assert await glide_client.ttl(key1) == -1 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_copy_no_database(self, redis_client: TGlideClient): + async def test_copy_no_database(self, glide_client: TGlideClient): min_version = "6.2.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") source = f"{{testKey}}:1-{get_random_string(10)}" @@ -8370,31 +8370,31 @@ async def test_copy_no_database(self, redis_client: TGlideClient): value1_encoded = value1.encode() # neither key exists - assert await redis_client.copy(source, destination, replace=False) is False - assert await redis_client.copy(source, destination) is False + assert await glide_client.copy(source, destination, replace=False) is False + assert await glide_client.copy(source, destination) is False # source exists, destination does not - await redis_client.set(source, value1) - assert await redis_client.copy(source, destination, replace=False) is True - assert await redis_client.get(destination) == value1_encoded + await glide_client.set(source, value1) + assert await glide_client.copy(source, destination, replace=False) is True + assert await glide_client.get(destination) == value1_encoded # new value for source key - await redis_client.set(source, value2) + await glide_client.set(source, value2) # both exists, no REPLACE - assert await redis_client.copy(source, destination) is False - assert await redis_client.copy(source, destination, replace=False) is False - assert await redis_client.get(destination) == value1_encoded + assert await glide_client.copy(source, destination) is False + assert await glide_client.copy(source, destination, replace=False) is False + assert await glide_client.get(destination) == value1_encoded # both exists, with REPLACE - assert await redis_client.copy(source, destination, replace=True) is True - assert await redis_client.get(destination) == value2.encode() + assert await glide_client.copy(source, destination, replace=True) is True + assert await glide_client.get(destination) == value2.encode() @pytest.mark.parametrize("cluster_mode", [False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_copy_database(self, redis_client: GlideClient): + async def test_copy_database(self, glide_client: GlideClient): min_version = "6.2.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") source = get_random_string(10) @@ -8408,103 +8408,103 @@ async def test_copy_database(self, redis_client: GlideClient): index2 = 2 try: - assert await redis_client.select(index0) == OK + assert await glide_client.select(index0) == OK # neither key exists assert ( - await redis_client.copy(source, destination, index1, replace=False) + await glide_client.copy(source, destination, index1, replace=False) is False ) # source exists, destination does not - await redis_client.set(source, value1) + await glide_client.set(source, value1) assert ( - await redis_client.copy(source, destination, index1, replace=False) + await glide_client.copy(source, destination, index1, replace=False) is True ) - assert await redis_client.select(index1) == OK - assert await redis_client.get(destination) == value1_encoded + assert await glide_client.select(index1) == OK + assert await glide_client.get(destination) == value1_encoded # new value for source key - assert await redis_client.select(index0) == OK - await redis_client.set(source, value2) + assert await glide_client.select(index0) == OK + await glide_client.set(source, value2) # no REPLACE, copying to existing key on DB 0 & 1, non-existing key on DB 2 assert ( - await redis_client.copy(source, destination, index1, replace=False) + await glide_client.copy(source, destination, index1, replace=False) is False ) assert ( - await redis_client.copy(source, destination, index2, replace=False) + await glide_client.copy(source, destination, index2, replace=False) is True ) # new value only gets copied to DB 2 - assert await redis_client.select(index1) == OK - assert await redis_client.get(destination) == value1_encoded - assert await redis_client.select(index2) == OK - assert await redis_client.get(destination) == value2_encoded + assert await glide_client.select(index1) == OK + assert await glide_client.get(destination) == value1_encoded + assert await glide_client.select(index2) == OK + assert await glide_client.get(destination) == value2_encoded # both exists, with REPLACE, when value isn't the same, source always get copied to destination - assert await redis_client.select(index0) == OK + assert await glide_client.select(index0) == OK assert ( - await redis_client.copy(source, destination, index1, replace=True) + await glide_client.copy(source, destination, index1, replace=True) is True ) - assert await redis_client.select(index1) == OK - assert await redis_client.get(destination) == value2_encoded + assert await glide_client.select(index1) == OK + assert await glide_client.get(destination) == value2_encoded # invalid DB index with pytest.raises(RequestError): - await redis_client.copy(source, destination, -1, replace=True) + await glide_client.copy(source, destination, -1, replace=True) finally: - assert await redis_client.select(0) == OK + assert await glide_client.select(0) == OK @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_wait(self, redis_client: TGlideClient): + async def test_wait(self, glide_client: TGlideClient): key = f"{{key}}-1{get_random_string(5)}" value = get_random_string(5) value2 = get_random_string(5) - assert await redis_client.set(key, value) == OK - if isinstance(redis_client, GlideClusterClient): - assert await redis_client.wait(1, 1000) >= 1 + assert await glide_client.set(key, value) == OK + if isinstance(glide_client, GlideClusterClient): + assert await glide_client.wait(1, 1000) >= 1 else: - assert await redis_client.wait(1, 1000) >= 0 + assert await glide_client.wait(1, 1000) >= 0 # ensure that command doesn't time out even if timeout > request timeout (250ms by default) - assert await redis_client.set(key, value2) == OK - assert await redis_client.wait(100, 500) >= 0 + assert await glide_client.set(key, value2) == OK + assert await glide_client.wait(100, 500) >= 0 # command should fail on a negative timeout value with pytest.raises(RequestError): - await redis_client.wait(1, -1) + await glide_client.wait(1, -1) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_lolwut(self, redis_client: TGlideClient): - result = await redis_client.lolwut() + async def test_lolwut(self, glide_client: TGlideClient): + result = await glide_client.lolwut() assert b"Redis ver. " in result - result = await redis_client.lolwut(parameters=[]) + result = await glide_client.lolwut(parameters=[]) assert b"Redis ver. " in result - result = await redis_client.lolwut(parameters=[50, 20]) + result = await glide_client.lolwut(parameters=[50, 20]) assert b"Redis ver. " in result - result = await redis_client.lolwut(6) + result = await glide_client.lolwut(6) assert b"Redis ver. " in result - result = await redis_client.lolwut(5, [30, 4, 4]) + result = await glide_client.lolwut(5, [30, 4, 4]) assert b"Redis ver. " in result - if isinstance(redis_client, GlideClusterClient): + if isinstance(glide_client, GlideClusterClient): # test with multi-node route - result = await redis_client.lolwut(route=AllNodes()) + result = await glide_client.lolwut(route=AllNodes()) assert isinstance(result, dict) result_decoded = cast(dict, convert_bytes_to_string_object(result)) assert result_decoded is not None for node_result in result_decoded.values(): assert "Redis ver. " in node_result - result = await redis_client.lolwut(parameters=[10, 20], route=AllNodes()) + result = await glide_client.lolwut(parameters=[10, 20], route=AllNodes()) assert isinstance(result, dict) result_decoded = cast(dict, convert_bytes_to_string_object(result)) assert result_decoded is not None @@ -8512,148 +8512,148 @@ async def test_lolwut(self, redis_client: TGlideClient): assert "Redis ver. " in node_result # test with single-node route - result = await redis_client.lolwut(2, route=RandomNode()) + result = await glide_client.lolwut(2, route=RandomNode()) assert isinstance(result, bytes) assert b"Redis ver. " in result - result = await redis_client.lolwut(2, [10, 20], RandomNode()) + result = await glide_client.lolwut(2, [10, 20], RandomNode()) assert isinstance(result, bytes) assert b"Redis ver. " in result @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_cluster_client_random_key(self, redis_client: GlideClusterClient): + async def test_cluster_client_random_key(self, glide_client: GlideClusterClient): key = get_random_string(10) # setup: delete all keys - assert await redis_client.flushall(FlushMode.SYNC) + assert await glide_client.flushall(FlushMode.SYNC) # no keys exists, so random_key returns None - assert await redis_client.random_key() is None + assert await glide_client.random_key() is None - assert await redis_client.set(key, "foo") == OK + assert await glide_client.set(key, "foo") == OK # `key` should be the only existing key, so random_key should return `key` - assert await redis_client.random_key() == key.encode() - assert await redis_client.random_key(AllPrimaries()) == key.encode() + assert await glide_client.random_key() == key.encode() + assert await glide_client.random_key(AllPrimaries()) == key.encode() @pytest.mark.parametrize("cluster_mode", [False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_standalone_client_random_key(self, redis_client: GlideClient): + async def test_standalone_client_random_key(self, glide_client: GlideClient): key = get_random_string(10) # setup: delete all keys in DB 0 and DB 1 - assert await redis_client.select(0) == OK - assert await redis_client.flushdb(FlushMode.SYNC) == OK - assert await redis_client.select(1) == OK - assert await redis_client.flushdb(FlushMode.SYNC) == OK + assert await glide_client.select(0) == OK + assert await glide_client.flushdb(FlushMode.SYNC) == OK + assert await glide_client.select(1) == OK + assert await glide_client.flushdb(FlushMode.SYNC) == OK # no keys exist so random_key returns None - assert await redis_client.random_key() is None + assert await glide_client.random_key() is None # set `key` in DB 1 - assert await redis_client.set(key, "foo") == OK + assert await glide_client.set(key, "foo") == OK # `key` should be the only key in the database - assert await redis_client.random_key() == key.encode() + assert await glide_client.random_key() == key.encode() # switch back to DB 0 - assert await redis_client.select(0) == OK + assert await glide_client.select(0) == OK # DB 0 should still have no keys, so random_key should still return None - assert await redis_client.random_key() is None + assert await glide_client.random_key() is None @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_dump_restore(self, redis_client: TGlideClient): + async def test_dump_restore(self, glide_client: TGlideClient): key1 = f"{{key}}-1{get_random_string(10)}" key2 = f"{{key}}-2{get_random_string(10)}" key3 = f"{{key}}-3{get_random_string(10)}" nonExistingKey = f"{{key}}-4{get_random_string(10)}" value = get_random_string(5) - await redis_client.set(key1, value) + await glide_client.set(key1, value) # Dump an existing key - bytesData = await redis_client.dump(key1) + bytesData = await glide_client.dump(key1) assert bytesData is not None # Dump non-existing key - assert await redis_client.dump(nonExistingKey) is None + assert await glide_client.dump(nonExistingKey) is None # Restore to a new key and verify its value - assert await redis_client.restore(key2, 0, bytesData) == OK - newValue = await redis_client.get(key2) + assert await glide_client.restore(key2, 0, bytesData) == OK + newValue = await glide_client.get(key2) assert newValue == value.encode() # Restore to an existing key with pytest.raises(RequestError) as e: - await redis_client.restore(key2, 0, bytesData) + await glide_client.restore(key2, 0, bytesData) assert "Target key name already exists" in str(e) # Restore using a value with checksum error with pytest.raises(RequestError) as e: - await redis_client.restore(key3, 0, value.encode()) + await glide_client.restore(key3, 0, value.encode()) assert "payload version or checksum are wrong" in str(e) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_dump_restore_options(self, redis_client: TGlideClient): + async def test_dump_restore_options(self, glide_client: TGlideClient): key1 = f"{{key}}-1{get_random_string(10)}" key2 = f"{{key}}-2{get_random_string(10)}" key3 = f"{{key}}-3{get_random_string(10)}" value = get_random_string(5) - await redis_client.set(key1, value) + await glide_client.set(key1, value) # Dump an existing key - bytesData = await redis_client.dump(key1) + bytesData = await glide_client.dump(key1) assert bytesData is not None # Restore without option - assert await redis_client.restore(key2, 0, bytesData) == OK + assert await glide_client.restore(key2, 0, bytesData) == OK # Restore with REPLACE option - assert await redis_client.restore(key2, 0, bytesData, replace=True) == OK + assert await glide_client.restore(key2, 0, bytesData, replace=True) == OK # Restore to an existing key holding different value with REPLACE option - assert await redis_client.sadd(key3, ["a"]) == 1 - assert await redis_client.restore(key3, 0, bytesData, replace=True) == OK + assert await glide_client.sadd(key3, ["a"]) == 1 + assert await glide_client.restore(key3, 0, bytesData, replace=True) == OK # Restore with REPLACE, ABSTTL, and positive TTL assert ( - await redis_client.restore(key2, 1000, bytesData, replace=True, absttl=True) + await glide_client.restore(key2, 1000, bytesData, replace=True, absttl=True) == OK ) # Restore with REPLACE, ABSTTL, and negative TTL with pytest.raises(RequestError) as e: - await redis_client.restore(key2, -10, bytesData, replace=True, absttl=True) + await glide_client.restore(key2, -10, bytesData, replace=True, absttl=True) assert "Invalid TTL value" in str(e) # Restore with REPLACE and positive idletime assert ( - await redis_client.restore(key2, 0, bytesData, replace=True, idletime=10) + await glide_client.restore(key2, 0, bytesData, replace=True, idletime=10) == OK ) # Restore with REPLACE and negative idletime with pytest.raises(RequestError) as e: - await redis_client.restore(key2, 0, bytesData, replace=True, idletime=-10) + await glide_client.restore(key2, 0, bytesData, replace=True, idletime=-10) assert "Invalid IDLETIME value" in str(e) # Restore with REPLACE and positive frequency assert ( - await redis_client.restore(key2, 0, bytesData, replace=True, frequency=10) + await glide_client.restore(key2, 0, bytesData, replace=True, frequency=10) == OK ) # Restore with REPLACE and negative frequency with pytest.raises(RequestError) as e: - await redis_client.restore(key2, 0, bytesData, replace=True, frequency=-10) + await glide_client.restore(key2, 0, bytesData, replace=True, frequency=-10) assert "Invalid FREQ value" in str(e) @pytest.mark.parametrize("cluster_mode", [False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_lcs(self, redis_client: GlideClient): + async def test_lcs(self, glide_client: GlideClient): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") key1 = "testKey1" value1 = "abcd" @@ -8662,22 +8662,22 @@ async def test_lcs(self, redis_client: GlideClient): nonexistent_key = "nonexistent_key" expected_subsequence = "acd" expected_subsequence_with_nonexistent_key = "" - assert await redis_client.mset({key1: value1, key2: value2}) == OK - assert await redis_client.lcs(key1, key2) == expected_subsequence.encode() + assert await glide_client.mset({key1: value1, key2: value2}) == OK + assert await glide_client.lcs(key1, key2) == expected_subsequence.encode() assert ( - await redis_client.lcs(key1, nonexistent_key) + await glide_client.lcs(key1, nonexistent_key) == expected_subsequence_with_nonexistent_key.encode() ) lcs_non_string_key = "lcs_non_string_key" - assert await redis_client.sadd(lcs_non_string_key, ["Hello", "world"]) == 2 + assert await glide_client.sadd(lcs_non_string_key, ["Hello", "world"]) == 2 with pytest.raises(RequestError): - await redis_client.lcs(key1, lcs_non_string_key) + await glide_client.lcs(key1, lcs_non_string_key) @pytest.mark.parametrize("cluster_mode", [False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_lcs_len(self, redis_client: GlideClient): + async def test_lcs_len(self, glide_client: GlideClient): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") key1 = "testKey1" value1 = "abcd" @@ -8686,22 +8686,22 @@ async def test_lcs_len(self, redis_client: GlideClient): nonexistent_key = "nonexistent_key" expected_subsequence_length = 3 expected_subsequence_length_with_nonexistent_key = 0 - assert await redis_client.mset({key1: value1, key2: value2}) == OK - assert await redis_client.lcs_len(key1, key2) == expected_subsequence_length + assert await glide_client.mset({key1: value1, key2: value2}) == OK + assert await glide_client.lcs_len(key1, key2) == expected_subsequence_length assert ( - await redis_client.lcs_len(key1, nonexistent_key) + await glide_client.lcs_len(key1, nonexistent_key) == expected_subsequence_length_with_nonexistent_key ) lcs_non_string_key = "lcs_non_string_key" - assert await redis_client.sadd(lcs_non_string_key, ["Hello", "world"]) == 2 + assert await glide_client.sadd(lcs_non_string_key, ["Hello", "world"]) == 2 with pytest.raises(RequestError): - await redis_client.lcs_len(key1, lcs_non_string_key) + await glide_client.lcs_len(key1, lcs_non_string_key) @pytest.mark.parametrize("cluster_mode", [False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_lcs_idx(self, redis_client: GlideClient): + async def test_lcs_idx(self, glide_client: GlideClient): min_version = "7.0.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") key1 = "testKey1" value1 = "abcd1234" @@ -8759,75 +8759,75 @@ async def test_lcs_idx(self, redis_client: GlideClient): b"matches": [], b"len": 0, } - assert await redis_client.mset({key1: value1, key2: value2}) == OK + assert await glide_client.mset({key1: value1, key2: value2}) == OK assert ( - await redis_client.lcs_idx(key1, key2) + await glide_client.lcs_idx(key1, key2) == expected_response_no_min_match_len_no_with_match_len ) assert ( - await redis_client.lcs_idx(key1, key2, min_match_len=4) + await glide_client.lcs_idx(key1, key2, min_match_len=4) == expected_response_with_min_match_len_equals_four_no_with_match_len ) assert ( # negative min_match_len should have no affect on the output - await redis_client.lcs_idx(key1, key2, min_match_len=-3) + await glide_client.lcs_idx(key1, key2, min_match_len=-3) == expected_response_no_min_match_len_no_with_match_len ) assert ( - await redis_client.lcs_idx(key1, key2, with_match_len=True) + await glide_client.lcs_idx(key1, key2, with_match_len=True) == expected_response_no_min_match_len_with_match_len ) assert ( - await redis_client.lcs_idx(key1, key2, min_match_len=4, with_match_len=True) + await glide_client.lcs_idx(key1, key2, min_match_len=4, with_match_len=True) == expected_response_with_min_match_len_equals_four_and_with_match_len ) assert ( - await redis_client.lcs_idx(key1, nonexistent_key) + await glide_client.lcs_idx(key1, nonexistent_key) == expected_response_with_nonexistent_key ) lcs_non_string_key = "lcs_non_string_key" - assert await redis_client.sadd(lcs_non_string_key, ["Hello", "world"]) == 2 + assert await glide_client.sadd(lcs_non_string_key, ["Hello", "world"]) == 2 with pytest.raises(RequestError): - await redis_client.lcs_idx(key1, lcs_non_string_key) + await glide_client.lcs_idx(key1, lcs_non_string_key) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_watch(self, redis_client: GlideClient): + async def test_watch(self, glide_client: GlideClient): # watched key didn't change outside of transaction before transaction execution, transaction will execute - assert await redis_client.set("key1", "original_value") == OK - assert await redis_client.watch(["key1"]) == OK + assert await glide_client.set("key1", "original_value") == OK + assert await glide_client.watch(["key1"]) == OK transaction = Transaction() transaction.set("key1", "transaction_value") transaction.get("key1") - assert await redis_client.exec(transaction) is not None + assert await glide_client.exec(transaction) is not None # watched key changed outside of transaction before transaction execution, transaction will not execute - assert await redis_client.set("key1", "original_value") == OK - assert await redis_client.watch(["key1"]) == OK + assert await glide_client.set("key1", "original_value") == OK + assert await glide_client.watch(["key1"]) == OK transaction = Transaction() transaction.set("key1", "transaction_value") - assert await redis_client.set("key1", "standalone_value") == OK + assert await glide_client.set("key1", "standalone_value") == OK transaction.get("key1") - assert await redis_client.exec(transaction) is None + assert await glide_client.exec(transaction) is None # empty list not supported with pytest.raises(RequestError): - await redis_client.watch([]) + await glide_client.watch([]) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_unwatch(self, redis_client: GlideClient): + async def test_unwatch(self, glide_client: GlideClient): # watched key unwatched before transaction execution even if changed # outside of transaction, transaction will still execute - assert await redis_client.set("key1", "original_value") == OK - assert await redis_client.watch(["key1"]) == OK + assert await glide_client.set("key1", "original_value") == OK + assert await glide_client.watch(["key1"]) == OK transaction = Transaction() transaction.set("key1", "transaction_value") - assert await redis_client.set("key1", "standalone_value") == OK + assert await glide_client.set("key1", "standalone_value") == OK transaction.get("key1") - assert await redis_client.unwatch() == OK - result = await redis_client.exec(transaction) + assert await glide_client.unwatch() == OK + result = await glide_client.exec(transaction) assert result is not None assert isinstance(result, list) assert len(result) == 2 @@ -8835,18 +8835,18 @@ async def test_unwatch(self, redis_client: GlideClient): assert result[1] == b"transaction_value" # UNWATCH returns OK when there no watched keys - assert await redis_client.unwatch() == OK + assert await glide_client.unwatch() == OK @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_unwatch_with_route(self, redis_client: GlideClusterClient): - assert await redis_client.unwatch(RandomNode()) == OK + async def test_unwatch_with_route(self, glide_client: GlideClusterClient): + assert await glide_client.unwatch(RandomNode()) == OK @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_lpos(self, redis_client: TGlideClient): + async def test_lpos(self, glide_client: TGlideClient): min_version = "6.0.6" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): # TODO: change it to pytest fixture after we'll implement a sync client return pytest.mark.skip(reason=f"Redis version required >= {min_version}") key = f"{{key}}-1{get_random_string(5)}" @@ -8854,123 +8854,123 @@ async def test_lpos(self, redis_client: TGlideClient): mylist: List[TEncodable] = ["a", "a", "b", "c", "a", "b"] # basic case - await redis_client.rpush(key, mylist) - assert await redis_client.lpos(key, "b") == 2 + await glide_client.rpush(key, mylist) + assert await glide_client.lpos(key, "b") == 2 # reverse traversal - assert await redis_client.lpos(key, "b", -2) == 2 + assert await glide_client.lpos(key, "b", -2) == 2 # unlimited comparisons - assert await redis_client.lpos(key, "a", 1, None, 0) == 0 + assert await glide_client.lpos(key, "a", 1, None, 0) == 0 # limited comparisons - assert await redis_client.lpos(key, "c", 1, None, 2) is None + assert await glide_client.lpos(key, "c", 1, None, 2) is None # element does not exist - assert await redis_client.lpos(key, "non_existing") is None + assert await glide_client.lpos(key, "non_existing") is None # with count - assert await redis_client.lpos(key, "a", 1, 0, 0) == [0, 1, 4] + assert await glide_client.lpos(key, "a", 1, 0, 0) == [0, 1, 4] # with count and rank - assert await redis_client.lpos(key, "a", -2, 0, 0) == [1, 0] + assert await glide_client.lpos(key, "a", -2, 0, 0) == [1, 0] # key does not exist - assert await redis_client.lpos("non_existing", "non_existing") is None + assert await glide_client.lpos("non_existing", "non_existing") is None # invalid rank value with pytest.raises(RequestError): - await redis_client.lpos(key, "a", 0) + await glide_client.lpos(key, "a", 0) # invalid count with pytest.raises(RequestError): - await redis_client.lpos(non_list_key, "a", None, -1) + await glide_client.lpos(non_list_key, "a", None, -1) # invalid max_len with pytest.raises(RequestError): - await redis_client.lpos(non_list_key, "a", None, None, -1) + await glide_client.lpos(non_list_key, "a", None, None, -1) # wrong data type - await redis_client.set(non_list_key, "non_list_value") + await glide_client.set(non_list_key, "non_list_value") with pytest.raises(RequestError): - await redis_client.lpos(non_list_key, "a") + await glide_client.lpos(non_list_key, "a") class TestMultiKeyCommandCrossSlot: @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_multi_key_command_returns_cross_slot_error( - self, redis_client: GlideClusterClient + self, glide_client: GlideClusterClient ): promises: List[Any] = [ - redis_client.blpop(["abc", "zxy", "lkn"], 0.1), - redis_client.brpop(["abc", "zxy", "lkn"], 0.1), - redis_client.rename("abc", "zxy"), - redis_client.zdiffstore("abc", ["zxy", "lkn"]), - redis_client.zdiff(["abc", "zxy", "lkn"]), - redis_client.zdiff_withscores(["abc", "zxy", "lkn"]), - redis_client.zrangestore("abc", "zxy", RangeByIndex(0, -1)), - redis_client.zinterstore( + glide_client.blpop(["abc", "zxy", "lkn"], 0.1), + glide_client.brpop(["abc", "zxy", "lkn"], 0.1), + glide_client.rename("abc", "zxy"), + glide_client.zdiffstore("abc", ["zxy", "lkn"]), + glide_client.zdiff(["abc", "zxy", "lkn"]), + glide_client.zdiff_withscores(["abc", "zxy", "lkn"]), + glide_client.zrangestore("abc", "zxy", RangeByIndex(0, -1)), + glide_client.zinterstore( "{xyz}", cast(Union[List[Union[TEncodable]]], ["{abc}", "{def}"]) ), - redis_client.zunionstore( + glide_client.zunionstore( "{xyz}", cast(Union[List[Union[TEncodable]]], ["{abc}", "{def}"]) ), - redis_client.bzpopmin(["abc", "zxy", "lkn"], 0.5), - redis_client.bzpopmax(["abc", "zxy", "lkn"], 0.5), - redis_client.smove("abc", "def", "_"), - redis_client.sunionstore("abc", ["zxy", "lkn"]), - redis_client.sinter(["abc", "zxy", "lkn"]), - redis_client.sinterstore("abc", ["zxy", "lkn"]), - redis_client.sdiff(["abc", "zxy", "lkn"]), - redis_client.sdiffstore("abc", ["def", "ghi"]), - redis_client.renamenx("abc", "def"), - redis_client.pfcount(["def", "ghi"]), - redis_client.pfmerge("abc", ["def", "ghi"]), - redis_client.zinter(["def", "ghi"]), - redis_client.zinter_withscores( + glide_client.bzpopmin(["abc", "zxy", "lkn"], 0.5), + glide_client.bzpopmax(["abc", "zxy", "lkn"], 0.5), + glide_client.smove("abc", "def", "_"), + glide_client.sunionstore("abc", ["zxy", "lkn"]), + glide_client.sinter(["abc", "zxy", "lkn"]), + glide_client.sinterstore("abc", ["zxy", "lkn"]), + glide_client.sdiff(["abc", "zxy", "lkn"]), + glide_client.sdiffstore("abc", ["def", "ghi"]), + glide_client.renamenx("abc", "def"), + glide_client.pfcount(["def", "ghi"]), + glide_client.pfmerge("abc", ["def", "ghi"]), + glide_client.zinter(["def", "ghi"]), + glide_client.zinter_withscores( cast(Union[List[TEncodable]], ["def", "ghi"]) ), - redis_client.zunion(["def", "ghi"]), - redis_client.zunion_withscores(cast(List[TEncodable], ["def", "ghi"])), - redis_client.sort_store("abc", "zxy"), - redis_client.lmove("abc", "zxy", ListDirection.LEFT, ListDirection.LEFT), - redis_client.blmove( + glide_client.zunion(["def", "ghi"]), + glide_client.zunion_withscores(cast(List[TEncodable], ["def", "ghi"])), + glide_client.sort_store("abc", "zxy"), + glide_client.lmove("abc", "zxy", ListDirection.LEFT, ListDirection.LEFT), + glide_client.blmove( "abc", "zxy", ListDirection.LEFT, ListDirection.LEFT, 1 ), - redis_client.msetnx({"abc": "abc", "zxy": "zyx"}), - redis_client.sunion(["def", "ghi"]), - redis_client.bitop(BitwiseOperation.OR, "abc", ["zxy", "lkn"]), - redis_client.xread({"abc": "0-0", "zxy": "0-0"}), + glide_client.msetnx({"abc": "abc", "zxy": "zyx"}), + glide_client.sunion(["def", "ghi"]), + glide_client.bitop(BitwiseOperation.OR, "abc", ["zxy", "lkn"]), + glide_client.xread({"abc": "0-0", "zxy": "0-0"}), ] - if not await check_if_server_version_lt(redis_client, "6.2.0"): + if not await check_if_server_version_lt(glide_client, "6.2.0"): promises.extend( [ - redis_client.geosearchstore( + glide_client.geosearchstore( "abc", "zxy", GeospatialData(15, 37), GeoSearchByBox(400, 400, GeoUnit.KILOMETERS), ), - redis_client.copy("abc", "zxy", replace=True), + glide_client.copy("abc", "zxy", replace=True), ] ) - if not await check_if_server_version_lt(redis_client, "7.0.0"): + if not await check_if_server_version_lt(glide_client, "7.0.0"): promises.extend( [ - redis_client.bzmpop(["abc", "zxy", "lkn"], ScoreFilter.MAX, 0.1), - redis_client.zintercard(["abc", "def"]), - redis_client.zmpop(["abc", "zxy", "lkn"], ScoreFilter.MAX), - redis_client.sintercard(["def", "ghi"]), - redis_client.lmpop(["def", "ghi"], ListDirection.LEFT), - redis_client.blmpop(["def", "ghi"], ListDirection.LEFT, 1), - redis_client.lcs("abc", "def"), - redis_client.lcs_len("abc", "def"), - redis_client.lcs_idx("abc", "def"), - redis_client.fcall("func", ["abc", "zxy", "lkn"], []), - redis_client.fcall_ro("func", ["abc", "zxy", "lkn"], []), + glide_client.bzmpop(["abc", "zxy", "lkn"], ScoreFilter.MAX, 0.1), + glide_client.zintercard(["abc", "def"]), + glide_client.zmpop(["abc", "zxy", "lkn"], ScoreFilter.MAX), + glide_client.sintercard(["def", "ghi"]), + glide_client.lmpop(["def", "ghi"], ListDirection.LEFT), + glide_client.blmpop(["def", "ghi"], ListDirection.LEFT, 1), + glide_client.lcs("abc", "def"), + glide_client.lcs_len("abc", "def"), + glide_client.lcs_idx("abc", "def"), + glide_client.fcall("func", ["abc", "zxy", "lkn"], []), + glide_client.fcall_ro("func", ["abc", "zxy", "lkn"], []), ] ) @@ -8985,15 +8985,15 @@ async def test_multi_key_command_returns_cross_slot_error( @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_multi_key_command_routed_to_multiple_nodes( - self, redis_client: GlideClusterClient + self, glide_client: GlideClusterClient ): - await redis_client.exists(["abc", "zxy", "lkn"]) - await redis_client.unlink(["abc", "zxy", "lkn"]) - await redis_client.delete(["abc", "zxy", "lkn"]) - await redis_client.mget(["abc", "zxy", "lkn"]) - await redis_client.mset({"abc": "1", "zxy": "2", "lkn": "3"}) - await redis_client.touch(["abc", "zxy", "lkn"]) - await redis_client.watch(["abc", "zxy", "lkn"]) + await glide_client.exists(["abc", "zxy", "lkn"]) + await glide_client.unlink(["abc", "zxy", "lkn"]) + await glide_client.delete(["abc", "zxy", "lkn"]) + await glide_client.mget(["abc", "zxy", "lkn"]) + await glide_client.mset({"abc": "1", "zxy": "2", "lkn": "3"}) + await glide_client.touch(["abc", "zxy", "lkn"]) + await glide_client.watch(["abc", "zxy", "lkn"]) class TestCommandsUnitTests: @@ -9092,10 +9092,10 @@ def test_is_single_response(self): class TestClusterRoutes: async def cluster_route_custom_command_multi_nodes( self, - redis_client: GlideClusterClient, + glide_client: GlideClusterClient, route: Route, ): - cluster_nodes = await redis_client.custom_command(["CLUSTER", "NODES"]) + cluster_nodes = await glide_client.custom_command(["CLUSTER", "NODES"]) assert isinstance(cluster_nodes, bytes) cluster_nodes = cluster_nodes.decode() assert isinstance(cluster_nodes, (str, list)) @@ -9112,7 +9112,7 @@ async def cluster_route_custom_command_multi_nodes( cluster_nodes.count("slave") if isinstance(route, AllNodes) else 0 ) - all_results = await redis_client.custom_command(["INFO", "REPLICATION"], route) + all_results = await glide_client.custom_command(["INFO", "REPLICATION"], route) assert isinstance(all_results, dict) assert len(all_results) == expected_num_of_results primary_count = 0 @@ -9131,25 +9131,25 @@ async def cluster_route_custom_command_multi_nodes( @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_cluster_route_custom_command_all_nodes( - self, redis_client: GlideClusterClient + self, glide_client: GlideClusterClient ): - await self.cluster_route_custom_command_multi_nodes(redis_client, AllNodes()) + await self.cluster_route_custom_command_multi_nodes(glide_client, AllNodes()) @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_cluster_route_custom_command_all_primaries( - self, redis_client: GlideClusterClient + self, glide_client: GlideClusterClient ): await self.cluster_route_custom_command_multi_nodes( - redis_client, AllPrimaries() + glide_client, AllPrimaries() ) @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_cluster_route_custom_command_random_node( - self, redis_client: GlideClusterClient + self, glide_client: GlideClusterClient ): - info_res = await redis_client.custom_command( + info_res = await glide_client.custom_command( ["INFO", "REPLICATION"], RandomNode() ) assert isinstance(info_res, bytes) @@ -9158,11 +9158,11 @@ async def test_cluster_route_custom_command_random_node( assert "role:master" in info_res or "role:slave" in info_res async def cluster_route_custom_command_slot_route( - self, redis_client: GlideClusterClient, is_slot_key: bool + self, glide_client: GlideClusterClient, is_slot_key: bool ): route_class = SlotKeyRoute if is_slot_key else SlotIdRoute route_second_arg = "foo" if is_slot_key else 4000 - primary_res = await redis_client.custom_command( + primary_res = await glide_client.custom_command( ["CLUSTER", "NODES"], route_class(SlotType.PRIMARY, route_second_arg) ) assert isinstance(primary_res, bytes) @@ -9175,7 +9175,7 @@ async def cluster_route_custom_command_slot_route( if "myself" in node_line: expected_primary_node_id = node_line.split(" ")[0] - replica_res = await redis_client.custom_command( + replica_res = await glide_client.custom_command( ["CLUSTER", "NODES"], route_class(SlotType.REPLICA, route_second_arg) ) assert isinstance(replica_res, bytes) @@ -9191,27 +9191,27 @@ async def cluster_route_custom_command_slot_route( @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_cluster_route_custom_command_slot_key_route( - self, redis_client: GlideClusterClient + self, glide_client: GlideClusterClient ): - await self.cluster_route_custom_command_slot_route(redis_client, True) + await self.cluster_route_custom_command_slot_route(glide_client, True) @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_cluster_route_custom_command_slot_id_route( - self, redis_client: GlideClusterClient + self, glide_client: GlideClusterClient ): - await self.cluster_route_custom_command_slot_route(redis_client, False) + await self.cluster_route_custom_command_slot_route(glide_client, False) @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_info_random_route(self, redis_client: GlideClusterClient): - info = await redis_client.info([InfoSection.SERVER], RandomNode()) + async def test_info_random_route(self, glide_client: GlideClusterClient): + info = await glide_client.info([InfoSection.SERVER], RandomNode()) assert b"# Server" in info @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_cluster_route_by_address_reaches_correct_node( - self, redis_client: GlideClusterClient + self, glide_client: GlideClusterClient ): # returns the line that contains the word "myself", up to that point. This is done because the values after it might change with time. def clean_result(value: TResult): @@ -9223,7 +9223,7 @@ def clean_result(value: TResult): f"Couldn't find 'myself' in the cluster nodes output: {value}" ) - cluster_nodes = await redis_client.custom_command( + cluster_nodes = await glide_client.custom_command( ["cluster", "nodes"], RandomNode() ) assert isinstance(cluster_nodes, bytes) @@ -9232,7 +9232,7 @@ def clean_result(value: TResult): assert isinstance(cluster_nodes, str) host = cluster_nodes.split(" ")[1].split("@")[0] - second_result = await redis_client.custom_command( + second_result = await glide_client.custom_command( ["cluster", "nodes"], ByAddressRoute(host) ) assert isinstance(second_result, bytes) @@ -9243,7 +9243,7 @@ def clean_result(value: TResult): host, port = host.split(":") port_as_int = int(port) - third_result = await redis_client.custom_command( + third_result = await glide_client.custom_command( ["cluster", "nodes"], ByAddressRoute(host, port_as_int) ) assert isinstance(third_result, bytes) @@ -9254,37 +9254,37 @@ def clean_result(value: TResult): @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_cluster_fail_routing_by_address_if_no_port_is_provided( - self, redis_client: GlideClusterClient + self, glide_client: GlideClusterClient ): with pytest.raises(RequestError): - await redis_client.info(route=ByAddressRoute("foo")) + await glide_client.info(route=ByAddressRoute("foo")) @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_cluster_flushdb(self, redis_client: GlideClusterClient): + async def test_cluster_flushdb(self, glide_client: GlideClusterClient): min_version = "6.2.0" key = f"{{key}}-1{get_random_string(5)}" value = get_random_string(5) - await redis_client.set(key, value) - assert await redis_client.dbsize() > 0 - assert await redis_client.flushdb(route=AllPrimaries()) == OK - assert await redis_client.dbsize() == 0 + await glide_client.set(key, value) + assert await glide_client.dbsize() > 0 + assert await glide_client.flushdb(route=AllPrimaries()) == OK + assert await glide_client.dbsize() == 0 - await redis_client.set(key, value) - assert await redis_client.dbsize() > 0 - assert await redis_client.flushdb(FlushMode.ASYNC, AllPrimaries()) == OK - assert await redis_client.dbsize() == 0 + await glide_client.set(key, value) + assert await glide_client.dbsize() > 0 + assert await glide_client.flushdb(FlushMode.ASYNC, AllPrimaries()) == OK + assert await glide_client.dbsize() == 0 - if not await check_if_server_version_lt(redis_client, min_version): - await redis_client.set(key, value) - assert await redis_client.dbsize() > 0 - assert await redis_client.flushdb(FlushMode.SYNC, AllPrimaries()) == OK - assert await redis_client.dbsize() == 0 + if not await check_if_server_version_lt(glide_client, min_version): + await glide_client.set(key, value) + assert await glide_client.dbsize() > 0 + assert await glide_client.flushdb(FlushMode.SYNC, AllPrimaries()) == OK + assert await glide_client.dbsize() == 0 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_sscan(self, redis_client: GlideClusterClient): + async def test_sscan(self, glide_client: GlideClusterClient): key1 = f"{{key}}-1{get_random_string(5)}" key2 = f"{{key}}-2{get_random_string(5)}" initial_cursor = "0" @@ -9297,36 +9297,36 @@ async def test_sscan(self, redis_client: GlideClusterClient): char_members: List[TEncodable] = ["a", "b", "c", "d", "e"] # Empty set - result = await redis_client.sscan(key1, initial_cursor) + result = await glide_client.sscan(key1, initial_cursor) assert result[result_cursor_index] == initial_cursor.encode() assert result[result_collection_index] == [] # Negative cursor - result = await redis_client.sscan(key1, "-1") + result = await glide_client.sscan(key1, "-1") assert result[result_cursor_index] == initial_cursor.encode() assert result[result_collection_index] == [] # Result contains the whole set - assert await redis_client.sadd(key1, char_members) == len(char_members) - result = await redis_client.sscan(key1, initial_cursor) + assert await glide_client.sadd(key1, char_members) == len(char_members) + result = await glide_client.sscan(key1, initial_cursor) assert result[result_cursor_index] == initial_cursor.encode() assert len(result[result_collection_index]) == len(char_members) assert set(result[result_collection_index]).issubset( cast(list, convert_string_to_bytes_object(char_members)) ) - result = await redis_client.sscan(key1, initial_cursor, match="a") + result = await glide_client.sscan(key1, initial_cursor, match="a") assert result[result_cursor_index] == initial_cursor.encode() assert set(result[result_collection_index]).issubset(set([b"a"])) # Result contains a subset of the key - assert await redis_client.sadd(key1, num_members) == len(num_members) + assert await glide_client.sadd(key1, num_members) == len(num_members) result_cursor = "0" result_values = set() # type: set[bytes] result = cast( list, convert_bytes_to_string_object( - await redis_client.sscan(key1, result_cursor) + await glide_client.sscan(key1, result_cursor) ), ) result_cursor = str(result[result_cursor_index]) @@ -9337,7 +9337,7 @@ async def test_sscan(self, redis_client: GlideClusterClient): next_result = cast( list, convert_bytes_to_string_object( - await redis_client.sscan(key1, result_cursor) + await glide_client.sscan(key1, result_cursor) ), ) next_result_cursor = str(next_result[result_cursor_index]) @@ -9353,35 +9353,35 @@ async def test_sscan(self, redis_client: GlideClusterClient): assert set(char_members).issubset(result_values) # Test match pattern - result = await redis_client.sscan(key1, initial_cursor, match="*") + result = await glide_client.sscan(key1, initial_cursor, match="*") assert result[result_cursor_index] != "0" assert len(result[result_collection_index]) >= default_count # Test count - result = await redis_client.sscan(key1, initial_cursor, count=20) + result = await glide_client.sscan(key1, initial_cursor, count=20) assert result[result_cursor_index] != "0" assert len(result[result_collection_index]) >= 20 # Test count with match returns a non-empty list - result = await redis_client.sscan(key1, initial_cursor, match="1*", count=20) + result = await glide_client.sscan(key1, initial_cursor, match="1*", count=20) assert result[result_cursor_index] != "0" assert len(result[result_collection_index]) >= 0 # Exceptions # Non-set key - assert await redis_client.set(key2, "test") == OK + assert await glide_client.set(key2, "test") == OK with pytest.raises(RequestError): - await redis_client.sscan(key2, initial_cursor) + await glide_client.sscan(key2, initial_cursor) with pytest.raises(RequestError): - await redis_client.sscan(key2, initial_cursor, match="test", count=20) + await glide_client.sscan(key2, initial_cursor, match="test", count=20) # Negative count with pytest.raises(RequestError): - await redis_client.sscan(key2, initial_cursor, count=-1) + await glide_client.sscan(key2, initial_cursor, count=-1) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_zscan(self, redis_client: GlideClusterClient): + async def test_zscan(self, glide_client: GlideClusterClient): key1 = f"{{key}}-1{get_random_string(5)}" key2 = f"{{key}}-2{get_random_string(5)}" initial_cursor = "0" @@ -9407,18 +9407,18 @@ async def test_zscan(self, redis_client: GlideClusterClient): } # Empty set - result = await redis_client.zscan(key1, initial_cursor) + result = await glide_client.zscan(key1, initial_cursor) assert result[result_cursor_index] == initial_cursor.encode() assert result[result_collection_index] == [] # Negative cursor - result = await redis_client.zscan(key1, "-1") + result = await glide_client.zscan(key1, "-1") assert result[result_cursor_index] == initial_cursor.encode() assert result[result_collection_index] == [] # Result contains the whole set - assert await redis_client.zadd(key1, char_map) == len(char_map) - result = await redis_client.zscan(key1, initial_cursor) + assert await glide_client.zadd(key1, char_map) == len(char_map) + result = await glide_client.zscan(key1, initial_cursor) result_collection = result[result_collection_index] assert result[result_cursor_index] == initial_cursor.encode() assert len(result_collection) == len(char_map) * 2 @@ -9426,18 +9426,18 @@ async def test_zscan(self, redis_client: GlideClusterClient): list, convert_string_to_bytes_object(char_map_with_str_scores) ) - result = await redis_client.zscan(key1, initial_cursor, match="a") + result = await glide_client.zscan(key1, initial_cursor, match="a") result_collection = result[result_collection_index] assert result[result_cursor_index] == initial_cursor.encode() assert convert_list_to_dict(result_collection) == {b"a": b"0"} # Result contains a subset of the key - assert await redis_client.zadd(key1, num_map) == len(num_map) + assert await glide_client.zadd(key1, num_map) == len(num_map) full_result_map = {} result = result = cast( list, convert_bytes_to_string_object( - await redis_client.zscan(key1, initial_cursor) + await glide_client.zscan(key1, initial_cursor) ), ) result_cursor = str(result[result_cursor_index]) @@ -9451,7 +9451,7 @@ async def test_zscan(self, redis_client: GlideClusterClient): next_result = cast( list, convert_bytes_to_string_object( - await redis_client.zscan(key1, result_cursor) + await glide_client.zscan(key1, result_cursor) ), ) next_result_cursor = next_result[result_cursor_index] @@ -9469,35 +9469,35 @@ async def test_zscan(self, redis_client: GlideClusterClient): assert num_map_with_str_scores == full_result_map # Test match pattern - result = await redis_client.zscan(key1, initial_cursor, match="*") + result = await glide_client.zscan(key1, initial_cursor, match="*") assert result[result_cursor_index] != b"0" assert len(result[result_collection_index]) >= default_count # Test count - result = await redis_client.zscan(key1, initial_cursor, count=20) + result = await glide_client.zscan(key1, initial_cursor, count=20) assert result[result_cursor_index] != b"0" assert len(result[result_collection_index]) >= 20 # Test count with match returns a non-empty list - result = await redis_client.zscan(key1, initial_cursor, match="1*", count=20) + result = await glide_client.zscan(key1, initial_cursor, match="1*", count=20) assert result[result_cursor_index] != b"0" assert len(result[result_collection_index]) >= 0 # Exceptions # Non-set key - assert await redis_client.set(key2, "test") == OK + assert await glide_client.set(key2, "test") == OK with pytest.raises(RequestError): - await redis_client.zscan(key2, initial_cursor) + await glide_client.zscan(key2, initial_cursor) with pytest.raises(RequestError): - await redis_client.zscan(key2, initial_cursor, match="test", count=20) + await glide_client.zscan(key2, initial_cursor, match="test", count=20) # Negative count with pytest.raises(RequestError): - await redis_client.zscan(key2, initial_cursor, count=-1) + await glide_client.zscan(key2, initial_cursor, count=-1) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_hscan(self, redis_client: GlideClusterClient): + async def test_hscan(self, glide_client: GlideClusterClient): key1 = f"{{key}}-1{get_random_string(5)}" key2 = f"{{key}}-2{get_random_string(5)}" initial_cursor = "0" @@ -9520,18 +9520,18 @@ async def test_hscan(self, redis_client: GlideClusterClient): } # Empty set - result = await redis_client.hscan(key1, initial_cursor) + result = await glide_client.hscan(key1, initial_cursor) assert result[result_cursor_index] == initial_cursor.encode() assert result[result_collection_index] == [] # Negative cursor - result = await redis_client.hscan(key1, "-1") + result = await glide_client.hscan(key1, "-1") assert result[result_cursor_index] == initial_cursor.encode() assert result[result_collection_index] == [] # Result contains the whole set - assert await redis_client.hset(key1, char_map) == len(char_map) - result = await redis_client.hscan(key1, initial_cursor) + assert await glide_client.hset(key1, char_map) == len(char_map) + result = await glide_client.hscan(key1, initial_cursor) result_collection = result[result_collection_index] assert result[result_cursor_index] == initial_cursor.encode() assert len(result_collection) == len(char_map) * 2 @@ -9539,18 +9539,18 @@ async def test_hscan(self, redis_client: GlideClusterClient): dict, convert_string_to_bytes_object(char_map) # type: ignore ) - result = await redis_client.hscan(key1, initial_cursor, match="field a") + result = await glide_client.hscan(key1, initial_cursor, match="field a") result_collection = result[result_collection_index] assert result[result_cursor_index] == initial_cursor.encode() assert convert_list_to_dict(result_collection) == {b"field a": b"value a"} # Result contains a subset of the key - assert await redis_client.hset(key1, num_map) == len(num_map) + assert await glide_client.hset(key1, num_map) == len(num_map) full_result_map = {} result = result = cast( list, convert_bytes_to_string_object( - await redis_client.hscan(key1, initial_cursor) + await glide_client.hscan(key1, initial_cursor) ), ) result_cursor = str(result[result_cursor_index]) @@ -9564,7 +9564,7 @@ async def test_hscan(self, redis_client: GlideClusterClient): next_result = cast( list, convert_bytes_to_string_object( - await redis_client.hscan(key1, result_cursor) + await glide_client.hscan(key1, result_cursor) ), ) next_result_cursor = next_result[result_cursor_index] @@ -9582,31 +9582,31 @@ async def test_hscan(self, redis_client: GlideClusterClient): assert num_map == full_result_map # Test match pattern - result = await redis_client.hscan(key1, initial_cursor, match="*") + result = await glide_client.hscan(key1, initial_cursor, match="*") assert result[result_cursor_index] != b"0" assert len(result[result_collection_index]) >= default_count # Test count - result = await redis_client.hscan(key1, initial_cursor, count=20) + result = await glide_client.hscan(key1, initial_cursor, count=20) assert result[result_cursor_index] != b"0" assert len(result[result_collection_index]) >= 20 # Test count with match returns a non-empty list - result = await redis_client.hscan(key1, initial_cursor, match="1*", count=20) + result = await glide_client.hscan(key1, initial_cursor, match="1*", count=20) assert result[result_cursor_index] != b"0" assert len(result[result_collection_index]) >= 0 # Exceptions # Non-hash key - assert await redis_client.set(key2, "test") == OK + assert await glide_client.set(key2, "test") == OK with pytest.raises(RequestError): - await redis_client.hscan(key2, initial_cursor) + await glide_client.hscan(key2, initial_cursor) with pytest.raises(RequestError): - await redis_client.hscan(key2, initial_cursor, match="test", count=20) + await glide_client.hscan(key2, initial_cursor, match="test", count=20) # Negative count with pytest.raises(RequestError): - await redis_client.hscan(key2, initial_cursor, count=-1) + await glide_client.hscan(key2, initial_cursor, count=-1) @pytest.mark.asyncio @@ -9614,57 +9614,57 @@ class TestScripts: @pytest.mark.smoke_test @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_script(self, redis_client: TGlideClient): + async def test_script(self, glide_client: TGlideClient): key1 = get_random_string(10) key2 = get_random_string(10) script = Script("return 'Hello'") - assert await redis_client.invoke_script(script) == "Hello".encode() + assert await glide_client.invoke_script(script) == "Hello".encode() script = Script("return redis.call('SET', KEYS[1], ARGV[1])") assert ( - await redis_client.invoke_script(script, keys=[key1], args=["value1"]) + await glide_client.invoke_script(script, keys=[key1], args=["value1"]) == "OK" ) # Reuse the same script with different parameters. assert ( - await redis_client.invoke_script(script, keys=[key2], args=["value2"]) + await glide_client.invoke_script(script, keys=[key2], args=["value2"]) == "OK" ) script = Script("return redis.call('GET', KEYS[1])") assert ( - await redis_client.invoke_script(script, keys=[key1]) == "value1".encode() + await glide_client.invoke_script(script, keys=[key1]) == "value1".encode() ) assert ( - await redis_client.invoke_script(script, keys=[key2]) == "value2".encode() + await glide_client.invoke_script(script, keys=[key2]) == "value2".encode() ) @pytest.mark.smoke_test @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_script_binary(self, redis_client: TGlideClient): + async def test_script_binary(self, glide_client: TGlideClient): key1 = bytes(get_random_string(10), "utf-8") key2 = bytes(get_random_string(10), "utf-8") script = Script(bytes("return 'Hello'", "utf-8")) - assert await redis_client.invoke_script(script) == "Hello".encode() + assert await glide_client.invoke_script(script) == "Hello".encode() script = Script(bytes("return redis.call('SET', KEYS[1], ARGV[1])", "utf-8")) assert ( - await redis_client.invoke_script( + await glide_client.invoke_script( script, keys=[key1], args=[bytes("value1", "utf-8")] ) == "OK" ) # Reuse the same script with different parameters. assert ( - await redis_client.invoke_script( + await glide_client.invoke_script( script, keys=[key2], args=[bytes("value2", "utf-8")] ) == "OK" ) script = Script(bytes("return redis.call('GET', KEYS[1])", "utf-8")) assert ( - await redis_client.invoke_script(script, keys=[key1]) == "value1".encode() + await glide_client.invoke_script(script, keys=[key1]) == "value1".encode() ) assert ( - await redis_client.invoke_script(script, keys=[key2]) == "value2".encode() + await glide_client.invoke_script(script, keys=[key2]) == "value2".encode() ) diff --git a/python/python/tests/test_scan.py b/python/python/tests/test_scan.py index 90422d587a..d59ac470b5 100644 --- a/python/python/tests/test_scan.py +++ b/python/python/tests/test_scan.py @@ -16,15 +16,15 @@ class TestScan: # Cluster scan tests @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_cluster_scan_simple(self, redis_client: GlideClusterClient): + async def test_cluster_scan_simple(self, glide_client: GlideClusterClient): key = get_random_string(10) expected_keys = [f"{key}:{i}" for i in range(100)] - await redis_client.mset({k: "value" for k in expected_keys}) + await glide_client.mset({k: "value" for k in expected_keys}) expected_keys_encoded = map(lambda k: k.encode(), expected_keys) cursor = ClusterScanCursor() keys: List[str] = [] while not cursor.is_finished(): - result = await redis_client.scan(cursor) + result = await glide_client.scan(cursor) cursor = cast(ClusterScanCursor, result[0]) result_keys = cast(List[str], result[1]) keys.extend(result_keys) @@ -34,25 +34,25 @@ async def test_cluster_scan_simple(self, redis_client: GlideClusterClient): @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_cluster_scan_with_object_type_and_pattern( - self, redis_client: GlideClusterClient + self, glide_client: GlideClusterClient ): key = get_random_string(10) expected_keys = [f"key:{key}:{i}" for i in range(100)] - await redis_client.mset({k: "value" for k in expected_keys}) + await glide_client.mset({k: "value" for k in expected_keys}) encoded_expected_keys = map(lambda k: k.encode(), expected_keys) unexpected_type_keys = [f"{key}:{i}" for i in range(100, 200)] for key in unexpected_type_keys: - await redis_client.sadd(key, ["value"]) + await glide_client.sadd(key, ["value"]) encoded_unexpected_type_keys = map(lambda k: k.encode(), unexpected_type_keys) unexpected_pattern_keys = [f"{i}" for i in range(200, 300)] - await redis_client.mset({k: "value" for k in unexpected_pattern_keys}) + await glide_client.mset({k: "value" for k in unexpected_pattern_keys}) encoded_unexpected_pattern_keys = map( lambda k: k.encode(), unexpected_pattern_keys ) keys: List[str] = [] cursor = ClusterScanCursor() while not cursor.is_finished(): - result = await redis_client.scan( + result = await glide_client.scan( cursor, match=b"key:*", type=ObjectType.STRING ) cursor = cast(ClusterScanCursor, result[0]) @@ -65,22 +65,22 @@ async def test_cluster_scan_with_object_type_and_pattern( @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_cluster_scan_with_count(self, redis_client: GlideClusterClient): + async def test_cluster_scan_with_count(self, glide_client: GlideClusterClient): key = get_random_string(10) expected_keys = [f"{key}:{i}" for i in range(100)] - await redis_client.mset({k: "value" for k in expected_keys}) + await glide_client.mset({k: "value" for k in expected_keys}) encoded_expected_keys = map(lambda k: k.encode(), expected_keys) cursor = ClusterScanCursor() keys: List[str] = [] successful_compared_scans = 0 while not cursor.is_finished(): - result_of_1 = await redis_client.scan(cursor, count=1) + result_of_1 = await glide_client.scan(cursor, count=1) cursor = cast(ClusterScanCursor, result_of_1[0]) result_keys_of_1 = cast(List[str], result_of_1[1]) keys.extend(result_keys_of_1) if cursor.is_finished(): break - result_of_100 = await redis_client.scan(cursor, count=100) + result_of_100 = await glide_client.scan(cursor, count=100) cursor = cast(ClusterScanCursor, result_of_100[0]) result_keys_of_100 = cast(List[str], result_of_100[1]) keys.extend(result_keys_of_100) @@ -92,18 +92,18 @@ async def test_cluster_scan_with_count(self, redis_client: GlideClusterClient): @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_cluster_scan_with_match(self, redis_client: GlideClusterClient): + async def test_cluster_scan_with_match(self, glide_client: GlideClusterClient): unexpected_keys = [f"{i}" for i in range(100)] - await redis_client.mset({k: "value" for k in unexpected_keys}) + await glide_client.mset({k: "value" for k in unexpected_keys}) encoded_unexpected_keys = map(lambda k: k.encode(), unexpected_keys) key = get_random_string(10) expected_keys = [f"key:{key}:{i}" for i in range(100)] - await redis_client.mset({k: "value" for k in expected_keys}) + await glide_client.mset({k: "value" for k in expected_keys}) encoded_expected_keys = map(lambda k: k.encode(), expected_keys) cursor = ClusterScanCursor() keys: List[str] = [] while not cursor.is_finished(): - result = await redis_client.scan(cursor, match="key:*") + result = await glide_client.scan(cursor, match="key:*") cursor = cast(ClusterScanCursor, result[0]) result_keys = cast(List[str], result[1]) keys.extend(result_keys) @@ -113,67 +113,67 @@ async def test_cluster_scan_with_match(self, redis_client: GlideClusterClient): @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) # We test whether the cursor is cleaned up after it is deleted, which we expect to happen when th GC is called - async def test_cluster_scan_cleaning_cursor(self, redis_client: GlideClusterClient): + async def test_cluster_scan_cleaning_cursor(self, glide_client: GlideClusterClient): key = get_random_string(10) - await redis_client.mset( + await glide_client.mset( {k: "value" for k in [f"{key}:{i}" for i in range(100)]} ) cursor = cast( - ClusterScanCursor, (await redis_client.scan(ClusterScanCursor()))[0] + ClusterScanCursor, (await glide_client.scan(ClusterScanCursor()))[0] ) cursor_string = cursor.get_cursor() print(cursor_string) del cursor new_cursor_with_same_id = ClusterScanCursor(cursor_string) with pytest.raises(RequestError) as e_info: - await redis_client.scan(new_cursor_with_same_id) + await glide_client.scan(new_cursor_with_same_id) print(new_cursor_with_same_id) print(new_cursor_with_same_id.get_cursor()) assert "Invalid scan_state_cursor id" in str(e_info.value) @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_cluster_scan_all_types(self, redis_client: GlideClusterClient): + async def test_cluster_scan_all_types(self, glide_client: GlideClusterClient): # We test that the scan command work for all types of keys key = get_random_string(10) string_keys = [f"{key}:{i}" for i in range(100)] - await redis_client.mset({k: "value" for k in string_keys}) + await glide_client.mset({k: "value" for k in string_keys}) encoded_string_keys = list(map(lambda k: k.encode(), string_keys)) set_key = get_random_string(10) set_keys = [f"{set_key}:{i}" for i in range(100, 200)] for key in set_keys: - await redis_client.sadd(key, ["value"]) + await glide_client.sadd(key, ["value"]) encoded_set_keys = list(map(lambda k: k.encode(), set_keys)) hash_key = get_random_string(10) hash_keys = [f"{hash_key}:{i}" for i in range(200, 300)] for key in hash_keys: - await redis_client.hset(key, {"field": "value"}) + await glide_client.hset(key, {"field": "value"}) encoded_hash_keys = list(map(lambda k: k.encode(), hash_keys)) list_key = get_random_string(10) list_keys = [f"{list_key}:{i}" for i in range(300, 400)] for key in list_keys: - await redis_client.lpush(key, ["value"]) + await glide_client.lpush(key, ["value"]) encoded_list_keys = list(map(lambda k: k.encode(), list_keys)) zset_key = get_random_string(10) zset_keys = [f"{zset_key}:{i}" for i in range(400, 500)] for key in zset_keys: - await redis_client.zadd(key, {"value": 1}) + await glide_client.zadd(key, {"value": 1}) encoded_zset_keys = list(map(lambda k: k.encode(), zset_keys)) stream_key = get_random_string(10) stream_keys = [f"{stream_key}:{i}" for i in range(500, 600)] for key in stream_keys: - await redis_client.xadd(key, [("field", "value")]) + await glide_client.xadd(key, [("field", "value")]) encoded_stream_keys = list(map(lambda k: k.encode(), stream_keys)) cursor = ClusterScanCursor() keys: List[bytes] = [] while not cursor.is_finished(): - result = await redis_client.scan(cursor, type=ObjectType.STRING) + result = await glide_client.scan(cursor, type=ObjectType.STRING) cursor = cast(ClusterScanCursor, result[0]) result_keys = result[1] keys.extend(cast(List[bytes], result_keys)) @@ -187,7 +187,7 @@ async def test_cluster_scan_all_types(self, redis_client: GlideClusterClient): cursor = ClusterScanCursor() keys.clear() while not cursor.is_finished(): - result = await redis_client.scan(cursor, type=ObjectType.SET) + result = await glide_client.scan(cursor, type=ObjectType.SET) cursor = cast(ClusterScanCursor, result[0]) result_keys = result[1] keys.extend(cast(List[bytes], result_keys)) @@ -201,7 +201,7 @@ async def test_cluster_scan_all_types(self, redis_client: GlideClusterClient): cursor = ClusterScanCursor() keys.clear() while not cursor.is_finished(): - result = await redis_client.scan(cursor, type=ObjectType.HASH) + result = await glide_client.scan(cursor, type=ObjectType.HASH) cursor = cast(ClusterScanCursor, result[0]) result_keys = result[1] keys.extend(cast(List[bytes], result_keys)) @@ -215,7 +215,7 @@ async def test_cluster_scan_all_types(self, redis_client: GlideClusterClient): cursor = ClusterScanCursor() keys.clear() while not cursor.is_finished(): - result = await redis_client.scan(cursor, type=ObjectType.LIST) + result = await glide_client.scan(cursor, type=ObjectType.LIST) cursor = cast(ClusterScanCursor, result[0]) result_keys = result[1] keys.extend(cast(List[bytes], result_keys)) @@ -229,7 +229,7 @@ async def test_cluster_scan_all_types(self, redis_client: GlideClusterClient): cursor = ClusterScanCursor() keys.clear() while not cursor.is_finished(): - result = await redis_client.scan(cursor, type=ObjectType.ZSET) + result = await glide_client.scan(cursor, type=ObjectType.ZSET) cursor = cast(ClusterScanCursor, result[0]) result_keys = result[1] keys.extend(cast(List[bytes], result_keys)) @@ -243,7 +243,7 @@ async def test_cluster_scan_all_types(self, redis_client: GlideClusterClient): cursor = ClusterScanCursor() keys.clear() while not cursor.is_finished(): - result = await redis_client.scan(cursor, type=ObjectType.STREAM) + result = await glide_client.scan(cursor, type=ObjectType.STREAM) cursor = cast(ClusterScanCursor, result[0]) result_keys = result[1] keys.extend(cast(List[bytes], result_keys)) @@ -257,15 +257,15 @@ async def test_cluster_scan_all_types(self, redis_client: GlideClusterClient): # Standalone scan tests @pytest.mark.parametrize("cluster_mode", [False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_standalone_scan_simple(self, redis_client: GlideClient): + async def test_standalone_scan_simple(self, glide_client: GlideClient): key = get_random_string(10) expected_keys = [f"{key}:{i}" for i in range(100)] - await redis_client.mset({k: "value" for k in expected_keys}) + await glide_client.mset({k: "value" for k in expected_keys}) encoded_expected_keys = map(lambda k: k.encode(), expected_keys) keys: List[str] = [] cursor = b"0" while True: - result = await redis_client.scan(cursor) + result = await glide_client.scan(cursor) cursor_bytes = cast(bytes, result[0]) cursor = cursor_bytes new_keys = cast(List[str], result[1]) @@ -277,21 +277,21 @@ async def test_standalone_scan_simple(self, redis_client: GlideClient): @pytest.mark.parametrize("cluster_mode", [False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_standalone_scan_with_object_type_and_pattern( - self, redis_client: GlideClient + self, glide_client: GlideClient ): key = get_random_string(10) expected_keys = [f"key:{key}:{i}" for i in range(100)] - await redis_client.mset({k: "value" for k in expected_keys}) + await glide_client.mset({k: "value" for k in expected_keys}) unexpected_type_keys = [f"key:{i}" for i in range(100, 200)] for key in unexpected_type_keys: - await redis_client.sadd(key, ["value"]) + await glide_client.sadd(key, ["value"]) unexpected_pattern_keys = [f"{i}" for i in range(200, 300)] for key in unexpected_pattern_keys: - await redis_client.set(key, "value") + await glide_client.set(key, "value") keys: List[str] = [] cursor = b"0" while True: - result = await redis_client.scan( + result = await glide_client.scan( cursor, match=b"key:*", type=ObjectType.STRING ) cursor = cast(bytes, result[0]) @@ -304,21 +304,21 @@ async def test_standalone_scan_with_object_type_and_pattern( @pytest.mark.parametrize("cluster_mode", [False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_standalone_scan_with_count(self, redis_client: GlideClient): + async def test_standalone_scan_with_count(self, glide_client: GlideClient): key = get_random_string(10) expected_keys = [f"{key}:{i}" for i in range(100)] - await redis_client.mset({k: "value" for k in expected_keys}) + await glide_client.mset({k: "value" for k in expected_keys}) encoded_expected_keys = map(lambda k: k.encode(), expected_keys) cursor = "0" keys: List[str] = [] successful_compared_scans = 0 while True: - result_of_1 = await redis_client.scan(cursor, count=1) + result_of_1 = await glide_client.scan(cursor, count=1) cursor_bytes = cast(bytes, result_of_1[0]) cursor = cursor_bytes.decode() keys_of_1 = cast(List[str], result_of_1[1]) keys.extend(keys_of_1) - result_of_100 = await redis_client.scan(cursor, count=100) + result_of_100 = await glide_client.scan(cursor, count=100) cursor_bytes = cast(bytes, result_of_100[0]) cursor = cursor_bytes.decode() keys_of_100 = cast(List[str], result_of_100[1]) @@ -332,18 +332,18 @@ async def test_standalone_scan_with_count(self, redis_client: GlideClient): @pytest.mark.parametrize("cluster_mode", [False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_standalone_scan_with_match(self, redis_client: GlideClient): + async def test_standalone_scan_with_match(self, glide_client: GlideClient): key = get_random_string(10) expected_keys = [f"key:{key}:{i}" for i in range(100)] - await redis_client.mset({k: "value" for k in expected_keys}) + await glide_client.mset({k: "value" for k in expected_keys}) encoded_expected_keys = map(lambda k: k.encode(), expected_keys) unexpected_keys = [f"{i}" for i in range(100)] - await redis_client.mset({k: "value" for k in [f"{i}" for i in range(100)]}) + await glide_client.mset({k: "value" for k in [f"{i}" for i in range(100)]}) encoded_unexpected_keys = map(lambda k: k.encode(), unexpected_keys) cursor = "0" keys: List[str] = [] while True: - result = await redis_client.scan(cursor, match="key:*") + result = await glide_client.scan(cursor, match="key:*") cursor_bytes = cast(bytes, result[0]) cursor = cursor_bytes.decode() new_keys = cast(List[str], result[1]) @@ -355,42 +355,42 @@ async def test_standalone_scan_with_match(self, redis_client: GlideClient): @pytest.mark.parametrize("cluster_mode", [False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_standalone_scan_all_types(self, redis_client: GlideClient): + async def test_standalone_scan_all_types(self, glide_client: GlideClient): # We test that the scan command work for all types of keys key = get_random_string(10) string_keys = [f"{key}:{i}" for i in range(100)] - await redis_client.mset({k: "value" for k in string_keys}) + await glide_client.mset({k: "value" for k in string_keys}) encoded_string_keys = list(map(lambda k: k.encode(), string_keys)) set_keys = [f"{key}:{i}" for i in range(100, 200)] for key in set_keys: - await redis_client.sadd(key, ["value"]) + await glide_client.sadd(key, ["value"]) encoded_set_keys = list(map(lambda k: k.encode(), set_keys)) hash_keys = [f"{key}:{i}" for i in range(200, 300)] for key in hash_keys: - await redis_client.hset(key, {"field": "value"}) + await glide_client.hset(key, {"field": "value"}) encoded_hash_keys = list(map(lambda k: k.encode(), hash_keys)) list_keys = [f"{key}:{i}" for i in range(300, 400)] for key in list_keys: - await redis_client.lpush(key, ["value"]) + await glide_client.lpush(key, ["value"]) encoded_list_keys = list(map(lambda k: k.encode(), list_keys)) zset_keys = [f"{key}:{i}" for i in range(400, 500)] for key in zset_keys: - await redis_client.zadd(key, {"value": 1}) + await glide_client.zadd(key, {"value": 1}) encoded_zset_keys = list(map(lambda k: k.encode(), zset_keys)) stream_keys = [f"{key}:{i}" for i in range(500, 600)] for key in stream_keys: - await redis_client.xadd(key, [("field", "value")]) + await glide_client.xadd(key, [("field", "value")]) encoded_stream_keys = list(map(lambda k: k.encode(), stream_keys)) cursor = "0" keys: List[bytes] = [] while True: - result = await redis_client.scan(cursor, type=ObjectType.STRING) + result = await glide_client.scan(cursor, type=ObjectType.STRING) cursor_bytes = cast(bytes, result[0]) cursor = cursor_bytes.decode() new_keys = result[1] @@ -406,7 +406,7 @@ async def test_standalone_scan_all_types(self, redis_client: GlideClient): keys.clear() while True: - result = await redis_client.scan(cursor, type=ObjectType.SET) + result = await glide_client.scan(cursor, type=ObjectType.SET) cursor_bytes = cast(bytes, result[0]) cursor = cursor_bytes.decode() new_keys = result[1] @@ -422,7 +422,7 @@ async def test_standalone_scan_all_types(self, redis_client: GlideClient): keys.clear() while True: - result = await redis_client.scan(cursor, type=ObjectType.HASH) + result = await glide_client.scan(cursor, type=ObjectType.HASH) cursor_bytes = cast(bytes, result[0]) cursor = cursor_bytes.decode() new_keys = result[1] @@ -438,7 +438,7 @@ async def test_standalone_scan_all_types(self, redis_client: GlideClient): keys.clear() while True: - result = await redis_client.scan(cursor, type=ObjectType.LIST) + result = await glide_client.scan(cursor, type=ObjectType.LIST) cursor_bytes = cast(bytes, result[0]) cursor = cursor_bytes.decode() new_keys = result[1] @@ -454,7 +454,7 @@ async def test_standalone_scan_all_types(self, redis_client: GlideClient): keys.clear() while True: - result = await redis_client.scan(cursor, type=ObjectType.ZSET) + result = await glide_client.scan(cursor, type=ObjectType.ZSET) cursor_bytes = cast(bytes, result[0]) cursor = cursor_bytes.decode() new_keys = result[1] @@ -470,7 +470,7 @@ async def test_standalone_scan_all_types(self, redis_client: GlideClient): keys.clear() while True: - result = await redis_client.scan(cursor, type=ObjectType.STREAM) + result = await glide_client.scan(cursor, type=ObjectType.STREAM) cursor_bytes = cast(bytes, result[0]) cursor = cursor_bytes.decode() new_keys = result[1] diff --git a/python/python/tests/test_transaction.py b/python/python/tests/test_transaction.py index 87b2d225a8..e980f2fef5 100644 --- a/python/python/tests/test_transaction.py +++ b/python/python/tests/test_transaction.py @@ -67,7 +67,7 @@ async def transaction_test( transaction: Union[Transaction, ClusterTransaction], keyslot: str, - redis_client: TGlideClient, + glide_client: TGlideClient, ) -> List[TResult]: key = "{{{}}}:{}".format(keyslot, get_random_string(3)) # to get the same slot key2 = "{{{}}}:{}".format(keyslot, get_random_string(3)) # to get the same slot @@ -105,7 +105,7 @@ async def transaction_test( code = generate_lua_lib_code(lib_name, {func_name: "return args[1]"}, True) args: List[TResult] = [] - if not await check_if_server_version_lt(redis_client, "7.0.0"): + if not await check_if_server_version_lt(glide_client, "7.0.0"): transaction.function_load(code) args.append(lib_name.encode()) transaction.function_load(code, True) @@ -182,13 +182,13 @@ async def transaction_test( args.append(False) transaction.ttl(key) args.append(-1) - if not await check_if_server_version_lt(redis_client, "7.0.0"): + if not await check_if_server_version_lt(glide_client, "7.0.0"): transaction.expiretime(key) args.append(-1) transaction.pexpiretime(key) args.append(-1) - if not await check_if_server_version_lt(redis_client, "6.2.0"): + if not await check_if_server_version_lt(glide_client, "6.2.0"): transaction.copy(key, key2, replace=True) args.append(True) @@ -318,7 +318,7 @@ async def transaction_test( args.append([value2_bytes, value_bytes]) transaction.linsert(key5, InsertPosition.BEFORE, "non_existing_pivot", "element") args.append(0) - if not await check_if_server_version_lt(redis_client, "7.0.0"): + if not await check_if_server_version_lt(glide_client, "7.0.0"): transaction.lpush(key5, [value, value2]) args.append(2) transaction.lmpop([key5], ListDirection.LEFT) @@ -376,7 +376,7 @@ async def transaction_test( args.append({b"foo", b"bar"}) transaction.sinterstore(key7, [key7, key7]) args.append(2) - if not await check_if_server_version_lt(redis_client, "7.0.0"): + if not await check_if_server_version_lt(glide_client, "7.0.0"): transaction.sintercard([key7, key7]) args.append(2) transaction.sintercard([key7, key7], 1) @@ -394,7 +394,7 @@ async def transaction_test( args.append(0) transaction.zrevrank(key8, "one") args.append(3) - if not await check_if_server_version_lt(redis_client, "7.2.0"): + if not await check_if_server_version_lt(glide_client, "7.2.0"): transaction.zrank_withscore(key8, "one") args.append([0, 1]) transaction.zrevrank_withscore(key8, "one") @@ -448,7 +448,7 @@ async def transaction_test( args.append(0) transaction.zdiffstore(key8, [key8, key8]) args.append(0) - if not await check_if_server_version_lt(redis_client, "7.0.0"): + if not await check_if_server_version_lt(glide_client, "7.0.0"): transaction.zmpop([key8], ScoreFilter.MAX) args.append(None) transaction.zmpop([key8], ScoreFilter.MAX, 1) @@ -460,7 +460,7 @@ async def transaction_test( args.append([b"one", b"two"]) transaction.zdiff_withscores([key13, key8]) args.append({b"one": 1.0, b"two": 2.0}) - if not await check_if_server_version_lt(redis_client, "7.0.0"): + if not await check_if_server_version_lt(glide_client, "7.0.0"): transaction.zintercard([key13, key8]) args.append(0) transaction.zintercard([key13, key8], 1) @@ -506,7 +506,7 @@ async def transaction_test( transaction.bitpos(key20, 1) args.append(1) - if not await check_if_server_version_lt(redis_client, "6.0.0"): + if not await check_if_server_version_lt(glide_client, "6.0.0"): transaction.bitfield_read_only( key20, [BitFieldGet(SignedEncoding(5), BitOffset(3))] ) @@ -523,7 +523,7 @@ async def transaction_test( ) args.append([609]) - if not await check_if_server_version_lt(redis_client, "7.0.0"): + if not await check_if_server_version_lt(glide_client, "7.0.0"): transaction.set(key20, "foobar") args.append(OK) transaction.bitcount(key20, OffsetOptions(5, 30, BitmapIndexType.BIT)) @@ -625,12 +625,12 @@ async def transaction_test( args.append([1, b"0-3", b"0-3", [[consumer.encode(), b"1"]]]) min_version = "6.2.0" - if not await check_if_server_version_lt(redis_client, min_version): + if not await check_if_server_version_lt(glide_client, min_version): transaction.xautoclaim(key11, group_name1, consumer, 0, "0-0") transaction.xautoclaim_just_id(key11, group_name1, consumer, 0, "0-0") # if using Redis 7.0.0 or above, responses also include a list of entry IDs that were removed from the Pending # Entries List because they no longer exist in the stream - if await check_if_server_version_lt(redis_client, "7.0.0"): + if await check_if_server_version_lt(glide_client, "7.0.0"): args.append( [b"0-0", {b"0-3": [[b"foo", b"bar"]]}] ) # transaction.xautoclaim(key11, group_name1, consumer, 0, "0-0") @@ -696,7 +696,7 @@ async def transaction_test( args.append(key.encode()) min_version = "6.0.6" - if not await check_if_server_version_lt(redis_client, min_version): + if not await check_if_server_version_lt(glide_client, min_version): transaction.rpush(key25, ["a", "a", "b", "c", "a", "b"]) args.append(6) transaction.lpos(key25, "a") @@ -705,14 +705,14 @@ async def transaction_test( args.append([0, 1, 4]) min_version = "6.2.0" - if not await check_if_server_version_lt(redis_client, min_version): + if not await check_if_server_version_lt(glide_client, min_version): transaction.flushall(FlushMode.SYNC) args.append(OK) transaction.flushdb(FlushMode.SYNC) args.append(OK) min_version = "6.2.0" - if not await check_if_server_version_lt(redis_client, min_version): + if not await check_if_server_version_lt(glide_client, min_version): transaction.set(key22, "value") args.append(OK) transaction.getex(key22) @@ -721,7 +721,7 @@ async def transaction_test( args.append(b"value") min_version = "7.0.0" - if not await check_if_server_version_lt(redis_client, min_version): + if not await check_if_server_version_lt(glide_client, min_version): transaction.zadd(key16, {"a": 1, "b": 2, "c": 3, "d": 4}) args.append(4) transaction.bzmpop([key16], ScoreFilter.MAX, 0.1) @@ -749,93 +749,93 @@ async def transaction_test( class TestTransaction: @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_transaction_with_different_slots(self, redis_client: TGlideClient): + async def test_transaction_with_different_slots(self, glide_client: TGlideClient): transaction = ( Transaction() - if isinstance(redis_client, GlideClient) + if isinstance(glide_client, GlideClient) else ClusterTransaction() ) transaction.set("key1", "value1") transaction.set("key2", "value2") with pytest.raises(RequestError, match="CrossSlot"): - await redis_client.exec(transaction) + await glide_client.exec(transaction) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_transaction_custom_command(self, redis_client: TGlideClient): + async def test_transaction_custom_command(self, glide_client: TGlideClient): key = get_random_string(10) transaction = ( Transaction() - if isinstance(redis_client, GlideClient) + if isinstance(glide_client, GlideClient) else ClusterTransaction() ) transaction.custom_command(["HSET", key, "foo", "bar"]) transaction.custom_command(["HGET", key, "foo"]) - result = await redis_client.exec(transaction) + result = await glide_client.exec(transaction) assert result == [1, b"bar"] @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_transaction_custom_unsupported_command( - self, redis_client: TGlideClient + self, glide_client: TGlideClient ): key = get_random_string(10) transaction = ( Transaction() - if isinstance(redis_client, GlideClient) + if isinstance(glide_client, GlideClient) else ClusterTransaction() ) transaction.custom_command(["WATCH", key]) with pytest.raises(RequestError) as e: - await redis_client.exec(transaction) + await glide_client.exec(transaction) assert "WATCH inside MULTI is not allowed" in str( e ) # TODO : add an assert on EXEC ABORT @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_transaction_discard_command(self, redis_client: TGlideClient): + async def test_transaction_discard_command(self, glide_client: TGlideClient): key = get_random_string(10) - await redis_client.set(key, "1") + await glide_client.set(key, "1") transaction = ( Transaction() - if isinstance(redis_client, GlideClient) + if isinstance(glide_client, GlideClient) else ClusterTransaction() ) transaction.custom_command(["INCR", key]) transaction.custom_command(["DISCARD"]) with pytest.raises(RequestError) as e: - await redis_client.exec(transaction) + await glide_client.exec(transaction) assert "EXEC without MULTI" in str(e) # TODO : add an assert on EXEC ABORT - value = await redis_client.get(key) + value = await glide_client.get(key) assert value == b"1" @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_transaction_exec_abort(self, redis_client: TGlideClient): + async def test_transaction_exec_abort(self, glide_client: TGlideClient): key = get_random_string(10) transaction = BaseTransaction() transaction.custom_command(["INCR", key, key, key]) with pytest.raises(RequestError) as e: - await redis_client.exec(transaction) + await glide_client.exec(transaction) assert "wrong number of arguments" in str( e ) # TODO : add an assert on EXEC ABORT @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_cluster_transaction(self, redis_client: GlideClusterClient): - assert await redis_client.custom_command(["FLUSHALL"]) == OK + async def test_cluster_transaction(self, glide_client: GlideClusterClient): + assert await glide_client.custom_command(["FLUSHALL"]) == OK keyslot = get_random_string(3) transaction = ClusterTransaction() transaction.info() - if await check_if_server_version_lt(redis_client, "7.0.0"): + if await check_if_server_version_lt(glide_client, "7.0.0"): transaction.publish("test_message", keyslot, False) else: transaction.publish("test_message", keyslot, True) - expected = await transaction_test(transaction, keyslot, redis_client) - result = await redis_client.exec(transaction) + expected = await transaction_test(transaction, keyslot, glide_client) + result = await glide_client.exec(transaction) assert isinstance(result, list) assert isinstance(result[0], bytes) result[0] = result[0].decode() @@ -848,9 +848,9 @@ async def test_cluster_transaction(self, redis_client: GlideClusterClient): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_can_return_null_on_watch_transaction_failures( - self, redis_client: TGlideClient, request + self, glide_client: TGlideClient, request ): - is_cluster = isinstance(redis_client, GlideClusterClient) + is_cluster = isinstance(glide_client, GlideClusterClient) client2 = await create_client( request, is_cluster, @@ -858,13 +858,13 @@ async def test_can_return_null_on_watch_transaction_failures( keyslot = get_random_string(3) transaction = ClusterTransaction() if is_cluster else Transaction() transaction.get(keyslot) - result1 = await redis_client.watch([keyslot]) + result1 = await glide_client.watch([keyslot]) assert result1 == OK result2 = await client2.set(keyslot, "foo") assert result2 == OK - result3 = await redis_client.exec(transaction) + result3 = await glide_client.exec(transaction) assert result3 is None await client2.close() @@ -872,7 +872,7 @@ async def test_can_return_null_on_watch_transaction_failures( @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_transaction_large_values(self, request, cluster_mode, protocol): - redis_client = await create_client( + glide_client = await create_client( request, cluster_mode=cluster_mode, protocol=protocol, timeout=5000 ) length = 2**25 # 33mb @@ -881,15 +881,15 @@ async def test_transaction_large_values(self, request, cluster_mode, protocol): transaction = Transaction() transaction.set(key, value) transaction.get(key) - result = await redis_client.exec(transaction) + result = await glide_client.exec(transaction) assert isinstance(result, list) assert result[0] == OK assert result[1] == value.encode() @pytest.mark.parametrize("cluster_mode", [False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_standalone_transaction(self, redis_client: GlideClient): - assert await redis_client.custom_command(["FLUSHALL"]) == OK + async def test_standalone_transaction(self, glide_client: GlideClient): + assert await glide_client.custom_command(["FLUSHALL"]) == OK keyslot = get_random_string(3) key = "{{{}}}:{}".format(keyslot, get_random_string(3)) # to get the same slot key1 = "{{{}}}:{}".format(keyslot, get_random_string(3)) # to get the same slot @@ -921,8 +921,8 @@ async def test_standalone_transaction(self, redis_client: GlideClient): transaction.select(0) transaction.get(key) transaction.publish("test_message", "test_channel") - expected = await transaction_test(transaction, keyslot, redis_client) - result = await redis_client.exec(transaction) + expected = await transaction_test(transaction, keyslot, glide_client) + result = await glide_client.exec(transaction) assert isinstance(result, list) assert isinstance(result[0], bytes) result[0] = result[0].decode() @@ -941,9 +941,9 @@ def test_transaction_clear(self): @pytest.mark.parametrize("cluster_mode", [False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_standalone_copy_transaction(self, redis_client: GlideClient): + async def test_standalone_copy_transaction(self, glide_client: GlideClient): min_version = "6.2.0" - if await check_if_server_version_lt(redis_client, min_version): + if await check_if_server_version_lt(glide_client, min_version): return pytest.mark.skip(reason=f"Redis version required >= {min_version}") keyslot = get_random_string(3) @@ -955,21 +955,21 @@ async def test_standalone_copy_transaction(self, redis_client: GlideClient): transaction.set(key, value) transaction.copy(key, key1, 1, replace=True) transaction.get(key1) - result = await redis_client.exec(transaction) + result = await glide_client.exec(transaction) assert result is not None assert result[2] == True assert result[3] == value.encode() @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_transaction_chaining_calls(self, redis_client: TGlideClient): - cluster_mode = isinstance(redis_client, GlideClusterClient) + async def test_transaction_chaining_calls(self, glide_client: TGlideClient): + cluster_mode = isinstance(glide_client, GlideClusterClient) key = get_random_string(3) transaction = ClusterTransaction() if cluster_mode else Transaction() transaction.set(key, "value").get(key).delete([key]) - assert await redis_client.exec(transaction) == [OK, b"value", 1] + assert await glide_client.exec(transaction) == [OK, b"value", 1] # The object commands are tested here instead of transaction_test because they have special requirements: # - OBJECT FREQ and OBJECT IDLETIME require specific maxmemory policies to be set on the config @@ -978,11 +978,11 @@ async def test_transaction_chaining_calls(self, redis_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_transaction_object_commands( - self, redis_client: TGlideClient, cluster_mode: bool + self, glide_client: TGlideClient, cluster_mode: bool ): string_key = get_random_string(10) maxmemory_policy_key = "maxmemory-policy" - config = await redis_client.config_get([maxmemory_policy_key]) + config = await glide_client.config_get([maxmemory_policy_key]) config_decoded = cast(dict, convert_bytes_to_string_object(config)) assert config_decoded is not None maxmemory_policy = cast(str, config_decoded.get(maxmemory_policy_key)) @@ -999,7 +999,7 @@ async def test_transaction_object_commands( transaction.config_set({maxmemory_policy_key: "allkeys-random"}) transaction.object_idletime(string_key) - response = await redis_client.exec(transaction) + response = await glide_client.exec(transaction) assert response is not None assert response[0] == OK # transaction.set(string_key, "foo") assert response[1] == b"embstr" # transaction.object_encoding(string_key) @@ -1013,18 +1013,18 @@ async def test_transaction_object_commands( # transaction.object_idletime(string_key) assert cast(int, response[6]) >= 0 finally: - await redis_client.config_set({maxmemory_policy_key: maxmemory_policy}) + await glide_client.config_set({maxmemory_policy_key: maxmemory_policy}) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_transaction_lastsave( - self, redis_client: TGlideClient, cluster_mode: bool + self, glide_client: TGlideClient, cluster_mode: bool ): yesterday = date.today() - timedelta(1) yesterday_unix_time = time.mktime(yesterday.timetuple()) transaction = ClusterTransaction() if cluster_mode else Transaction() transaction.lastsave() - response = await redis_client.exec(transaction) + response = await glide_client.exec(transaction) assert isinstance(response, list) lastsave_time = response[0] assert isinstance(lastsave_time, int) @@ -1032,10 +1032,10 @@ async def test_transaction_lastsave( @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_lolwut_transaction(self, redis_client: GlideClusterClient): + async def test_lolwut_transaction(self, glide_client: GlideClusterClient): transaction = Transaction() transaction.lolwut().lolwut(5).lolwut(parameters=[1, 2]).lolwut(6, [42]) - results = await redis_client.exec(transaction) + results = await glide_client.exec(transaction) assert results is not None for element in results: diff --git a/python/python/tests/tests_redis_modules/test_json.py b/python/python/tests/tests_redis_modules/test_json.py index a6ace91b2d..f425cd5670 100644 --- a/python/python/tests/tests_redis_modules/test_json.py +++ b/python/python/tests/tests_redis_modules/test_json.py @@ -17,37 +17,37 @@ class TestJson: @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_json_module_is_loaded(self, redis_client: TGlideClient): - res = parse_info_response(await redis_client.info([InfoSection.MODULES])) + async def test_json_module_is_loaded(self, glide_client: TGlideClient): + res = parse_info_response(await glide_client.info([InfoSection.MODULES])) assert "ReJSON" in res["module"] @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_json_set_get(self, redis_client: TGlideClient): + async def test_json_set_get(self, glide_client: TGlideClient): key = get_random_string(5) json_value = {"a": 1.0, "b": 2} - assert await json.set(redis_client, key, "$", OuterJson.dumps(json_value)) == OK + assert await json.set(glide_client, key, "$", OuterJson.dumps(json_value)) == OK - result = await json.get(redis_client, key, ".") + result = await json.get(glide_client, key, ".") assert isinstance(result, str) assert OuterJson.loads(result) == json_value - result = await json.get(redis_client, key, ["$.a", "$.b"]) + result = await json.get(glide_client, key, ["$.a", "$.b"]) assert isinstance(result, str) assert OuterJson.loads(result) == {"$.a": [1.0], "$.b": [2]} - assert await json.get(redis_client, "non_existing_key", "$") is None - assert await json.get(redis_client, key, "$.d") == "[]" + assert await json.get(glide_client, "non_existing_key", "$") is None + assert await json.get(glide_client, key, "$.d") == "[]" @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_json_set_get_multiple_values(self, redis_client: TGlideClient): + async def test_json_set_get_multiple_values(self, glide_client: TGlideClient): key = get_random_string(5) assert ( await json.set( - redis_client, + glide_client, key, "$", OuterJson.dumps({"a": {"c": 1, "d": 4}, "b": {"c": 2}, "c": True}), @@ -55,27 +55,27 @@ async def test_json_set_get_multiple_values(self, redis_client: TGlideClient): == OK ) - result = await json.get(redis_client, key, "$..c") + result = await json.get(glide_client, key, "$..c") assert isinstance(result, str) assert OuterJson.loads(result) == [True, 1, 2] - result = await json.get(redis_client, key, ["$..c", "$.c"]) + result = await json.get(glide_client, key, ["$..c", "$.c"]) assert isinstance(result, str) assert OuterJson.loads(result) == {"$..c": [True, 1, 2], "$.c": [True]} - assert await json.set(redis_client, key, "$..c", '"new_value"') == OK - result = await json.get(redis_client, key, "$..c") + assert await json.set(glide_client, key, "$..c", '"new_value"') == OK + result = await json.get(glide_client, key, "$..c") assert isinstance(result, str) assert OuterJson.loads(result) == ["new_value"] * 3 @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_json_set_conditional_set(self, redis_client: TGlideClient): + async def test_json_set_conditional_set(self, glide_client: TGlideClient): key = get_random_string(5) value = OuterJson.dumps({"a": 1.0, "b": 2}) assert ( await json.set( - redis_client, + glide_client, key, "$", value, @@ -85,7 +85,7 @@ async def test_json_set_conditional_set(self, redis_client: TGlideClient): ) assert ( await json.set( - redis_client, + glide_client, key, "$", value, @@ -96,7 +96,7 @@ async def test_json_set_conditional_set(self, redis_client: TGlideClient): assert ( await json.set( - redis_client, + glide_client, key, "$.a", "4.5", @@ -105,11 +105,11 @@ async def test_json_set_conditional_set(self, redis_client: TGlideClient): is None ) - assert await json.get(redis_client, key, ".a") == "1.0" + assert await json.get(glide_client, key, ".a") == "1.0" assert ( await json.set( - redis_client, + glide_client, key, "$.a", "4.5", @@ -118,15 +118,15 @@ async def test_json_set_conditional_set(self, redis_client: TGlideClient): == OK ) - assert await json.get(redis_client, key, ".a") == "4.5" + assert await json.get(glide_client, key, ".a") == "4.5" @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_json_get_formatting(self, redis_client: TGlideClient): + async def test_json_get_formatting(self, glide_client: TGlideClient): key = get_random_string(5) assert ( await json.set( - redis_client, + glide_client, key, "$", OuterJson.dumps({"a": 1.0, "b": 2, "c": {"d": 3, "e": 4}}), @@ -135,14 +135,14 @@ async def test_json_get_formatting(self, redis_client: TGlideClient): ) result = await json.get( - redis_client, key, "$", JsonGetOptions(indent=" ", newline="\n", space=" ") + glide_client, key, "$", JsonGetOptions(indent=" ", newline="\n", space=" ") ) expected_result = '[\n {\n "a": 1.0,\n "b": 2,\n "c": {\n "d": 3,\n "e": 4\n }\n }\n]' assert result == expected_result result = await json.get( - redis_client, key, "$", JsonGetOptions(indent="~", newline="\n", space="*") + glide_client, key, "$", JsonGetOptions(indent="~", newline="\n", space="*") ) expected_result = ( @@ -152,55 +152,55 @@ async def test_json_get_formatting(self, redis_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_del(self, redis_client: TGlideClient): + async def test_del(self, glide_client: TGlideClient): key = get_random_string(5) json_value = {"a": 1.0, "b": {"a": 1, "b": 2.5, "c": True}} - assert await json.set(redis_client, key, "$", OuterJson.dumps(json_value)) == OK + assert await json.set(glide_client, key, "$", OuterJson.dumps(json_value)) == OK - assert await json.delete(redis_client, key, "$..a") == 2 - assert await json.get(redis_client, key, "$..a") == "[]" + assert await json.delete(glide_client, key, "$..a") == 2 + assert await json.get(glide_client, key, "$..a") == "[]" - result = await json.get(redis_client, key, "$") + result = await json.get(glide_client, key, "$") assert isinstance(result, str) assert OuterJson.loads(result) == [{"b": {"b": 2.5, "c": True}}] - assert await json.delete(redis_client, key, "$") == 1 - assert await json.delete(redis_client, key) == 0 - assert await json.get(redis_client, key, "$") == None + assert await json.delete(glide_client, key, "$") == 1 + assert await json.delete(glide_client, key) == 0 + assert await json.get(glide_client, key, "$") == None @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_forget(self, redis_client: TGlideClient): + async def test_forget(self, glide_client: TGlideClient): key = get_random_string(5) json_value = {"a": 1.0, "b": {"a": 1, "b": 2.5, "c": True}} - assert await json.set(redis_client, key, "$", OuterJson.dumps(json_value)) == OK + assert await json.set(glide_client, key, "$", OuterJson.dumps(json_value)) == OK - assert await json.forget(redis_client, key, "$..a") == 2 - assert await json.get(redis_client, key, "$..a") == "[]" + assert await json.forget(glide_client, key, "$..a") == 2 + assert await json.get(glide_client, key, "$..a") == "[]" - result = await json.get(redis_client, key, "$") + result = await json.get(glide_client, key, "$") assert isinstance(result, str) assert OuterJson.loads(result) == [{"b": {"b": 2.5, "c": True}}] - assert await json.forget(redis_client, key, "$") == 1 - assert await json.forget(redis_client, key) == 0 - assert await json.get(redis_client, key, "$") == None + assert await json.forget(glide_client, key, "$") == 1 + assert await json.forget(glide_client, key) == 0 + assert await json.get(glide_client, key, "$") == None @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_json_toggle(self, redis_client: TGlideClient): + async def test_json_toggle(self, glide_client: TGlideClient): key = get_random_string(10) json_value = {"bool": True, "nested": {"bool": False, "nested": {"bool": 10}}} - assert await json.set(redis_client, key, "$", OuterJson.dumps(json_value)) == OK + assert await json.set(glide_client, key, "$", OuterJson.dumps(json_value)) == OK - assert await json.toggle(redis_client, key, "$..bool") == [False, True, None] - assert await json.toggle(redis_client, key, "bool") is True + assert await json.toggle(glide_client, key, "$..bool") == [False, True, None] + assert await json.toggle(glide_client, key, "bool") is True - assert await json.toggle(redis_client, key, "$.nested") == [None] + assert await json.toggle(glide_client, key, "$.nested") == [None] with pytest.raises(RequestError): - assert await json.toggle(redis_client, key, "nested") + assert await json.toggle(glide_client, key, "nested") with pytest.raises(RequestError): - assert await json.toggle(redis_client, "non_exiting_key", "$") + assert await json.toggle(glide_client, "non_exiting_key", "$") From 5a6911e4a51b817b97589d359723fc2cf3529cc9 Mon Sep 17 00:00:00 2001 From: Bar Shaul <88437685+barshaul@users.noreply.github.com> Date: Thu, 4 Jul 2024 12:11:14 +0300 Subject: [PATCH 12/23] Core + Python: Added support in large script requests (#1781) --- glide-core/src/protobuf/redis_request.proto | 12 +++++- glide-core/src/socket_listener.rs | 45 +++++++++++++++++---- python/python/glide/glide_client.py | 22 ++++++---- python/python/tests/test_async_client.py | 45 +++++++++++++++++++++ 4 files changed, 107 insertions(+), 17 deletions(-) diff --git a/glide-core/src/protobuf/redis_request.proto b/glide-core/src/protobuf/redis_request.proto index b14c51992d..146872cc79 100644 --- a/glide-core/src/protobuf/redis_request.proto +++ b/glide-core/src/protobuf/redis_request.proto @@ -261,6 +261,13 @@ message Command { } } +// Used for script requests with large keys or args vectors +message ScriptInvocationPointers { + string hash = 1; + optional uint64 keys_pointer = 2; + optional uint64 args_pointer = 3; +} + message ScriptInvocation { string hash = 1; repeated bytes keys = 2; @@ -285,7 +292,8 @@ message RedisRequest { Command single_command = 2; Transaction transaction = 3; ScriptInvocation script_invocation = 4; - ClusterScan cluster_scan = 5; + ScriptInvocationPointers script_invocation_pointers = 5; + ClusterScan cluster_scan = 6; } - Routes route = 6; + Routes route = 7; } diff --git a/glide-core/src/socket_listener.rs b/glide-core/src/socket_listener.rs index 24f5c425e9..bce4c8bf6c 100644 --- a/glide-core/src/socket_listener.rs +++ b/glide-core/src/socket_listener.rs @@ -7,8 +7,7 @@ use crate::cluster_scan_container::get_cluster_scan_cursor; use crate::connection_request::ConnectionRequest; use crate::errors::{error_message, error_type, RequestErrorType}; use crate::redis_request::{ - command, redis_request, ClusterScan, Command, RedisRequest, Routes, ScriptInvocation, - SlotTypes, Transaction, + command, redis_request, ClusterScan, Command, RedisRequest, Routes, SlotTypes, Transaction, }; use crate::response; use crate::response::Response; @@ -17,7 +16,7 @@ use bytes::Bytes; use directories::BaseDirs; use dispose::{Disposable, Dispose}; use logger_core::{log_debug, log_error, log_info, log_trace, log_warn}; -use protobuf::Message; +use protobuf::{Chars, Message}; use redis::cluster_routing::{ MultipleNodeRoutingInfo, Route, RoutingInfo, SingleNodeRoutingInfo, SlotAddr, }; @@ -364,15 +363,24 @@ async fn cluster_scan(cluster_scan: ClusterScan, mut client: Client) -> ClientUs } async fn invoke_script( - script: ScriptInvocation, + hash: Chars, + keys: Option>, + args: Option>, mut client: Client, routing: Option, ) -> ClientUsageResult { // convert Vec to vec<[u8]> - let keys: Vec<&[u8]> = script.keys.iter().map(|e| e.as_ref()).collect(); - let args: Vec<&[u8]> = script.args.iter().map(|e| e.as_ref()).collect(); + let keys: Vec<&[u8]> = keys + .as_ref() + .map(|keys| keys.iter().map(|e| e.as_ref()).collect()) + .unwrap_or_default(); + let args: Vec<&[u8]> = args + .as_ref() + .map(|keys| keys.iter().map(|e| e.as_ref()).collect()) + .unwrap_or_default(); + client - .invoke_script(&script.hash, &keys, &args, routing) + .invoke_script(&hash, &keys, &args, routing) .await .map_err(|err| err.into()) } @@ -490,7 +498,28 @@ fn handle_request(request: RedisRequest, client: Client, writer: Rc) { } redis_request::Command::ScriptInvocation(script) => { match get_route(request.route.0, None) { - Ok(routes) => invoke_script(script, client, routes).await, + Ok(routes) => { + invoke_script( + script.hash, + Some(script.keys), + Some(script.args), + client, + routes, + ) + .await + } + Err(e) => Err(e), + } + } + redis_request::Command::ScriptInvocationPointers(script) => { + let keys = script + .keys_pointer + .map(|pointer| *unsafe { Box::from_raw(pointer as *mut Vec) }); + let args = script + .args_pointer + .map(|pointer| *unsafe { Box::from_raw(pointer as *mut Vec) }); + match get_route(request.route.0, None) { + Ok(routes) => invoke_script(script.hash, keys, args, client, routes).await, Err(e) => Err(e), } } diff --git a/python/python/glide/glide_client.py b/python/python/glide/glide_client.py index 788640eb70..2ee030c555 100644 --- a/python/python/glide/glide_client.py +++ b/python/python/glide/glide_client.py @@ -305,13 +305,21 @@ async def _execute_script( ) request = RedisRequest() request.callback_idx = self._get_callback_index() - request.script_invocation.hash = hash - request.script_invocation.args[:] = ( - [self._encode_arg(elem) for elem in args] if args is not None else [] - ) - request.script_invocation.keys[:] = ( - [self._encode_arg(elem) for elem in keys] if keys is not None else [] - ) + (encoded_keys, keys_size) = self._encode_and_sum_size(keys) + (encoded_args, args_size) = self._encode_and_sum_size(args) + if (keys_size + args_size) < MAX_REQUEST_ARGS_LEN: + request.script_invocation.hash = hash + request.script_invocation.keys[:] = encoded_keys + request.script_invocation.args[:] = encoded_args + + else: + request.script_invocation_pointers.hash = hash + request.script_invocation_pointers.keys_pointer = create_leaked_bytes_vec( + encoded_keys + ) + request.script_invocation_pointers.args_pointer = create_leaked_bytes_vec( + encoded_args + ) set_protobuf_route(request, route) return await self._write_request_await_response(request) diff --git a/python/python/tests/test_async_client.py b/python/python/tests/test_async_client.py index cf2c1ae596..c8ed08d140 100644 --- a/python/python/tests/test_async_client.py +++ b/python/python/tests/test_async_client.py @@ -9668,3 +9668,48 @@ async def test_script_binary(self, glide_client: TGlideClient): assert ( await glide_client.invoke_script(script, keys=[key2]) == "value2".encode() ) + + @pytest.mark.parametrize("cluster_mode", [True, False]) + @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) + async def test_script_large_keys_no_args(self, request, cluster_mode, protocol): + redis_client = await create_client( + request, cluster_mode=cluster_mode, protocol=protocol, timeout=5000 + ) + length = 2**13 # 8kb + key = "0" * length + script = Script("return KEYS[1]") + assert await redis_client.invoke_script(script, keys=[key]) == key.encode() + await redis_client.close() + + @pytest.mark.parametrize("cluster_mode", [True, False]) + @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) + async def test_script_large_args_no_keys(self, request, cluster_mode, protocol): + redis_client = await create_client( + request, cluster_mode=cluster_mode, protocol=protocol, timeout=5000 + ) + length = 2**12 # 4kb + arg1 = "0" * length + arg2 = "1" * length + + script = Script("return ARGV[2]") + assert ( + await redis_client.invoke_script(script, args=[arg1, arg2]) == arg2.encode() + ) + await redis_client.close() + + @pytest.mark.parametrize("cluster_mode", [True, False]) + @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) + async def test_script_large_keys_and_args(self, request, cluster_mode, protocol): + redis_client = await create_client( + request, cluster_mode=cluster_mode, protocol=protocol, timeout=5000 + ) + length = 2**12 # 4kb + key = "0" * length + arg = "1" * length + + script = Script("return KEYS[1]") + assert ( + await redis_client.invoke_script(script, keys=[key], args=[arg]) + == key.encode() + ) + await redis_client.close() From e095599ec73cd07112d00784b7c1459fe40df6d5 Mon Sep 17 00:00:00 2001 From: Shoham Elias <116083498+shohamazon@users.noreply.github.com> Date: Thu, 4 Jul 2024 13:53:34 +0300 Subject: [PATCH 13/23] Update dependency installation and setup instructions for macOS in developer.md (#1776) --- go/DEVELOPER.md | 9 +++++++-- python/DEVELOPER.md | 10 ++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/go/DEVELOPER.md b/go/DEVELOPER.md index 6f365c756d..013c713abb 100644 --- a/go/DEVELOPER.md +++ b/go/DEVELOPER.md @@ -85,10 +85,15 @@ brew install go make git gcc pkgconfig protobuf@3 openssl export PATH="$PATH:$HOME/go/bin" curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source "$HOME/.cargo/env" -# Check that the protobuf compiler is installed. A minimum version of 3.20.0 is required. -protoc --version # Check that the Rust compiler is installed rustc --version +# Verify the Protobuf compiler installation +protoc --version + +# If protoc is not found or does not work correctly, update the PATH +echo 'export PATH="/opt/homebrew/opt/protobuf@3/bin:$PATH"' >> /Users/$USER/.bash_profile +source /Users/$USER/.bash_profile +protoc --version ``` #### Building and installation steps diff --git a/python/DEVELOPER.md b/python/DEVELOPER.md index 6983d543fb..b24a50b220 100644 --- a/python/DEVELOPER.md +++ b/python/DEVELOPER.md @@ -66,12 +66,18 @@ protoc --version ```bash brew update -brew install python3 git gcc pkgconfig protobuf@3 openssl -pip3 install virtualenv +brew install python3 git gcc pkgconfig protobuf@3 openssl virtualenv curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source "$HOME/.cargo/env" # Check that the Rust compiler is installed rustc --version +# Verify the Protobuf compiler installation +protoc --version + +# If protoc is not found or does not work correctly, update the PATH +echo 'export PATH="/opt/homebrew/opt/protobuf@3/bin:$PATH"' >> /Users/$USER/.bash_profile +source /Users/$USER/.bash_profile +protoc --version ``` #### Building and installation steps From 70d351641e01cfb7ddf71593c1ab6b046a5cb1b0 Mon Sep 17 00:00:00 2001 From: Gilboab <97948000+GilboaAWS@users.noreply.github.com> Date: Thu, 4 Jul 2024 14:05:02 +0300 Subject: [PATCH 14/23] Python: add SORT_RO command. (#1528) * Python: add SORT_RO command. --- .../glide/async_commands/cluster_commands.py | 50 ++++++++ .../async_commands/standalone_commands.py | 66 +++++++++++ .../glide/async_commands/transaction.py | 80 +++++++++++++ python/python/tests/test_async_client.py | 110 ++++++++++++++++-- python/python/tests/test_transaction.py | 8 ++ 5 files changed, 302 insertions(+), 12 deletions(-) diff --git a/python/python/glide/async_commands/cluster_commands.py b/python/python/glide/async_commands/cluster_commands.py index 98b83f21fb..45efd16d7d 100644 --- a/python/python/glide/async_commands/cluster_commands.py +++ b/python/python/glide/async_commands/cluster_commands.py @@ -691,6 +691,7 @@ async def sort( ) -> List[bytes]: """ Sorts the elements in the list, set, or sorted set at `key` and returns the result. + This command is routed to primary nodes only. To store the result into a new key, see `sort_store`. By default, sorting is numeric, and elements are compared by their value interpreted as double precision floating point numbers. @@ -728,6 +729,55 @@ async def sort( result = await self._execute_command(RequestType.Sort, args) return cast(List[bytes], result) + async def sort_ro( + self, + key: TEncodable, + limit: Optional[Limit] = None, + order: Optional[OrderBy] = None, + alpha: Optional[bool] = None, + ) -> List[bytes]: + """ + Sorts the elements in the list, set, or sorted set at `key` and returns the result. + The `sort_ro` command can be used to sort elements based on different criteria and apply transformations on sorted elements. + This command is routed depending on the client's `ReadFrom` strategy. + + By default, sorting is numeric, and elements are compared by their value interpreted as double precision floating point numbers. + + See https://valkey.io/commands/sort for more details. + + Args: + key (TEncodable): The key of the list, set, or sorted set to be sorted. + limit (Optional[Limit]): Limiting the range of the query by setting offset and result count. See `Limit` class for more information. + order (Optional[OrderBy]): Specifies the order to sort the elements. + Can be `OrderBy.ASC` (ascending) or `OrderBy.DESC` (descending). + alpha (Optional[bool]): When `True`, sorts elements lexicographically. When `False` (default), sorts elements numerically. + Use this when the list, set, or sorted set contains string values that cannot be converted into double precision floating point numbers. + + Returns: + List[bytes]: A list of sorted elements. + + Examples: + >>> await client.lpush("mylist", '3', '1', '2') + >>> await client.sort_ro("mylist") + [b'1', b'2', b'3'] + + >>> await client.sort_ro("mylist", order=OrderBy.DESC) + [b'3', b'2', b'1'] + + >>> await client.lpush("mylist", '2', '1', '2', '3', '3', '1') + >>> await client.sort_ro("mylist", limit=Limit(2, 3)) + [b'1', b'2', b'2'] + + >>> await client.lpush("mylist", "a", "b", "c", "d") + >>> await client.sort_ro("mylist", limit=Limit(2, 2), order=OrderBy.DESC, alpha=True) + [b'b', b'a'] + + Since: Redis version 7.0.0. + """ + args = _build_sort_args(key, None, limit, None, order, alpha) + result = await self._execute_command(RequestType.SortReadOnly, args) + return cast(List[bytes], result) + async def sort_store( self, key: TEncodable, diff --git a/python/python/glide/async_commands/standalone_commands.py b/python/python/glide/async_commands/standalone_commands.py index 83823ca6b9..781a3ec6c0 100644 --- a/python/python/glide/async_commands/standalone_commands.py +++ b/python/python/glide/async_commands/standalone_commands.py @@ -487,6 +487,7 @@ async def sort( """ Sorts the elements in the list, set, or sorted set at `key` and returns the result. The `sort` command can be used to sort elements based on different criteria and apply transformations on sorted elements. + This command is routed to primary nodes only. To store the result into a new key, see `sort_store`. See https://valkey.io/commands/sort for more details. @@ -538,6 +539,71 @@ async def sort( result = await self._execute_command(RequestType.Sort, args) return cast(List[Optional[bytes]], result) + async def sort_ro( + self, + key: TEncodable, + by_pattern: Optional[TEncodable] = None, + limit: Optional[Limit] = None, + get_patterns: Optional[List[TEncodable]] = None, + order: Optional[OrderBy] = None, + alpha: Optional[bool] = None, + ) -> List[Optional[bytes]]: + """ + Sorts the elements in the list, set, or sorted set at `key` and returns the result. + The `sort_ro` command can be used to sort elements based on different criteria and apply transformations on sorted elements. + This command is routed depending on the client's `ReadFrom` strategy. + + See https://valkey.io/commands/sort for more details. + + Args: + key (TEncodable): The key of the list, set, or sorted set to be sorted. + by_pattern (Optional[TEncodable]): A pattern to sort by external keys instead of by the elements stored at the key themselves. + The pattern should contain an asterisk (*) as a placeholder for the element values, where the value + from the key replaces the asterisk to create the key name. For example, if `key` contains IDs of objects, + `by_pattern` can be used to sort these IDs based on an attribute of the objects, like their weights or + timestamps. + E.g., if `by_pattern` is `weight_*`, the command will sort the elements by the values of the + keys `weight_`. + If not provided, elements are sorted by their value. + limit (Optional[Limit]): Limiting the range of the query by setting offset and result count. See `Limit` class for more information. + get_pattern (Optional[TEncodable]): A pattern used to retrieve external keys' values, instead of the elements at `key`. + The pattern should contain an asterisk (*) as a placeholder for the element values, where the value + from `key` replaces the asterisk to create the key name. This allows the sorted elements to be + transformed based on the related keys values. For example, if `key` contains IDs of users, `get_pattern` + can be used to retrieve specific attributes of these users, such as their names or email addresses. + E.g., if `get_pattern` is `name_*`, the command will return the values of the keys `name_` + for each sorted element. Multiple `get_pattern` arguments can be provided to retrieve multiple attributes. + The special value `#` can be used to include the actual element from `key` being sorted. + If not provided, only the sorted elements themselves are returned. + order (Optional[OrderBy]): Specifies the order to sort the elements. + Can be `OrderBy.ASC` (ascending) or `OrderBy.DESC` (descending). + alpha (Optional[bool]): When `True`, sorts elements lexicographically. When `False` (default), sorts elements numerically. + Use this when the list, set, or sorted set contains string values that cannot be converted into double precision floating point + + Returns: + List[Optional[bytes]]: Returns a list of sorted elements. + + Examples: + >>> await client.lpush("mylist", 3, 1, 2) + >>> await client.sort_ro("mylist") + [b'1', b'2', b'3'] + >>> await client.sort_ro("mylist", order=OrderBy.DESC) + [b'3', b'2', b'1'] + >>> await client.lpush("mylist2", 2, 1, 2, 3, 3, 1) + >>> await client.sort_ro("mylist2", limit=Limit(2, 3)) + [b'2', b'2', b'3'] + >>> await client.hset("user:1", "name", "Alice", "age", 30) + >>> await client.hset("user:2", "name", "Bob", "age", 25) + >>> await client.lpush("user_ids", 2, 1) + >>> await client.sort_ro("user_ids", by_pattern="user:*->age", get_patterns=["user:*->name"]) + [b'Bob', b'Alice'] + + Since: Redis version 7.0.0. + """ + args = _build_sort_args(key, by_pattern, limit, get_patterns, order, alpha) + result = await self._execute_command(RequestType.SortReadOnly, args) + return cast(List[Optional[bytes]], result) + async def sort_store( self, key: TEncodable, diff --git a/python/python/glide/async_commands/transaction.py b/python/python/glide/async_commands/transaction.py index 607ccad1f6..af9c50ffcb 100644 --- a/python/python/glide/async_commands/transaction.py +++ b/python/python/glide/async_commands/transaction.py @@ -4722,6 +4722,55 @@ def sort( args = _build_sort_args(key, by_pattern, limit, get_patterns, order, alpha) return self.append_command(RequestType.Sort, args) + def sort_ro( + self: TTransaction, + key: TEncodable, + by_pattern: Optional[TEncodable] = None, + limit: Optional[Limit] = None, + get_patterns: Optional[List[TEncodable]] = None, + order: Optional[OrderBy] = None, + alpha: Optional[bool] = None, + ) -> TTransaction: + """ + Sorts the elements in the list, set, or sorted set at `key` and returns the result. + The `sort_ro` command can be used to sort elements based on different criteria and apply transformations on sorted elements. + This command is routed depending on the client's `ReadFrom` strategy. + + See https://valkey.io/commands/sort for more details. + + Args: + key (TEncodable): The key of the list, set, or sorted set to be sorted. + by_pattern (Optional[TEncodable]): A pattern to sort by external keys instead of by the elements stored at the key themselves. + The pattern should contain an asterisk (*) as a placeholder for the element values, where the value + from the key replaces the asterisk to create the key name. For example, if `key` contains IDs of objects, + `by_pattern` can be used to sort these IDs based on an attribute of the objects, like their weights or + timestamps. + E.g., if `by_pattern` is `weight_*`, the command will sort the elements by the values of the + keys `weight_`. + If not provided, elements are sorted by their value. + limit (Optional[Limit]): Limiting the range of the query by setting offset and result count. See `Limit` class for more information. + get_pattern (Optional[TEncodable]): A pattern used to retrieve external keys' values, instead of the elements at `key`. + The pattern should contain an asterisk (*) as a placeholder for the element values, where the value + from `key` replaces the asterisk to create the key name. This allows the sorted elements to be + transformed based on the related keys values. For example, if `key` contains IDs of users, `get_pattern` + can be used to retrieve specific attributes of these users, such as their names or email addresses. + E.g., if `get_pattern` is `name_*`, the command will return the values of the keys `name_` + for each sorted element. Multiple `get_pattern` arguments can be provided to retrieve multiple attributes. + The special value `#` can be used to include the actual element from `key` being sorted. + If not provided, only the sorted elements themselves are returned. + order (Optional[OrderBy]): Specifies the order to sort the elements. + Can be `OrderBy.ASC` (ascending) or `OrderBy.DESC` (descending). + alpha (Optional[bool]): When `True`, sorts elements lexicographically. When `False` (default), sorts elements numerically. + Use this when the list, set, or sorted set contains string values that cannot be converted into double precision floating point numbers. + + Command response: + List[Optional[bytes]]: Returns a list of sorted elements. + + Since: Redis version 7.0.0. + """ + args = _build_sort_args(key, by_pattern, limit, get_patterns, order, alpha) + return self.append_command(RequestType.SortReadOnly, args) + def sort_store( self: TTransaction, key: TEncodable, @@ -4843,6 +4892,7 @@ def sort( ) -> TTransaction: """ Sorts the elements in the list, set, or sorted set at `key` and returns the result. + This command is routed to primary only. To store the result into a new key, see `sort_store`. See https://valkey.io/commands/sort for more details. @@ -4861,6 +4911,36 @@ def sort( args = _build_sort_args(key, None, limit, None, order, alpha) return self.append_command(RequestType.Sort, args) + def sort_ro( + self: TTransaction, + key: TEncodable, + limit: Optional[Limit] = None, + order: Optional[OrderBy] = None, + alpha: Optional[bool] = None, + ) -> TTransaction: + """ + Sorts the elements in the list, set, or sorted set at `key` and returns the result. + The `sort_ro` command can be used to sort elements based on different criteria and apply transformations on sorted elements. + This command is routed depending on the client's `ReadFrom` strategy. + + See https://valkey.io/commands/sort for more details. + + Args: + key (TEncodable): The key of the list, set, or sorted set to be sorted. + limit (Optional[Limit]): Limiting the range of the query by setting offset and result count. See `Limit` class for more information. + order (Optional[OrderBy]): Specifies the order to sort the elements. + Can be `OrderBy.ASC` (ascending) or `OrderBy.DESC` (descending). + alpha (Optional[bool]): When `True`, sorts elements lexicographically. When `False` (default), sorts elements numerically. + Use this when the list, set, or sorted set contains string values that cannot be converted into double precision floating point numbers. + + Command response: + List[bytes]: A list of sorted elements. + + Since: Redis version 7.0.0. + """ + args = _build_sort_args(key, None, limit, None, order, alpha) + return self.append_command(RequestType.SortReadOnly, args) + def sort_store( self: TTransaction, key: TEncodable, diff --git a/python/python/tests/test_async_client.py b/python/python/tests/test_async_client.py index c8ed08d140..cc1c51eccf 100644 --- a/python/python/tests/test_async_client.py +++ b/python/python/tests/test_async_client.py @@ -4716,6 +4716,12 @@ async def test_sort_and_sort_store_with_get_or_by_args( assert await glide_client.hset(user_key5, {"name": "Eve", "age": "40"}) == 2 assert await glide_client.lpush("user_ids", ["5", "4", "3", "2", "1"]) == 5 + # SORT_RO Available since: 7.0.0 + skip_sort_ro_test = False + min_version = "7.0.0" + if await check_if_server_version_lt(glide_client, min_version): + skip_sort_ro_test = True + # Test sort with all arguments assert await glide_client.lpush(key, ["3", "1", "2"]) == 3 result = await glide_client.sort( @@ -4727,6 +4733,16 @@ async def test_sort_and_sort_store_with_get_or_by_args( ) assert result == [b"Alice", b"Bob"] + if not skip_sort_ro_test: + result_ro = await glide_client.sort_ro( + key, + limit=Limit(0, 2), + get_patterns=[b"user:*->name"], + order=OrderBy.ASC, + alpha=True, + ) + assert result_ro == [b"Alice", b"Bob"] + # Test sort_store with all arguments sort_store_result = await glide_client.sort_store( key, @@ -4747,9 +4763,16 @@ async def test_sort_and_sort_store_with_get_or_by_args( get_patterns=["user:*->name"], alpha=True, ) - assert result == convert_string_to_bytes_object( - ["Dave", "Bob", "Alice", "Charlie", "Eve"] - ) + assert result == [b"Dave", b"Bob", b"Alice", b"Charlie", b"Eve"] + + if not skip_sort_ro_test: + result_ro = await glide_client.sort_ro( + b"user_ids", + by_pattern=b"user:*->age", + get_patterns=["user:*->name"], + alpha=True, + ) + assert result_ro == [b"Dave", b"Bob", b"Alice", b"Charlie", b"Eve"] # Test sort with `by` argument with missing keys to sort by assert await glide_client.lpush("user_ids", ["a"]) == 6 @@ -4763,6 +4786,15 @@ async def test_sort_and_sort_store_with_get_or_by_args( [None, "Dave", "Bob", "Alice", "Charlie", "Eve"] ) + if not skip_sort_ro_test: + result_ro = await glide_client.sort_ro( + "user_ids", + by_pattern=b"user:*->age", + get_patterns=["user:*->name"], + alpha=True, + ) + assert result_ro == [None, b"Dave", b"Bob", b"Alice", b"Charlie", b"Eve"] + # Test sort with `by` argument with missing keys to sort by result = await glide_client.sort( "user_ids", @@ -4774,6 +4806,15 @@ async def test_sort_and_sort_store_with_get_or_by_args( [None, "30", "25", "35", "20", "40"] ) + if not skip_sort_ro_test: + result_ro = await glide_client.sort_ro( + "user_ids", + by_pattern=b"user:*->name", + get_patterns=[b"user:*->age"], + alpha=True, + ) + assert result_ro == [None, b"30", b"25", b"35", b"20", b"40"] + # Test Limit with count 0 result = await glide_client.sort( "user_ids", @@ -4782,6 +4823,14 @@ async def test_sort_and_sort_store_with_get_or_by_args( ) assert result == [] + if not skip_sort_ro_test: + result_ro = await glide_client.sort_ro( + "user_ids", + limit=Limit(0, 0), + alpha=True, + ) + assert result_ro == [] + @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_sort_and_sort_store_without_get_or_by_args( @@ -4790,10 +4839,20 @@ async def test_sort_and_sort_store_without_get_or_by_args( key = "{SameSlotKey}" + get_random_string(10) store = "{SameSlotKey}" + get_random_string(10) + # SORT_RO Available since: 7.0.0 + skip_sort_ro_test = False + min_version = "7.0.0" + if await check_if_server_version_lt(glide_client, min_version): + skip_sort_ro_test = True + # Test sort with non-existing key result = await glide_client.sort("non_existing_key") assert result == [] + if not skip_sort_ro_test: + result_ro = await glide_client.sort_ro(b"non_existing_key") + assert result_ro == [] + # Test sort_store with non-existing key sort_store_result = await glide_client.sort_store( "{SameSlotKey}:non_existing_key", store @@ -4807,30 +4866,57 @@ async def test_sort_and_sort_store_without_get_or_by_args( result = await glide_client.sort(key) assert result == [b"1", b"2", b"3", b"4", b"5"] + if not skip_sort_ro_test: + result_ro = await glide_client.sort_ro(key) + assert result_ro == [b"1", b"2", b"3", b"4", b"5"] + # limit argument result = await glide_client.sort(key, limit=Limit(1, 3)) assert result == [b"2", b"3", b"4"] + if not skip_sort_ro_test: + result_ro = await glide_client.sort_ro(key, limit=Limit(1, 3)) + assert result_ro == [b"2", b"3", b"4"] + # order argument result = await glide_client.sort(key, order=OrderBy.DESC) assert result == [b"5", b"4", b"3", b"2", b"1"] + if not skip_sort_ro_test: + result_ro = await glide_client.sort_ro(key, order=OrderBy.DESC) + assert result_ro == [b"5", b"4", b"3", b"2", b"1"] + assert await glide_client.lpush(key, ["a"]) == 6 with pytest.raises(RequestError) as e: await glide_client.sort(key) assert "can't be converted into double" in str(e).lower() + if not skip_sort_ro_test: + with pytest.raises(RequestError) as e: + await glide_client.sort_ro(key) + assert "can't be converted into double" in str(e).lower() + # alpha argument result = await glide_client.sort(key, alpha=True) assert result == [b"1", b"2", b"3", b"4", b"5", b"a"] + if not skip_sort_ro_test: + result_ro = await glide_client.sort_ro(key, alpha=True) + assert result_ro == [b"1", b"2", b"3", b"4", b"5", b"a"] + # Combining multiple arguments result = await glide_client.sort( key, limit=Limit(1, 3), order=OrderBy.DESC, alpha=True ) assert result == [b"5", b"4", b"3"] + if not skip_sort_ro_test: + result_ro = await glide_client.sort_ro( + key, limit=Limit(1, 3), order=OrderBy.DESC, alpha=True + ) + assert result_ro == [b"5", b"4", b"3"] + # Test sort_store with combined arguments sort_store_result = await glide_client.sort_store( key, store, limit=Limit(1, 3), order=OrderBy.DESC, alpha=True @@ -9672,19 +9758,19 @@ async def test_script_binary(self, glide_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_script_large_keys_no_args(self, request, cluster_mode, protocol): - redis_client = await create_client( + glide_client = await create_client( request, cluster_mode=cluster_mode, protocol=protocol, timeout=5000 ) length = 2**13 # 8kb key = "0" * length script = Script("return KEYS[1]") - assert await redis_client.invoke_script(script, keys=[key]) == key.encode() - await redis_client.close() + assert await glide_client.invoke_script(script, keys=[key]) == key.encode() + await glide_client.close() @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_script_large_args_no_keys(self, request, cluster_mode, protocol): - redis_client = await create_client( + glide_client = await create_client( request, cluster_mode=cluster_mode, protocol=protocol, timeout=5000 ) length = 2**12 # 4kb @@ -9693,14 +9779,14 @@ async def test_script_large_args_no_keys(self, request, cluster_mode, protocol): script = Script("return ARGV[2]") assert ( - await redis_client.invoke_script(script, args=[arg1, arg2]) == arg2.encode() + await glide_client.invoke_script(script, args=[arg1, arg2]) == arg2.encode() ) - await redis_client.close() + await glide_client.close() @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_script_large_keys_and_args(self, request, cluster_mode, protocol): - redis_client = await create_client( + glide_client = await create_client( request, cluster_mode=cluster_mode, protocol=protocol, timeout=5000 ) length = 2**12 # 4kb @@ -9709,7 +9795,7 @@ async def test_script_large_keys_and_args(self, request, cluster_mode, protocol) script = Script("return KEYS[1]") assert ( - await redis_client.invoke_script(script, keys=[key], args=[arg]) + await glide_client.invoke_script(script, keys=[key], args=[arg]) == key.encode() ) - await redis_client.close() + await glide_client.close() diff --git a/python/python/tests/test_transaction.py b/python/python/tests/test_transaction.py index e980f2fef5..de878e5866 100644 --- a/python/python/tests/test_transaction.py +++ b/python/python/tests/test_transaction.py @@ -668,6 +668,14 @@ async def transaction_test( alpha=True, ) args.append([b"2", b"3", b"4", b"a"]) + if not await check_if_server_version_lt(glide_client, "7.0.0"): + transaction.sort_ro( + key17, + limit=Limit(1, 4), + order=OrderBy.ASC, + alpha=True, + ) + args.append([b"2", b"3", b"4", b"a"]) transaction.sort_store( key17, key18, From 2e14feb4f782ef302d03f751a6053bb9d7cd23f6 Mon Sep 17 00:00:00 2001 From: yulazariy Date: Thu, 4 Jul 2024 14:55:08 +0300 Subject: [PATCH 15/23] Add function list binary output support (#1800) * Add function list binary output support 1. Add new API to get pattern as GlideString 2. Add new function handleFunctionListResponseBinary to handle binary output 3. Add new test utility to validate binary output Note: there is a bug where the flags set always return as string. for now I fix the assert of the set with my own assert assertSetsEqual that convert to GlideString. --------- Co-authored-by: Yulazari --- .github/workflows/java.yml | 2 +- .../src/main/java/glide/api/BaseClient.java | 12 ++ .../src/main/java/glide/api/RedisClient.java | 21 ++++ .../java/glide/api/RedisClusterClient.java | 62 ++++++++++ .../ScriptingAndFunctionsClusterCommands.java | 115 ++++++++++++++++++ .../ScriptingAndFunctionsCommands.java | 52 ++++++++ .../test/java/glide/api/RedisClientTest.java | 51 ++++++++ .../glide/api/RedisClusterClientTest.java | 104 ++++++++++++++++ .../src/test/java/glide/TestUtilities.java | 50 ++++++++ .../test/java/glide/cluster/CommandTests.java | 113 +++++++---------- .../java/glide/standalone/CommandTests.java | 45 +++---- 11 files changed, 532 insertions(+), 95 deletions(-) diff --git a/.github/workflows/java.yml b/.github/workflows/java.yml index 4964a7dbed..0a773d2f08 100644 --- a/.github/workflows/java.yml +++ b/.github/workflows/java.yml @@ -126,7 +126,7 @@ jobs: - 17 runs-on: ubuntu-latest container: amazonlinux:latest - timeout-minutes: 15 + timeout-minutes: 20 steps: - name: Install git run: | diff --git a/java/client/src/main/java/glide/api/BaseClient.java b/java/client/src/main/java/glide/api/BaseClient.java index d0b71a9c45..66b093954f 100644 --- a/java/client/src/main/java/glide/api/BaseClient.java +++ b/java/client/src/main/java/glide/api/BaseClient.java @@ -653,6 +653,18 @@ protected Map[] handleFunctionListResponse(Object[] response) { return data; } + /** Process a FUNCTION LIST standalone response. */ + @SuppressWarnings("unchecked") + protected Map[] handleFunctionListResponseBinary(Object[] response) { + Map[] data = castArray(response, Map.class); + for (Map libraryInfo : data) { + Object[] functions = (Object[]) libraryInfo.get(gs("functions")); + var functionInfo = castArray(functions, Map.class); + libraryInfo.put(gs("functions"), functionInfo); + } + return data; + } + /** Process a FUNCTION STATS standalone response. */ protected Map> handleFunctionStatsResponse( Map> response) { diff --git a/java/client/src/main/java/glide/api/RedisClient.java b/java/client/src/main/java/glide/api/RedisClient.java index 568af95702..ce2bfa3fcc 100644 --- a/java/client/src/main/java/glide/api/RedisClient.java +++ b/java/client/src/main/java/glide/api/RedisClient.java @@ -292,6 +292,14 @@ public CompletableFuture[]> functionList(boolean withCode) { response -> handleFunctionListResponse(handleArrayResponse(response))); } + @Override + public CompletableFuture[]> functionListBinary(boolean withCode) { + return commandManager.submitNewCommand( + FunctionList, + new ArgsBuilder().addIf(WITH_CODE_REDIS_API, withCode).toArray(), + response -> handleFunctionListResponseBinary(handleArrayResponseBinary(response))); + } + @Override public CompletableFuture[]> functionList( @NonNull String libNamePattern, boolean withCode) { @@ -303,6 +311,19 @@ public CompletableFuture[]> functionList( response -> handleFunctionListResponse(handleArrayResponse(response))); } + @Override + public CompletableFuture[]> functionListBinary( + @NonNull GlideString libNamePattern, boolean withCode) { + return commandManager.submitNewCommand( + FunctionList, + new ArgsBuilder() + .add(LIBRARY_NAME_REDIS_API) + .add(libNamePattern) + .addIf(WITH_CODE_REDIS_API, withCode) + .toArray(), + response -> handleFunctionListResponseBinary(handleArrayResponseBinary(response))); + } + @Override public CompletableFuture functionFlush() { return commandManager.submitNewCommand( diff --git a/java/client/src/main/java/glide/api/RedisClusterClient.java b/java/client/src/main/java/glide/api/RedisClusterClient.java index 89517ec581..8e96ea2dff 100644 --- a/java/client/src/main/java/glide/api/RedisClusterClient.java +++ b/java/client/src/main/java/glide/api/RedisClusterClient.java @@ -580,6 +580,25 @@ protected ClusterValue[]> handleFunctionListResponse( } } + /** Process a FUNCTION LIST cluster response. */ + protected ClusterValue[]> handleFunctionListResponseBinary( + Response response, Route route) { + if (route instanceof SingleNodeRoute) { + Map[] data = + handleFunctionListResponseBinary(handleArrayResponseBinary(response)); + return ClusterValue.ofSingleValue(data); + } else { + // each `Object` is a `Map[]` actually + Map info = handleBinaryStringMapResponse(response); + Map[]> data = new HashMap<>(); + for (var nodeInfo : info.entrySet()) { + data.put( + nodeInfo.getKey(), handleFunctionListResponseBinary((Object[]) nodeInfo.getValue())); + } + return ClusterValue.ofMultiValueBinary(data); + } + } + @Override public CompletableFuture[]> functionList(boolean withCode) { return commandManager.submitNewCommand( @@ -588,6 +607,14 @@ public CompletableFuture[]> functionList(boolean withCode) { response -> handleFunctionListResponse(handleArrayResponse(response))); } + @Override + public CompletableFuture[]> functionListBinary(boolean withCode) { + return commandManager.submitNewCommand( + FunctionList, + new ArgsBuilder().addIf(WITH_CODE_REDIS_API, withCode).toArray(), + response -> handleFunctionListResponseBinary(handleArrayResponseBinary(response))); + } + @Override public CompletableFuture[]> functionList( @NonNull String libNamePattern, boolean withCode) { @@ -599,6 +626,19 @@ public CompletableFuture[]> functionList( response -> handleFunctionListResponse(handleArrayResponse(response))); } + @Override + public CompletableFuture[]> functionListBinary( + @NonNull GlideString libNamePattern, boolean withCode) { + return commandManager.submitNewCommand( + FunctionList, + new ArgsBuilder() + .add(LIBRARY_NAME_REDIS_API) + .add(libNamePattern) + .addIf(WITH_CODE_REDIS_API, withCode) + .toArray(), + response -> handleFunctionListResponseBinary(handleArrayResponseBinary(response))); + } + @Override public CompletableFuture[]>> functionList( boolean withCode, @NonNull Route route) { @@ -609,6 +649,15 @@ public CompletableFuture[]>> functionList( response -> handleFunctionListResponse(response, route)); } + public CompletableFuture[]>> functionListBinary( + boolean withCode, @NonNull Route route) { + return commandManager.submitNewCommand( + FunctionList, + new ArgsBuilder().addIf(WITH_CODE_REDIS_API, withCode).toArray(), + route, + response -> handleFunctionListResponseBinary(response, route)); + } + @Override public CompletableFuture[]>> functionList( @NonNull String libNamePattern, boolean withCode, @NonNull Route route) { @@ -621,6 +670,19 @@ public CompletableFuture[]>> functionList( response -> handleFunctionListResponse(response, route)); } + public CompletableFuture[]>> functionListBinary( + @NonNull GlideString libNamePattern, boolean withCode, @NonNull Route route) { + return commandManager.submitNewCommand( + FunctionList, + new ArgsBuilder() + .add(LIBRARY_NAME_REDIS_API) + .add(libNamePattern) + .addIf(WITH_CODE_REDIS_API, withCode) + .toArray(), + route, + response -> handleFunctionListResponseBinary(response, route)); + } + @Override public CompletableFuture functionFlush() { return commandManager.submitNewCommand( diff --git a/java/client/src/main/java/glide/api/commands/ScriptingAndFunctionsClusterCommands.java b/java/client/src/main/java/glide/api/commands/ScriptingAndFunctionsClusterCommands.java index fa80d15dd7..55449d4b98 100644 --- a/java/client/src/main/java/glide/api/commands/ScriptingAndFunctionsClusterCommands.java +++ b/java/client/src/main/java/glide/api/commands/ScriptingAndFunctionsClusterCommands.java @@ -124,6 +124,32 @@ CompletableFuture functionLoad( */ CompletableFuture[]> functionList(boolean withCode); + /** + * Returns information about the functions and libraries.
+ * The command will be routed to a random node. + * + * @since Redis 7.0 and above. + * @see valkey.io for details. + * @param withCode Specifies whether to request the library code from the server or not. + * @return Info about all libraries and their functions. + * @example + *
{@code
+     * Map[] response = client.functionList(true).get();
+     * for (Map libraryInfo : response) {
+     *     System.out.printf("Server has library '%s' which runs on %s engine%n",
+     *         libraryInfo.get(gs("library_name")), libraryInfo.get(gs("engine")));
+     *     Map[] functions = (Map[]) libraryInfo.get(gs("functions"));
+     *     for (Map function : functions) {
+     *         Set flags = (Set) function.get(gs("flags"));
+     *         System.out.printf("Library has function '%s' with flags '%s' described as %s%n",
+     *             function.get(gs("name")), gs(String.join(", ", flags)), function.get(gs("description")));
+     *     }
+     *     System.out.printf("Library code:%n%s%n", libraryInfo.get(gs("library_code")));
+     * }
+     * }
+ */ + CompletableFuture[]> functionListBinary(boolean withCode); + /** * Returns information about the functions and libraries.
* The command will be routed to a random node. @@ -151,6 +177,34 @@ CompletableFuture functionLoad( */ CompletableFuture[]> functionList(String libNamePattern, boolean withCode); + /** + * Returns information about the functions and libraries.
+ * The command will be routed to a random node. + * + * @since Redis 7.0 and above. + * @see valkey.io for details. + * @param libNamePattern A wildcard pattern for matching library names. + * @param withCode Specifies whether to request the library code from the server or not. + * @return Info about queried libraries and their functions. + * @example + *
{@code
+     * Map[] response = client.functionList(gs("myLib?_backup"), true).get();
+     * for (Map libraryInfo : response) {
+     *     System.out.printf("Server has library '%s' which runs on %s engine%n",
+     *         libraryInfo.get(gs("library_name")), libraryInfo.get(gs("engine")));
+     *     Map[] functions = (Map[]) libraryInfo.get(gs("functions"));
+     *     for (Map function : functions) {
+     *         Set flags = (Set) function.get(gs("flags"));
+     *         System.out.printf("Library has function '%s' with flags '%s' described as %s%n",
+     *             function.get(gs("name")), gs(String.join(", ", flags)), function.get(gs("description")));
+     *     }
+     *     System.out.printf("Library code:%n%s%n", libraryInfo.get(gs("library_code")));
+     * }
+     * }
+ */ + CompletableFuture[]> functionListBinary( + GlideString libNamePattern, boolean withCode); + /** * Returns information about the functions and libraries. * @@ -181,6 +235,36 @@ CompletableFuture functionLoad( CompletableFuture[]>> functionList( boolean withCode, Route route); + /** + * Returns information about the functions and libraries. + * + * @since Redis 7.0 and above. + * @see valkey.io for details. + * @param withCode Specifies whether to request the library code from the server or not. + * @param route Specifies the routing configuration for the command. The client will route the + * command to the nodes defined by route. + * @return Info about all libraries and their functions. + * @example + *
{@code
+     * ClusterValue[]> response = client.functionList(true, ALL_NODES).get();
+     * for (String node : response.getMultiValue().keySet()) {
+     *   for (Map libraryInfo : response) {
+     *     System.out.printf("Server has library '%s' which runs on %s engine%n",
+     *         libraryInfo.get(gs("library_name")), libraryInfo.get(gs("engine")));
+     *     Map[] functions = (Map[]) libraryInfo.get(gs("functions"));
+     *     for (Map function : functions) {
+     *         Set flags = (Set) function.get(gs("flags"));
+     *         System.out.printf("Library has function '%s' with flags '%s' described as %s%n",
+     *             function.get(gs("name")), gs(String.join(", ", flags)), function.get(gs("description")));
+     *     }
+     *     System.out.printf("Library code:%n%s%n", libraryInfo.get(gs("library_code")));
+     *   }
+     * }
+     * }
+ */ + CompletableFuture[]>> functionListBinary( + boolean withCode, Route route); + /** * Returns information about the functions and libraries. * @@ -212,6 +296,37 @@ CompletableFuture[]>> functionList( CompletableFuture[]>> functionList( String libNamePattern, boolean withCode, Route route); + /** + * Returns information about the functions and libraries. + * + * @since Redis 7.0 and above. + * @see valkey.io for details. + * @param libNamePattern A wildcard pattern for matching library names. + * @param withCode Specifies whether to request the library code from the server or not. + * @param route Specifies the routing configuration for the command. The client will route the + * command to the nodes defined by route. + * @return Info about queried libraries and their functions. + * @example + *
{@code
+     * ClusterValue[]> response = client.functionList(gs("myLib?_backup"), true, ALL_NODES).get();
+     * for (String node : response.getMultiValue().keySet()) {
+     *   for (Map libraryInfo : response) {
+     *     System.out.printf("Server has library '%s' which runs on %s engine%n",
+     *         libraryInfo.get(gs("library_name")), libraryInfo.get(gs("engine")));
+     *     Map[] functions = (Map[]) libraryInfo.get(gs("functions"));
+     *     for (Map function : functions) {
+     *         Set flags = (Set) function.get(gs("flags"));
+     *         System.out.printf("Library has function '%s' with flags '%s' described as %s%n",
+     *             function.get(gs("name")), gs(String.join(", ", flags)), function.get(gs("description")));
+     *     }
+     *     System.out.printf("Library code:%n%s%n", libraryInfo.get(gs("library_code")));
+     *   }
+     * }
+     * }
+ */ + CompletableFuture[]>> functionListBinary( + GlideString libNamePattern, boolean withCode, Route route); + /** * Deletes all function libraries.
* The command will be routed to all primary nodes. diff --git a/java/client/src/main/java/glide/api/commands/ScriptingAndFunctionsCommands.java b/java/client/src/main/java/glide/api/commands/ScriptingAndFunctionsCommands.java index f753f5ba87..34c3298aa2 100644 --- a/java/client/src/main/java/glide/api/commands/ScriptingAndFunctionsCommands.java +++ b/java/client/src/main/java/glide/api/commands/ScriptingAndFunctionsCommands.java @@ -77,6 +77,31 @@ public interface ScriptingAndFunctionsCommands { */ CompletableFuture[]> functionList(boolean withCode); + /** + * Returns information about the functions and libraries. + * + * @since Redis 7.0 and above. + * @see valkey.io for details. + * @param withCode Specifies whether to request the library code from the server or not. + * @return Info about all libraries and their functions. + * @example + *
{@code
+     * Map[] response = client.functionList(true).get();
+     * for (Map libraryInfo : response) {
+     *     System.out.printf("Server has library '%s' which runs on %s engine%n",
+     *         libraryInfo.get("library_name"), libraryInfo.get("engine"));
+     *     Map[] functions = (Map[]) libraryInfo.get("functions");
+     *     for (Map function : functions) {
+     *         Set flags = (Set) function.get("flags");
+     *         System.out.printf("Library has function '%s' with flags '%s' described as %s%n",
+     *             function.get("name"), String. join(", ", flags), function.get("description"));
+     *     }
+     *     System.out.printf("Library code:%n%s%n", libraryInfo.get("library_code"));
+     * }
+     * }
+ */ + CompletableFuture[]> functionListBinary(boolean withCode); + /** * Returns information about the functions and libraries. * @@ -103,6 +128,33 @@ public interface ScriptingAndFunctionsCommands { */ CompletableFuture[]> functionList(String libNamePattern, boolean withCode); + /** + * Returns information about the functions and libraries. + * + * @since Redis 7.0 and above. + * @see valkey.io for details. + * @param libNamePattern A wildcard pattern for matching library names. + * @param withCode Specifies whether to request the library code from the server or not. + * @return Info about queried libraries and their functions. + * @example + *
{@code
+     * Map[] response = client.functionList("myLib?_backup", true).get();
+     * for (Map libraryInfo : response) {
+     *     System.out.printf("Server has library '%s' which runs on %s engine%n",
+     *         libraryInfo.get("library_name"), libraryInfo.get("engine"));
+     *     Map[] functions = (Map[]) libraryInfo.get("functions");
+     *     for (Map function : functions) {
+     *         Set flags = (Set) function.get("flags");
+     *         System.out.printf("Library has function '%s' with flags '%s' described as %s%n",
+     *             function.get("name"), String. join(", ", flags), function.get("description"));
+     *     }
+     *     System.out.printf("Library code:%n%s%n", libraryInfo.get("library_code"));
+     * }
+     * }
+ */ + CompletableFuture[]> functionListBinary( + GlideString libNamePattern, boolean withCode); + /** * Deletes all function libraries. * diff --git a/java/client/src/test/java/glide/api/RedisClientTest.java b/java/client/src/test/java/glide/api/RedisClientTest.java index f981d4be5a..590efeadff 100644 --- a/java/client/src/test/java/glide/api/RedisClientTest.java +++ b/java/client/src/test/java/glide/api/RedisClientTest.java @@ -9270,6 +9270,30 @@ public void functionList_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void functionList_binary_returns_success() { + // setup + GlideString[] args = new GlideString[0]; + @SuppressWarnings("unchecked") + Map[] value = new Map[0]; + CompletableFuture[]> testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.[]>submitNewCommand( + eq(FunctionList), eq(args), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture[]> response = service.functionListBinary(false); + Map[] payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void functionList_with_pattern_returns_success() { @@ -9294,6 +9318,33 @@ public void functionList_with_pattern_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void functionList_binary_with_pattern_returns_success() { + // setup + GlideString pattern = gs("*"); + GlideString[] args = + new GlideString[] {gs(LIBRARY_NAME_REDIS_API), pattern, gs(WITH_CODE_REDIS_API)}; + @SuppressWarnings("unchecked") + Map[] value = new Map[0]; + CompletableFuture[]> testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.[]>submitNewCommand( + eq(FunctionList), eq(args), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture[]> response = + service.functionListBinary(pattern, true); + Map[] payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void functionFlush_returns_success() { diff --git a/java/client/src/test/java/glide/api/RedisClusterClientTest.java b/java/client/src/test/java/glide/api/RedisClusterClientTest.java index d93c6417d3..6f60a0f675 100644 --- a/java/client/src/test/java/glide/api/RedisClusterClientTest.java +++ b/java/client/src/test/java/glide/api/RedisClusterClientTest.java @@ -1532,6 +1532,30 @@ public void functionList_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void functionList_binary_returns_success() { + // setup + GlideString[] args = new GlideString[0]; + @SuppressWarnings("unchecked") + Map[] value = new Map[0]; + CompletableFuture[]> testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.[]>submitNewCommand( + eq(FunctionList), eq(args), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture[]> response = service.functionListBinary(false); + Map[] payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void functionList_with_pattern_returns_success() { @@ -1556,6 +1580,33 @@ public void functionList_with_pattern_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void functionList_binary_with_pattern_returns_success() { + // setup + GlideString pattern = gs("*"); + GlideString[] args = + new GlideString[] {gs(LIBRARY_NAME_REDIS_API), pattern, gs(WITH_CODE_REDIS_API)}; + @SuppressWarnings("unchecked") + Map[] value = new Map[0]; + CompletableFuture[]> testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.[]>submitNewCommand( + eq(FunctionList), eq(args), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture[]> response = + service.functionListBinary(pattern, true); + Map[] payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void functionList_with_route_returns_success() { @@ -1581,6 +1632,32 @@ public void functionList_with_route_returns_success() { assertEquals(value, payload.getSingleValue()); } + @SneakyThrows + @Test + public void functionList_binary_with_route_returns_success() { + // setup + GlideString[] args = new GlideString[] {gs(WITH_CODE_REDIS_API)}; + @SuppressWarnings("unchecked") + Map[] value = new Map[0]; + CompletableFuture[]>> testResponse = + new CompletableFuture<>(); + testResponse.complete(ClusterValue.ofSingleValue(value)); + + // match on protobuf request + when(commandManager.[]>>submitNewCommand( + eq(FunctionList), eq(args), eq(RANDOM), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture[]>> response = + service.functionListBinary(true, RANDOM); + ClusterValue[]> payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload.getSingleValue()); + } + @SneakyThrows @Test public void functionList_with_pattern_and_route_returns_success() { @@ -1607,6 +1684,33 @@ public void functionList_with_pattern_and_route_returns_success() { assertEquals(value, payload.getSingleValue()); } + @SneakyThrows + @Test + public void functionList_binary_with_pattern_and_route_returns_success() { + // setup + GlideString pattern = gs("*"); + GlideString[] args = new GlideString[] {gs(LIBRARY_NAME_REDIS_API), pattern}; + @SuppressWarnings("unchecked") + Map[] value = new Map[0]; + CompletableFuture[]>> testResponse = + new CompletableFuture<>(); + testResponse.complete(ClusterValue.ofSingleValue(value)); + + // match on protobuf request + when(commandManager.[]>>submitNewCommand( + eq(FunctionList), eq(args), eq(RANDOM), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture[]>> response = + service.functionListBinary(pattern, false, RANDOM); + ClusterValue[]> payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload.getSingleValue()); + } + @SneakyThrows @Test public void functionFlush_returns_success() { diff --git a/java/integTest/src/test/java/glide/TestUtilities.java b/java/integTest/src/test/java/glide/TestUtilities.java index a43105f577..26f76b970c 100644 --- a/java/integTest/src/test/java/glide/TestUtilities.java +++ b/java/integTest/src/test/java/glide/TestUtilities.java @@ -168,6 +168,56 @@ public static void checkFunctionListResponse( assertTrue(hasLib); } + private void assertSetsEqual(Set expected, Set actual) { + // Convert both sets to lists. It is needed due to issue that rust return the flags as string + List expectedList = + expected.stream().sorted().map(GlideString::of).collect(Collectors.toList()); + List actualList = + actual.stream().sorted().map(GlideString::of).collect(Collectors.toList()); + + assertEquals(expectedList, actualList); + } + + /** + * Validate whether `FUNCTION LIST` response contains required info. + * + * @param response The response from redis. + * @param libName Expected library name. + * @param functionDescriptions Expected function descriptions. Key - function name, value - + * description. + * @param functionFlags Expected function flags. Key - function name, value - flags set. + * @param libCode Expected library to check if given. + */ + @SuppressWarnings("unchecked") + public static void checkFunctionListResponseBinary( + Map[] response, + GlideString libName, + Map functionDescriptions, + Map> functionFlags, + Optional libCode) { + assertTrue(response.length > 0); + boolean hasLib = false; + for (var lib : response) { + hasLib = lib.containsValue(libName); + if (hasLib) { + var functions = (Object[]) lib.get(gs("functions")); + assertEquals(functionDescriptions.size(), functions.length); + for (var functionInfo : functions) { + var function = (Map) functionInfo; + var functionName = (GlideString) function.get(gs("name")); + assertEquals(functionDescriptions.get(functionName), function.get(gs("description"))); + assertSetsEqual( + functionFlags.get(functionName), (Set) function.get(gs("flags"))); + } + if (libCode.isPresent()) { + assertEquals(libCode.get(), lib.get(gs("library_code"))); + } + break; + } + } + assertTrue(hasLib); + } + /** * Validate whether `FUNCTION STATS` response contains required info. * diff --git a/java/integTest/src/test/java/glide/cluster/CommandTests.java b/java/integTest/src/test/java/glide/cluster/CommandTests.java index be9d29d4cf..0abc88032e 100644 --- a/java/integTest/src/test/java/glide/cluster/CommandTests.java +++ b/java/integTest/src/test/java/glide/cluster/CommandTests.java @@ -4,6 +4,7 @@ import static glide.TestConfiguration.REDIS_VERSION; import static glide.TestUtilities.assertDeepEquals; import static glide.TestUtilities.checkFunctionListResponse; +import static glide.TestUtilities.checkFunctionListResponseBinary; import static glide.TestUtilities.checkFunctionStatsBinaryResponse; import static glide.TestUtilities.checkFunctionStatsResponse; import static glide.TestUtilities.commonClusterClientConfig; @@ -1210,47 +1211,39 @@ public void function_commands_without_keys_with_route_binary(boolean singleNodeR } var expectedDescription = - new HashMap() { + new HashMap() { { - put(funcName.toString(), null); + put(funcName, null); } }; var expectedFlags = - new HashMap>() { + new HashMap>() { { - put(funcName.toString(), Set.of("no-writes")); + put(funcName, Set.of(gs("no-writes"))); } }; - var response = clusterClient.functionList(false, route).get(); + var response = clusterClient.functionListBinary(false, route).get(); if (singleNodeRoute) { var flist = response.getSingleValue(); - checkFunctionListResponse( - flist, libName.toString(), expectedDescription, expectedFlags, Optional.empty()); + checkFunctionListResponseBinary( + flist, libName, expectedDescription, expectedFlags, Optional.empty()); } else { for (var flist : response.getMultiValue().values()) { - checkFunctionListResponse( - flist, libName.toString(), expectedDescription, expectedFlags, Optional.empty()); + checkFunctionListResponseBinary( + flist, libName, expectedDescription, expectedFlags, Optional.empty()); } } - response = clusterClient.functionList(true, route).get(); + response = clusterClient.functionListBinary(true, route).get(); if (singleNodeRoute) { var flist = response.getSingleValue(); - checkFunctionListResponse( - flist, - libName.toString(), - expectedDescription, - expectedFlags, - Optional.of(code.toString())); + checkFunctionListResponseBinary( + flist, libName, expectedDescription, expectedFlags, Optional.of(code)); } else { for (var flist : response.getMultiValue().values()) { - checkFunctionListResponse( - flist, - libName.toString(), - expectedDescription, - expectedFlags, - Optional.of(code.toString())); + checkFunctionListResponseBinary( + flist, libName, expectedDescription, expectedFlags, Optional.of(code)); } } @@ -1273,18 +1266,18 @@ public void function_commands_without_keys_with_route_binary(boolean singleNodeR assertEquals(libName, clusterClient.functionLoad(newCode, true, route).get()); - expectedDescription.put(newFuncName.toString(), null); - expectedFlags.put(newFuncName.toString(), Set.of("no-writes")); + expectedDescription.put(newFuncName, null); + expectedFlags.put(newFuncName, Set.of(gs("no-writes"))); - response = clusterClient.functionList(false, route).get(); + response = clusterClient.functionListBinary(false, route).get(); if (singleNodeRoute) { var flist = response.getSingleValue(); - checkFunctionListResponse( - flist, libName.toString(), expectedDescription, expectedFlags, Optional.empty()); + checkFunctionListResponseBinary( + flist, libName, expectedDescription, expectedFlags, Optional.empty()); } else { for (var flist : response.getMultiValue().values()) { - checkFunctionListResponse( - flist, libName.toString(), expectedDescription, expectedFlags, Optional.empty()); + checkFunctionListResponseBinary( + flist, libName, expectedDescription, expectedFlags, Optional.empty()); } } @@ -1302,23 +1295,15 @@ public void function_commands_without_keys_with_route_binary(boolean singleNodeR assertInstanceOf(RequestException.class, executionException.getCause()); assertTrue(executionException.getMessage().contains("Library not found")); - response = clusterClient.functionList(true, route).get(); + response = clusterClient.functionListBinary(true, route).get(); if (singleNodeRoute) { var flist = response.getSingleValue(); - checkFunctionListResponse( - flist, - libName.toString(), - expectedDescription, - expectedFlags, - Optional.of(newCode.toString())); + checkFunctionListResponseBinary( + flist, libName, expectedDescription, expectedFlags, Optional.of(newCode)); } else { for (var flist : response.getMultiValue().values()) { - checkFunctionListResponse( - flist, - libName.toString(), - expectedDescription, - expectedFlags, - Optional.of(newCode.toString())); + checkFunctionListResponseBinary( + flist, libName, expectedDescription, expectedFlags, Optional.of(newCode)); } } @@ -1452,29 +1437,25 @@ public void function_commands_without_keys_and_without_route_binary() { "one", clusterClient.fcallReadOnly(funcName, new GlideString[] {gs("one"), gs("two")}).get()); - var flist = clusterClient.functionList(false).get(); + var flist = clusterClient.functionListBinary(false).get(); var expectedDescription = - new HashMap() { + new HashMap() { { - put(funcName.toString(), null); + put(funcName, null); } }; var expectedFlags = - new HashMap>() { + new HashMap>() { { - put(funcName.toString(), Set.of("no-writes")); + put(funcName, Set.of(gs("no-writes"))); } }; - checkFunctionListResponse( - flist, libName.toString(), expectedDescription, expectedFlags, Optional.empty()); + checkFunctionListResponseBinary( + flist, libName, expectedDescription, expectedFlags, Optional.empty()); - flist = clusterClient.functionList(true).get(); - checkFunctionListResponse( - flist, - libName.toString(), - expectedDescription, - expectedFlags, - Optional.of(code.toString())); + flist = clusterClient.functionListBinary(true).get(); + checkFunctionListResponseBinary( + flist, libName, expectedDescription, expectedFlags, Optional.of(code)); // re-load library without overwriting var executionException = @@ -1507,19 +1488,15 @@ public void function_commands_without_keys_and_without_route_binary() { assertInstanceOf(RequestException.class, executionException.getCause()); assertTrue(executionException.getMessage().contains("Library not found")); - flist = clusterClient.functionList(libName.toString(), false).get(); - expectedDescription.put(newFuncName.toString(), null); - expectedFlags.put(newFuncName.toString(), Set.of("no-writes")); - checkFunctionListResponse( - flist, libName.toString(), expectedDescription, expectedFlags, Optional.empty()); + flist = clusterClient.functionListBinary(libName, false).get(); + expectedDescription.put(newFuncName, null); + expectedFlags.put(newFuncName, Set.of(gs("no-writes"))); + checkFunctionListResponseBinary( + flist, libName, expectedDescription, expectedFlags, Optional.empty()); - flist = clusterClient.functionList(libName.toString(), true).get(); - checkFunctionListResponse( - flist, - libName.toString(), - expectedDescription, - expectedFlags, - Optional.of(newCode.toString())); + flist = clusterClient.functionListBinary(libName, true).get(); + checkFunctionListResponseBinary( + flist, libName, expectedDescription, expectedFlags, Optional.of(newCode)); assertEquals( 2L, clusterClient.fcall(newFuncName, new GlideString[] {gs("one"), gs("two")}).get()); diff --git a/java/integTest/src/test/java/glide/standalone/CommandTests.java b/java/integTest/src/test/java/glide/standalone/CommandTests.java index a02bfe690b..321ad2fe34 100644 --- a/java/integTest/src/test/java/glide/standalone/CommandTests.java +++ b/java/integTest/src/test/java/glide/standalone/CommandTests.java @@ -4,6 +4,7 @@ import static glide.TestConfiguration.REDIS_VERSION; import static glide.TestUtilities.assertDeepEquals; import static glide.TestUtilities.checkFunctionListResponse; +import static glide.TestUtilities.checkFunctionListResponseBinary; import static glide.TestUtilities.checkFunctionStatsBinaryResponse; import static glide.TestUtilities.checkFunctionStatsResponse; import static glide.TestUtilities.commonClientConfig; @@ -605,29 +606,25 @@ public void function_commands_binary() { .get(); assertEquals("one", functionResult); - var flist = regularClient.functionList(false).get(); + var flist = regularClient.functionListBinary(false).get(); var expectedDescription = - new HashMap() { + new HashMap() { { - put(funcName.toString(), null); + put(funcName, null); } }; var expectedFlags = - new HashMap>() { + new HashMap>() { { - put(funcName.toString(), Set.of("no-writes")); + put(funcName, Set.of(gs("no-writes"))); } }; - checkFunctionListResponse( - flist, libName.toString(), expectedDescription, expectedFlags, Optional.empty()); + checkFunctionListResponseBinary( + flist, libName, expectedDescription, expectedFlags, Optional.empty()); - flist = regularClient.functionList(true).get(); - checkFunctionListResponse( - flist, - libName.toString(), - expectedDescription, - expectedFlags, - Optional.of(code.toString())); + flist = regularClient.functionListBinary(true).get(); + checkFunctionListResponseBinary( + flist, libName, expectedDescription, expectedFlags, Optional.of(code)); // re-load library without overwriting var executionException = @@ -659,19 +656,15 @@ public void function_commands_binary() { assertInstanceOf(RequestException.class, executionException.getCause()); assertTrue(executionException.getMessage().contains("Library not found")); - flist = regularClient.functionList(libName.toString(), false).get(); - expectedDescription.put(newFuncName.toString(), null); - expectedFlags.put(newFuncName.toString(), Set.of("no-writes")); - checkFunctionListResponse( - flist, libName.toString(), expectedDescription, expectedFlags, Optional.empty()); + flist = regularClient.functionListBinary(libName, false).get(); + expectedDescription.put(newFuncName, null); + expectedFlags.put(newFuncName, Set.of(gs("no-writes"))); + checkFunctionListResponseBinary( + flist, libName, expectedDescription, expectedFlags, Optional.empty()); - flist = regularClient.functionList(libName.toString(), true).get(); - checkFunctionListResponse( - flist, - libName.toString(), - expectedDescription, - expectedFlags, - Optional.of(newCode.toString())); + flist = regularClient.functionListBinary(libName, true).get(); + checkFunctionListResponseBinary( + flist, libName, expectedDescription, expectedFlags, Optional.of(newCode)); functionResult = regularClient From 473df92f1073c7d4bc142e565165f2f557355179 Mon Sep 17 00:00:00 2001 From: aws-talbenjo Date: Thu, 4 Jul 2024 15:08:49 +0300 Subject: [PATCH 16/23] randomkey binary support (#1805) * randomkey binary support --- .../src/main/java/glide/api/RedisClient.java | 6 ++++ .../java/glide/api/RedisClusterClient.java | 12 +++++++ .../api/commands/GenericClusterCommands.java | 36 +++++++++++++++++++ .../glide/api/commands/GenericCommands.java | 16 +++++++++ .../test/java/glide/api/RedisClientTest.java | 17 +++++++++ .../test/java/glide/cluster/CommandTests.java | 22 ++++++++++++ .../java/glide/standalone/CommandTests.java | 17 +++++++++ 7 files changed, 126 insertions(+) diff --git a/java/client/src/main/java/glide/api/RedisClient.java b/java/client/src/main/java/glide/api/RedisClient.java index ce2bfa3fcc..cdf10a3034 100644 --- a/java/client/src/main/java/glide/api/RedisClient.java +++ b/java/client/src/main/java/glide/api/RedisClient.java @@ -462,6 +462,12 @@ public CompletableFuture randomKey() { RandomKey, new String[0], this::handleStringOrNullResponse); } + @Override + public CompletableFuture randomKeyBinary() { + return commandManager.submitNewCommand( + RandomKey, new GlideString[0], this::handleGlideStringOrNullResponse); + } + @Override public CompletableFuture sort(@NonNull String key, @NonNull SortOptions sortOptions) { String[] arguments = ArrayUtils.addFirst(sortOptions.toArgs(), key); diff --git a/java/client/src/main/java/glide/api/RedisClusterClient.java b/java/client/src/main/java/glide/api/RedisClusterClient.java index 8e96ea2dff..508ebfcffb 100644 --- a/java/client/src/main/java/glide/api/RedisClusterClient.java +++ b/java/client/src/main/java/glide/api/RedisClusterClient.java @@ -1005,12 +1005,24 @@ public CompletableFuture randomKey(@NonNull Route route) { RandomKey, new String[0], route, this::handleStringOrNullResponse); } + @Override + public CompletableFuture randomKeyBinary(@NonNull Route route) { + return commandManager.submitNewCommand( + RandomKey, new GlideString[0], route, this::handleGlideStringOrNullResponse); + } + @Override public CompletableFuture randomKey() { return commandManager.submitNewCommand( RandomKey, new String[0], this::handleStringOrNullResponse); } + @Override + public CompletableFuture randomKeyBinary() { + return commandManager.submitNewCommand( + RandomKey, new GlideString[0], this::handleGlideStringOrNullResponse); + } + @Override public CompletableFuture scan(ClusterScanCursor cursor) { return commandManager diff --git a/java/client/src/main/java/glide/api/commands/GenericClusterCommands.java b/java/client/src/main/java/glide/api/commands/GenericClusterCommands.java index 9e9765e6c3..ac09255318 100644 --- a/java/client/src/main/java/glide/api/commands/GenericClusterCommands.java +++ b/java/client/src/main/java/glide/api/commands/GenericClusterCommands.java @@ -137,6 +137,25 @@ public interface GenericClusterCommands { */ CompletableFuture randomKey(Route route); + /** + * Returns a random key. + * + * @see redis.io for details. + * @param route Specifies the routing configuration for the command. The client will route the + * command to the nodes defined by route, and will return the first successful + * result. + * @return A random key from the database. + * @example + *
{@code
+     * String value = client.set("key", "value").get();
+     * String value_1 = client.set("key1", "value_1").get();
+     * GlideString key = client.randomKeyBinary(RANDOM).get();
+     * System.out.println("The random key is: " + key);
+     * // The value of key is either "key" or "key1"
+     * }
+ */ + CompletableFuture randomKeyBinary(Route route); + /** * Returns a random key.
* The command will be routed to all primary nodes, and will return the first successful result. @@ -154,6 +173,23 @@ public interface GenericClusterCommands { */ CompletableFuture randomKey(); + /** + * Returns a random key.
+ * The command will be routed to all primary nodes, and will return the first successful result. + * + * @see redis.io for details. + * @return A random key from the database. + * @example + *
{@code
+     * String value = client.set(gs("key"),gs( "value")).get();
+     * String value_1 = client.set(gs("key1"), gs("value_1")).get();
+     * GlideString key = client.randomKeyBinary().get();
+     * System.out.println("The random key is: " + key);
+     * // The value of key is either "key" or "key1"
+     * }
+ */ + CompletableFuture randomKeyBinary(); + /** * Incrementally iterates over the keys in the Cluster. * diff --git a/java/client/src/main/java/glide/api/commands/GenericCommands.java b/java/client/src/main/java/glide/api/commands/GenericCommands.java index d747e073a5..80cd91a009 100644 --- a/java/client/src/main/java/glide/api/commands/GenericCommands.java +++ b/java/client/src/main/java/glide/api/commands/GenericCommands.java @@ -198,6 +198,22 @@ CompletableFuture copy( */ CompletableFuture randomKey(); + /** + * Returns a random key from currently selected database. + * + * @see redis.io for details. + * @return A random key from the database. + * @example + *
{@code
+     * String value = client.set(gs("key"), gs("value")).get();
+     * String value_1 = client.set(gs("key1"), gs("value_1")).get();
+     * String key = client.randomKeyBinary().get();
+     * System.out.println("The random key is: " + key);
+     * // The value of key is either "key" or "key1"
+     * }
+ */ + CompletableFuture randomKeyBinary(); + /** * Sorts the elements in the list, set, or sorted set at key and returns the result. * The sort command can be used to sort elements based on different criteria and diff --git a/java/client/src/test/java/glide/api/RedisClientTest.java b/java/client/src/test/java/glide/api/RedisClientTest.java index 590efeadff..f9dbb589c6 100644 --- a/java/client/src/test/java/glide/api/RedisClientTest.java +++ b/java/client/src/test/java/glide/api/RedisClientTest.java @@ -7849,6 +7849,23 @@ public void randomKey() { assertEquals(testResponse, response); } + @SneakyThrows + @Test + public void randomKeyBinary() { + // setup + GlideString key1 = gs("key1"); + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(key1); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(RandomKey), eq(new GlideString[0]), any())) + .thenReturn(testResponse); + CompletableFuture response = service.randomKeyBinary(); + + // verify + assertEquals(testResponse, response); + } + @SneakyThrows @Test public void rename() { diff --git a/java/integTest/src/test/java/glide/cluster/CommandTests.java b/java/integTest/src/test/java/glide/cluster/CommandTests.java index 0abc88032e..bd604e71fd 100644 --- a/java/integTest/src/test/java/glide/cluster/CommandTests.java +++ b/java/integTest/src/test/java/glide/cluster/CommandTests.java @@ -2626,6 +2626,28 @@ public void randomKey() { assertNull(clusterClient.randomKey().get()); } + @Test + @SneakyThrows + public void randomKeyBinary() { + GlideString key1 = gs("{key}" + UUID.randomUUID()); + GlideString key2 = gs("{key}" + UUID.randomUUID()); + + assertEquals(OK, clusterClient.set(key1, gs("a")).get()); + assertEquals(OK, clusterClient.set(key2, gs("b")).get()); + + GlideString randomKey = clusterClient.randomKeyBinary().get(); + assertEquals(1L, clusterClient.exists(new GlideString[] {randomKey}).get()); + + GlideString randomKeyPrimaries = clusterClient.randomKeyBinary(ALL_PRIMARIES).get(); + assertEquals(1L, clusterClient.exists(new GlideString[] {randomKeyPrimaries}).get()); + + // no keys in database + assertEquals(OK, clusterClient.flushall(SYNC).get()); + + // no keys in database returns null + assertNull(clusterClient.randomKey().get()); + } + @Test @SneakyThrows public void sort() { diff --git a/java/integTest/src/test/java/glide/standalone/CommandTests.java b/java/integTest/src/test/java/glide/standalone/CommandTests.java index 321ad2fe34..1d7cc47e4e 100644 --- a/java/integTest/src/test/java/glide/standalone/CommandTests.java +++ b/java/integTest/src/test/java/glide/standalone/CommandTests.java @@ -1164,6 +1164,23 @@ public void randomkey() { assertNull(regularClient.randomKey().get()); } + @SneakyThrows + @Test + public void randomKeyBinary() { + GlideString key1 = gs("{key}" + UUID.randomUUID()); + GlideString key2 = gs("{key}" + UUID.randomUUID()); + + assertEquals(OK, regularClient.set(key1, gs("a")).get()); + assertEquals(OK, regularClient.set(key2, gs("b")).get()); + + GlideString randomKeyBinary = regularClient.randomKeyBinary().get(); + assertEquals(1L, regularClient.exists(new GlideString[] {randomKeyBinary}).get()); + + // no keys in database + assertEquals(OK, regularClient.flushall().get()); + assertNull(regularClient.randomKeyBinary().get()); + } + @Test @SneakyThrows public void sort() { From 2cf4c93e62b0d0ba38f338b3ce872c949bf72801 Mon Sep 17 00:00:00 2001 From: adarovadya Date: Thu, 4 Jul 2024 15:51:45 +0300 Subject: [PATCH 17/23] Python: add tests bytes (#1791) * Python: add tests bytes --------- Co-authored-by: Adar Ovadia --- python/python/tests/test_async_client.py | 62 +++++++++++++++++++++--- python/python/tests/test_transaction.py | 8 +++ 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/python/python/tests/test_async_client.py b/python/python/tests/test_async_client.py index cc1c51eccf..3f940beeee 100644 --- a/python/python/tests/test_async_client.py +++ b/python/python/tests/test_async_client.py @@ -140,6 +140,9 @@ async def test_send_and_receive_non_ascii_unicode(self, glide_client: TGlideClie assert value == "שלום hello 汉字" await glide_client.set(key, value) assert await glide_client.get(key) == value.encode() + # check set and get in bytes + await glide_client.set(key.encode(), value.encode()) + assert await glide_client.get(key.encode()) == value.encode() @pytest.mark.parametrize("value_size", [100, 2**16]) @pytest.mark.parametrize("cluster_mode", [True, False]) @@ -360,6 +363,21 @@ async def test_custom_command_multi_arg(self, glide_client: TGlideClient): assert b"id" in res assert b"cmd=client" in res + @pytest.mark.parametrize("cluster_mode", [True, False]) + @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) + async def test_custom_command_multi_arg_in_TEncodable( + self, glide_client: TGlideClient + ): + # Test multi args command + client_list = await glide_client.custom_command( + ["CLIENT", b"LIST", "TYPE", b"NORMAL"] + ) + assert isinstance(client_list, (bytes, list)) + res = get_first_result(client_list) + assert res is not None + assert b"id" in res + assert b"cmd=client" in res + @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_custom_command_lower_and_upper_case( @@ -447,6 +465,23 @@ async def test_move(self, glide_client: GlideClient): with pytest.raises(RequestError) as e: await glide_client.move(key, -1) + @pytest.mark.parametrize("cluster_mode", [False]) + @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) + async def test_move_with_bytes(self, glide_client: GlideClient): + key = get_random_string(10) + value = get_random_string(10) + + assert await glide_client.select(0) == OK + + assert await glide_client.set(key, value) == OK + assert await glide_client.get(key.encode()) == value.encode() + + assert await glide_client.move(key.encode(), 1) is True + assert await glide_client.get(key) is None + assert await glide_client.get(key.encode()) is None + assert await glide_client.select(1) == OK + assert await glide_client.get(key) == value.encode() + @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_delete(self, glide_client: TGlideClient): @@ -492,6 +527,7 @@ async def test_getrange(self, glide_client: TGlideClient): assert await glide_client.set(key, value) == OK assert await glide_client.getrange(key, 0, 3) == value_encoded[:4] assert await glide_client.getrange(key, -3, -1) == value_encoded[-3:] + assert await glide_client.getrange(key.encode(), -3, -1) == value_encoded[-3:] assert await glide_client.getrange(key, 0, -1) == value_encoded # out of range @@ -2706,10 +2742,11 @@ async def test_geosearchstore_by_box(self, glide_client: TGlideClient): async def test_geosearchstore_by_radius(self, glide_client: TGlideClient): key = f"{{testKey}}:{get_random_string(10)}" destination_key = f"{{testKey}}:{get_random_string(8)}" + # Checking when parts of the value contain bytes members_coordinates: Mapping[TEncodable, GeospatialData] = { - "Palermo": GeospatialData(13.361389, 38.115556), + b"Palermo": GeospatialData(13.361389, 38.115556), "Catania": GeospatialData(15.087269, 37.502669), - "edge1": GeospatialData(12.758489, 38.788135), + b"edge1": GeospatialData(12.758489, 38.788135), "edge2": GeospatialData(17.241510, 38.788135), } result = { @@ -4671,6 +4708,10 @@ async def test_type(self, glide_client: TGlideClient): assert (await glide_client.type(key)).lower() == b"string" assert await glide_client.delete([key]) == 1 + assert await glide_client.set(key.encode(), "value") == OK + assert (await glide_client.type(key.encode())).lower() == b"string" + assert await glide_client.delete([key.encode()]) == 1 + assert await glide_client.lpush(key, ["value"]) == 1 assert (await glide_client.type(key)).lower() == b"list" assert await glide_client.delete([key]) == 1 @@ -4708,12 +4749,21 @@ async def test_sort_and_sort_store_with_get_or_by_args( "user:5", ) - # Prepare some data + # Prepare some data. Some keys and values randomaly encoded assert await glide_client.hset(user_key1, {"name": "Alice", "age": "30"}) == 2 - assert await glide_client.hset(user_key2, {"name": "Bob", "age": "25"}) == 2 + assert ( + await glide_client.hset(user_key2.encode(), {"name": "Bob", "age": "25"}) + == 2 + ) assert await glide_client.hset(user_key3, {"name": "Charlie", "age": "35"}) == 2 - assert await glide_client.hset(user_key4, {"name": "Dave", "age": "20"}) == 2 - assert await glide_client.hset(user_key5, {"name": "Eve", "age": "40"}) == 2 + assert ( + await glide_client.hset(user_key4, {"name": "Dave", "age".encode(): "20"}) + == 2 + ) + assert ( + await glide_client.hset(user_key5, {"name": "Eve", "age": "40".encode()}) + == 2 + ) assert await glide_client.lpush("user_ids", ["5", "4", "3", "2", "1"]) == 5 # SORT_RO Available since: 7.0.0 diff --git a/python/python/tests/test_transaction.py b/python/python/tests/test_transaction.py index de878e5866..0c2175d4de 100644 --- a/python/python/tests/test_transaction.py +++ b/python/python/tests/test_transaction.py @@ -169,12 +169,20 @@ async def transaction_test( args.append(len(value)) transaction.get(key) args.append(value_bytes) + transaction.get(key.encode()) + args.append(value_bytes) transaction.type(key) args.append(b"string") + transaction.type(key.encode()) + args.append(b"string") transaction.echo(value) args.append(value_bytes) + transaction.echo(value.encode()) + args.append(value_bytes) transaction.strlen(key) args.append(len(value)) + transaction.strlen(key.encode()) + args.append(len(value)) transaction.append(key, value) args.append(len(value) * 2) From 043ffdc681296e8874dbbe70946123453528cb81 Mon Sep 17 00:00:00 2001 From: Shoham Elias <116083498+shohamazon@users.noreply.github.com> Date: Thu, 4 Jul 2024 16:00:37 +0300 Subject: [PATCH 18/23] Python: more renaming and doc fixes (#1804) --- examples/python/README.md | 2 +- python/python/glide/__init__.py | 8 +- python/python/glide/async_commands/bitmap.py | 4 +- .../glide/async_commands/cluster_commands.py | 58 +++--- .../glide/async_commands/command_args.py | 4 +- python/python/glide/async_commands/core.py | 167 +++++++++--------- .../python/glide/async_commands/sorted_set.py | 10 +- .../async_commands/standalone_commands.py | 40 ++--- python/python/glide/async_commands/stream.py | 78 ++++---- .../glide/async_commands/transaction.py | 106 +++++------ python/python/glide/config.py | 26 +-- python/python/glide/exceptions.py | 6 +- python/python/tests/conftest.py | 8 +- python/python/tests/test_async_client.py | 84 ++++----- python/python/tests/test_pubsub.py | 22 +-- python/python/tests/test_transaction.py | 4 +- python/python/tests/utils/utils.py | 6 +- 17 files changed, 317 insertions(+), 316 deletions(-) diff --git a/examples/python/README.md b/examples/python/README.md index be0e79160f..156627e6a3 100644 --- a/examples/python/README.md +++ b/examples/python/README.md @@ -1,5 +1,5 @@ ## Run -To run the example or any other Python application utilizing GLIDE for Redis, activate the virtual environment that created by the 'Build' stage: +To run the example or any other Python application utilizing Valkey GLIDE, activate the virtual environment that created by the 'Build' stage: ``` cd examples/python pip install -r requirements.txt diff --git a/python/python/glide/__init__.py b/python/python/glide/__init__.py index 53564a5127..61a0137275 100644 --- a/python/python/glide/__init__.py +++ b/python/python/glide/__init__.py @@ -74,7 +74,7 @@ PeriodicChecksStatus, ProtocolVersion, ReadFrom, - RedisCredentials, + ServerCredentials, ) from glide.constants import OK from glide.exceptions import ( @@ -82,7 +82,7 @@ ConfigurationError, ConnectionError, ExecAbortError, - RedisError, + GlideError, RequestError, TimeoutError, ) @@ -113,7 +113,7 @@ "ClusterClientConfiguration", "BackoffStrategy", "ReadFrom", - "RedisCredentials", + "ServerCredentials", "NodeAddress", "ProtocolVersion", "PeriodicChecksManualInterval", @@ -196,7 +196,7 @@ "ConfigurationError", "ConnectionError", "ExecAbortError", - "RedisError", + "GlideError", "RequestError", "TimeoutError", ] diff --git a/python/python/glide/async_commands/bitmap.py b/python/python/glide/async_commands/bitmap.py index c5cfdca0d3..46fdf61c70 100644 --- a/python/python/glide/async_commands/bitmap.py +++ b/python/python/glide/async_commands/bitmap.py @@ -9,7 +9,7 @@ class BitmapIndexType(Enum): Enumeration specifying if index arguments are BYTE indexes or BIT indexes. Can be specified in `OffsetOptions`, which is an optional argument to the `BITCOUNT` command. - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ BYTE = "BYTE" @@ -36,7 +36,7 @@ def __init__( start (int): The starting offset index. end (int): The ending offset index. index_type (Optional[BitmapIndexType]): The index offset type. This option can only be specified if you are - using Redis version 7.0.0 or above. Could be either `BitmapIndexType.BYTE` or `BitmapIndexType.BIT`. + using Valkey version 7.0.0 or above. Could be either `BitmapIndexType.BYTE` or `BitmapIndexType.BIT`. If no index type is provided, the indexes will be assumed to be byte indexes. """ self.start = start diff --git a/python/python/glide/async_commands/cluster_commands.py b/python/python/glide/async_commands/cluster_commands.py index 45efd16d7d..a6aa53f7c8 100644 --- a/python/python/glide/async_commands/cluster_commands.py +++ b/python/python/glide/async_commands/cluster_commands.py @@ -58,7 +58,7 @@ async def info( route: Optional[Route] = None, ) -> TClusterResponse[bytes]: """ - Get information and statistics about the Redis server. + Get information and statistics about the server. See https://valkey.io/commands/info/ for details. Args: @@ -87,7 +87,7 @@ async def exec( ) -> Optional[List[TResult]]: """ Execute a transaction by processing the queued commands. - See https://redis.io/topics/Transactions/ for details on Redis Transactions. + See https://redis.io/topics/Transactions/ for details on Transactions. Args: transaction (ClusterTransaction): A ClusterTransaction object containing a list of commands to be executed. @@ -109,7 +109,7 @@ async def config_resetstat( route: Optional[Route] = None, ) -> TOK: """ - Resets the statistics reported by Redis using the INFO and LATENCY HISTOGRAM commands. + Resets the statistics reported by the server using the INFO and LATENCY HISTOGRAM commands. See https://valkey.io/commands/config-resetstat/ for details. Args: @@ -173,7 +173,7 @@ async def ping( self, message: Optional[TEncodable] = None, route: Optional[Route] = None ) -> bytes: """ - Ping the Redis server. + Ping the server. See https://valkey.io/commands/ping/ for more details. Args: @@ -324,10 +324,10 @@ async def echo( {Address (bytes) : response (bytes) , ... } with type of Dict[bytes, bytes]. Examples: - >>> await client.echo(b"Glide-for-Redis") - b'Glide-for-Redis' - >>> await client.echo("Glide-for-Redis", AllNodes()) - {b'addr': b'Glide-for-Redis', b'addr2': b'Glide-for-Redis', b'addr3': b'Glide-for-Redis'} + >>> await client.echo(b"Valkey GLIDE") + b'Valkey GLIDE' + >>> await client.echo("Valkey GLIDE", AllNodes()) + {b'addr': b'Valkey GLIDE', b'addr2': b'Valkey GLIDE', b'addr3': b'Valkey GLIDE'} """ return cast( TClusterResponse[bytes], @@ -341,7 +341,7 @@ async def function_load( route: Optional[Route] = None, ) -> bytes: """ - Loads a library to Redis. + Loads a library to Valkey. See https://valkey.io/commands/function-load/ for more details. @@ -360,7 +360,7 @@ async def function_load( >>> await client.function_load(code, True, RandomNode()) b"mylib" - Since: Redis 7.0.0. + Since: Valkey 7.0.0. """ return cast( bytes, @@ -405,7 +405,7 @@ async def function_list( b"library_code": b"#!lua name=mylib \n redis.register_function('myfunc', function(keys, args) return args[1] end)" }] - Since: Redis 7.0.0. + Since: Valkey 7.0.0. """ args = [] if library_name_pattern is not None: @@ -441,7 +441,7 @@ async def function_flush( >>> await client.function_flush(FlushMode.SYNC) "OK" - Since: Redis 7.0.0. + Since: Valkey 7.0.0. """ return cast( TOK, @@ -472,7 +472,7 @@ async def function_delete( >>> await client.function_delete("my_lib") "OK" - Since: Redis 7.0.0. + Since: Valkey 7.0.0. """ return cast( TOK, @@ -510,7 +510,7 @@ async def fcall_route( >>> await client.fcall("Deep_Thought", ["Answer", "to", "the", "Ultimate", "Question", "of", "Life,", "the", "Universe,", "and", "Everything"], RandomNode()) b'new_value' # Returns the function's return value. - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ args = [function, "0"] if arguments is not None: @@ -545,7 +545,7 @@ async def fcall_ro_route( >>> await client.fcall_ro_route("Deep_Thought", ALL_NODES) 42 # The return value on the function that was executed - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ args: List[TEncodable] = [function, "0"] if arguments is not None: @@ -578,7 +578,7 @@ async def function_dump( >>> await client.function_restore(payload) "OK" # The serialized dump response was used to restore the libraries. - Since: Redis 7.0.0. + Since: Valkey 7.0.0. """ return cast( TClusterResponse[bytes], @@ -615,7 +615,7 @@ async def function_restore( >>> await client.function_restore(payload, FunctionRestorePolicy.FLUSH, AllPrimaries()) "OK" # The serialized dump response was used to restore the libraries with the specified route and policy. - Since: Redis 7.0.0. + Since: Valkey 7.0.0. """ args: List[TEncodable] = [payload] if policy is not None: @@ -832,7 +832,7 @@ async def publish( Args: message (TEncodable): Message to publish. channel (TEncodable): Channel to publish the message on. - sharded (bool): Use sharded pubsub mode. Available since Redis version 7.0. + sharded (bool): Use sharded pubsub mode. Available since Valkey version 7.0. Returns: int: Number of subscriptions in that node that received the message. @@ -942,7 +942,7 @@ async def copy( >>> await client.get("destination") b"sheep" - Since: Redis version 6.2.0. + Since: Valkey version 6.2.0. """ args: List[TEncodable] = [source, destination] if replace is True: @@ -959,7 +959,7 @@ async def lolwut( route: Optional[Route] = None, ) -> TClusterResponse[bytes]: """ - Displays a piece of generative computer art and the Redis version. + Displays a piece of generative computer art and the Valkey version. See https://valkey.io/commands/lolwut for more details. @@ -972,13 +972,13 @@ async def lolwut( in which case the client will route the command to the nodes defined by `route`. Returns: - TClusterResponse[bytes]: A piece of generative computer art along with the current Redis version. + TClusterResponse[bytes]: A piece of generative computer art along with the current Valkey version. When specifying a route other than a single node, response will be: {Address (bytes) : response (bytes) , ... } with type of Dict[bytes, bytes]. Examples: >>> await client.lolwut(6, [40, 20], RandomNode()); - b"Redis ver. 7.2.3" # Indicates the current Redis version + b"Redis ver. 7.2.3" # Indicates the current Valkey version """ args: List[TEncodable] = [] if version is not None: @@ -1108,28 +1108,28 @@ async def scan( Examples: >>> # In the following example, we will iterate over the keys in the cluster. - await redis_client.mset({b'key1': b'value1', b'key2': b'value2', b'key3': b'value3'}) + await client.mset({b'key1': b'value1', b'key2': b'value2', b'key3': b'value3'}) cursor = ClusterScanCursor() all_keys = [] while not cursor.is_finished(): - cursor, keys = await redis_client.scan(cursor, count=10) + cursor, keys = await client.scan(cursor, count=10) all_keys.extend(keys) print(all_keys) # [b'key1', b'key2', b'key3'] >>> # In the following example, we will iterate over the keys in the cluster that match the pattern "*key*". - await redis_client.mset({b"key1": b"value1", b"key2": b"value2", b"not_my_key": b"value3", b"something_else": b"value4"}) + await client.mset({b"key1": b"value1", b"key2": b"value2", b"not_my_key": b"value3", b"something_else": b"value4"}) cursor = ClusterScanCursor() all_keys = [] while not cursor.is_finished(): - cursor, keys = await redis_client.scan(cursor, match=b"*key*", count=10) + cursor, keys = await client.scan(cursor, match=b"*key*", count=10) all_keys.extend(keys) print(all_keys) # [b'my_key1', b'my_key2', b'not_my_key'] >>> # In the following example, we will iterate over the keys in the cluster that are of type STRING. - await redis_client.mset({b'key1': b'value1', b'key2': b'value2', b'key3': b'value3'}) - await redis_client.sadd(b"this_is_a_set", [b"value4"]) + await client.mset({b'key1': b'value1', b'key2': b'value2', b'key3': b'value3'}) + await client.sadd(b"this_is_a_set", [b"value4"]) cursor = ClusterScanCursor() all_keys = [] while not cursor.is_finished(): - cursor, keys = await redis_client.scan(cursor, type=ObjectType.STRING) + cursor, keys = await client.scan(cursor, type=ObjectType.STRING) all_keys.extend(keys) print(all_keys) # [b'key1', b'key2', b'key3'] """ diff --git a/python/python/glide/async_commands/command_args.py b/python/python/glide/async_commands/command_args.py index 2b00665a7d..92e0100665 100644 --- a/python/python/glide/async_commands/command_args.py +++ b/python/python/glide/async_commands/command_args.py @@ -6,12 +6,12 @@ class Limit: """ - Represents a limit argument for range queries in various Redis commands. + Represents a limit argument for range queries in various commands. The `LIMIT` argument is commonly used to specify a subset of results from the matching elements, similar to the `LIMIT` clause in SQL (e.g., `SELECT LIMIT offset, count`). - This class can be utilized in multiple Redis commands that support limit options, + This class can be utilized in multiple commands that support limit options, such as [ZRANGE](https://valkey.io/commands/zrange), [SORT](https://valkey.io/commands/sort/), and others. Args: diff --git a/python/python/glide/async_commands/core.py b/python/python/glide/async_commands/core.py index 4169b5d4af..e357bc2302 100644 --- a/python/python/glide/async_commands/core.py +++ b/python/python/glide/async_commands/core.py @@ -65,8 +65,8 @@ class ConditionalChange(Enum): """ A condition to the `SET`, `ZADD` and `GEOADD` commands. - - ONLY_IF_EXISTS - Only update key / elements that already exist. Equivalent to `XX` in the Redis API - - ONLY_IF_DOES_NOT_EXIST - Only set key / add elements that does not already exist. Equivalent to `NX` in the Redis API + - ONLY_IF_EXISTS - Only update key / elements that already exist. Equivalent to `XX` in the Valkey API. + - ONLY_IF_DOES_NOT_EXIST - Only set key / add elements that does not already exist. Equivalent to `NX` in the Valkey API. """ ONLY_IF_EXISTS = "XX" @@ -75,56 +75,56 @@ class ConditionalChange(Enum): class ExpiryType(Enum): """SET option: The type of the expiry. - - SEC - Set the specified expire time, in seconds. Equivalent to `EX` in the Redis API. - - MILLSEC - Set the specified expire time, in milliseconds. Equivalent to `PX` in the Redis API. - - UNIX_SEC - Set the specified Unix time at which the key will expire, in seconds. Equivalent to `EXAT` in the Redis API. + - SEC - Set the specified expire time, in seconds. Equivalent to `EX` in the Valkey API. + - MILLSEC - Set the specified expire time, in milliseconds. Equivalent to `PX` in the Valkey API. + - UNIX_SEC - Set the specified Unix time at which the key will expire, in seconds. Equivalent to `EXAT` in the Valkey API. - UNIX_MILLSEC - Set the specified Unix time at which the key will expire, in milliseconds. Equivalent to `PXAT` in the - Redis API. - - KEEP_TTL - Retain the time to live associated with the key. Equivalent to `KEEPTTL` in the Redis API. + Valkey API. + - KEEP_TTL - Retain the time to live associated with the key. Equivalent to `KEEPTTL` in the Valkey API. """ - SEC = 0, Union[int, timedelta] # Equivalent to `EX` in the Redis API - MILLSEC = 1, Union[int, timedelta] # Equivalent to `PX` in the Redis API - UNIX_SEC = 2, Union[int, datetime] # Equivalent to `EXAT` in the Redis API - UNIX_MILLSEC = 3, Union[int, datetime] # Equivalent to `PXAT` in the Redis API - KEEP_TTL = 4, Type[None] # Equivalent to `KEEPTTL` in the Redis API + SEC = 0, Union[int, timedelta] # Equivalent to `EX` in the Valkey API + MILLSEC = 1, Union[int, timedelta] # Equivalent to `PX` in the Valkey API + UNIX_SEC = 2, Union[int, datetime] # Equivalent to `EXAT` in the Valkey API + UNIX_MILLSEC = 3, Union[int, datetime] # Equivalent to `PXAT` in the Valkey API + KEEP_TTL = 4, Type[None] # Equivalent to `KEEPTTL` in the Valkey API class ExpiryTypeGetEx(Enum): """GetEx option: The type of the expiry. - - EX - Set the specified expire time, in seconds. Equivalent to `EX` in the Redis API. - - PX - Set the specified expire time, in milliseconds. Equivalent to `PX` in the Redis API. - - UNIX_SEC - Set the specified Unix time at which the key will expire, in seconds. Equivalent to `EXAT` in the Redis API. + - EX - Set the specified expire time, in seconds. Equivalent to `EX` in the Valkey API. + - PX - Set the specified expire time, in milliseconds. Equivalent to `PX` in the Valkey API. + - UNIX_SEC - Set the specified Unix time at which the key will expire, in seconds. Equivalent to `EXAT` in the Valkey API. - UNIX_MILLSEC - Set the specified Unix time at which the key will expire, in milliseconds. Equivalent to `PXAT` in the - Redis API. - - PERSIST - Remove the time to live associated with the key. Equivalent to `PERSIST` in the Redis API. + Valkey API. + - PERSIST - Remove the time to live associated with the key. Equivalent to `PERSIST` in the Valkey API. """ - SEC = 0, Union[int, timedelta] # Equivalent to `EX` in the Redis API - MILLSEC = 1, Union[int, timedelta] # Equivalent to `PX` in the Redis API - UNIX_SEC = 2, Union[int, datetime] # Equivalent to `EXAT` in the Redis API - UNIX_MILLSEC = 3, Union[int, datetime] # Equivalent to `PXAT` in the Redis API - PERSIST = 4, Type[None] # Equivalent to `PERSIST` in the Redis API + SEC = 0, Union[int, timedelta] # Equivalent to `EX` in the Valkey API + MILLSEC = 1, Union[int, timedelta] # Equivalent to `PX` in the Valkey API + UNIX_SEC = 2, Union[int, datetime] # Equivalent to `EXAT` in the Valkey API + UNIX_MILLSEC = 3, Union[int, datetime] # Equivalent to `PXAT` in the Valkey API + PERSIST = 4, Type[None] # Equivalent to `PERSIST` in the Valkey API class InfoSection(Enum): """ INFO option: a specific section of information: - -SERVER: General information about the Redis server + -SERVER: General information about the server -CLIENTS: Client connections section -MEMORY: Memory consumption related information -PERSISTENCE: RDB and AOF related information -STATS: General statistics -REPLICATION: Master/replica replication information -CPU: CPU consumption statistics - -COMMANDSTATS: Redis command statistics - -LATENCYSTATS: Redis command latency percentile distribution statistics - -SENTINEL: Redis Sentinel section (only applicable to Sentinel instances) - -CLUSTER: Redis Cluster section + -COMMANDSTATS: Valkey command statistics + -LATENCYSTATS: Valkey command latency percentile distribution statistics + -SENTINEL: Valkey Sentinel section (only applicable to Sentinel instances) + -CLUSTER: Valkey Cluster section -MODULES: Modules section -KEYSPACE: Database related statistics - -ERRORSTATS: Redis error statistics + -ERRORSTATS: Valkey error statistics -ALL: Return all sections (excluding module generated ones) -DEFAULT: Return only the default set of sections -EVERYTHING: Includes all and modules @@ -154,11 +154,11 @@ class ExpireOptions(Enum): """ EXPIRE option: options for setting key expiry. - - HasNoExpiry: Set expiry only when the key has no expiry (Equivalent to "NX" in Redis). - - HasExistingExpiry: Set expiry only when the key has an existing expiry (Equivalent to "XX" in Redis). + - HasNoExpiry: Set expiry only when the key has no expiry (Equivalent to "NX" in Valkey). + - HasExistingExpiry: Set expiry only when the key has an existing expiry (Equivalent to "XX" in Valkey). - NewExpiryGreaterThanCurrent: Set expiry only when the new expiry is greater than the current one (Equivalent - to "GT" in Redis). - - NewExpiryLessThanCurrent: Set expiry only when the new expiry is less than the current one (Equivalent to "LT" in Redis). + to "GT" in Valkey). + - NewExpiryLessThanCurrent: Set expiry only when the new expiry is less than the current one (Equivalent to "LT" in Valkey). """ HasNoExpiry = "NX" @@ -402,12 +402,12 @@ async def set( key (TEncodable): the key to store. value (TEncodable): the value to store with the given key. conditional_set (Optional[ConditionalChange], optional): set the key only if the given condition is met. - Equivalent to [`XX` | `NX`] in the Redis API. Defaults to None. + Equivalent to [`XX` | `NX`] in the Valkey API. Defaults to None. expiry (Optional[ExpirySet], optional): set expiriation to the given key. - Equivalent to [`EX` | `PX` | `EXAT` | `PXAT` | `KEEPTTL`] in the Redis API. Defaults to None. + Equivalent to [`EX` | `PX` | `EXAT` | `PXAT` | `KEEPTTL`] in the Valkey API. Defaults to None. return_old_value (bool, optional): Return the old value stored at key, or None if key did not exist. An error is returned and SET aborted if the value stored at key is not a string. - Equivalent to `GET` in the Redis API. Defaults to False. + Equivalent to `GET` in the Valkey API. Defaults to False. Returns: Optional[bytes]: @@ -708,7 +708,7 @@ async def setrange(self, key: TEncodable, offset: int, value: TEncodable) -> int Examples: >>> await client.set("key", "Hello World") - >>> await client.setrange("key", 6, "Redis") + >>> await client.setrange("key", 6, "Glide") 11 # The length of the string stored at `key` after it was modified. """ return cast( @@ -1397,7 +1397,7 @@ async def lmpop( >>> await client.lmpop(["testKey"], ListDirection.LEFT, 2) {b"testKey": [b"three", b"two"]} - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ args = [str(len(keys)), *keys, direction.value] if count is not None: @@ -1440,7 +1440,7 @@ async def blmpop( >>> await client.blmpop(["testKey"], ListDirection.LEFT, 0.1, 2) {b"testKey": [b"three", b"two"]} - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ args = [str(timeout), str(len(keys)), *keys, direction.value] if count is not None: @@ -1740,7 +1740,7 @@ async def lmove( >>> await client.lrange("testKey2", 0, -1) [b"one", b"three", b"four"] - Since: Redis version 6.2.0. + Since: Valkey version 6.2.0. """ return cast( Optional[bytes], @@ -1790,7 +1790,7 @@ async def blmove( >>> updated_array2 = await client.lrange("testKey2", 0, -1) [b"one", b"three", bb"four"] - Since: Redis version 6.2.0. + Since: Valkey version 6.2.0. """ return cast( Optional[bytes], @@ -2493,7 +2493,7 @@ async def expiretime(self, key: TEncodable) -> int: >>> await client.expiretime("my_key") 1718614954 - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ return cast(int, await self._execute_command(RequestType.ExpireTime, [key])) @@ -2520,7 +2520,7 @@ async def pexpiretime(self, key: TEncodable) -> int: >>> await client.pexpiretime("my_key") 1718615446670 - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ return cast(int, await self._execute_command(RequestType.PExpireTime, [key])) @@ -3013,7 +3013,7 @@ async def xgroup_set_id( group_name (TEncodable): The consumer group name. stream_id (TEncodable): The stream entry ID that should be set as the last delivered ID for the consumer group. entries_read: (Optional[int]): A value representing the number of stream entries already read by the - group. This option can only be specified if you are using Redis version 7.0.0 or above. + group. This option can only be specified if you are using Valkey version 7.0.0 or above. Returns: TOK: A simple "OK" response. @@ -3265,7 +3265,7 @@ async def xclaim_just_id( ) -> List[TEncodable]: """ Changes the ownership of a pending message. This function returns a List with - only the message/entry IDs, and is equivalent to using JUSTID in the Redis API. + only the message/entry IDs, and is equivalent to using JUSTID in the Valkey API. See https://valkey.io/commands/xclaim for more details. @@ -3299,7 +3299,7 @@ async def xclaim_just_id( consumer, str(min_idle_time_ms), *ids, - StreamClaimOptions.JUST_ID_REDIS_API, + StreamClaimOptions.JUST_ID_VALKEY_API, ] if options: @@ -3340,12 +3340,12 @@ async def xautoclaim( scanned. - A mapping of the claimed entries, with the keys being the claimed entry IDs and the values being a 2D list of the field-value pairs in the format `[[field1, value1], [field2, value2], ...]`. - - If you are using Redis 7.0.0 or above, the response list will also include a list containing the + - If you are using Valkey 7.0.0 or above, the response list will also include a list containing the message IDs that were in the Pending Entries List but no longer exist in the stream. These IDs are deleted from the Pending Entries List. Examples: - # Redis version < 7.0.0: + # Valkey version < 7.0.0: >>> await client.xautoclaim("my_stream", "my_group", "my_consumer", 3_600_000, "0-0") [ b"0-0", @@ -3359,7 +3359,7 @@ async def xautoclaim( # Stream entry "1-1" was idle for over an hour and was thus claimed by "my_consumer". The entire stream # was scanned. - # Redis version 7.0.0 and above: + # Valkey version 7.0.0 and above: >>> await client.xautoclaim("my_stream", "my_group", "my_consumer", 3_600_000, "0-0") [ b"0-0", @@ -3375,7 +3375,7 @@ async def xautoclaim( # was scanned. Additionally, entry "1-2" was removed from the Pending Entries List because it no longer # exists in the stream. - Since: Redis version 6.2.0. + Since: Valkey version 6.2.0. """ args: List[TEncodable] = [ key, @@ -3423,25 +3423,25 @@ async def xautoclaim_just_id( to the next ID in the stream after the entries that were scanned, or "0-0" if the entire stream was scanned. - A list of the IDs for the claimed entries. - - If you are using Redis 7.0.0 or above, the response list will also include a list containing the + - If you are using Valkey 7.0.0 or above, the response list will also include a list containing the message IDs that were in the Pending Entries List but no longer exist in the stream. These IDs are deleted from the Pending Entries List. Examples: - # Redis version < 7.0.0: + # Valkey version < 7.0.0: >>> await client.xautoclaim_just_id("my_stream", "my_group", "my_consumer", 3_600_000, "0-0") [b"0-0", [b"1-1"]] # Stream entry "1-1" was idle for over an hour and was thus claimed by "my_consumer". The entire stream # was scanned. - # Redis version 7.0.0 and above: + # Valkey version 7.0.0 and above: >>> await client.xautoclaim_just_id("my_stream", "my_group", "my_consumer", 3_600_000, "0-0") [b"0-0", [b"1-1"], [b"1-2"]] # Stream entry "1-1" was idle for over an hour and was thus claimed by "my_consumer". The entire stream # was scanned. Additionally, entry "1-2" was removed from the Pending Entries List because it no longer # exists in the stream. - Since: Redis version 6.2.0. + Since: Valkey version 6.2.0. """ args: List[TEncodable] = [ key, @@ -3484,8 +3484,8 @@ async def xinfo_groups( b"consumers": 2, b"pending": 2, b"last-delivered-id": b"1638126030001-0", - b"entries-read": 2, # The "entries-read" field was added in Redis version 7.0.0. - b"lag": 0, # The "lag" field was added in Redis version 7.0.0. + b"entries-read": 2, # The "entries-read" field was added in Valkey version 7.0.0. + b"lag": 0, # The "lag" field was added in Valkey version 7.0.0. }, { b"name": b"some-other-group", @@ -3529,7 +3529,7 @@ async def xinfo_consumers( b"name": b"Alice", b"pending": 1, b"idle": 9104628, - b"inactive": 18104698, # The "inactive" field was added in Redis version 7.2.0. + b"inactive": 18104698, # The "inactive" field was added in Valkey version 7.2.0. }, { b"name": b"Bob", @@ -3760,7 +3760,7 @@ async def geosearch( ], ] # Returns locations within the square box of 400 km, with the center being a specific point, from nearest to farthest with the dist, hash and coords. - Since: Redis version 6.2.0. + Since: Valkey version 6.2.0. """ args = _create_geosearch_args( [key], @@ -3825,7 +3825,7 @@ async def geosearchstore( >>> await client.zrange_withscores("my_dest_sorted_set", RangeByIndex(0, -1)) {b"Catania": 56.4412578701582, b"Palermo": 190.44242984775784} # The elements within te search area, with the distance as score. - Since: Redis version 6.2.0. + Since: Valkey version 6.2.0. """ args = _create_geosearch_args( [destination, source], @@ -4370,7 +4370,7 @@ async def zrank_withscore( >>> await client.zrank_withscore("my_sorted_set", "non_existing_member") None # Indicates that "non_existing_member" is not present in the sorted set "my_sorted_set". - Since: Redis version 7.2.0. + Since: Valkey version 7.2.0. """ return cast( Optional[List[Union[int, float]]], @@ -4427,7 +4427,7 @@ async def zrevrank_withscore( >>> await client.zrevrank("my_sorted_set", "member2") [2, 8.2] # "member2" with score 8.2 has the third-highest score in the sorted set "my_sorted_set" - Since: Redis version 7.2.0. + Since: Valkey version 7.2.0. """ return cast( Optional[List[Union[int, float]]], @@ -5145,7 +5145,7 @@ async def zmpop( >>> await client.zmpop(["zSet1", "zSet2"], ScoreFilter.MAX, 2) [b'zSet1', {b'three': 3.0, b'two': 2.0}] # "three" with score 3.0 and "two" with score 2.0 were popped from "zSet1". - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ args: List[TEncodable] = [str(len(keys))] + keys + [filter.value] if count is not None: @@ -5198,7 +5198,7 @@ async def bzmpop( >>> await client.bzmpop(["zSet1", "zSet2"], ScoreFilter.MAX, 0.5, 2) [b'zSet1', {b'three': 3.0, b'two': 2.0}] # "three" with score 3.0 and "two" with score 2.0 were popped from "zSet1". - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ args = [str(timeout), str(len(keys))] + keys + [modifier.value] if count is not None: @@ -5238,7 +5238,7 @@ async def zintercard( >>> await client.zintercard(["key1", "key2"], 1) 1 # A `limit` of 1 was provided, so the intersection computation exits early and yields the `limit` value of 1. - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ args = [str(len(keys))] + keys if limit is not None: @@ -5257,10 +5257,10 @@ async def invoke_script( ) -> TResult: """ Invokes a Lua script with its keys and arguments. - This method simplifies the process of invoking scripts on a Redis server by using an object that represents a Lua script. + This method simplifies the process of invoking scripts on a the server by using an object that represents a Lua script. The script loading, argument preparation, and execution will all be handled internally. - If the script has not already been loaded, it will be loaded automatically using the Redis `SCRIPT LOAD` command. - After that, it will be invoked using the Redis `EVALSHA` command. + If the script has not already been loaded, it will be loaded automatically using the `SCRIPT LOAD` command. + After that, it will be invoked using the `EVALSHA` command. See https://valkey.io/commands/script-load/ and https://valkey.io/commands/evalsha/ for more details. @@ -5502,7 +5502,7 @@ async def bitpos_interval( numbers indicating offsets starting at the end of the list, with `-1` being the last element of the list, `-2` being the penultimate, and so on. - If you are using Redis 7.0.0 or above, the optional `index_type` can also be provided to specify whether the + If you are using Valkey 7.0.0 or above, the optional `index_type` can also be provided to specify whether the `start` and `end` offsets specify BIT or BYTE offsets. If `index_type` is not provided, BYTE offsets are assumed. If BIT is specified, `start=0` and `end=2` means to look at the first three bits. If BYTE is specified, `start=0` and `end=2` means to look at the first three bytes. @@ -5515,7 +5515,7 @@ async def bitpos_interval( start (int): The starting offset. end (int): The ending offset. index_type (Optional[BitmapIndexType]): The index offset type. This option can only be specified if you are - using Redis version 7.0.0 or above. Could be either `BitmapIndexType.BYTE` or `BitmapIndexType.BIT`. + using Valkey version 7.0.0 or above. Could be either `BitmapIndexType.BYTE` or `BitmapIndexType.BIT`. If no index type is provided, the indexes will be assumed to be byte indexes. Returns: @@ -5635,7 +5635,7 @@ async def bitfield_read_only( >>> await client.bitfield_read_only("my_key", [BitFieldGet(UnsignedEncoding(2), Offset(1))]) [2] # The value at offset 1 with an unsigned encoding of 2 is 3. - Since: Redis version 6.0.0. + Since: Valkey version 6.0.0. """ args = [key] + _create_bitfield_read_only_args(subcommands) return cast( @@ -5667,7 +5667,7 @@ async def object_encoding(self, key: TEncodable) -> Optional[bytes]: async def object_freq(self, key: TEncodable) -> Optional[int]: """ - Returns the logarithmic access frequency counter of a Redis object stored at `key`. + Returns the logarithmic access frequency counter of a Valkey object stored at `key`. See https://valkey.io/commands/object-freq for more details. @@ -5795,7 +5795,7 @@ async def getex( Args: key (TEncodable): The key to get. expiry (Optional[ExpiryGetEx], optional): set expiriation to the given key. - Equivalent to [`EX` | `PX` | `EXAT` | `PXAT` | `PERSIST`] in the Redis API. + Equivalent to [`EX` | `PX` | `EXAT` | `PXAT` | `PERSIST`] in the Valkey API. Returns: Optional[bytes]: @@ -5813,7 +5813,7 @@ async def getex( >>> await client.getex(b"key") None - Since: Redis version 6.2.0. + Since: Valkey version 6.2.0. """ args = [key] if expiry is not None: @@ -5940,7 +5940,7 @@ async def sscan( # Assume "key" contains a set with 130 members >>> result_cursor = "0" >>> while True: - ... result = await redis_client.sscan("key", "0", match="*") + ... result = await client.sscan("key", "0", match="*") ... new_cursor = str(result [0]) ... print("Cursor: ", new_cursor) ... print("Members: ", result[1]) @@ -6001,7 +6001,7 @@ async def zscan( # Assume "key" contains a sorted set with multiple members >>> result_cursor = "0" >>> while True: - ... result = await redis_client.zscan("key", "0", match="*", count=5) + ... result = await client.zscan("key", "0", match="*", count=5) ... new_cursor = str(result [0]) ... print("Cursor: ", new_cursor) ... print("Members: ", result[1]) @@ -6062,7 +6062,7 @@ async def hscan( # Assume "key" contains a hash with multiple members >>> result_cursor = "0" >>> while True: - ... result = await redis_client.hscan("key", "0", match="*", count=3) + ... result = await client.hscan("key", "0", match="*", count=3) ... new_cursor = str(result [0]) ... print("Cursor: ", new_cursor) ... print("Members: ", result[1]) @@ -6110,7 +6110,8 @@ async def fcall( Example: >>> await client.fcall("Deep_Thought") b'new_value' # Returns the function's return value. - Since: Redis version 7.0.0. + + Since: Valkey version 7.0.0. """ args: List[TEncodable] = [] if keys is not None: @@ -6153,7 +6154,7 @@ async def fcall_ro( "Ultimate", "Question", "of", "Life,", "the", "Universe,", "and", "Everything"]) 42 # The return value on the function that was executed - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ args: List[TEncodable] = [] if keys is not None: @@ -6188,7 +6189,7 @@ async def watch(self, keys: List[TEncodable]) -> TOK: >>> await client.watch("sampleKey") 'OK' >>> transaction.set("sampleKey", "foobar") - >>> await redis_client.exec(transaction) + >>> await client.exec(transaction) 'OK' # Executes successfully and keys are unwatched. >>> await client.watch("sampleKey") @@ -6196,7 +6197,7 @@ async def watch(self, keys: List[TEncodable]) -> TOK: >>> transaction.set("sampleKey", "foobar") >>> await client.set("sampleKey", "hello world") 'OK' - >>> await redis_client.exec(transaction) + >>> await client.exec(transaction) None # None is returned when the watched key is modified before transaction execution. """ @@ -6284,7 +6285,7 @@ async def lcs( >>> await client.lcs("testKey1", "testKey2") b'acd' - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ args: List[TEncodable] = [key1, key2] @@ -6322,7 +6323,7 @@ async def lcs_len( >>> await client.lcs_len("testKey1", "testKey2") 3 # the length of the longest common subsequence between these 2 strings (b"acd") is 3. - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ args: List[TEncodable] = [key1, key2, "LEN"] @@ -6409,7 +6410,7 @@ async def lcs_idx( b'len': 7 } - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ args: List[TEncodable] = [key1, key2, "IDX"] @@ -6464,7 +6465,7 @@ async def lpos( >>> await client.lpos(key, 'c', count = 0) [2, 6, 7] - Since: Redis version 6.0.6. + Since: Valkey version 6.0.6. """ args: List[TEncodable] = [key, element] diff --git a/python/python/glide/async_commands/sorted_set.py b/python/python/glide/async_commands/sorted_set.py index 95968a8488..76ec384712 100644 --- a/python/python/glide/async_commands/sorted_set.py +++ b/python/python/glide/async_commands/sorted_set.py @@ -73,7 +73,7 @@ class ScoreBoundary: """ def __init__(self, value: float, is_inclusive: bool = True): - # Convert the score boundary to the Redis protocol format + # Convert the score boundary to Valkey protocol format self.value = str(value) if is_inclusive else f"({value}" @@ -87,7 +87,7 @@ class LexBoundary: """ def __init__(self, value: str, is_inclusive: bool = True): - # Convert the lexicographic boundary to the Redis protocol format + # Convert the lexicographic boundary to Valkey protocol format self.value = f"[{value}" if is_inclusive else f"({value}" @@ -213,7 +213,7 @@ def __init__(self, radius: float, unit: GeoUnit): def to_args(self) -> List[str]: """ - Convert the search criteria to the corresponding part of the Redis command. + Convert the search criteria to the corresponding part of the command. Returns: List[str]: List representation of the search criteria. @@ -241,7 +241,7 @@ def __init__(self, width: float, height: float, unit: GeoUnit): def to_args(self) -> List[str]: """ - Convert the search criteria to the corresponding part of the Redis command. + Convert the search criteria to the corresponding part of the command. Returns: List[str]: List representation of the search criteria. @@ -268,7 +268,7 @@ def __init__(self, count: int, any_option: bool = False): def to_args(self) -> List[str]: """ - Convert the count option to the corresponding part of the Redis command. + Convert the count option to the corresponding part of the command. Returns: List[str]: List representation of the count option. diff --git a/python/python/glide/async_commands/standalone_commands.py b/python/python/glide/async_commands/standalone_commands.py index 781a3ec6c0..5acdad2855 100644 --- a/python/python/glide/async_commands/standalone_commands.py +++ b/python/python/glide/async_commands/standalone_commands.py @@ -41,7 +41,7 @@ async def info( sections: Optional[List[InfoSection]] = None, ) -> bytes: """ - Get information and statistics about the Redis server. + Get information and statistics about the server. See https://valkey.io/commands/info/ for details. Args: @@ -63,7 +63,7 @@ async def exec( ) -> Optional[List[TResult]]: """ Execute a transaction by processing the queued commands. - See https://redis.io/topics/Transactions/ for details on Redis Transactions. + See https://redis.io/topics/Transactions/ for details on Transactions. Args: transaction (Transaction): A Transaction object containing a list of commands to be executed. @@ -79,7 +79,7 @@ async def exec( async def select(self, index: int) -> TOK: """ - Change the currently selected Redis database. + Change the currently selected database. See https://valkey.io/commands/select/ for details. Args: @@ -92,7 +92,7 @@ async def select(self, index: int) -> TOK: async def config_resetstat(self) -> TOK: """ - Resets the statistics reported by Redis using the INFO and LATENCY HISTOGRAM commands. + Resets the statistics reported by the server using the INFO and LATENCY HISTOGRAM commands. See https://valkey.io/commands/config-resetstat/ for details. Returns: @@ -124,7 +124,7 @@ async def client_id( async def ping(self, message: Optional[TEncodable] = None) -> bytes: """ - Ping the Redis server. + Ping the server. See https://valkey.io/commands/ping/ for more details. Args: @@ -230,8 +230,8 @@ async def echo(self, message: TEncodable) -> bytes: bytes: The provided `message`. Examples: - >>> await client.echo("Glide-for-Redis") - b'Glide-for-Redis' + >>> await client.echo("Valkey GLIDE") + b'Valkey GLIDE' """ return cast(bytes, await self._execute_command(RequestType.Echo, [message])) @@ -239,7 +239,7 @@ async def function_load( self, library_code: TEncodable, replace: bool = False ) -> bytes: """ - Loads a library to Redis. + Loads a library to Valkey. See https://valkey.io/commands/function-load/ for more details. @@ -256,7 +256,7 @@ async def function_load( >>> await client.function_load(code, True) b"mylib" - Since: Redis 7.0.0. + Since: Valkey 7.0.0. """ return cast( bytes, @@ -292,10 +292,10 @@ async def function_list( b"description": None, b"flags": {b"no-writes"}, }], - b"library_code": b"#!lua name=mylib \n redis.register_function('myfunc', function(keys, args) return args[1] end)" + b"library_code": b"#!lua name=mylib \n sever.register_function('myfunc', function(keys, args) return args[1] end)" }] - Since: Redis 7.0.0. + Since: Valkey 7.0.0. """ args = [] if library_name_pattern is not None: @@ -326,7 +326,7 @@ async def function_flush(self, mode: Optional[FlushMode] = None) -> TOK: >>> await client.function_flush(FlushMode.SYNC) "OK" - Since: Redis 7.0.0. + Since: Valkey 7.0.0. """ return cast( TOK, @@ -352,7 +352,7 @@ async def function_delete(self, library_name: TEncodable) -> TOK: >>> await client.function_delete("my_lib") "OK" - Since: Redis 7.0.0. + Since: Valkey 7.0.0. """ return cast( TOK, @@ -378,7 +378,7 @@ async def function_dump(self) -> bytes: >>> await client.function_restore(payload) "OK" # The serialized dump response was used to restore the libraries. - Since: Redis 7.0.0. + Since: Valkey 7.0.0. """ return cast(bytes, await self._execute_command(RequestType.FunctionDump, [])) @@ -406,7 +406,7 @@ async def function_restore( >>> await client.function_restore(payload, FunctionRestorePolicy.FLUSH) "OK" # The serialized dump response was used to restore the libraries with the specified policy. - Since: Redis 7.0.0. + Since: Valkey 7.0.0. """ args: List[TEncodable] = [payload] if policy is not None: @@ -768,7 +768,7 @@ async def copy( >>> await client.get("destination") b"sheep" - Since: Redis version 6.2.0. + Since: Valkey version 6.2.0. """ args: List[TEncodable] = [source, destination] if destinationDB is not None: @@ -786,7 +786,7 @@ async def lolwut( parameters: Optional[List[int]] = None, ) -> bytes: """ - Displays a piece of generative computer art and the Redis version. + Displays a piece of generative computer art and the Valkey version. See https://valkey.io/commands/lolwut for more details. @@ -797,13 +797,13 @@ async def lolwut( For version `6`, those are number of columns and number of lines. Returns: - bytes: A piece of generative computer art along with the current Redis version. + bytes: A piece of generative computer art along with the current Valkey version. Examples: >>> await client.lolwut(6, [40, 20]); - b"Redis ver. 7.2.3" # Indicates the current Redis version + b"Redis ver. 7.2.3" # Indicates the current Valkey version >>> await client.lolwut(5, [30, 5, 5]); - b"Redis ver. 7.2.3" # Indicates the current Redis version + b"Redis ver. 7.2.3" # Indicates the current Valkey version """ args: List[TEncodable] = [] if version is not None: diff --git a/python/python/glide/async_commands/stream.py b/python/python/glide/async_commands/stream.py index 1904c7ba14..33f6ff6224 100644 --- a/python/python/glide/async_commands/stream.py +++ b/python/python/glide/async_commands/stream.py @@ -42,10 +42,10 @@ def __init__( def to_args(self) -> List[str]: """ - Convert options to arguments for Redis command. + Convert options to arguments for the command. Returns: - List[str]: List of arguments for Redis command. + List[str]: List of arguments for the command. """ option_args = [ self.method, @@ -120,10 +120,10 @@ def __init__( def to_args(self) -> List[TEncodable]: """ - Convert options to arguments for Redis command. + Convert options to arguments for the command. Returns: - List[str]: List of arguments for Redis command. + List[str]: List of arguments for the command. """ option_args: List[TEncodable] = [] if not self.make_stream: @@ -155,10 +155,10 @@ class MinId(StreamRangeBound): to get the first stream ID. """ - MIN_RANGE_REDIS_API = "-" + MIN_RANGE_VALKEY_API = "-" def to_arg(self) -> str: - return self.MIN_RANGE_REDIS_API + return self.MIN_RANGE_VALKEY_API class MaxId(StreamRangeBound): @@ -167,10 +167,10 @@ class MaxId(StreamRangeBound): to get the last stream ID. """ - MAX_RANGE_REDIS_API = "+" + MAX_RANGE_VALKEY_API = "+" def to_arg(self) -> str: - return self.MAX_RANGE_REDIS_API + return self.MAX_RANGE_VALKEY_API class IdBound(StreamRangeBound): @@ -209,10 +209,10 @@ class ExclusiveIdBound(StreamRangeBound): a timestamp and sequence number separated by a dash ("-"), for example "1526985054069-0". Stream ID bounds can also be incomplete, with just a timestamp. - Since: Redis version 6.2.0. + Since: Valkey version 6.2.0. """ - EXCLUSIVE_BOUND_REDIS_API = "(" + EXCLUSIVE_BOUND_VALKEY_API = "(" @staticmethod def from_timestamp(timestamp: int) -> ExclusiveIdBound: @@ -233,15 +233,15 @@ def __init__(self, stream_id: TEncodable): """ if isinstance(stream_id, bytes): stream_id = stream_id.decode("utf-8") - self.stream_id = f"{self.EXCLUSIVE_BOUND_REDIS_API}{stream_id}" + self.stream_id = f"{self.EXCLUSIVE_BOUND_VALKEY_API}{stream_id}" def to_arg(self) -> TEncodable: return self.stream_id class StreamReadOptions: - READ_COUNT_REDIS_API = "COUNT" - READ_BLOCK_REDIS_API = "BLOCK" + READ_COUNT_VALKEY_API = "COUNT" + READ_BLOCK_VALKEY_API = "BLOCK" def __init__(self, block_ms: Optional[int] = None, count: Optional[int] = None): """ @@ -249,8 +249,8 @@ def __init__(self, block_ms: Optional[int] = None, count: Optional[int] = None): Args: block_ms (Optional[int]): If provided, the request will be blocked for the set amount of milliseconds or - until the server has the required number of entries. Equivalent to `BLOCK` in the Redis API. - count (Optional[int]): The maximum number of elements requested. Equivalent to `COUNT` in the Redis API. + until the server has the required number of entries. Equivalent to `BLOCK` in the Valkey API. + count (Optional[int]): The maximum number of elements requested. Equivalent to `COUNT` in the Valkey API. """ self.block_ms = block_ms self.count = count @@ -264,17 +264,17 @@ def to_args(self) -> List[TEncodable]: """ args: List[TEncodable] = [] if self.block_ms is not None: - args.extend([self.READ_BLOCK_REDIS_API, str(self.block_ms)]) + args.extend([self.READ_BLOCK_VALKEY_API, str(self.block_ms)]) if self.count is not None: - args.extend([self.READ_COUNT_REDIS_API, str(self.count)]) + args.extend([self.READ_COUNT_VALKEY_API, str(self.count)]) return args class StreamGroupOptions: - MAKE_STREAM_REDIS_API = "MKSTREAM" - ENTRIES_READ_REDIS_API = "ENTRIESREAD" + MAKE_STREAM_VALKEY_API = "MKSTREAM" + ENTRIES_READ_VALKEY_API = "ENTRIESREAD" def __init__(self, make_stream: bool = False, entries_read: Optional[int] = None): """ @@ -284,7 +284,7 @@ def __init__(self, make_stream: bool = False, entries_read: Optional[int] = None make_stream (bool): If set to True and the stream doesn't exist, this creates a new stream with a length of 0. entries_read: (Optional[int]): A value representing the number of stream entries already read by the - group. This option can only be specified if you are using Redis version 7.0.0 or above. + group. This option can only be specified if you are using Valkey version 7.0.0 or above. """ self.make_stream = make_stream self.entries_read = entries_read @@ -298,16 +298,16 @@ def to_args(self) -> List[TEncodable]: """ args: List[TEncodable] = [] if self.make_stream is True: - args.append(self.MAKE_STREAM_REDIS_API) + args.append(self.MAKE_STREAM_VALKEY_API) if self.entries_read is not None: - args.extend([self.ENTRIES_READ_REDIS_API, str(self.entries_read)]) + args.extend([self.ENTRIES_READ_VALKEY_API, str(self.entries_read)]) return args class StreamReadGroupOptions(StreamReadOptions): - READ_NOACK_REDIS_API = "NOACK" + READ_NOACK_VALKEY_API = "NOACK" def __init__( self, no_ack=False, block_ms: Optional[int] = None, count: Optional[int] = None @@ -318,10 +318,10 @@ def __init__( Args: no_ack (bool): If set, messages are not added to the Pending Entries List (PEL). This is equivalent to - acknowledging the message when it is read. Equivalent to `NOACK` in the Redis API. + acknowledging the message when it is read. Equivalent to `NOACK` in the Valkey API. block_ms (Optional[int]): If provided, the request will be blocked for the set amount of milliseconds or - until the server has the required number of entries. Equivalent to `BLOCK` in the Redis API. - count (Optional[int]): The maximum number of elements requested. Equivalent to `COUNT` in the Redis API. + until the server has the required number of entries. Equivalent to `BLOCK` in the Valkey API. + count (Optional[int]): The maximum number of elements requested. Equivalent to `COUNT` in the Valkey API. """ super().__init__(block_ms=block_ms, count=count) self.no_ack = no_ack @@ -335,13 +335,13 @@ def to_args(self) -> List[TEncodable]: """ args: List[TEncodable] = super().to_args() if self.no_ack: - args.append(self.READ_NOACK_REDIS_API) + args.append(self.READ_NOACK_VALKEY_API) return args class StreamPendingOptions: - IDLE_TIME_REDIS_API = "IDLE" + IDLE_TIME_VALKEY_API = "IDLE" def __init__( self, @@ -353,7 +353,7 @@ def __init__( Args: min_idle_time_ms (Optional[int]): Filters pending entries by their minimum idle time in milliseconds. This - option can only be specified if you are using Redis version 6.2.0 or above. + option can only be specified if you are using Valkey version 6.2.0 or above. consumer_name (Optional[TEncodable]): Filters pending entries by consumer name. """ self.min_idle_time = min_idle_time_ms @@ -361,11 +361,11 @@ def __init__( class StreamClaimOptions: - IDLE_REDIS_API = "IDLE" - TIME_REDIS_API = "TIME" - RETRY_COUNT_REDIS_API = "RETRYCOUNT" - FORCE_REDIS_API = "FORCE" - JUST_ID_REDIS_API = "JUSTID" + IDLE_VALKEY_API = "IDLE" + TIME_VALKEY_API = "TIME" + RETRY_COUNT_VALKEY_API = "RETRYCOUNT" + FORCE_VALKEY_API = "FORCE" + JUST_ID_VALKEY_API = "JUSTID" def __init__( self, @@ -406,19 +406,19 @@ def to_args(self) -> List[TEncodable]: """ args: List[TEncodable] = [] if self.idle: - args.append(self.IDLE_REDIS_API) + args.append(self.IDLE_VALKEY_API) args.append(str(self.idle)) if self.idle_unix_time: - args.append(self.TIME_REDIS_API) + args.append(self.TIME_VALKEY_API) args.append(str(self.idle_unix_time)) if self.retry_count: - args.append(self.RETRY_COUNT_REDIS_API) + args.append(self.RETRY_COUNT_VALKEY_API) args.append(str(self.retry_count)) if self.is_force: - args.append(self.FORCE_REDIS_API) + args.append(self.FORCE_VALKEY_API) return args @@ -433,7 +433,7 @@ def _create_xpending_range_args( ) -> List[TEncodable]: args = [key, group_name] if options is not None and options.min_idle_time is not None: - args.extend([options.IDLE_TIME_REDIS_API, str(options.min_idle_time)]) + args.extend([options.IDLE_TIME_VALKEY_API, str(options.min_idle_time)]) args.extend([start.to_arg(), end.to_arg(), str(count)]) if options is not None and options.consumer_name is not None: diff --git a/python/python/glide/async_commands/transaction.py b/python/python/glide/async_commands/transaction.py index af9c50ffcb..5eccc19605 100644 --- a/python/python/glide/async_commands/transaction.py +++ b/python/python/glide/async_commands/transaction.py @@ -64,7 +64,7 @@ class BaseTransaction: Base class encompassing shared commands for both standalone and cluster mode implementations in transaction. Command Response: - The response for each command depends on the executed Redis command. Specific response types + The response for each command depends on the executed command. Specific response types are documented alongside each method. Example: @@ -164,12 +164,12 @@ def set( key (TEncodable): the key to store. value (TEncodable): the value to store with the given key. conditional_set (Optional[ConditionalChange], optional): set the key only if the given condition is met. - Equivalent to [`XX` | `NX`] in the Redis API. Defaults to None. + Equivalent to [`XX` | `NX`] in the Valkey API. Defaults to None. expiry (Optional[ExpirySet], optional): set expiriation to the given key. - Equivalent to [`EX` | `PX` | `EXAT` | `PXAT` | `KEEPTTL`] in the Redis API. Defaults to None. + Equivalent to [`EX` | `PX` | `EXAT` | `PXAT` | `KEEPTTL`] in the Valkey API. Defaults to None. return_old_value (bool, optional): Return the old value stored at key, or None if key did not exist. An error is returned and SET aborted if the value stored at key is not a string. - Equivalent to `GET` in the Redis API. Defaults to False. + Equivalent to `GET` in the Valkey API. Defaults to False. Command response: Optional[bytes]: @@ -281,7 +281,7 @@ def info( sections: Optional[List[InfoSection]] = None, ) -> TTransaction: """ - Get information and statistics about the Redis server. + Get information and statistics about the server. See https://valkey.io/commands/info/ for details. Args: @@ -344,7 +344,7 @@ def config_set( def config_resetstat(self: TTransaction) -> TTransaction: """ - Resets the statistics reported by Redis using the INFO and LATENCY HISTOGRAM commands. + Resets the statistics reported by the server using the INFO and LATENCY HISTOGRAM commands. See https://valkey.io/commands/config-resetstat/ for details. Command response: @@ -486,7 +486,7 @@ def incrbyfloat(self: TTransaction, key: TEncodable, amount: float) -> TTransact def ping(self: TTransaction, message: Optional[TEncodable] = None) -> TTransaction: """ - Ping the Redis server. + Ping the server. See https://valkey.io/commands/ping/ for more details. Args: @@ -957,7 +957,7 @@ def lmpop( Command response: Optional[Mapping[bytes, List[bytes]]]: A map of `key` name mapped to an array of popped elements, or None if no elements could be popped. - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ args = [str(len(keys)), *keys, direction.value] if count is not None: @@ -988,7 +988,7 @@ def blmpop( Command response: Optional[Mapping[bytes, List[bytes]]]: A map of `key` name mapped to an array of popped elements, or None if no elements could be popped and the timeout expired. - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ args = [str(timeout), str(len(keys)), *keys, direction.value] if count is not None: @@ -1209,7 +1209,7 @@ def lmove( Command response: Optional[bytes]: The popped element, or `None` if `source` does not exist. - Since: Redis version 6.2.0. + Since: Valkey version 6.2.0. """ return self.append_command( RequestType.LMove, [source, destination, where_from.value, where_to.value] @@ -1241,7 +1241,7 @@ def blmove( Command response: Optional[bytes]: The popped element, or `None` if `source` does not exist or if the operation timed-out. - Since: Redis version 6.2.0. + Since: Valkey version 6.2.0. """ return self.append_command( RequestType.BLMove, @@ -1755,7 +1755,7 @@ def expiretime(self: TTransaction, key: TEncodable) -> TTransaction: Commands response: int: The expiration Unix timestamp in seconds, -2 if `key` does not exist or -1 if `key` exists but has no associated expire. - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ return self.append_command(RequestType.ExpireTime, [key]) @@ -1772,7 +1772,7 @@ def pexpiretime(self: TTransaction, key: TEncodable) -> TTransaction: Commands response: int: The expiration Unix timestamp in milliseconds, -2 if `key` does not exist, or -1 if `key` exists but has no associated expiration. - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ return self.append_command(RequestType.PExpireTime, [key]) @@ -1867,7 +1867,7 @@ def function_load( self: TTransaction, library_code: TEncodable, replace: bool = False ) -> TTransaction: """ - Loads a library to Redis. + Loads a library to Valkey. See https://valkey.io/commands/function-load/ for more details. @@ -1879,7 +1879,7 @@ def function_load( Commands response: bytes: The library name that was loaded. - Since: Redis 7.0.0. + Since: Valkey 7.0.0. """ return self.append_command( RequestType.FunctionLoad, @@ -1904,7 +1904,7 @@ def function_list( TFunctionListResponse: Info about all or selected libraries and their functions. - Since: Redis 7.0.0. + Since: Valkey 7.0.0. """ args = [] if library_name_pattern is not None: @@ -1930,7 +1930,7 @@ def function_flush( Commands response: TOK: A simple `OK`. - Since: Redis 7.0.0. + Since: Valkey 7.0.0. """ return self.append_command( RequestType.FunctionFlush, @@ -1949,7 +1949,7 @@ def function_delete(self: TTransaction, library_name: TEncodable) -> TTransactio Commands response: TOK: A simple `OK`. - Since: Redis 7.0.0. + Since: Valkey 7.0.0. """ return self.append_command( RequestType.FunctionDelete, @@ -1975,7 +1975,7 @@ def fcall( Command Response: TResult: The invoked function's return value. - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ args = [] if keys is not None: @@ -2008,7 +2008,7 @@ def fcall_ro( Command Response: TResult: The return value depends on the function that was executed. - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ args = [] if keys is not None: @@ -2311,7 +2311,7 @@ def xgroup_set_id( stream_id (TEncodable): The stream entry ID that should be set as the last delivered ID for the consumer group. entries_read_id (Optional[str]): An arbitrary ID (that isn't the first ID, last ID, or the zero ID ("0-0")) used to find out how many entries are between the arbitrary ID (excluding it) and the stream's last - entry. This argument can only be specified if you are using Redis version 7.0.0 or above. + entry. This argument can only be specified if you are using Valkey version 7.0.0 or above. Command response: TOK: A simple "OK" response. @@ -2478,11 +2478,11 @@ def xautoclaim( scanned. - A mapping of the claimed entries, with the keys being the claimed entry IDs and the values being a 2D list of the field-value pairs in the format `[[field1, value1], [field2, value2], ...]`. - - If you are using Redis 7.0.0 or above, the response list will also include a list containing the + - If you are using Valkey 7.0.0 or above, the response list will also include a list containing the message IDs that were in the Pending Entries List but no longer exist in the stream. These IDs are deleted from the Pending Entries List. - Since: Redis version 6.2.0. + Since: Valkey version 6.2.0. """ args = [key, group_name, consumer_name, str(min_idle_time_ms), start] if count is not None: @@ -2521,11 +2521,11 @@ def xautoclaim_just_id( to the next ID in the stream after the entries that were scanned, or "0-0" if the entire stream was scanned. - A list of the IDs for the claimed entries. - - If you are using Redis 7.0.0 or above, the response list will also include a list containing the + - If you are using Valkey 7.0.0 or above, the response list will also include a list containing the message IDs that were in the Pending Entries List but no longer exist in the stream. These IDs are deleted from the Pending Entries List. - Since: Redis version 6.2.0. + Since: Valkey version 6.2.0. """ args = [key, group_name, consumer_name, str(min_idle_time_ms), start] if count is not None: @@ -2727,7 +2727,7 @@ def geosearch( (int): The Geohash integer, if `with_hash` is set to True. List[float]: The coordinates as a two item [longitude,latitude] array, if `with_coord` is set to True. - Since: Redis version 6.2.0. + Since: Valkey version 6.2.0. """ args = _create_geosearch_args( [key], @@ -2777,7 +2777,7 @@ def geosearchstore( Commands response: int: The number of elements in the resulting sorted set stored at `destination`.s - Since: Redis version 6.2.0. + Since: Valkey version 6.2.0. """ args = _create_geosearch_args( [destination, source], @@ -3194,7 +3194,7 @@ def zrank_withscore( Optional[List[Union[int, float]]]: A list containing the rank and score of `member` in the sorted set. If `key` doesn't exist, or if `member` is not present in the set, None will be returned. - Since: Redis version 7.2.0. + Since: Valkey version 7.2.0. """ return self.append_command(RequestType.ZRank, [key, member, "WITHSCORE"]) @@ -3237,7 +3237,7 @@ def zrevrank_withscore( in the sorted set, where ranks are ordered from high to low based on scores. If `key` doesn't exist, or if `member` is not present in the set, `None` will be returned. - Since: Redis version 7.2.0. + Since: Valkey version 7.2.0. """ return self.append_command(RequestType.ZRevRank, [key, member, "WITHSCORE"]) @@ -3722,7 +3722,7 @@ def zmpop( which elements were popped, and a member-score mapping of the popped elements. If no members could be popped, returns None. - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ args = [str(len(keys))] + keys + [filter.value] if count is not None: @@ -3765,7 +3765,7 @@ def bzmpop( which elements were popped, and a member-score mapping. If no members could be popped and the timeout expired, returns None. - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ args = [str(timeout), str(len(keys))] + keys + [modifier.value] if count is not None: @@ -3791,7 +3791,7 @@ def zintercard( Command response: int: The cardinality of the intersection of the given sorted sets, or the `limit` if reached. - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ args = [str(len(keys))] + keys if limit is not None: @@ -3969,7 +3969,7 @@ def bitpos_interval( numbers indicating offsets starting at the end of the list, with `-1` being the last element of the list, `-2` being the penultimate, and so on. - If you are using Redis 7.0.0 or above, the optional `index_type` can also be provided to specify whether the + If you are using Valkey 7.0.0 or above, the optional `index_type` can also be provided to specify whether the `start` and `end` offsets specify BIT or BYTE offsets. If `index_type` is not provided, BYTE offsets are assumed. If BIT is specified, `start=0` and `end=2` means to look at the first three bits. If BYTE is specified, `start=0` and `end=2` means to look at the first three bytes. @@ -3982,7 +3982,7 @@ def bitpos_interval( start (int): The starting offset. end (int): The ending offset. index_type (Optional[BitmapIndexType]): The index offset type. This option can only be specified if you are - using Redis version 7.0.0 or above. Could be either `BitmapIndexType.BYTE` or `BitmapIndexType.BIT`. + using Valkey version 7.0.0 or above. Could be either `BitmapIndexType.BYTE` or `BitmapIndexType.BIT`. If no index type is provided, the indexes will be assumed to be byte indexes. Command response: @@ -4067,14 +4067,14 @@ def bitfield_read_only( Command response: List[int]: An array of results from the "GET" subcommands. - Since: Redis version 6.0.0. + Since: Valkey version 6.0.0. """ args = [key] + _create_bitfield_read_only_args(subcommands) return self.append_command(RequestType.BitFieldReadOnly, args) def object_encoding(self: TTransaction, key: TEncodable) -> TTransaction: """ - Returns the internal encoding for the Redis object stored at `key`. + Returns the internal encoding for the Valkey object stored at `key`. See https://valkey.io/commands/object-encoding for more details. @@ -4212,14 +4212,14 @@ def getex( Args: key (TEncodable): The key to get. expiry (Optional[ExpirySet], optional): set expiriation to the given key. - Equivalent to [`EX` | `PX` | `EXAT` | `PXAT` | `PERSIST`] in the Redis API. + Equivalent to [`EX` | `PX` | `EXAT` | `PXAT` | `PERSIST`] in the Valkey API. Command Response: Optional[bytes]: If `key` exists, return the value stored at `key` If 'key` does not exist, return 'None' - Since: Redis version 6.2.0. + Since: Valkey version 6.2.0. """ args: List[TEncodable] = [key] if expiry is not None: @@ -4232,7 +4232,7 @@ def lolwut( parameters: Optional[List[int]] = None, ) -> TTransaction: """ - Displays a piece of generative computer art and the Redis version. + Displays a piece of generative computer art and the Valkey version. See https://valkey.io/commands/lolwut for more details. @@ -4243,7 +4243,7 @@ def lolwut( For version `6`, those are number of columns and number of lines. Command Response: - bytes: A piece of generative computer art along with the current Redis version. + bytes: A piece of generative computer art along with the current Valkey version. """ args: List[TEncodable] = [] if version is not None: @@ -4407,7 +4407,7 @@ def lcs( A Bytes String containing the longest common subsequence between the 2 strings. An empty Bytes String is returned if the keys do not exist or have no common subsequences. - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ args = [key1, key2] @@ -4436,7 +4436,7 @@ def lcs_len( Command Response: The length of the longest common subsequence between the 2 strings. - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ args = [key1, key2, "LEN"] @@ -4475,7 +4475,7 @@ def lcs_idx( represent the location of the common subsequences in the strings held by key1 and key2, with the length of the match after each matches, if with_match_len is enabled. - Since: Redis version 7.0.0. + Since: Valkey version 7.0.0. """ args = [key1, key2, "IDX"] @@ -4536,7 +4536,7 @@ def lpos( or None if `element` is not in the list. With the `count` option, a list of indices of matching elements will be returned. - Since: Redis version 6.0.6. + Since: Valkey version 6.0.6. """ args = [key, element] @@ -4596,7 +4596,7 @@ def xclaim_just_id( ) -> TTransaction: """ Changes the ownership of a pending message. This function returns a List with - only the message/entry IDs, and is equivalent to using JUSTID in the Redis API. + only the message/entry IDs, and is equivalent to using JUSTID in the Valkey API. See https://valkey.io/commands/xclaim for more details. @@ -4618,7 +4618,7 @@ def xclaim_just_id( consumer, str(min_idle_time_ms), *ids, - StreamClaimOptions.JUST_ID_REDIS_API, + StreamClaimOptions.JUST_ID_VALKEY_API, ] if options: @@ -4629,10 +4629,10 @@ def xclaim_just_id( class Transaction(BaseTransaction): """ - Extends BaseTransaction class for standalone Redis commands that are not supported in Redis cluster mode. + Extends BaseTransaction class for standalone commands that are not supported in cluster mode. Command Response: - The response for each command depends on the executed Redis command. Specific response types + The response for each command depends on the executed command. Specific response types are documented alongside each method. Example: @@ -4664,7 +4664,7 @@ def move(self, key: TEncodable, db_index: int) -> "Transaction": def select(self, index: int) -> "Transaction": """ - Change the currently selected Redis database. + Change the currently selected database. See https://valkey.io/commands/select/ for details. Args: @@ -4846,7 +4846,7 @@ def copy( Command response: bool: True if the source was copied. Otherwise, return False. - Since: Redis version 6.2.0. + Since: Valkey version 6.2.0. """ args = [source, destination] if destinationDB is not None: @@ -4879,7 +4879,7 @@ class ClusterTransaction(BaseTransaction): Extends BaseTransaction class for cluster mode commands that are not supported in standalone. Command Response: - The response for each command depends on the executed Redis command. Specific response types + The response for each command depends on the executed command. Specific response types are documented alongside each method. """ @@ -4991,7 +4991,7 @@ def copy( Command response: bool: True if the source was copied. Otherwise, return False. - Since: Redis version 6.2.0. + Since: Valkey version 6.2.0. """ args = [source, destination] if replace is not None: @@ -5011,7 +5011,7 @@ def publish( Args: message (str): Message to publish channel (str): Channel to publish the message on. - sharded (bool): Use sharded pubsub mode. Available since Redis version 7.0. + sharded (bool): Use sharded pubsub mode. Available since Valkey version 7.0. Returns: int: Number of subscriptions in that shard that received the message. diff --git a/python/python/glide/config.py b/python/python/glide/config.py index 080d03c5c7..e4ad281b76 100644 --- a/python/python/glide/config.py +++ b/python/python/glide/config.py @@ -50,11 +50,11 @@ class ProtocolVersion(Enum): RESP2 = SentProtocolVersion.RESP2 """ - Communicate using Redis RESP2. + Communicate using RESP2. """ RESP3 = SentProtocolVersion.RESP3 """ - Communicate using Redis RESP3. + Communicate using RESP3. """ @@ -79,18 +79,18 @@ def __init__(self, num_of_retries: int, factor: int, exponent_base: int): self.exponent_base = exponent_base -class RedisCredentials: +class ServerCredentials: def __init__( self, password: str, username: Optional[str] = None, ): """ - Represents the credentials for connecting to a Redis server. + Represents the credentials for connecting to a server. Args: - password (str): The password that will be used for authenticating connections to the Redis servers. - username (Optional[str]): The username that will be used for authenticating connections to the Redis servers. + password (str): The password that will be used for authenticating connections to the servers. + username (Optional[str]): The username that will be used for authenticating connections to the servers. If not supplied, "default" will be used. """ self.password = password @@ -129,7 +129,7 @@ def __init__( self, addresses: List[NodeAddress], use_tls: bool = False, - credentials: Optional[RedisCredentials] = None, + credentials: Optional[ServerCredentials] = None, read_from: ReadFrom = ReadFrom.PRIMARY, request_timeout: Optional[int] = None, client_name: Optional[str] = None, @@ -151,7 +151,7 @@ def __init__( ]. use_tls (bool): True if communication with the cluster should use Transport Level Security. Should match the TLS configuration of the server/cluster, otherwise the connection attempt will fail - credentials (RedisCredentials): Credentials for authentication process. + credentials (ServerCredentials): Credentials for authentication process. If none are set, the client will not authenticate itself with the server. read_from (ReadFrom): If not set, `PRIMARY` will be used. request_timeout (Optional[int]): The duration in milliseconds that the client should wait for a request to complete. @@ -221,7 +221,7 @@ class GlideClientConfiguration(BaseClientConfiguration): {address: sample-address-0002.use2.cache.amazonaws.com, port:6379} ]. use_tls (bool): True if communication with the cluster should use Transport Level Security. - credentials (RedisCredentials): Credentials for authentication process. + credentials (ServerCredentials): Credentials for authentication process. If none are set, the client will not authenticate itself with the server. read_from (ReadFrom): If not set, `PRIMARY` will be used. request_timeout (Optional[int]): The duration in milliseconds that the client should wait for a request to complete. @@ -272,7 +272,7 @@ def __init__( self, addresses: List[NodeAddress], use_tls: bool = False, - credentials: Optional[RedisCredentials] = None, + credentials: Optional[ServerCredentials] = None, read_from: ReadFrom = ReadFrom.PRIMARY, request_timeout: Optional[int] = None, reconnect_strategy: Optional[BackoffStrategy] = None, @@ -357,7 +357,7 @@ class ClusterClientConfiguration(BaseClientConfiguration): {address:configuration-endpoint.use1.cache.amazonaws.com, port:6379} ]. use_tls (bool): True if communication with the cluster should use Transport Level Security. - credentials (RedisCredentials): Credentials for authentication process. + credentials (ServerCredentials): Credentials for authentication process. If none are set, the client will not authenticate itself with the server. read_from (ReadFrom): If not set, `PRIMARY` will be used. request_timeout (Optional[int]): The duration in milliseconds that the client should wait for a request to complete. @@ -388,7 +388,7 @@ class PubSubChannelModes(IntEnum): Pattern = 1 """ Use channel name patterns """ Sharded = 2 - """ Use sharded pubsub. Available since Redis version 7.0. """ + """ Use sharded pubsub. Available since Valkey version 7.0. """ @dataclass class PubSubSubscriptions: @@ -413,7 +413,7 @@ def __init__( self, addresses: List[NodeAddress], use_tls: bool = False, - credentials: Optional[RedisCredentials] = None, + credentials: Optional[ServerCredentials] = None, read_from: ReadFrom = ReadFrom.PRIMARY, request_timeout: Optional[int] = None, client_name: Optional[str] = None, diff --git a/python/python/glide/exceptions.py b/python/python/glide/exceptions.py index 6420fa4e5d..5c5659974c 100644 --- a/python/python/glide/exceptions.py +++ b/python/python/glide/exceptions.py @@ -3,7 +3,7 @@ from typing import Optional -class RedisError(Exception): +class GlideError(Exception): """ Base class for errors. """ @@ -15,7 +15,7 @@ def name(self): return self.__class__.__name__ -class ClosingError(RedisError): +class ClosingError(GlideError): """ Errors that report that the client has closed and is no longer usable. """ @@ -23,7 +23,7 @@ class ClosingError(RedisError): pass -class RequestError(RedisError): +class RequestError(GlideError): """ Errors that were reported during a request. """ diff --git a/python/python/tests/conftest.py b/python/python/tests/conftest.py index 1f7548b954..b10b0eadcf 100644 --- a/python/python/tests/conftest.py +++ b/python/python/tests/conftest.py @@ -9,7 +9,7 @@ GlideClientConfiguration, NodeAddress, ProtocolVersion, - RedisCredentials, + ServerCredentials, ) from glide.glide_client import GlideClient, GlideClusterClient, TGlideClient from glide.logger import Level as logLevel @@ -28,14 +28,14 @@ def pytest_addoption(parser): "--host", default=DEFAULT_HOST, action="store", - help="Redis host endpoint, defaults to `%(default)s`", + help="Server host endpoint, defaults to `%(default)s`", ) parser.addoption( "--port", default=DEFAULT_PORT, action="store", - help="Redis port, defaults to `%(default)s`", + help="Server port, defaults to `%(default)s`", ) parser.addoption( @@ -217,7 +217,7 @@ async def glide_client( async def create_client( request, cluster_mode: bool, - credentials: Optional[RedisCredentials] = None, + credentials: Optional[ServerCredentials] = None, database_id: int = 0, addresses: Optional[List[NodeAddress]] = None, client_name: Optional[str] = None, diff --git a/python/python/tests/test_async_client.py b/python/python/tests/test_async_client.py index 3f940beeee..58b3113d14 100644 --- a/python/python/tests/test_async_client.py +++ b/python/python/tests/test_async_client.py @@ -74,7 +74,7 @@ ClusterClientConfiguration, GlideClientConfiguration, ProtocolVersion, - RedisCredentials, + ServerCredentials, ) from glide.constants import OK, TEncodable, TResult from glide.glide_client import GlideClient, GlideClusterClient, TGlideClient @@ -111,7 +111,7 @@ async def test_register_client_name_and_version(self, glide_client: TGlideClient min_version = "7.2.0" if await check_if_server_version_lt(glide_client, min_version): # TODO: change it to pytest fixture after we'll implement a sync client - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") info = await glide_client.custom_command(["CLIENT", "INFO"]) assert isinstance(info, bytes) info_str = info.decode() @@ -173,7 +173,7 @@ async def test_can_connect_with_auth_requirepass( ): is_cluster = isinstance(glide_client, GlideClusterClient) password = "TEST_AUTH" - credentials = RedisCredentials(password) + credentials = ServerCredentials(password) try: await glide_client.custom_command( ["CONFIG", "SET", "requirepass", password] @@ -235,7 +235,7 @@ async def test_can_connect_with_auth_acl( ) key = get_random_string(10) assert await glide_client.set(key, key) == OK - credentials = RedisCredentials(password, username) + credentials = ServerCredentials(password, username) testuser_client = await create_client( request, @@ -332,7 +332,7 @@ async def test_set_return_old_value(self, glide_client: TGlideClient): min_version = "6.2.0" if await check_if_server_version_lt(glide_client, min_version): # TODO: change it to pytest fixture after we'll implement a sync client - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") key = get_random_string(10) value = get_random_string(10) res = await glide_client.set(key, value) @@ -1167,7 +1167,7 @@ async def endless_blpop_call(): async def test_lmpop(self, glide_client: TGlideClient): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") key1 = f"{{test}}-1-f{get_random_string(10)}" key2 = f"{{test}}-2-f{get_random_string(10)}" @@ -1206,7 +1206,7 @@ async def test_lmpop(self, glide_client: TGlideClient): async def test_blmpop(self, glide_client: TGlideClient): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") key1 = f"{{test}}-1-f{get_random_string(10)}" key2 = f"{{test}}-2-f{get_random_string(10)}" @@ -1890,7 +1890,7 @@ async def test_sinterstore(self, glide_client: TGlideClient): async def test_sintercard(self, glide_client: TGlideClient): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") key1 = f"{{testKey}}:{get_random_string(10)}" key2 = f"{{testKey}}:{get_random_string(10)}" @@ -2950,7 +2950,7 @@ async def test_geohash(self, glide_client: TGlideClient): == [None] * 3 ) - # Neccessary to check since we are enforcing the user to pass a list of members while redis don't + # Neccessary to check since we are enforcing the user to pass a list of members while valkey don't # But when running the command with key only (and no members) the returned value will always be an empty list # So in case of any changes, this test will fail and inform us that we should allow not passing any members. assert await glide_client.geohash(key, []) == [] @@ -3021,7 +3021,7 @@ async def test_geopos(self, glide_client: TGlideClient): == [None] * 3 ) - # Neccessary to check since we are enforcing the user to pass a list of members while redis don't + # Neccessary to check since we are enforcing the user to pass a list of members while valkey don't # But when running the command with key only (and no members) the returned value will always be an empty list # So in case of any changes, this test will fail and inform us that we should allow not passing any members. assert await glide_client.geohash(key, []) == [] @@ -4452,7 +4452,7 @@ async def test_zdiffstore(self, glide_client: TGlideClient): async def test_bzmpop(self, glide_client: TGlideClient): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") key1 = f"{{test}}-1-f{get_random_string(10)}" key2 = f"{{test}}-2-f{get_random_string(10)}" @@ -4610,7 +4610,7 @@ async def test_zrandmember_withscores(self, glide_client: TGlideClient): async def test_zintercard(self, glide_client: TGlideClient): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") key1 = f"{{testKey}}:1-{get_random_string(10)}" key2 = f"{{testKey}}:2-{get_random_string(10)}" @@ -4652,7 +4652,7 @@ async def test_zintercard(self, glide_client: TGlideClient): async def test_zmpop(self, glide_client: TGlideClient): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") key1 = f"{{test}}-1-f{get_random_string(10)}" key2 = f"{{test}}-2-f{get_random_string(10)}" @@ -5104,7 +5104,7 @@ async def test_xadd_xtrim_xlen(self, glide_client: TGlideClient): assert await glide_client.xlen(key) == 1 assert await glide_client.xtrim(key, TrimByMaxLen(threshold=0, exact=True)) == 1 - # Unlike other Redis collection types, stream keys still exist even after removing all entries + # Unlike other Valkey collection types, stream keys still exist even after removing all entries assert await glide_client.exists([key]) == 1 assert await glide_client.xlen(key) == 0 @@ -5468,7 +5468,7 @@ async def test_xgroup_create_xgroup_destroy( with pytest.raises(RequestError): await glide_client.xgroup_destroy(non_existing_key, group_name1) - # "ENTRIESREAD" option was added in Redis 7.0.0 + # "ENTRIESREAD" option was added in Valkey 7.0.0 if await check_if_server_version_lt(glide_client, "7.0.0"): with pytest.raises(RequestError): await glide_client.xgroup_create( @@ -6396,7 +6396,7 @@ async def test_xclaim_edge_cases_and_failures(self, glide_client: TGlideClient): async def test_xautoclaim(self, glide_client: TGlideClient, protocol): min_version = "6.2.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") if await check_if_server_version_lt(glide_client, "7.0.0"): version7_or_above = False @@ -6453,7 +6453,7 @@ async def test_xautoclaim(self, glide_client: TGlideClient, protocol): ) assert result[0] == stream_id1_1.encode() assert result[1] == {stream_id1_0.encode(): [[b"f1", b"v1"], [b"f2", b"v2"]]} - # if using Redis 7.0.0 or above, responses also include a list of entry IDs that were removed from the Pending + # if using Valkey 7.0.0 or above, responses also include a list of entry IDs that were removed from the Pending # Entries List because they no longer exist in the stream if version7_or_above: assert result[2] == [] @@ -6488,7 +6488,7 @@ async def test_xautoclaim(self, glide_client: TGlideClient, protocol): ] assert just_id_result[2] == [] else: - # in Redis < 7.0.0, specifically for XAUTOCLAIM with JUSTID, entry IDs that were in the Pending Entries List + # in Valkey < 7.0.0, specifically for XAUTOCLAIM with JUSTID, entry IDs that were in the Pending Entries List # but are no longer in the stream still show up in the response assert just_id_result[1] == [ stream_id1_0.encode(), @@ -6504,7 +6504,7 @@ async def test_xautoclaim_edge_cases_and_failures( ): min_version = "6.2.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") if await check_if_server_version_lt(glide_client, "7.0.0"): version7_or_above = False @@ -6555,7 +6555,7 @@ async def test_xautoclaim_edge_cases_and_failures( ) assert result[0] == stream_id0_0.encode() assert result[1] == {stream_id1_0.encode(): [[b"f1", b"v1"]]} - # if using Redis 7.0.0 or above, responses also include a list of entry IDs that were removed from the Pending + # if using Valkey 7.0.0 or above, responses also include a list of entry IDs that were removed from the Pending # Entries List because they no longer exist in the stream if version7_or_above: assert result[2] == [] @@ -6677,7 +6677,7 @@ async def test_xinfo_groups_xinfo_consumers( if not await check_if_server_version_lt(glide_client, "7.2.0"): assert ( cast(int, consumer1_info.get(b"inactive")) - > 0 # "inactive" was added in Redis 7.2.0 + > 0 # "inactive" was added in Valkey 7.2.0 ) # create consumer2 and read the rest of the entries with it @@ -7360,7 +7360,7 @@ async def test_bitfield(self, glide_client: TGlideClient): async def test_bitfield_read_only(self, glide_client: TGlideClient): min_version = "6.0.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") key = get_random_string(10) non_existing_key = get_random_string(10) @@ -7571,7 +7571,7 @@ async def test_object_refcount(self, glide_client: TGlideClient): async def test_function_load(self, glide_client: TGlideClient): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") lib_name = f"mylib1C{get_random_string(5)}" func_name = f"myfunc1c{get_random_string(5)}" @@ -7625,7 +7625,7 @@ async def test_function_load_cluster_with_route( ): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") lib_name = f"mylib1C{get_random_string(5)}" func_name = f"myfunc1c{get_random_string(5)}" @@ -7735,7 +7735,7 @@ async def test_function_load_cluster_with_route( async def test_function_list(self, glide_client: TGlideClient): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") original_functions_count = len(await glide_client.function_list()) @@ -7800,7 +7800,7 @@ async def test_function_list_with_routing( ): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") route = SlotKeyRoute(SlotType.PRIMARY, "1") if single_route else AllPrimaries() @@ -7887,7 +7887,7 @@ async def test_function_list_with_multiple_functions( ): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") await glide_client.function_flush() assert len(await glide_client.function_list()) == 0 @@ -7932,7 +7932,7 @@ async def test_function_list_with_multiple_functions( async def test_function_flush(self, glide_client: TGlideClient): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - pytest.skip(f"Redis version required >= {min_version}") + pytest.skip(f"Valkey version required >= {min_version}") lib_name = f"mylib1C{get_random_string(5)}" func_name = f"myfunc1c{get_random_string(5)}" @@ -7968,7 +7968,7 @@ async def test_function_flush_with_routing( ): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - pytest.skip(f"Redis version required >= {min_version}") + pytest.skip(f"Valkey version required >= {min_version}") lib_name = f"mylib1C{get_random_string(5)}" func_name = f"myfunc1c{get_random_string(5)}" @@ -8020,7 +8020,7 @@ async def test_function_flush_with_routing( async def test_function_delete(self, glide_client: TGlideClient): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - pytest.skip(f"Redis version required >= {min_version}") + pytest.skip(f"Valkey version required >= {min_version}") lib_name = f"mylib1C{get_random_string(5)}" func_name = f"myfunc1c{get_random_string(5)}" @@ -8051,7 +8051,7 @@ async def test_function_delete_with_routing( ): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - pytest.skip(f"Redis version required >= {min_version}") + pytest.skip(f"Valkey version required >= {min_version}") lib_name = f"mylib1C{get_random_string(5)}" func_name = f"myfunc1c{get_random_string(5)}" @@ -8092,7 +8092,7 @@ async def test_function_delete_with_routing( async def test_fcall_with_key(self, glide_client: GlideClusterClient): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") key1 = f"{{testKey}}:1-{get_random_string(10)}" key2 = f"{{testKey}}:2-{get_random_string(10)}" @@ -8139,7 +8139,7 @@ async def test_fcall_with_key(self, glide_client: GlideClusterClient): async def test_fcall_readonly_function(self, glide_client: GlideClusterClient): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") lib_name = f"fcall_readonly_function{get_random_string(5)}" # intentionally using a REPLICA route @@ -8189,7 +8189,7 @@ async def test_fcall_readonly_function(self, glide_client: GlideClusterClient): async def test_function_dump_restore_standalone(self, glide_client: GlideClient): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") assert await glide_client.function_flush(FlushMode.SYNC) is OK @@ -8263,7 +8263,7 @@ async def test_function_dump_restore_cluster( ): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") assert await glide_client.function_flush(FlushMode.SYNC) is OK @@ -8461,7 +8461,7 @@ async def test_standalone_flushdb(self, glide_client: GlideClient): async def test_getex(self, glide_client: TGlideClient): min_version = "6.2.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") key1 = get_random_string(10) non_existing_key = get_random_string(10) @@ -8497,7 +8497,7 @@ async def test_getex(self, glide_client: TGlideClient): async def test_copy_no_database(self, glide_client: TGlideClient): min_version = "6.2.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") source = f"{{testKey}}:1-{get_random_string(10)}" destination = f"{{testKey}}:2-{get_random_string(10)}" @@ -8531,7 +8531,7 @@ async def test_copy_no_database(self, glide_client: TGlideClient): async def test_copy_database(self, glide_client: GlideClient): min_version = "6.2.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") source = get_random_string(10) destination = get_random_string(10) @@ -8790,7 +8790,7 @@ async def test_dump_restore_options(self, glide_client: TGlideClient): async def test_lcs(self, glide_client: GlideClient): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") key1 = "testKey1" value1 = "abcd" key2 = "testKey2" @@ -8814,7 +8814,7 @@ async def test_lcs(self, glide_client: GlideClient): async def test_lcs_len(self, glide_client: GlideClient): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") key1 = "testKey1" value1 = "abcd" key2 = "testKey2" @@ -8838,7 +8838,7 @@ async def test_lcs_len(self, glide_client: GlideClient): async def test_lcs_idx(self, glide_client: GlideClient): min_version = "7.0.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") key1 = "testKey1" value1 = "abcd1234" key2 = "testKey2" @@ -8984,7 +8984,7 @@ async def test_lpos(self, glide_client: TGlideClient): min_version = "6.0.6" if await check_if_server_version_lt(glide_client, min_version): # TODO: change it to pytest fixture after we'll implement a sync client - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") key = f"{{key}}-1{get_random_string(5)}" non_list_key = f"{{key}}-2{get_random_string(5)}" mylist: List[TEncodable] = ["a", "a", "b", "c", "a", "b"] diff --git a/python/python/tests/test_pubsub.py b/python/python/tests/test_pubsub.py index 9a636a8494..f447ed9fe9 100644 --- a/python/python/tests/test_pubsub.py +++ b/python/python/tests/test_pubsub.py @@ -469,7 +469,7 @@ async def test_sharded_pubsub( ) min_version = "7.0.0" if await check_if_server_version_lt(publishing_client, min_version): - pytest.skip(reason=f"Redis version required >= {min_version}") + pytest.skip(reason=f"Valkey version required >= {min_version}") try: assert ( @@ -527,7 +527,7 @@ async def test_sharded_pubsub_co_existence(self, request, cluster_mode: bool): min_version = "7.0.0" if await check_if_server_version_lt(publishing_client, min_version): - pytest.skip(reason=f"Redis version required >= {min_version}") + pytest.skip(reason=f"Valkey version required >= {min_version}") try: assert ( @@ -621,7 +621,7 @@ async def test_sharded_pubsub_many_channels( min_version = "7.0.0" if await check_if_server_version_lt(publishing_client, min_version): - pytest.skip(reason=f"Redis version required >= {min_version}") + pytest.skip(reason=f"Valkey version required >= {min_version}") try: # Publish messages to each channel @@ -1323,9 +1323,9 @@ async def test_pubsub_combined_exact_pattern_and_sharded_multi_client( pub_sub_exact, ) - # Setup PUBSUB for sharded channels (Redis version > 7) + # Setup PUBSUB for sharded channels (Valkey version > 7) if await check_if_server_version_lt(publishing_client, "7.0.0"): - pytest.skip("Redis version required >= 7.0.0") + pytest.skip("Valkey version required >= 7.0.0") if method == MethodTesting.Callback: context = callback_messages_pattern @@ -1507,9 +1507,9 @@ async def test_pubsub_combined_different_channels_with_same_name( pub_sub_exact, ) - # (Redis version > 7) + # (Valkey version > 7) if await check_if_server_version_lt(publishing_client, "7.0.0"): - pytest.skip("Redis version required >= 7.0.0") + pytest.skip("Valkey version required >= 7.0.0") # Setup PUBSUB for pattern channel if method == MethodTesting.Callback: @@ -1764,9 +1764,9 @@ async def test_pubsub_three_publishing_clients_same_name_with_sharded( _, client_sharded = await create_two_clients( request, cluster_mode, pub_sub_sharded ) - # (Redis version > 7) + # (Valkey version > 7) if await check_if_server_version_lt(client_pattern, "7.0.0"): - pytest.skip("Redis version required >= 7.0.0") + pytest.skip("Valkey version required >= 7.0.0") try: # Publish messages to each channel - both clients publishing @@ -2067,9 +2067,9 @@ async def test_pubsub_sharded_max_size_message_callback( request, cluster_mode, pub_sub ) - # (Redis version > 7) + # (Valkey version > 7) if await check_if_server_version_lt(publishing_client, "7.0.0"): - pytest.skip("Redis version required >= 7.0.0") + pytest.skip("Valkey version required >= 7.0.0") try: assert ( diff --git a/python/python/tests/test_transaction.py b/python/python/tests/test_transaction.py index 0c2175d4de..a66f1038ee 100644 --- a/python/python/tests/test_transaction.py +++ b/python/python/tests/test_transaction.py @@ -636,7 +636,7 @@ async def transaction_test( if not await check_if_server_version_lt(glide_client, min_version): transaction.xautoclaim(key11, group_name1, consumer, 0, "0-0") transaction.xautoclaim_just_id(key11, group_name1, consumer, 0, "0-0") - # if using Redis 7.0.0 or above, responses also include a list of entry IDs that were removed from the Pending + # if using Valkey 7.0.0 or above, responses also include a list of entry IDs that were removed from the Pending # Entries List because they no longer exist in the stream if await check_if_server_version_lt(glide_client, "7.0.0"): args.append( @@ -960,7 +960,7 @@ def test_transaction_clear(self): async def test_standalone_copy_transaction(self, glide_client: GlideClient): min_version = "6.2.0" if await check_if_server_version_lt(glide_client, min_version): - return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + return pytest.mark.skip(reason=f"Valkey version required >= {min_version}") keyslot = get_random_string(3) key = "{{{}}}:{}".format(keyslot, get_random_string(3)) # to get the same slot diff --git a/python/python/tests/utils/utils.py b/python/python/tests/utils/utils.py index cd1ac3a8c7..d13dc9dbc6 100644 --- a/python/python/tests/utils/utils.py +++ b/python/python/tests/utils/utils.py @@ -73,9 +73,9 @@ def get_random_string(length): async def check_if_server_version_lt(client: TGlideClient, min_version: str) -> bool: # TODO: change it to pytest fixture after we'll implement a sync client info_str = await client.info([InfoSection.SERVER]) - redis_version = parse_info_response(info_str).get("redis_version") - assert redis_version is not None - return version.parse(redis_version) < version.parse(min_version) + server_version = parse_info_response(info_str).get("redis_version") + assert server_version is not None + return version.parse(server_version) < version.parse(min_version) def compare_maps( From b74c3f0736a8a7a9cd795d3443036e409343de1f Mon Sep 17 00:00:00 2001 From: Alon Arenberg <93711356+alon-arenberg@users.noreply.github.com> Date: Thu, 4 Jul 2024 17:06:02 +0300 Subject: [PATCH 19/23] support lcs with GlideString (#1802) * support lcs with GlideString * fix variable name in lcs_binary integration tests --- .../src/main/java/glide/api/BaseClient.java | 66 ++++++ .../api/commands/StringBaseCommands.java | 224 ++++++++++++++++++ .../test/java/glide/api/RedisClientTest.java | 177 ++++++++++++++ .../test/java/glide/SharedCommandTests.java | 143 +++++++++++ 4 files changed, 610 insertions(+) diff --git a/java/client/src/main/java/glide/api/BaseClient.java b/java/client/src/main/java/glide/api/BaseClient.java index 66b093954f..6cc9006f4f 100644 --- a/java/client/src/main/java/glide/api/BaseClient.java +++ b/java/client/src/main/java/glide/api/BaseClient.java @@ -3711,12 +3711,24 @@ public CompletableFuture lcs(@NonNull String key1, @NonNull String key2) return commandManager.submitNewCommand(LCS, arguments, this::handleStringResponse); } + @Override + public CompletableFuture lcs(@NonNull GlideString key1, @NonNull GlideString key2) { + GlideString[] arguments = new GlideString[] {key1, key2}; + return commandManager.submitNewCommand(LCS, arguments, this::handleGlideStringResponse); + } + @Override public CompletableFuture lcsLen(@NonNull String key1, @NonNull String key2) { String[] arguments = new String[] {key1, key2, LEN_REDIS_API}; return commandManager.submitNewCommand(LCS, arguments, this::handleLongResponse); } + @Override + public CompletableFuture lcsLen(@NonNull GlideString key1, @NonNull GlideString key2) { + GlideString[] arguments = new ArgsBuilder().add(key1).add(key2).add(LEN_REDIS_API).toArray(); + return commandManager.submitNewCommand(LCS, arguments, this::handleLongResponse); + } + @Override public CompletableFuture> lcsIdx(@NonNull String key1, @NonNull String key2) { String[] arguments = new String[] {key1, key2, IDX_COMMAND_STRING}; @@ -3724,6 +3736,16 @@ public CompletableFuture> lcsIdx(@NonNull String key1, @NonN LCS, arguments, response -> handleLcsIdxResponse(handleMapResponse(response))); } + @Override + public CompletableFuture> lcsIdx( + @NonNull GlideString key1, @NonNull GlideString key2) { + GlideString[] arguments = + new ArgsBuilder().add(key1).add(key2).add(IDX_COMMAND_STRING).toArray(); + + return commandManager.submitNewCommand( + LCS, arguments, response -> handleLcsIdxResponse(handleMapResponse(response))); + } + @Override public CompletableFuture> lcsIdx( @NonNull String key1, @NonNull String key2, long minMatchLen) { @@ -3735,6 +3757,21 @@ public CompletableFuture> lcsIdx( LCS, arguments, response -> handleLcsIdxResponse(handleMapResponse(response))); } + @Override + public CompletableFuture> lcsIdx( + @NonNull GlideString key1, @NonNull GlideString key2, long minMatchLen) { + GlideString[] arguments = + new ArgsBuilder() + .add(key1) + .add(key2) + .add(IDX_COMMAND_STRING) + .add(MINMATCHLEN_COMMAND_STRING) + .add(minMatchLen) + .toArray(); + return commandManager.submitNewCommand( + LCS, arguments, response -> handleLcsIdxResponse(handleMapResponse(response))); + } + @Override public CompletableFuture> lcsIdxWithMatchLen( @NonNull String key1, @NonNull String key2) { @@ -3742,6 +3779,19 @@ public CompletableFuture> lcsIdxWithMatchLen( return commandManager.submitNewCommand(LCS, arguments, this::handleMapResponse); } + @Override + public CompletableFuture> lcsIdxWithMatchLen( + @NonNull GlideString key1, @NonNull GlideString key2) { + GlideString[] arguments = + new ArgsBuilder() + .add(key1) + .add(key2) + .add(IDX_COMMAND_STRING) + .add(WITHMATCHLEN_COMMAND_STRING) + .toArray(); + return commandManager.submitNewCommand(LCS, arguments, this::handleMapResponse); + } + @Override public CompletableFuture> lcsIdxWithMatchLen( @NonNull String key1, @NonNull String key2, long minMatchLen) { @@ -3758,6 +3808,22 @@ public CompletableFuture> lcsIdxWithMatchLen( return commandManager.submitNewCommand(LCS, arguments, this::handleMapResponse); } + @Override + public CompletableFuture> lcsIdxWithMatchLen( + @NonNull GlideString key1, @NonNull GlideString key2, long minMatchLen) { + GlideString[] arguments = + new ArgsBuilder() + .add(key1) + .add(key2) + .add(IDX_COMMAND_STRING) + .add(MINMATCHLEN_COMMAND_STRING) + .add(minMatchLen) + .add(WITHMATCHLEN_COMMAND_STRING) + .toArray(); + + return commandManager.submitNewCommand(LCS, arguments, this::handleMapResponse); + } + @Override public CompletableFuture publish(@NonNull String channel, @NonNull String message) { return commandManager.submitNewCommand( diff --git a/java/client/src/main/java/glide/api/commands/StringBaseCommands.java b/java/client/src/main/java/glide/api/commands/StringBaseCommands.java index 4767417d1a..151b5e909b 100644 --- a/java/client/src/main/java/glide/api/commands/StringBaseCommands.java +++ b/java/client/src/main/java/glide/api/commands/StringBaseCommands.java @@ -662,6 +662,28 @@ public interface StringBaseCommands { */ CompletableFuture lcs(String key1, String key2); + /** + * Returns the longest common subsequence between strings stored at key1 and + * key2. + * + * @since Redis 7.0 and above. + * @apiNote When in cluster mode, key1 and key2 must map to the same + * hash slot. + * @see valkey.io for details. + * @param key1 The key that stores the first string. + * @param key2 The key that stores the second string. + * @return A String containing the longest common subsequence between the 2 strings. + * An empty String is returned if the keys do not exist or have no common + * subsequences. + * @example + *
{@code
+     * // testKey1 = abcd, testKey2 = axcd
+     * GlideString result = client.lcs(gs("testKey1"), gs("testKey2")).get();
+     * assert result.equals(gs("acd"));
+     * }
+ */ + CompletableFuture lcs(GlideString key1, GlideString key2); + /** * Returns the length of the longest common subsequence between strings stored at key1 * and key2. @@ -682,6 +704,26 @@ public interface StringBaseCommands { */ CompletableFuture lcsLen(String key1, String key2); + /** + * Returns the length of the longest common subsequence between strings stored at key1 + * and key2. + * + * @since Redis 7.0 and above. + * @apiNote When in cluster mode, key1 and key2 must map to the same + * hash slot. + * @see valkey.io for details. + * @param key1 The key that stores the first string. + * @param key2 The key that stores the second string. + * @return The length of the longest common subsequence between the 2 strings. + * @example + *
{@code
+     * // testKey1 = abcd, testKey2 = axcd
+     * Long result = client.lcsLen(gs("testKey1"), gs("testKey2")).get();
+     * assert result.equals(3L);
+     * }
+ */ + CompletableFuture lcsLen(GlideString key1, GlideString key2); + /** * Returns the indices and length of the longest common subsequence between strings stored at * key1 and key2. @@ -725,6 +767,49 @@ public interface StringBaseCommands { */ CompletableFuture> lcsIdx(String key1, String key2); + /** + * Returns the indices and length of the longest common subsequence between strings stored at + * key1 and key2. + * + * @since Redis 7.0 and above. + * @apiNote When in cluster mode, key1 and key2 must map to the same + * hash slot. + * @see valkey.io for details. + * @param key1 The key that stores the first string. + * @param key2 The key that stores the second string. + * @return A Map containing the indices of the longest common subsequence between the + * 2 strings and the length of the longest common subsequence. The resulting map contains two + * keys, "matches" and "len": + *
    + *
  • "len" is mapped to the length of the longest common subsequence between the 2 strings + * stored as Long. + *
  • "matches" is mapped to a three dimensional Long array that stores pairs + * of indices that represent the location of the common subsequences in the strings held + * by key1 and key2. + *
+ * + * @example If key1 holds the GlideString gs("abcd123") and key2 + * holds the GlideString gs("bcdef123") then the sample result would be + *
{@code
+     * new Long[][][] {
+     *      {
+     *          {4L, 6L},
+     *          {5L, 7L}
+     *      },
+     *      {
+     *          {1L, 3L},
+     *          {0L, 2L}
+     *      }
+     *  }
+     * }
+ * The result indicates that the first substring match is gs("123") in key1 + * at index 4 to 6 which matches the substring in key2 + * at index 5 to 7. And the second substring match is + * gs("bcd") in key1 at index 1 to 3 which + * matches the substring in key2 at index 0 to 2. + */ + CompletableFuture> lcsIdx(GlideString key1, GlideString key2); + /** * Returns the indices and length of the longest common subsequence between strings stored at * key1 and key2. @@ -769,6 +854,51 @@ public interface StringBaseCommands { */ CompletableFuture> lcsIdx(String key1, String key2, long minMatchLen); + /** + * Returns the indices and length of the longest common subsequence between strings stored at + * key1 and key2. + * + * @since Redis 7.0 and above. + * @apiNote When in cluster mode, key1 and key2 must map to the same + * hash slot. + * @see valkey.io for details. + * @param key1 The key that stores the first string. + * @param key2 The key that stores the second string. + * @param minMatchLen The minimum length of matches to include in the result. + * @return A Map containing the indices of the longest common subsequence between the + * 2 strings and the length of the longest common subsequence. The resulting map contains two + * keys, "matches" and "len": + *
    + *
  • "len" is mapped to the length of the longest common subsequence between the 2 strings + * stored as Long. + *
  • "matches" is mapped to a three dimensional Long array that stores pairs + * of indices that represent the location of the common subsequences in the strings held + * by key1 and key2. + *
+ * + * @example If key1 holds the GlideString gs("abcd123") and key2 + * holds the GlideString gs("bcdef123") then the sample result would be + *
{@code
+     * new Long[][][] {
+     *      {
+     *          {4L, 6L},
+     *          {5L, 7L}
+     *      },
+     *      {
+     *          {1L, 3L},
+     *          {0L, 2L}
+     *      }
+     *  }
+     * }
+ * The result indicates that the first substring match is gs("123") in key1 + * at index 4 to 6 which matches the substring in key2 + * at index 5 to 7. And the second substring match is + * gs("bcd") in key1 at index 1 to 3 which + * matches the substring in key2 at index 0 to 2. + */ + CompletableFuture> lcsIdx( + GlideString key1, GlideString key2, long minMatchLen); + /** * Returns the indices and length of the longest common subsequence between strings stored at * key1 and key2. @@ -814,6 +944,52 @@ public interface StringBaseCommands { */ CompletableFuture> lcsIdxWithMatchLen(String key1, String key2); + /** + * Returns the indices and length of the longest common subsequence between strings stored at + * key1 and key2. + * + * @since Redis 7.0 and above. + * @apiNote When in cluster mode, key1 and key2 must map to the same + * hash slot. + * @see valkey.io for details. + * @param key1 The key that stores the first string. + * @param key2 The key that stores the second string. + * @return A Map containing the indices of the longest common subsequence between the + * 2 strings and the length of the longest common subsequence. The resulting map contains two + * keys, "matches" and "len": + *
    + *
  • "len" is mapped to the length of the longest common subsequence between the 2 strings + * stored as Long. + *
  • "matches" is mapped to a three dimensional Long array that stores pairs + * of indices that represent the location of the common subsequences in the strings held + * by key1 and key2. + *
+ * + * @example If key1 holds the GlideString gs("abcd1234") and key2 + * holds the GlideString gs("bcdef1234") then the sample result would be + *
{@code
+     * new Object[] {
+     *      new Object[] {
+     *          new Long[] {4L, 7L},
+     *          new Long[] {5L, 8L},
+     *          4L},
+     *      new Object[] {
+     *          new Long[] {1L, 3L},
+     *          new Long[] {0L, 2L},
+     *          3L}
+     *      }
+     * }
+ * The result indicates that the first substring match is gs("1234") in + * key1 + * at index 4 to 7 which matches the substring in key2 + * at index 5 to 8 and the last element in the array is the + * length of the substring match which is 4. And the second substring match is + * gs("bcd") in key1 at index 1 to 3 which + * matches the substring in key2 at index 0 to 2 and + * the last element in the array is the length of the substring match which is 3. + */ + CompletableFuture> lcsIdxWithMatchLen(GlideString key1, GlideString key2); + /** * Returns the indices and length of the longest common subsequence between strings stored at * key1 and key2. @@ -860,4 +1036,52 @@ public interface StringBaseCommands { */ CompletableFuture> lcsIdxWithMatchLen( String key1, String key2, long minMatchLen); + + /** + * Returns the indices and length of the longest common subsequence between strings stored at + * key1 and key2. + * + * @since Redis 7.0 and above. + * @apiNote When in cluster mode, key1 and key2 must map to the same + * hash slot. + * @see valkey.io for details. + * @param key1 The key that stores the first string. + * @param key2 The key that stores the second string. + * @param minMatchLen The minimum length of matches to include in the result. + * @return A Map containing the indices of the longest common subsequence between the + * 2 strings and the length of the longest common subsequence. The resulting map contains two + * keys, "matches" and "len": + *
    + *
  • "len" is mapped to the length of the longest common subsequence between the 2 strings + * stored as Long. + *
  • "matches" is mapped to a three dimensional Long array that stores pairs + * of indices that represent the location of the common subsequences in the strings held + * by key1 and key2. + *
+ * + * @example If key1 holds the GlideString gs("abcd1234") and key2 + * holds the GlideString gs("bcdef1234") then the sample result would be + *
{@code
+     * new Object[] {
+     *      new Object[] {
+     *          new Long[] {4L, 7L},
+     *          new Long[] {5L, 8L},
+     *          4L},
+     *      new Object[] {
+     *          new Long[] {1L, 3L},
+     *          new Long[] {0L, 2L},
+     *          3L}
+     *      }
+     * }
+ * The result indicates that the first substring match is gs("1234") in + * key1 + * at index 4 to 7 which matches the substring in key2 + * at index 5 to 8 and the last element in the array is the + * length of the substring match which is 4. And the second substring match is + * gs("bcd") in key1 at index 1 to 3 which + * matches the substring in key2 at index 0 to 2 and + * the last element in the array is the length of the substring match which is 3. + */ + CompletableFuture> lcsIdxWithMatchLen( + GlideString key1, GlideString key2, long minMatchLen); } diff --git a/java/client/src/test/java/glide/api/RedisClientTest.java b/java/client/src/test/java/glide/api/RedisClientTest.java index f9dbb589c6..e16e8675cf 100644 --- a/java/client/src/test/java/glide/api/RedisClientTest.java +++ b/java/client/src/test/java/glide/api/RedisClientTest.java @@ -11270,6 +11270,31 @@ public void lcs() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void lcs_binary() { + // setup + GlideString key1 = gs("testKey1"); + GlideString key2 = gs("testKey2"); + GlideString[] arguments = new GlideString[] {key1, key2}; + GlideString value = gs("foo"); + + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(LCS), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.lcs(key1, key2); + GlideString payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void lcs_with_len_option() { @@ -11295,6 +11320,31 @@ public void lcs_with_len_option() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void lcs_with_len_option_binary() { + // setup + GlideString key1 = gs("testKey1"); + GlideString key2 = gs("testKey2"); + GlideString[] arguments = new GlideString[] {key1, key2, gs(LEN_REDIS_API)}; + Long value = 3L; + + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(LCS), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.lcsLen(key1, key2); + Long payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void lcsIdx() { @@ -11320,6 +11370,31 @@ public void lcsIdx() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void lcsIdx_binary() { + // setup + GlideString key1 = gs("testKey1"); + GlideString key2 = gs("testKey2"); + GlideString[] arguments = new GlideString[] {key1, key2, gs(IDX_COMMAND_STRING)}; + Map value = Map.of("matches", new Long[][][] {{{1L, 3L}, {0L, 2L}}}, "len", 3L); + + CompletableFuture> testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.>submitNewCommand(eq(LCS), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture> response = service.lcsIdx(key1, key2); + Map payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void lcsIdx_throws_NullPointerException() { @@ -11366,6 +11441,39 @@ public void lcsIdx_with_options() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void lcsIdx_with_options_binary() { + // setup + GlideString key1 = gs("testKey1"); + GlideString key2 = gs("testKey2"); + GlideString[] arguments = + new GlideString[] { + key1, key2, gs(IDX_COMMAND_STRING), gs(MINMATCHLEN_COMMAND_STRING), gs("2") + }; + Map value = + Map.of( + "matches", + new Object[] {new Object[] {new Long[] {1L, 3L}, new Long[] {0L, 2L}, 3L}}, + "len", + 3L); + + CompletableFuture> testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.>submitNewCommand(eq(LCS), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture> response = service.lcsIdx(key1, key2, 2); + Map payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void lcsIdxWithMatchLen() { @@ -11396,6 +11504,37 @@ public void lcsIdxWithMatchLen() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void lcsIdxWithMatchLen_binary() { + // setup + GlideString key1 = gs("testKey1"); + GlideString key2 = gs("testKey2"); + GlideString[] arguments = + new GlideString[] {key1, key2, gs(IDX_COMMAND_STRING), gs(WITHMATCHLEN_COMMAND_STRING)}; + Map value = + Map.of( + "matches", + new Object[] {new Object[] {new Long[] {1L, 3L}, new Long[] {0L, 2L}, 3L}}, + "len", + 3L); + + CompletableFuture> testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.>submitNewCommand(eq(LCS), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture> response = service.lcsIdxWithMatchLen(key1, key2); + Map payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void lcsIdxWithMatchLen_with_options() { @@ -11434,6 +11573,44 @@ public void lcsIdxWithMatchLen_with_options() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void lcsIdxWithMatchLen_with_options_binary() { + // setup + GlideString key1 = gs("testKey1"); + GlideString key2 = gs("testKey2"); + GlideString[] arguments = + new GlideString[] { + key1, + key2, + gs(IDX_COMMAND_STRING), + gs(MINMATCHLEN_COMMAND_STRING), + gs("2"), + gs(WITHMATCHLEN_COMMAND_STRING) + }; + Map value = + Map.of( + "matches", + new Object[] {new Object[] {new Long[] {1L, 3L}, new Long[] {0L, 2L}, 3L}}, + "len", + 3L); + + CompletableFuture> testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.>submitNewCommand(eq(LCS), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture> response = service.lcsIdxWithMatchLen(key1, key2, 2); + Map payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void watch_returns_success() { diff --git a/java/integTest/src/test/java/glide/SharedCommandTests.java b/java/integTest/src/test/java/glide/SharedCommandTests.java index 30c731bb5d..d5372ffca3 100644 --- a/java/integTest/src/test/java/glide/SharedCommandTests.java +++ b/java/integTest/src/test/java/glide/SharedCommandTests.java @@ -9773,6 +9773,36 @@ public void lcs(BaseClient client) { assertInstanceOf(RequestException.class, executionException.getCause()); } + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void lcs_binary(BaseClient client) { + assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0"), "This feature added in redis 7.0.0"); + // setup + GlideString key1 = gs("{key}-1" + UUID.randomUUID()); + GlideString key2 = gs("{key}-2" + UUID.randomUUID()); + GlideString key3 = gs("{key}-3" + UUID.randomUUID()); + GlideString notExistingKey = gs("{key}-4" + UUID.randomUUID()); + + // keys does not exist or is empty + assertEquals(gs(""), client.lcs(key1, key2).get()); + + // setting string values + client.set(key1, gs("abcd")); + client.set(key2, gs("bcde")); + client.set(key3, gs("wxyz")); + + // getting the lcs + assertEquals(gs(""), client.lcs(key1, key3).get()); + assertEquals(gs("bcd"), client.lcs(key1, key2).get()); + + // non set keys are used + client.sadd(notExistingKey, new GlideString[] {gs("setmember")}).get(); + ExecutionException executionException = + assertThrows(ExecutionException.class, () -> client.lcs(notExistingKey, key1).get()); + assertInstanceOf(RequestException.class, executionException.getCause()); + } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -9803,6 +9833,36 @@ public void lcs_with_len_option(BaseClient client) { assertInstanceOf(RequestException.class, executionException.getCause()); } + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void lcs_with_len_option_binary(BaseClient client) { + assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0"), "This feature added in redis 7.0.0"); + // setup + GlideString key1 = gs("{key}-1" + UUID.randomUUID()); + GlideString key2 = gs("{key}-2" + UUID.randomUUID()); + GlideString key3 = gs("{key}-3" + UUID.randomUUID()); + GlideString notExistingKey = gs("{key}-4" + UUID.randomUUID()); + + // keys does not exist or is empty + assertEquals(0, client.lcsLen(key1, key2).get()); + + // setting string values + client.set(key1, gs("abcd")); + client.set(key2, gs("bcde")); + client.set(key3, gs("wxyz")); + + // getting the lcs + assertEquals(0, client.lcsLen(key1, key3).get()); + assertEquals(3, client.lcsLen(key1, key2).get()); + + // non set keys are used + client.sadd(notExistingKey, new GlideString[] {gs("setmember")}).get(); + ExecutionException executionException = + assertThrows(ExecutionException.class, () -> client.lcs(notExistingKey, key1).get()); + assertInstanceOf(RequestException.class, executionException.getCause()); + } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -10149,6 +10209,89 @@ public void lcsIdx(BaseClient client) { assertInstanceOf(RequestException.class, executionException.getCause()); } + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void lcsIdx_binary(BaseClient client) { + assumeTrue(REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0"), "This feature added in redis 7.0.0"); + // setup + GlideString key1 = gs("{key}-1" + UUID.randomUUID()); + GlideString key2 = gs("{key}-2" + UUID.randomUUID()); + GlideString notExistingKey = gs("{key}-4" + UUID.randomUUID()); + + // keys does not exist or is empty + Map result = client.lcsIdx(key1, key2).get(); + assertDeepEquals(new Object[0], result.get("matches")); + assertEquals(0L, result.get("len")); + result = client.lcsIdx(key1, key2, 10L).get(); + assertDeepEquals(new Object[0], result.get("matches")); + assertEquals(0L, result.get("len")); + result = client.lcsIdxWithMatchLen(key1, key2).get(); + assertDeepEquals(new Object[0], result.get("matches")); + assertEquals(0L, result.get("len")); + + // setting string values + client.set(key1, gs("abcdefghijk")); + client.set(key2, gs("defjkjuighijk")); + + // LCS with only IDX + Object expectedMatchesObject = new Long[][][] {{{6L, 10L}, {8L, 12L}}, {{3L, 5L}, {0L, 2L}}}; + result = client.lcsIdx(key1, key2).get(); + assertDeepEquals(expectedMatchesObject, result.get("matches")); + assertEquals(8L, result.get("len")); + + // LCS with IDX and WITHMATCHLEN + expectedMatchesObject = + new Object[] { + new Object[] {new Long[] {6L, 10L}, new Long[] {8L, 12L}, 5L}, + new Object[] {new Long[] {3L, 5L}, new Long[] {0L, 2L}, 3L} + }; + result = client.lcsIdxWithMatchLen(key1, key2).get(); + assertDeepEquals(expectedMatchesObject, result.get("matches")); + assertEquals(8L, result.get("len")); + + // LCS with IDX and MINMATCHLEN + expectedMatchesObject = new Long[][][] {{{6L, 10L}, {8L, 12L}}}; + result = client.lcsIdx(key1, key2, 4).get(); + assertDeepEquals(expectedMatchesObject, result.get("matches")); + assertEquals(8L, result.get("len")); + + // LCS with IDX and a negative MINMATCHLEN + expectedMatchesObject = new Long[][][] {{{6L, 10L}, {8L, 12L}}, {{3L, 5L}, {0L, 2L}}}; + result = client.lcsIdx(key1, key2, -1L).get(); + assertDeepEquals(expectedMatchesObject, result.get("matches")); + assertEquals(8L, result.get("len")); + + // LCS with IDX, MINMATCHLEN, and WITHMATCHLEN + expectedMatchesObject = + new Object[] {new Object[] {new Long[] {6L, 10L}, new Long[] {8L, 12L}, 5L}}; + result = client.lcsIdxWithMatchLen(key1, key2, 4L).get(); + assertDeepEquals(expectedMatchesObject, result.get("matches")); + assertEquals(8L, result.get("len")); + + // non-string keys are used + client.sadd(notExistingKey, new GlideString[] {gs("setmember")}).get(); + ExecutionException executionException = + assertThrows(ExecutionException.class, () -> client.lcsIdx(notExistingKey, key1).get()); + assertInstanceOf(RequestException.class, executionException.getCause()); + + executionException = + assertThrows( + ExecutionException.class, () -> client.lcsIdx(notExistingKey, key1, 10L).get()); + assertInstanceOf(RequestException.class, executionException.getCause()); + + executionException = + assertThrows( + ExecutionException.class, () -> client.lcsIdxWithMatchLen(notExistingKey, key1).get()); + assertInstanceOf(RequestException.class, executionException.getCause()); + + executionException = + assertThrows( + ExecutionException.class, + () -> client.lcsIdxWithMatchLen(notExistingKey, key1, 10L).get()); + assertInstanceOf(RequestException.class, executionException.getCause()); + } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") From 250d7edffc7e5c2ef1dcac3d9e623ba1a3fa88df Mon Sep 17 00:00:00 2001 From: Shoham Elias <116083498+shohamazon@users.noreply.github.com> Date: Thu, 4 Jul 2024 17:29:38 +0300 Subject: [PATCH 20/23] Python: Rename ClusterClientConfiguration to GlideClusterClientConfiguration (#1806) --- CHANGELOG.md | 1 + examples/python/client_example.py | 4 +- python/README.md | 4 +- python/python/glide/__init__.py | 4 +- python/python/glide/config.py | 8 +- python/python/tests/conftest.py | 6 +- python/python/tests/test_async_client.py | 2 +- python/python/tests/test_config.py | 4 +- python/python/tests/test_pubsub.py | 94 ++++++++++++++---------- 9 files changed, 74 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d595d5328..94cd88286a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -85,6 +85,7 @@ * Node: Update XREAD to return a Map of Map ([#1494](https://github.com/aws/glide-for-redis/pull/1494)) * Node: Rename RedisClient to GlideClient and RedisClusterClient to GlideClusterClient ([#1670](https://github.com/aws/glide-for-redis/pull/1670)) * Python: Rename RedisClient to GlideClient, RedisClusterClient to GlideClusterClient and BaseRedisClient to BaseClient([#1669](https://github.com/aws/glide-for-redis/pull/1669)) +* Python: Rename ClusterClientConfiguration to GlideClusterClientConfiguration ([#1806](https://github.com/aws/glide-for-redis/pull/1806)) ## 0.4.1 (2024-02-06) diff --git a/examples/python/client_example.py b/examples/python/client_example.py index bcc52be8e8..35d9ea5a8b 100755 --- a/examples/python/client_example.py +++ b/examples/python/client_example.py @@ -39,7 +39,7 @@ async def test_standalone_client(host: str = "localhost", port: int = 6379): # When in Redis is in standalone mode, add address of the primary node, # and any replicas you'd like to be able to read from. addresses = [NodeAddress(host, port)] - # Check `GlideClientConfiguration/ClusterClientConfiguration` for additional options. + # Check `GlideClientConfiguration/GlideClusterClientConfiguration` for additional options. config = BaseClientConfiguration( addresses=addresses, client_name="test_standalone_client", @@ -59,7 +59,7 @@ async def test_standalone_client(host: str = "localhost", port: int = 6379): async def test_cluster_client(host: str = "localhost", port: int = 6379): # When in Redis is cluster mode, add address of any nodes, and the client will find all nodes in the cluster. addresses = [NodeAddress(host, port)] - # Check `GlideClientConfiguration/ClusterClientConfiguration` for additional options. + # Check `GlideClientConfiguration/GlideClusterClientConfiguration` for additional options. config = BaseClientConfiguration( addresses=addresses, client_name="test_cluster_client", diff --git a/python/README.md b/python/README.md index 22c01d75ce..f857b69789 100644 --- a/python/README.md +++ b/python/README.md @@ -51,10 +51,10 @@ To install GLIDE for Redis using `pip`, follow these steps: ```python: >>> import asyncio ->>> from glide import ClusterClientConfiguration, NodeAddress, GlideClusterClient +>>> from glide import GlideClusterClientConfiguration, NodeAddress, GlideClusterClient >>> async def test_cluster_client(): ... addresses = [NodeAddress("redis.example.com", 6379)] -... config = ClusterClientConfiguration(addresses) +... config = GlideClusterClientConfiguration(addresses) ... client = await GlideClusterClient.create(config) ... set_result = await client.set("foo", "bar") ... print(f"Set response is {set_result}") diff --git a/python/python/glide/__init__.py b/python/python/glide/__init__.py index 61a0137275..c755f201f3 100644 --- a/python/python/glide/__init__.py +++ b/python/python/glide/__init__.py @@ -67,8 +67,8 @@ from glide.config import ( BackoffStrategy, BaseClientConfiguration, - ClusterClientConfiguration, GlideClientConfiguration, + GlideClusterClientConfiguration, NodeAddress, PeriodicChecksManualInterval, PeriodicChecksStatus, @@ -110,7 +110,7 @@ # Config "BaseClientConfiguration", "GlideClientConfiguration", - "ClusterClientConfiguration", + "GlideClusterClientConfiguration", "BackoffStrategy", "ReadFrom", "ServerCredentials", diff --git a/python/python/glide/config.py b/python/python/glide/config.py index e4ad281b76..662bffd889 100644 --- a/python/python/glide/config.py +++ b/python/python/glide/config.py @@ -345,7 +345,7 @@ def _get_pubsub_callback_and_context( return None, None -class ClusterClientConfiguration(BaseClientConfiguration): +class GlideClusterClientConfiguration(BaseClientConfiguration): """ Represents the configuration settings for a Cluster Glide client. @@ -369,7 +369,7 @@ class ClusterClientConfiguration(BaseClientConfiguration): These checks evaluate changes in the cluster's topology, triggering a slot refresh when detected. Periodic checks ensure a quick and efficient process by querying a limited number of nodes. Defaults to PeriodicChecksStatus.ENABLED_DEFAULT_CONFIGS. - pubsub_subscriptions (Optional[ClusterClientConfiguration.PubSubSubscriptions]): Pubsub subscriptions to be used for the client. + pubsub_subscriptions (Optional[GlideClusterClientConfiguration.PubSubSubscriptions]): Pubsub subscriptions to be used for the client. Will be applied via SUBSCRIBE/PSUBSCRIBE/SSUBSCRIBE commands during connection establishment. Notes: @@ -395,7 +395,7 @@ class PubSubSubscriptions: """Describes pubsub configuration for cluster mode client. Attributes: - channels_and_patterns (Dict[ClusterClientConfiguration.PubSubChannelModes, Set[str]]): + channels_and_patterns (Dict[GlideClusterClientConfiguration.PubSubChannelModes, Set[str]]): Channels and patterns by modes. callback (Optional[Callable[[CoreCommands.PubSubMsg, Any], None]]): Optional callback to accept the incoming messages. @@ -404,7 +404,7 @@ class PubSubSubscriptions: """ channels_and_patterns: Dict[ - ClusterClientConfiguration.PubSubChannelModes, Set[str] + GlideClusterClientConfiguration.PubSubChannelModes, Set[str] ] callback: Optional[Callable[[CoreCommands.PubSubMsg, Any], None]] context: Any diff --git a/python/python/tests/conftest.py b/python/python/tests/conftest.py index b10b0eadcf..4fab580098 100644 --- a/python/python/tests/conftest.py +++ b/python/python/tests/conftest.py @@ -5,8 +5,8 @@ import pytest from glide.config import ( - ClusterClientConfiguration, GlideClientConfiguration, + GlideClusterClientConfiguration, NodeAddress, ProtocolVersion, ServerCredentials, @@ -224,7 +224,7 @@ async def create_client( protocol: ProtocolVersion = ProtocolVersion.RESP3, timeout: Optional[int] = None, cluster_mode_pubsub: Optional[ - ClusterClientConfiguration.PubSubSubscriptions + GlideClusterClientConfiguration.PubSubSubscriptions ] = None, standalone_mode_pubsub: Optional[ GlideClientConfiguration.PubSubSubscriptions @@ -237,7 +237,7 @@ async def create_client( assert database_id == 0 k = min(3, len(pytest.redis_cluster.nodes_addr)) seed_nodes = random.sample(pytest.redis_cluster.nodes_addr, k=k) - cluster_config = ClusterClientConfiguration( + cluster_config = GlideClusterClientConfiguration( addresses=seed_nodes if addresses is None else addresses, use_tls=use_tls, credentials=credentials, diff --git a/python/python/tests/test_async_client.py b/python/python/tests/test_async_client.py index 58b3113d14..9ef669f54b 100644 --- a/python/python/tests/test_async_client.py +++ b/python/python/tests/test_async_client.py @@ -71,8 +71,8 @@ ) from glide.async_commands.transaction import ClusterTransaction, Transaction from glide.config import ( - ClusterClientConfiguration, GlideClientConfiguration, + GlideClusterClientConfiguration, ProtocolVersion, ServerCredentials, ) diff --git a/python/python/tests/test_config.py b/python/python/tests/test_config.py index 9c05db1199..93c280245f 100644 --- a/python/python/tests/test_config.py +++ b/python/python/tests/test_config.py @@ -2,7 +2,7 @@ from glide.config import ( BaseClientConfiguration, - ClusterClientConfiguration, + GlideClusterClientConfiguration, NodeAddress, PeriodicChecksManualInterval, PeriodicChecksStatus, @@ -38,7 +38,7 @@ def test_convert_to_protobuf(): def test_periodic_checks_interval_to_protobuf(): - config = ClusterClientConfiguration( + config = GlideClusterClientConfiguration( [NodeAddress("127.0.0.1")], ) request = config._create_a_protobuf_conn_request(cluster_mode=True) diff --git a/python/python/tests/test_pubsub.py b/python/python/tests/test_pubsub.py index f447ed9fe9..ae33e5ae0e 100644 --- a/python/python/tests/test_pubsub.py +++ b/python/python/tests/test_pubsub.py @@ -9,8 +9,8 @@ import pytest from glide.async_commands.core import CoreCommands from glide.config import ( - ClusterClientConfiguration, GlideClientConfiguration, + GlideClusterClientConfiguration, ProtocolVersion, ) from glide.constants import OK @@ -122,7 +122,7 @@ async def check_no_messages_left( def create_pubsub_subscription( cluster_mode, cluster_channels_and_patterns: Dict[ - ClusterClientConfiguration.PubSubChannelModes, Set[str] + GlideClusterClientConfiguration.PubSubChannelModes, Set[str] ], standalone_channels_and_patterns: Dict[ GlideClientConfiguration.PubSubChannelModes, Set[str] @@ -131,7 +131,7 @@ def create_pubsub_subscription( context=None, ): if cluster_mode: - return ClusterClientConfiguration.PubSubSubscriptions( + return GlideClusterClientConfiguration.PubSubSubscriptions( channels_and_patterns=cluster_channels_and_patterns, callback=callback, context=context, @@ -178,7 +178,7 @@ async def test_pubsub_exact_happy_path( pub_sub = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Exact: {channel}}, + {GlideClusterClientConfiguration.PubSubChannelModes.Exact: {channel}}, {GlideClientConfiguration.PubSubChannelModes.Exact: {channel}}, callback=callback, context=context, @@ -228,7 +228,7 @@ async def test_pubsub_exact_happy_path_coexistence( pub_sub = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Exact: {channel}}, + {GlideClusterClientConfiguration.PubSubChannelModes.Exact: {channel}}, {GlideClientConfiguration.PubSubChannelModes.Exact: {channel}}, ) @@ -305,7 +305,7 @@ async def test_pubsub_exact_happy_path_many_channels( pub_sub = create_pubsub_subscription( cluster_mode, { - ClusterClientConfiguration.PubSubChannelModes.Exact: set( + GlideClusterClientConfiguration.PubSubChannelModes.Exact: set( channels_and_messages.keys() ) }, @@ -380,7 +380,7 @@ async def test_pubsub_exact_happy_path_many_channels_co_existence( pub_sub = create_pubsub_subscription( cluster_mode, { - ClusterClientConfiguration.PubSubChannelModes.Exact: set( + GlideClusterClientConfiguration.PubSubChannelModes.Exact: set( channels_and_messages.keys() ) }, @@ -458,7 +458,7 @@ async def test_sharded_pubsub( pub_sub = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Sharded: {channel}}, + {GlideClusterClientConfiguration.PubSubChannelModes.Sharded: {channel}}, {}, callback=callback, context=context, @@ -517,7 +517,7 @@ async def test_sharded_pubsub_co_existence(self, request, cluster_mode: bool): pub_sub = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Sharded: {channel}}, + {GlideClusterClientConfiguration.PubSubChannelModes.Sharded: {channel}}, {}, ) @@ -606,7 +606,7 @@ async def test_sharded_pubsub_many_channels( pub_sub = create_pubsub_subscription( cluster_mode, { - ClusterClientConfiguration.PubSubChannelModes.Sharded: set( + GlideClusterClientConfiguration.PubSubChannelModes.Sharded: set( channels_and_messages.keys() ) }, @@ -690,7 +690,7 @@ async def test_pubsub_pattern( pub_sub = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Pattern: {PATTERN}}, + {GlideClusterClientConfiguration.PubSubChannelModes.Pattern: {PATTERN}}, {GlideClientConfiguration.PubSubChannelModes.Pattern: {PATTERN}}, callback=callback, context=context, @@ -747,7 +747,7 @@ async def test_pubsub_pattern_co_existence(self, request, cluster_mode: bool): pub_sub = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Pattern: {PATTERN}}, + {GlideClusterClientConfiguration.PubSubChannelModes.Pattern: {PATTERN}}, {GlideClientConfiguration.PubSubChannelModes.Pattern: {PATTERN}}, ) @@ -819,7 +819,7 @@ async def test_pubsub_pattern_many_channels( pub_sub = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Pattern: {PATTERN}}, + {GlideClusterClientConfiguration.PubSubChannelModes.Pattern: {PATTERN}}, {GlideClientConfiguration.PubSubChannelModes.Pattern: {PATTERN}}, callback=callback, context=context, @@ -906,10 +906,10 @@ async def test_pubsub_combined_exact_and_pattern_one_client( pub_sub_exact = create_pubsub_subscription( cluster_mode, { - ClusterClientConfiguration.PubSubChannelModes.Exact: set( + GlideClusterClientConfiguration.PubSubChannelModes.Exact: set( exact_channels_and_messages.keys() ), - ClusterClientConfiguration.PubSubChannelModes.Pattern: {PATTERN}, + GlideClusterClientConfiguration.PubSubChannelModes.Pattern: {PATTERN}, }, { GlideClientConfiguration.PubSubChannelModes.Exact: set( @@ -1017,7 +1017,7 @@ async def test_pubsub_combined_exact_and_pattern_multiple_clients( pub_sub_exact = create_pubsub_subscription( cluster_mode, { - ClusterClientConfiguration.PubSubChannelModes.Exact: set( + GlideClusterClientConfiguration.PubSubChannelModes.Exact: set( exact_channels_and_messages.keys() ) }, @@ -1044,7 +1044,7 @@ async def test_pubsub_combined_exact_and_pattern_multiple_clients( # Setup PUBSUB for pattern channels pub_sub_pattern = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Pattern: {PATTERN}}, + {GlideClusterClientConfiguration.PubSubChannelModes.Pattern: {PATTERN}}, {GlideClientConfiguration.PubSubChannelModes.Pattern: {PATTERN}}, callback=callback, context=context, @@ -1164,11 +1164,11 @@ async def test_pubsub_combined_exact_pattern_and_sharded_one_client( pub_sub_exact = create_pubsub_subscription( cluster_mode, { - ClusterClientConfiguration.PubSubChannelModes.Exact: set( + GlideClusterClientConfiguration.PubSubChannelModes.Exact: set( exact_channels_and_messages.keys() ), - ClusterClientConfiguration.PubSubChannelModes.Pattern: {PATTERN}, - ClusterClientConfiguration.PubSubChannelModes.Sharded: set( + GlideClusterClientConfiguration.PubSubChannelModes.Pattern: {PATTERN}, + GlideClusterClientConfiguration.PubSubChannelModes.Sharded: set( sharded_channels_and_messages.keys() ), }, @@ -1304,7 +1304,7 @@ async def test_pubsub_combined_exact_pattern_and_sharded_multi_client( pub_sub_exact = create_pubsub_subscription( cluster_mode, { - ClusterClientConfiguration.PubSubChannelModes.Exact: set( + GlideClusterClientConfiguration.PubSubChannelModes.Exact: set( exact_channels_and_messages.keys() ) }, @@ -1333,7 +1333,7 @@ async def test_pubsub_combined_exact_pattern_and_sharded_multi_client( # Setup PUBSUB for pattern channels pub_sub_pattern = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Pattern: {PATTERN}}, + {GlideClusterClientConfiguration.PubSubChannelModes.Pattern: {PATTERN}}, {GlideClientConfiguration.PubSubChannelModes.Pattern: {PATTERN}}, callback=callback, context=context, @@ -1345,7 +1345,7 @@ async def test_pubsub_combined_exact_pattern_and_sharded_multi_client( pub_sub_sharded = create_pubsub_subscription( cluster_mode, { - ClusterClientConfiguration.PubSubChannelModes.Sharded: set( + GlideClusterClientConfiguration.PubSubChannelModes.Sharded: set( sharded_channels_and_messages.keys() ) }, @@ -1495,7 +1495,7 @@ async def test_pubsub_combined_different_channels_with_same_name( # Setup PUBSUB for exact channel pub_sub_exact = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Exact: {CHANNEL_NAME}}, + {GlideClusterClientConfiguration.PubSubChannelModes.Exact: {CHANNEL_NAME}}, {GlideClientConfiguration.PubSubChannelModes.Exact: {CHANNEL_NAME}}, callback=callback, context=context, @@ -1518,7 +1518,11 @@ async def test_pubsub_combined_different_channels_with_same_name( # Setup PUBSUB for pattern channels pub_sub_pattern = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Pattern: {CHANNEL_NAME}}, + { + GlideClusterClientConfiguration.PubSubChannelModes.Pattern: { + CHANNEL_NAME + } + }, {GlideClientConfiguration.PubSubChannelModes.Pattern: {CHANNEL_NAME}}, callback=callback, context=context, @@ -1529,7 +1533,11 @@ async def test_pubsub_combined_different_channels_with_same_name( pub_sub_sharded = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Sharded: {CHANNEL_NAME}}, + { + GlideClusterClientConfiguration.PubSubChannelModes.Sharded: { + CHANNEL_NAME + } + }, {}, callback=callback, context=context, @@ -1635,7 +1643,7 @@ async def test_pubsub_two_publishing_clients_same_name( # Setup PUBSUB for exact channel pub_sub_exact = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Exact: {CHANNEL_NAME}}, + {GlideClusterClientConfiguration.PubSubChannelModes.Exact: {CHANNEL_NAME}}, {GlideClientConfiguration.PubSubChannelModes.Exact: {CHANNEL_NAME}}, callback=callback, context=context_exact, @@ -1643,7 +1651,11 @@ async def test_pubsub_two_publishing_clients_same_name( # Setup PUBSUB for pattern channels pub_sub_pattern = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Pattern: {CHANNEL_NAME}}, + { + GlideClusterClientConfiguration.PubSubChannelModes.Pattern: { + CHANNEL_NAME + } + }, {GlideClientConfiguration.PubSubChannelModes.Pattern: {CHANNEL_NAME}}, callback=callback, context=context_pattern, @@ -1736,7 +1748,7 @@ async def test_pubsub_three_publishing_clients_same_name_with_sharded( # Setup PUBSUB for exact channel pub_sub_exact = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Exact: {CHANNEL_NAME}}, + {GlideClusterClientConfiguration.PubSubChannelModes.Exact: {CHANNEL_NAME}}, {GlideClientConfiguration.PubSubChannelModes.Exact: {CHANNEL_NAME}}, callback=callback, context=context_exact, @@ -1744,7 +1756,11 @@ async def test_pubsub_three_publishing_clients_same_name_with_sharded( # Setup PUBSUB for pattern channels pub_sub_pattern = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Pattern: {CHANNEL_NAME}}, + { + GlideClusterClientConfiguration.PubSubChannelModes.Pattern: { + CHANNEL_NAME + } + }, {GlideClientConfiguration.PubSubChannelModes.Pattern: {CHANNEL_NAME}}, callback=callback, context=context_pattern, @@ -1752,7 +1768,11 @@ async def test_pubsub_three_publishing_clients_same_name_with_sharded( # Setup PUBSUB for pattern channels pub_sub_sharded = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Sharded: {CHANNEL_NAME}}, + { + GlideClusterClientConfiguration.PubSubChannelModes.Sharded: { + CHANNEL_NAME + } + }, {}, callback=callback, context=context_sharded, @@ -1854,7 +1874,7 @@ async def test_pubsub_exact_max_size_message(self, request, cluster_mode: bool): pub_sub = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Exact: {channel}}, + {GlideClusterClientConfiguration.PubSubChannelModes.Exact: {channel}}, {GlideClientConfiguration.PubSubChannelModes.Exact: {channel}}, ) @@ -1921,7 +1941,7 @@ async def test_pubsub_sharded_max_size_message(self, request, cluster_mode: bool pub_sub = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Sharded: {channel}}, + {GlideClusterClientConfiguration.PubSubChannelModes.Sharded: {channel}}, {}, ) @@ -2000,7 +2020,7 @@ async def test_pubsub_exact_max_size_message_callback( pub_sub = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Exact: {channel}}, + {GlideClusterClientConfiguration.PubSubChannelModes.Exact: {channel}}, {GlideClientConfiguration.PubSubChannelModes.Exact: {channel}}, callback=callback, context=context, @@ -2057,7 +2077,7 @@ async def test_pubsub_sharded_max_size_message_callback( pub_sub = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Sharded: {channel}}, + {GlideClusterClientConfiguration.PubSubChannelModes.Sharded: {channel}}, {}, callback=callback, context=context, @@ -2101,7 +2121,7 @@ async def test_pubsub_resp2_raise_an_error(self, request, cluster_mode: bool): pub_sub_exact = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Exact: {channel}}, + {GlideClusterClientConfiguration.PubSubChannelModes.Exact: {channel}}, {GlideClientConfiguration.PubSubChannelModes.Exact: {channel}}, ) @@ -2119,7 +2139,7 @@ async def test_pubsub_context_with_no_callback_raise_error( context: List[CoreCommands.PubSubMsg] = [] pub_sub_exact = create_pubsub_subscription( cluster_mode, - {ClusterClientConfiguration.PubSubChannelModes.Exact: {channel}}, + {GlideClusterClientConfiguration.PubSubChannelModes.Exact: {channel}}, {GlideClientConfiguration.PubSubChannelModes.Exact: {channel}}, context=context, ) From 4ccbc7ab77a26ebf179b1b2379991a5651b8dcdd Mon Sep 17 00:00:00 2001 From: talxsha <160726520+talxsha@users.noreply.github.com> Date: Thu, 4 Jul 2024 18:47:10 +0300 Subject: [PATCH 21/23] fcall bug fix (#1799) * fcall handlers and test fix --- .../src/main/java/glide/api/BaseClient.java | 5 +++-- .../java/glide/api/RedisClusterClient.java | 13 +++++++------ .../test/java/glide/cluster/CommandTests.java | 18 +++++++++--------- .../java/glide/standalone/CommandTests.java | 6 +++--- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/java/client/src/main/java/glide/api/BaseClient.java b/java/client/src/main/java/glide/api/BaseClient.java index 6cc9006f4f..a7514ccef8 100644 --- a/java/client/src/main/java/glide/api/BaseClient.java +++ b/java/client/src/main/java/glide/api/BaseClient.java @@ -3644,7 +3644,7 @@ public CompletableFuture fcall( GlideString[] args = concatenateArrays( new GlideString[] {function, gs(Long.toString(keys.length))}, keys, arguments); - return commandManager.submitNewCommand(FCall, args, this::handleObjectOrNullResponse); + return commandManager.submitNewCommand(FCall, args, this::handleBinaryObjectOrNullResponse); } @Override @@ -3663,7 +3663,8 @@ public CompletableFuture fcallReadOnly( GlideString[] args = concatenateArrays( new GlideString[] {function, gs(Long.toString(keys.length))}, keys, arguments); - return commandManager.submitNewCommand(FCallReadOnly, args, this::handleObjectOrNullResponse); + return commandManager.submitNewCommand( + FCallReadOnly, args, this::handleBinaryObjectOrNullResponse); } @Override diff --git a/java/client/src/main/java/glide/api/RedisClusterClient.java b/java/client/src/main/java/glide/api/RedisClusterClient.java index 508ebfcffb..194fb15bf0 100644 --- a/java/client/src/main/java/glide/api/RedisClusterClient.java +++ b/java/client/src/main/java/glide/api/RedisClusterClient.java @@ -814,7 +814,7 @@ public CompletableFuture fcall( @NonNull GlideString function, @NonNull GlideString[] arguments) { GlideString[] args = concatenateArrays(new GlideString[] {function, gs("0")}, arguments); // 0 - key count - return commandManager.submitNewCommand(FCall, args, this::handleObjectOrNullResponse); + return commandManager.submitNewCommand(FCall, args, this::handleBinaryObjectOrNullResponse); } @Override @@ -842,8 +842,8 @@ public CompletableFuture> fcall( route, response -> route instanceof SingleNodeRoute - ? ClusterValue.ofSingleValue(handleObjectOrNullResponse(response)) - : ClusterValue.ofMultiValue(handleMapResponse(response))); + ? ClusterValue.ofSingleValue(handleBinaryObjectOrNullResponse(response)) + : ClusterValue.ofMultiValueBinary(handleBinaryStringMapResponse(response))); } @Override @@ -880,7 +880,8 @@ public CompletableFuture fcallReadOnly( @NonNull GlideString function, @NonNull GlideString[] arguments) { GlideString[] args = concatenateArrays(new GlideString[] {function, gs("0")}, arguments); // 0 - key count - return commandManager.submitNewCommand(FCallReadOnly, args, this::handleObjectOrNullResponse); + return commandManager.submitNewCommand( + FCallReadOnly, args, this::handleBinaryObjectOrNullResponse); } @Override @@ -908,8 +909,8 @@ public CompletableFuture> fcallReadOnly( route, response -> route instanceof SingleNodeRoute - ? ClusterValue.ofSingleValue(handleObjectOrNullResponse(response)) - : ClusterValue.ofMultiValue(handleMapResponse(response))); + ? ClusterValue.ofSingleValue(handleBinaryObjectOrNullResponse(response)) + : ClusterValue.ofMultiValueBinary(handleBinaryStringMapResponse(response))); } @Override diff --git a/java/integTest/src/test/java/glide/cluster/CommandTests.java b/java/integTest/src/test/java/glide/cluster/CommandTests.java index bd604e71fd..79a39a844e 100644 --- a/java/integTest/src/test/java/glide/cluster/CommandTests.java +++ b/java/integTest/src/test/java/glide/cluster/CommandTests.java @@ -1192,10 +1192,10 @@ public void function_commands_without_keys_with_route_binary(boolean singleNodeR var fcallResult = clusterClient.fcall(funcName, new GlideString[] {gs("one"), gs("two")}, route).get(); if (route instanceof SingleNodeRoute) { - assertEquals("one", fcallResult.getSingleValue()); + assertEquals(gs("one"), fcallResult.getSingleValue()); } else { for (var nodeResponse : fcallResult.getMultiValue().values()) { - assertEquals("one", nodeResponse); + assertEquals(gs("one"), nodeResponse); } } fcallResult = @@ -1203,10 +1203,10 @@ public void function_commands_without_keys_with_route_binary(boolean singleNodeR .fcallReadOnly(funcName, new GlideString[] {gs("one"), gs("two")}, route) .get(); if (route instanceof SingleNodeRoute) { - assertEquals("one", fcallResult.getSingleValue()); + assertEquals(gs("one"), fcallResult.getSingleValue()); } else { for (var nodeResponse : fcallResult.getMultiValue().values()) { - assertEquals("one", nodeResponse); + assertEquals(gs("one"), nodeResponse); } } @@ -1432,9 +1432,9 @@ public void function_commands_without_keys_and_without_route_binary() { assertEquals(libName, clusterClient.functionLoad(code, false).get()); assertEquals( - "one", clusterClient.fcall(funcName, new GlideString[] {gs("one"), gs("two")}).get()); + gs("one"), clusterClient.fcall(funcName, new GlideString[] {gs("one"), gs("two")}).get()); assertEquals( - "one", + gs("one"), clusterClient.fcallReadOnly(funcName, new GlideString[] {gs("one"), gs("two")}).get()); var flist = clusterClient.functionListBinary(false).get(); @@ -1570,13 +1570,13 @@ public void fcall_binary_with_keys(String prefix) { clusterClient .fcall(funcName, new GlideString[] {gs(key + 1), gs(key + 2)}, new GlideString[0]) .get(); - assertArrayEquals(new Object[] {key + 1, key + 2}, (Object[]) functionResult); + assertArrayEquals(new Object[] {gs(key + 1), gs(key + 2)}, (Object[]) functionResult); functionResult = clusterClient .fcallReadOnly( funcName, new GlideString[] {gs(key + 1), gs(key + 2)}, new GlideString[0]) .get(); - assertArrayEquals(new Object[] {key + 1, key + 2}, (Object[]) functionResult); + assertArrayEquals(new Object[] {gs(key + 1), gs(key + 2)}, (Object[]) functionResult); // TODO: change to binary transaction version once available: // var transaction = @@ -2308,7 +2308,7 @@ public void functionStatsBinary_and_functionKill_write_function() { assertInstanceOf(RequestException.class, exception.getCause()); assertTrue(exception.getMessage().toLowerCase().contains("unkillable")); - assertEquals("Timed out 6 sec", promise.get()); + assertEquals(gs("Timed out 6 sec"), promise.get()); exception = assertThrows(ExecutionException.class, () -> clusterClient.functionKill(route).get()); diff --git a/java/integTest/src/test/java/glide/standalone/CommandTests.java b/java/integTest/src/test/java/glide/standalone/CommandTests.java index 1d7cc47e4e..4984e2d03c 100644 --- a/java/integTest/src/test/java/glide/standalone/CommandTests.java +++ b/java/integTest/src/test/java/glide/standalone/CommandTests.java @@ -599,12 +599,12 @@ public void function_commands_binary() { regularClient .fcall(funcName, new GlideString[0], new GlideString[] {gs("one"), gs("two")}) .get(); - assertEquals("one", functionResult); + assertEquals(gs("one"), functionResult); functionResult = regularClient .fcallReadOnly(funcName, new GlideString[0], new GlideString[] {gs("one"), gs("two")}) .get(); - assertEquals("one", functionResult); + assertEquals(gs("one"), functionResult); var flist = regularClient.functionListBinary(false).get(); var expectedDescription = @@ -990,7 +990,7 @@ public void functionStatsBinary_and_functionKill_write_function() { assertInstanceOf(RequestException.class, exception.getCause()); assertTrue(exception.getMessage().toLowerCase().contains("unkillable")); - assertEquals("Timed out 6 sec", promise.get()); + assertEquals(gs("Timed out 6 sec"), promise.get()); exception = assertThrows(ExecutionException.class, () -> regularClient.functionKill().get()); From 7b20bc125e562fe98f16db592125f83dea7d09d2 Mon Sep 17 00:00:00 2001 From: Shoham Elias <116083498+shohamazon@users.noreply.github.com> Date: Thu, 4 Jul 2024 19:34:09 +0300 Subject: [PATCH 22/23] Update README for Valkey GLIDE (#1812) --- README.md | 7 ++++--- java/DEVELOPER.md | 4 ++-- java/README.md | 10 ++++------ node/README.md | 4 ++-- python/DEVELOPER.md | 8 ++++---- python/README.md | 11 +++-------- 6 files changed, 19 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 2ef08f09a1..4c3110e11b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ -# GLIDE for Redis -General Language Independent Driver for the Enterprise (GLIDE) for Redis, is an AWS-sponsored, open-source Redis client. GLIDE for Redis works with any Redis distribution that adheres to the Redis Serialization Protocol (RESP) specification, including open-source Redis, Amazon ElastiCache for Redis, and Amazon MemoryDB for Redis. -Strategic, mission-critical Redis-based applications have requirements for security, optimized performance, minimal downtime, and observability. GLIDE for Redis is designed to provide a client experience that helps meet these objectives. It is sponsored and supported by AWS, and comes pre-configured with best practices learned from over a decade of operating Redis-compatible services used by hundreds of thousands of customers. To help ensure consistency in development and operations, GLIDE for Redis is implemented using a core driver framework, written in Rust, with extensions made available for each supported programming language. This design ensures that updates easily propagate to each language and reduces overall complexity. In this Preview release, GLIDE for Redis is available for Python and Javascript (Node.js), with support for Java actively under development. +### Valkey GLIDE + +Valkey General Language Independent Driver for the Enterprise (GLIDE), is an AWS-sponsored, open-source Valkey client that includes support for open-source Redis 6.2 to 7.2. Valkey GLIDE works with any distribution that adheres to the Redis Serialization Protocol (RESP) specification, including Amazon ElastiCache, and Amazon MemoryDB. +Strategic, mission-critical applications have requirements for security, optimized performance, minimal downtime, and observability. Valkey GLIDE is designed to provide a client experience that helps meet these objectives. It is sponsored and supported by AWS, and comes pre-configured with best practices learned from over a decade of operating RESP-compatible services used by hundreds of thousands of customers. To help ensure consistency in development and operations, Valkey GLIDE is implemented using a core driver framework, written in Rust, with extensions made available for each supported programming language. This design ensures that updates easily propagate to each language and reduces overall complexity. In this Preview release, Valkey GLIDE is available for Python and Java, with support for Javascript (Node.js) actively under development. ## Supported Engine Versions GLIDE for Redis is API-compatible with the following engine versions: diff --git a/java/DEVELOPER.md b/java/DEVELOPER.md index 9930d86149..93df6b333c 100644 --- a/java/DEVELOPER.md +++ b/java/DEVELOPER.md @@ -1,10 +1,10 @@ # Developer Guide -This document describes how to set up your development environment to build and test the GLIDE for Redis Java wrapper. +This document describes how to set up your development environment to build and test the Valkey GLIDE Java wrapper. ### Development Overview -The GLIDE for Redis Java wrapper consists of both Java and Rust code. Rust bindings for the Java Native Interface are implemented using [jni-rs](https://github.com/jni-rs/jni-rs), and the Java JAR is built using [Gradle](https://github.com/gradle/gradle). The Java and Rust components communicate using the [protobuf](https://github.com/protocolbuffers/protobuf) protocol. +The Valkey GLIDE Java wrapper consists of both Java and Rust code. Rust bindings for the Java Native Interface are implemented using [jni-rs](https://github.com/jni-rs/jni-rs), and the Java JAR is built using [Gradle](https://github.com/gradle/gradle). The Java and Rust components communicate using the [protobuf](https://github.com/protocolbuffers/protobuf) protocol. ### Build from source diff --git a/java/README.md b/java/README.md index 45d04b9e42..57682ca14c 100644 --- a/java/README.md +++ b/java/README.md @@ -1,11 +1,9 @@ -# Getting Started - Java Wrapper +## Valkey GLIDE -## Notice: Java Wrapper - Work in Progress +Valkey General Language Independent Driver for the Enterprise (GLIDE), is an AWS-sponsored, open-source Valkey client that includes support for open-source Redis 6.2 to 7.2. Valkey GLIDE works with any distribution that adheres to the Redis Serialization Protocol (RESP) specification, including Amazon ElastiCache, and Amazon MemoryDB. +Strategic, mission-critical applications have requirements for security, optimized performance, minimal downtime, and observability. Valkey GLIDE is designed to provide a client experience that helps meet these objectives. It is sponsored and supported by AWS, and comes pre-configured with best practices learned from over a decade of operating RESP-compatible services used by hundreds of thousands of customers. To help ensure consistency in development and operations, Valkey GLIDE is implemented using a core driver framework, written in Rust, with extensions made available for each supported programming language. This design ensures that updates easily propagate to each language and reduces overall complexity. In this Preview release, Valkey GLIDE is available for Python and Java, with support for Javascript (Node.js) actively under development. -We're excited to share that the Java client is currently in development! However, it's important to note that this client -is a work in progress and is not yet complete or fully tested. Your contributions and feedback are highly encouraged as -we work towards refining and improving this implementation. Thank you for your interest and understanding as we continue -to develop this Java wrapper. +# Getting Started - Java Wrapper The Java client contains the following parts: diff --git a/node/README.md b/node/README.md index bf5a151434..93685285ff 100644 --- a/node/README.md +++ b/node/README.md @@ -9,14 +9,14 @@ Refer to the [Supported Engine Versions table](https://github.com/aws/glide-for- ## Current Status -We've made GLIDE for Redis an open-source project, and are releasing it in Preview to the community to gather feedback, and actively collaborate on the project roadmap. We welcome questions and contributions from all Redis stakeholders. +We've made Valkey GLIDE an open-source project, and are releasing it in Preview to the community to gather feedback, and actively collaborate on the project roadmap. We welcome questions and contributions from all Redis stakeholders. This preview release is recommended for testing purposes only. # Getting Started - Node Wrapper ## System Requirements -The beta release of GLIDE for Redis was tested on Intel x86_64 using Ubuntu 22.04.1, Amazon Linux 2023 (AL2023), and macOS 12.7. +The beta release of Valkey GLIDE was tested on Intel x86_64 using Ubuntu 22.04.1, Amazon Linux 2023 (AL2023), and macOS 12.7. ## NodeJS supported version diff --git a/python/DEVELOPER.md b/python/DEVELOPER.md index b24a50b220..dbf7e9b5c0 100644 --- a/python/DEVELOPER.md +++ b/python/DEVELOPER.md @@ -1,10 +1,10 @@ # Developer Guide -This document describes how to set up your development environment to build and test the GLIDE for Redis Python wrapper. +This document describes how to set up your development environment to build and test the Valkey GLIDE Python wrapper. ### Development Overview -The GLIDE for Redis Python wrapper consists of both Python and Rust code. Rust bindings for Python are implemented using [PyO3](https://github.com/PyO3/pyo3), and the Python package is built using [maturin](https://github.com/PyO3/maturin). The Python and Rust components communicate using the [protobuf](https://github.com/protocolbuffers/protobuf) protocol. +The Valkey GLIDE Python wrapper consists of both Python and Rust code. Rust bindings for Python are implemented using [PyO3](https://github.com/PyO3/pyo3), and the Python package is built using [maturin](https://github.com/PyO3/maturin). The Python and Rust components communicate using the [protobuf](https://github.com/protocolbuffers/protobuf) protocol. ### Build from source @@ -161,7 +161,7 @@ git submodule update During the initial build, Python protobuf files were created in `python/python/glide/protobuf`. If modifications are made to the protobuf definition files (.proto files located in `glide-core/src/protofuf`), it becomes necessary to regenerate the Python protobuf files. To do so, run: ```bash -GLIDE_ROOT_FOLDER_PATH=. # e.g. /home/ubuntu/glide-for-redis +GLIDE_ROOT_FOLDER_PATH=. # e.g. /home/ubuntu/valkey-glide protoc -Iprotobuf=${GLIDE_ROOT_FOLDER_PATH}/glide-core/src/protobuf/ --python_out=${GLIDE_ROOT_FOLDER_PATH}/python/python/glide ${GLIDE_ROOT_FOLDER_PATH}/glide-core/src/protobuf/*.proto ``` @@ -170,7 +170,7 @@ protoc -Iprotobuf=${GLIDE_ROOT_FOLDER_PATH}/glide-core/src/protobuf/ --python_ou To generate the protobuf files with Python Interface files (pyi) for type-checking purposes, ensure you have installed `mypy-protobuf` with pip, and then execute the following command: ```bash -GLIDE_ROOT_FOLDER_PATH=. # e.g. /home/ubuntu/glide-for-redis +GLIDE_ROOT_FOLDER_PATH=. # e.g. /home/ubuntu/valkey-glide MYPY_PROTOC_PATH=`which protoc-gen-mypy` protoc --plugin=protoc-gen-mypy=${MYPY_PROTOC_PATH} -Iprotobuf=${GLIDE_ROOT_FOLDER_PATH}/glide-core/src/protobuf/ --python_out=${GLIDE_ROOT_FOLDER_PATH}/python/python/glide --mypy_out=${GLIDE_ROOT_FOLDER_PATH}/python/python/glide ${GLIDE_ROOT_FOLDER_PATH}/glide-core/src/protobuf/*.proto ``` diff --git a/python/README.md b/python/README.md index f857b69789..a8c130237c 100644 --- a/python/README.md +++ b/python/README.md @@ -1,17 +1,12 @@ -# GLIDE for Redis +## Valkey GLIDE -General Language Independent Driver for the Enterprise (GLIDE) for Redis, is an AWS-sponsored, open-source Redis client. GLIDE for Redis works with any Redis distribution that adheres to the Redis Serialization Protocol (RESP) specification, including open-source Redis, Amazon ElastiCache for Redis, and Amazon MemoryDB for Redis. -Strategic, mission-critical Redis-based applications have requirements for security, optimized performance, minimal downtime, and observability. GLIDE for Redis is designed to provide a client experience that helps meet these objectives. It is sponsored and supported by AWS, and comes pre-configured with best practices learned from over a decade of operating Redis-compatible services used by hundreds of thousands of customers. To help ensure consistency in development and operations, GLIDE for Redis is implemented using a core driver framework, written in Rust, with extensions made available for each supported programming language. This design ensures that updates easily propagate to each language and reduces overall complexity. In this Preview release, GLIDE for Redis is available for Python and Javascript (Node.js), with support for Java actively under development. +Valkey General Language Independent Driver for the Enterprise (GLIDE), is an AWS-sponsored, open-source Valkey client that includes support for open-source Redis 6.2 to 7.2. Valkey GLIDE works with any distribution that adheres to the Redis Serialization Protocol (RESP) specification, including Amazon ElastiCache, and Amazon MemoryDB. +Strategic, mission-critical applications have requirements for security, optimized performance, minimal downtime, and observability. Valkey GLIDE is designed to provide a client experience that helps meet these objectives. It is sponsored and supported by AWS, and comes pre-configured with best practices learned from over a decade of operating RESP-compatible services used by hundreds of thousands of customers. To help ensure consistency in development and operations, Valkey GLIDE is implemented using a core driver framework, written in Rust, with extensions made available for each supported programming language. This design ensures that updates easily propagate to each language and reduces overall complexity. In this Preview release, Valkey GLIDE is available for Python and Java, with support for Javascript (Node.js) actively under development. ## Supported Engine Versions Refer to the [Supported Engine Versions table](https://github.com/aws/glide-for-redis/blob/main/README.md#supported-engine-versions) for details. -## Current Status - -We've made GLIDE for Redis an open-source project, and are releasing it in Preview to the community to gather feedback, and actively collaborate on the project roadmap. We welcome questions and contributions from all Redis stakeholders. -This preview release is recommended for testing purposes only. - # Getting Started - Python Wrapper ## System Requirements From a8800ddcf2974598a4dedcbe14d397c131c980b8 Mon Sep 17 00:00:00 2001 From: Chloe Yip Date: Wed, 3 Jul 2024 22:58:37 -0700 Subject: [PATCH 23/23] need to fix build issue --- .../test/java/glide/api/RedisClientTest.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/java/client/src/test/java/glide/api/RedisClientTest.java b/java/client/src/test/java/glide/api/RedisClientTest.java index e16e8675cf..14ab6a11d3 100644 --- a/java/client/src/test/java/glide/api/RedisClientTest.java +++ b/java/client/src/test/java/glide/api/RedisClientTest.java @@ -7560,6 +7560,48 @@ public void xclaimJustId_binary_with_options_returns_success() { assertEquals(mockResult, payload); } + @SneakyThrows + @Test + public void xautoclaim() { + // setup + // String key = "testKey"; + // String groupName = "testGroupName"; + // String consumer = "testConsumer"; + // Long minIdleTime = 18L; + // String start = "0-0"; + + // StreamRange end = IdBound.ofExclusive("696969-10"); + // String[][] fieldValuesResult = {{"duration", "12345"}, {"event-id", "2"}, {"user-id", + // "42"}}; + // Map completedResult = Map.of(key, fieldValuesResult); + // + // String[] deletedMessageIds = new String[]{"13-1", "46-2", "89-3"}; + // + // String[] arguments = concatenateArrays(new String[] {key, groupName, consumer, "18", + // start}); + // Object[] mockResult = new Object[]{start, completedResult, deletedMessageIds}; + // + // CompletableFuture testResponse = new CompletableFuture<>(); + // testResponse.complete(mockResult); + // + // // match on protobuf request + // when(commandManager.submitNewCommand(eq(XAutoClaim), eq(arguments), any())) + // .thenReturn(testResponse); + // + // // exercise + // CompletableFuture response = + // service.xautoclaim(key, groupName, consumer, minIdleTime, start); + // Object[] payload = response.get(); + // + // // verify + // assertEquals(testResponse, response); + // assertEquals(mockResult, payload); + } + + @SneakyThrows + @Test + public void xautoclaimJustId() {} + @SneakyThrows @Test public void xack_binary_returns_success() {