From a7db26f5313bae8598f39bb3296b5026ea8e4497 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Mon, 24 Jun 2024 14:06:32 +0000 Subject: [PATCH 1/5] support objectEncoding, objectFreq, objectIdletime and objectRefcount with GlideString --- .../src/main/java/glide/api/BaseClient.java | 24 +++++ .../api/commands/GenericBaseCommands.java | 74 +++++++++++++++ .../test/java/glide/api/RedisClientTest.java | 91 +++++++++++++++++++ 3 files changed, 189 insertions(+) diff --git a/java/client/src/main/java/glide/api/BaseClient.java b/java/client/src/main/java/glide/api/BaseClient.java index f9303df43d..a2706175df 100644 --- a/java/client/src/main/java/glide/api/BaseClient.java +++ b/java/client/src/main/java/glide/api/BaseClient.java @@ -621,24 +621,48 @@ public CompletableFuture objectEncoding(@NonNull String key) { ObjectEncoding, new String[] {key}, this::handleStringOrNullResponse); } + @Override + public CompletableFuture objectEncoding(@NonNull GlideString key) { + return commandManager.submitNewCommand( + ObjectEncoding, new GlideString[] {key}, this::handleStringOrNullResponse); + } + @Override public CompletableFuture objectFreq(@NonNull String key) { return commandManager.submitNewCommand( ObjectFreq, new String[] {key}, this::handleLongOrNullResponse); } + @Override + public CompletableFuture objectFreq(@NonNull GlideString key) { + return commandManager.submitNewCommand( + ObjectFreq, new GlideString[] {key}, this::handleLongOrNullResponse); + } + @Override public CompletableFuture objectIdletime(@NonNull String key) { return commandManager.submitNewCommand( ObjectIdleTime, new String[] {key}, this::handleLongOrNullResponse); } + @Override + public CompletableFuture objectIdletime(@NonNull GlideString key) { + return commandManager.submitNewCommand( + ObjectIdleTime, new GlideString[] {key}, this::handleLongOrNullResponse); + } + @Override public CompletableFuture objectRefcount(@NonNull String key) { return commandManager.submitNewCommand( ObjectRefCount, new String[] {key}, this::handleLongOrNullResponse); } + @Override + public CompletableFuture objectRefcount(@NonNull GlideString key) { + return commandManager.submitNewCommand( + ObjectRefCount, new GlideString[] {key}, this::handleLongOrNullResponse); + } + @Override public CompletableFuture rename(@NonNull String key, @NonNull String newKey) { return commandManager.submitNewCommand( diff --git a/java/client/src/main/java/glide/api/commands/GenericBaseCommands.java b/java/client/src/main/java/glide/api/commands/GenericBaseCommands.java index 6c39ed8660..d855e15aba 100644 --- a/java/client/src/main/java/glide/api/commands/GenericBaseCommands.java +++ b/java/client/src/main/java/glide/api/commands/GenericBaseCommands.java @@ -438,6 +438,24 @@ CompletableFuture pexpireAt( */ CompletableFuture objectEncoding(String key); + /** + * Returns the internal encoding for the Redis object stored at key. + * + * @see redis.io for details. + * @param key The key of the object to get the internal encoding of. + * @return If key exists, returns the internal encoding of the object stored at + * key as a String. Otherwise, returns null. + * @example + *
{@code
+     * String encoding = client.objectEncoding(gs("my_hash")).get();
+     * assert encoding.equals("listpack");
+     *
+     * encoding = client.objectEncoding(gs("non_existing_key")).get();
+     * assert encoding == null;
+     * }
+ */ + CompletableFuture objectEncoding(GlideString key); + /** * Returns the logarithmic access frequency counter of a Redis object stored at key. * @@ -458,6 +476,26 @@ CompletableFuture pexpireAt( */ CompletableFuture objectFreq(String key); + /** + * Returns the logarithmic access frequency counter of a Redis object stored at key. + * + * @see redis.io for details. + * @param key The key of the object to get the logarithmic access frequency counter + * of. + * @return If key exists, returns the logarithmic access frequency counter of the + * object stored at key as a Long. Otherwise, returns null + * . + * @example + *
{@code
+     * Long frequency = client.objectFreq(gs("my_hash")).get();
+     * assert frequency == 2L;
+     *
+     * frequency = client.objectFreq(gs("non_existing_key")).get();
+     * assert frequency == null;
+     * }
+ */ + CompletableFuture objectFreq(GlideString key); + /** * Returns the time in seconds since the last access to the value stored at key. * @@ -476,6 +514,24 @@ CompletableFuture pexpireAt( */ CompletableFuture objectIdletime(String key); + /** + * Returns the time in seconds since the last access to the value stored at key. + * + * @see redis.io for details. + * @param key The key of the object to get the idle time of. + * @return If key exists, returns the idle time in seconds. Otherwise, returns + * null. + * @example + *
{@code
+     * Long idletime = client.objectIdletime(gs("my_hash")).get();
+     * assert idletime == 2L;
+     *
+     * idletime = client.objectIdletime(gs("non_existing_key")).get();
+     * assert idletime == null;
+     * }
+ */ + CompletableFuture objectIdletime(GlideString key); + /** * Returns the reference count of the object stored at key. * @@ -494,6 +550,24 @@ CompletableFuture pexpireAt( */ CompletableFuture objectRefcount(String key); + /** + * Returns the reference count of the object stored at key. + * + * @see redis.io for details. + * @param key The key of the object to get the reference count of. + * @return If key exists, returns the reference count of the object stored at + * key as a Long. Otherwise, returns null. + * @example + *
{@code
+     * Long refcount = client.objectRefcount(gs("my_hash")).get();
+     * assert refcount == 2L;
+     *
+     * refcount = client.objectRefcount(gs("non_existing_key")).get();
+     * assert refcount == null;
+     * }
+ */ + CompletableFuture objectRefcount(GlideString key); + /** * Renames key to newKey.
* If newKey already exists it is overwritten. diff --git a/java/client/src/test/java/glide/api/RedisClientTest.java b/java/client/src/test/java/glide/api/RedisClientTest.java index 29a1119943..5f86bdf50d 100644 --- a/java/client/src/test/java/glide/api/RedisClientTest.java +++ b/java/client/src/test/java/glide/api/RedisClientTest.java @@ -5376,6 +5376,29 @@ public void objectEncoding_returns_success() { assertEquals(encoding, payload); } + @SneakyThrows + @Test + public void objectEncoding_binary_returns_success() { + // setup + GlideString key = gs("testKey"); + String encoding = "testEncoding"; + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(encoding); + + // match on protobuf request + when(commandManager.submitNewCommand( + eq(ObjectEncoding), eq(new GlideString[] {key}), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.objectEncoding(key); + String payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(encoding, payload); + } + @SneakyThrows @Test public void objectFreq_returns_success() { @@ -5398,6 +5421,28 @@ public void objectFreq_returns_success() { assertEquals(frequency, payload); } + @SneakyThrows + @Test + public void objectFreq_binary_returns_success() { + // setup + GlideString key = gs("testKey"); + Long frequency = 0L; + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(frequency); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(ObjectFreq), eq(new GlideString[] {key}), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.objectFreq(key); + Long payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(frequency, payload); + } + @SneakyThrows @Test public void objectIdletime_returns_success() { @@ -5420,6 +5465,29 @@ public void objectIdletime_returns_success() { assertEquals(idletime, payload); } + @SneakyThrows + @Test + public void objectIdletime_binary_returns_success() { + // setup + GlideString key = gs("testKey"); + Long idletime = 0L; + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(idletime); + + // match on protobuf request + when(commandManager.submitNewCommand( + eq(ObjectIdleTime), eq(new GlideString[] {key}), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.objectIdletime(key); + Long payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(idletime, payload); + } + @SneakyThrows @Test public void objectRefcount_returns_success() { @@ -5442,6 +5510,29 @@ public void objectRefcount_returns_success() { assertEquals(refcount, payload); } + @SneakyThrows + @Test + public void objectRefcount_binary_returns_success() { + // setup + GlideString key = gs("testKey"); + Long refcount = 0L; + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(refcount); + + // match on protobuf request + when(commandManager.submitNewCommand( + eq(ObjectRefCount), eq(new GlideString[] {key}), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.objectRefcount(key); + Long payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(refcount, payload); + } + @SneakyThrows @Test public void touch_returns_success() { From 6b312cf45375cc5d74c303b078f95259873698dd Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 25 Jun 2024 08:43:29 +0000 Subject: [PATCH 2/5] add to integration tests the use of the API with GlideString parameters --- .../src/test/java/glide/SharedCommandTests.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/java/integTest/src/test/java/glide/SharedCommandTests.java b/java/integTest/src/test/java/glide/SharedCommandTests.java index 5bb762613f..a77e8504da 100644 --- a/java/integTest/src/test/java/glide/SharedCommandTests.java +++ b/java/integTest/src/test/java/glide/SharedCommandTests.java @@ -4332,11 +4332,11 @@ public void objectEncoding_returns_null(BaseClient client) { @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") public void objectEncoding_returns_string_raw(BaseClient client) { - String stringRawKey = UUID.randomUUID().toString(); + GlideString stringRawKey = gs(UUID.randomUUID().toString()); assertEquals( OK, client - .set(stringRawKey, "a really loooooooooooooooooooooooooooooooooooooooong value") + .set(stringRawKey, gs("a really loooooooooooooooooooooooooooooooooooooooong value")) .get()); assertEquals("raw", client.objectEncoding(stringRawKey).get()); } @@ -4345,8 +4345,8 @@ public void objectEncoding_returns_string_raw(BaseClient client) { @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") public void objectEncoding_returns_string_int(BaseClient client) { - String stringIntKey = UUID.randomUUID().toString(); - assertEquals(OK, client.set(stringIntKey, "2").get()); + GlideString stringIntKey = gs(UUID.randomUUID().toString()); + assertEquals(OK, client.set(stringIntKey, gs("2")).get()); assertEquals("int", client.objectEncoding(stringIntKey).get()); } @@ -4465,6 +4465,7 @@ public void objectEncoding_returns_stream(BaseClient client) { public void objectFreq_returns_null(BaseClient client) { String nonExistingKey = UUID.randomUUID().toString(); assertNull(client.objectFreq(nonExistingKey).get()); + assertNull(client.objectFreq(gs(nonExistingKey)).get()); } @SneakyThrows @@ -4479,8 +4480,8 @@ public void objectIdletime_returns_null(BaseClient client) { @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") public void objectIdletime(BaseClient client) { - String key = UUID.randomUUID().toString(); - assertEquals(OK, client.set(key, "").get()); + GlideString key = gs(UUID.randomUUID().toString()); + assertEquals(OK, client.set(key, gs("")).get()); Thread.sleep(2000); assertTrue(client.objectIdletime(key).get() > 0L); } @@ -4497,8 +4498,8 @@ public void objectRefcount_returns_null(BaseClient client) { @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") public void objectRefcount(BaseClient client) { - String key = UUID.randomUUID().toString(); - assertEquals(OK, client.set(key, "").get()); + GlideString key = gs(UUID.randomUUID().toString()); + assertEquals(OK, client.set(key, gs("")).get()); assertTrue(client.objectRefcount(key).get() >= 0L); } From 44655074040e7317c85499a0b83d9d0879a3c80d Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 25 Jun 2024 11:39:09 +0000 Subject: [PATCH 3/5] add binary version integration tests --- .../test/java/glide/SharedCommandTests.java | 96 ++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/java/integTest/src/test/java/glide/SharedCommandTests.java b/java/integTest/src/test/java/glide/SharedCommandTests.java index d0f8b9109a..1e21b09fed 100644 --- a/java/integTest/src/test/java/glide/SharedCommandTests.java +++ b/java/integTest/src/test/java/glide/SharedCommandTests.java @@ -4332,10 +4332,31 @@ public void objectEncoding_returns_null(BaseClient client) { assertNull(client.objectEncoding(nonExistingKey).get()); } + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void objectEncoding_binary_returns_null(BaseClient client) { + GlideString nonExistingKey = gs(UUID.randomUUID().toString()); + assertNull(client.objectEncoding(nonExistingKey).get()); + } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") public void objectEncoding_returns_string_raw(BaseClient client) { + String stringRawKey = UUID.randomUUID().toString(); + assertEquals( + OK, + client + .set(stringRawKey, "a really loooooooooooooooooooooooooooooooooooooooong value") + .get()); + assertEquals("raw", client.objectEncoding(stringRawKey).get()); + } + + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void objectEncoding_binary_returns_string_raw(BaseClient client) { GlideString stringRawKey = gs(UUID.randomUUID().toString()); assertEquals( OK, @@ -4349,6 +4370,15 @@ public void objectEncoding_returns_string_raw(BaseClient client) { @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") public void objectEncoding_returns_string_int(BaseClient client) { + String stringIntKey = UUID.randomUUID().toString(); + assertEquals(OK, client.set(stringIntKey, "2").get()); + assertEquals("int", client.objectEncoding(stringIntKey).get()); + } + + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void objectEncoding_binary_returns_string_int(BaseClient client) { GlideString stringIntKey = gs(UUID.randomUUID().toString()); assertEquals(OK, client.set(stringIntKey, gs("2")).get()); assertEquals("int", client.objectEncoding(stringIntKey).get()); @@ -4363,6 +4393,15 @@ public void objectEncoding_returns_string_embstr(BaseClient client) { assertEquals("embstr", client.objectEncoding(stringEmbstrKey).get()); } + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void objectEncoding_binary_returns_string_embstr(BaseClient client) { + GlideString stringEmbstrKey = gs(UUID.randomUUID().toString()); + assertEquals(OK, client.set(stringEmbstrKey, gs("value")).get()); + assertEquals("embstr", client.objectEncoding(stringEmbstrKey).get()); + } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -4376,6 +4415,19 @@ public void objectEncoding_returns_list_listpack(BaseClient client) { client.objectEncoding(listListpackKey).get()); } + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void objectEncoding_binary_returns_list_listpack(BaseClient client) { + GlideString listListpackKey = gs(UUID.randomUUID().toString()); + assertEquals(1, client.lpush(listListpackKey, new GlideString[] {gs("1")}).get()); + // API documentation states that a ziplist should be returned for Redis versions <= 6.2, but + // actual behavior returns a quicklist. + assertEquals( + REDIS_VERSION.isLowerThan("7.0.0") ? "quicklist" : "listpack", + client.objectEncoding(listListpackKey).get()); + } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") @@ -4469,7 +4521,14 @@ public void objectEncoding_returns_stream(BaseClient client) { public void objectFreq_returns_null(BaseClient client) { String nonExistingKey = UUID.randomUUID().toString(); assertNull(client.objectFreq(nonExistingKey).get()); - assertNull(client.objectFreq(gs(nonExistingKey)).get()); + } + + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void objectFreq_binary_returns_null(BaseClient client) { + GlideString nonExistingKey = gs(UUID.randomUUID().toString()); + assertNull(client.objectFreq(nonExistingKey).get()); } @SneakyThrows @@ -4480,10 +4539,28 @@ public void objectIdletime_returns_null(BaseClient client) { assertNull(client.objectIdletime(nonExistingKey).get()); } + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void objectIdletime_binary_returns_null(BaseClient client) { + GlideString nonExistingKey = gs(UUID.randomUUID().toString()); + assertNull(client.objectIdletime(nonExistingKey).get()); + } + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") public void objectIdletime(BaseClient client) { + String key = UUID.randomUUID().toString(); + assertEquals(OK, client.set(key, "").get()); + Thread.sleep(2000); + assertTrue(client.objectIdletime(key).get() > 0L); + } + + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void objectIdletime_binary_(BaseClient client) { GlideString key = gs(UUID.randomUUID().toString()); assertEquals(OK, client.set(key, gs("")).get()); Thread.sleep(2000); @@ -4494,6 +4571,14 @@ public void objectIdletime(BaseClient client) { @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") public void objectRefcount_returns_null(BaseClient client) { + GlideString nonExistingKey = gs(UUID.randomUUID().toString()); + assertNull(client.objectRefcount(nonExistingKey).get()); + } + + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void objectRefcount_binary_returns_null(BaseClient client) { String nonExistingKey = UUID.randomUUID().toString(); assertNull(client.objectRefcount(nonExistingKey).get()); } @@ -4502,6 +4587,15 @@ public void objectRefcount_returns_null(BaseClient client) { @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") public void objectRefcount(BaseClient client) { + String key = UUID.randomUUID().toString(); + assertEquals(OK, client.set(key, "").get()); + assertTrue(client.objectRefcount(key).get() >= 0L); + } + + @SneakyThrows + @ParameterizedTest(autoCloseArguments = false) + @MethodSource("getClients") + public void objectRefcount_binary(BaseClient client) { GlideString key = gs(UUID.randomUUID().toString()); assertEquals(OK, client.set(key, gs("")).get()); assertTrue(client.objectRefcount(key).get() >= 0L); From 74bf81ec8cd6dbb4f8db390bcf45985db5faab8a Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 25 Jun 2024 11:40:15 +0000 Subject: [PATCH 4/5] nit: spotlessApply --- java/integTest/src/test/java/glide/SharedCommandTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/integTest/src/test/java/glide/SharedCommandTests.java b/java/integTest/src/test/java/glide/SharedCommandTests.java index 1e21b09fed..6b3cbae8aa 100644 --- a/java/integTest/src/test/java/glide/SharedCommandTests.java +++ b/java/integTest/src/test/java/glide/SharedCommandTests.java @@ -4523,7 +4523,7 @@ public void objectFreq_returns_null(BaseClient client) { assertNull(client.objectFreq(nonExistingKey).get()); } - @SneakyThrows + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") public void objectFreq_binary_returns_null(BaseClient client) { @@ -4575,7 +4575,7 @@ public void objectRefcount_returns_null(BaseClient client) { assertNull(client.objectRefcount(nonExistingKey).get()); } - @SneakyThrows + @SneakyThrows @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") public void objectRefcount_binary_returns_null(BaseClient client) { From 55c4e04cf014bae41b035d07559106f8445d3b6d Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 25 Jun 2024 13:34:09 +0000 Subject: [PATCH 5/5] fix use of GlideString in objectRefcount_returns_null --- java/integTest/src/test/java/glide/SharedCommandTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/integTest/src/test/java/glide/SharedCommandTests.java b/java/integTest/src/test/java/glide/SharedCommandTests.java index 6b3cbae8aa..48625e5122 100644 --- a/java/integTest/src/test/java/glide/SharedCommandTests.java +++ b/java/integTest/src/test/java/glide/SharedCommandTests.java @@ -4571,7 +4571,7 @@ public void objectIdletime_binary_(BaseClient client) { @ParameterizedTest(autoCloseArguments = false) @MethodSource("getClients") public void objectRefcount_returns_null(BaseClient client) { - GlideString nonExistingKey = gs(UUID.randomUUID().toString()); + String nonExistingKey = UUID.randomUUID().toString(); assertNull(client.objectRefcount(nonExistingKey).get()); }