You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by je...@apache.org on 2020/06/18 17:44:54 UTC

[geode] branch develop updated: GEODE-8276: fix KEYS command to handle non-ASCII keys (#5272)

This is an automated email from the ASF dual-hosted git repository.

jensdeppe pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/develop by this push:
     new 9ea7a7c  GEODE-8276: fix KEYS command to handle non-ASCII keys (#5272)
9ea7a7c is described below

commit 9ea7a7cc58720041e31735643266f13e637bf002
Author: Darrel Schneider <ds...@pivotal.io>
AuthorDate: Thu Jun 18 10:44:27 2020 -0700

    GEODE-8276: fix KEYS command to handle non-ASCII keys (#5272)
---
 .../key/KeysNativeRedisAcceptanceTest.java         | 49 +++++++++++
 .../internal/executor/key/KeysIntegrationTest.java | 96 ++++++++++++++++++++++
 .../redis/internal/executor/key/KeysExecutor.java  |  4 +-
 3 files changed, 147 insertions(+), 2 deletions(-)

diff --git a/geode-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/executor/key/KeysNativeRedisAcceptanceTest.java b/geode-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/executor/key/KeysNativeRedisAcceptanceTest.java
new file mode 100644
index 0000000..960b76d
--- /dev/null
+++ b/geode-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/executor/key/KeysNativeRedisAcceptanceTest.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.geode.redis.internal.executor.key;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestRule;
+import org.testcontainers.containers.GenericContainer;
+import redis.clients.jedis.Jedis;
+
+import org.apache.geode.test.junit.categories.RedisTest;
+import org.apache.geode.test.junit.rules.IgnoreOnWindowsRule;
+
+@Category({RedisTest.class})
+public class KeysNativeRedisAcceptanceTest extends KeysIntegrationTest {
+
+  // Docker compose does not work on windows in CI. Ignore this test on windows
+  // Using a RuleChain to make sure we ignore the test before the rule comes into play
+  @ClassRule
+  public static TestRule ignoreOnWindowsRule = new IgnoreOnWindowsRule();
+
+  @BeforeClass
+  public static void setUp() {
+    GenericContainer redisContainer = new GenericContainer<>("redis:5.0.6").withExposedPorts(6379);
+    redisContainer.start();
+    jedis = new Jedis("localhost", redisContainer.getFirstMappedPort(), REDIS_CLIENT_TIMEOUT);
+  }
+
+  @AfterClass
+  public static void tearDown() {
+    jedis.close();
+  }
+
+}
diff --git a/geode-redis/src/integrationTest/java/org/apache/geode/redis/internal/executor/key/KeysIntegrationTest.java b/geode-redis/src/integrationTest/java/org/apache/geode/redis/internal/executor/key/KeysIntegrationTest.java
new file mode 100644
index 0000000..8ff4273
--- /dev/null
+++ b/geode-redis/src/integrationTest/java/org/apache/geode/redis/internal/executor/key/KeysIntegrationTest.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.geode.redis.internal.executor.key;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import redis.clients.jedis.Jedis;
+
+import org.apache.geode.redis.GeodeRedisServerRule;
+import org.apache.geode.test.awaitility.GeodeAwaitility;
+
+public class KeysIntegrationTest {
+
+  public static Jedis jedis;
+  public static int REDIS_CLIENT_TIMEOUT =
+      Math.toIntExact(GeodeAwaitility.getTimeout().toMillis());
+
+  @ClassRule
+  public static GeodeRedisServerRule server = new GeodeRedisServerRule();
+
+  @BeforeClass
+  public static void setUp() {
+    jedis = new Jedis("localhost", server.getPort(), REDIS_CLIENT_TIMEOUT);
+  }
+
+  @After
+  public void flushAll() {
+    jedis.flushAll();
+  }
+
+  @AfterClass
+  public static void tearDown() {
+    jedis.close();
+  }
+
+  @Test
+  public void keys_givenSplat_withASCIIdata_returnsExpectedMatches() {
+    jedis.set("string1", "v1");
+    jedis.sadd("set1", "member1");
+    jedis.hset("hash1", "key1", "field1");
+    assertThat(jedis.keys("*")).containsExactlyInAnyOrder("string1", "set1", "hash1");
+    assertThat(jedis.keys("s*")).containsExactlyInAnyOrder("string1", "set1");
+    assertThat(jedis.keys("h*")).containsExactlyInAnyOrder("hash1");
+    assertThat(jedis.keys("foo*")).isEmpty();
+  }
+
+  @Test
+  public void keys_givenSplat_withBinaryData_returnsExpectedMatches() {
+    byte[] stringKey =
+        new byte[] {(byte) 0xac, (byte) 0xed, 0, 4, 0, 5, 's', 't', 'r', 'i', 'n', 'g', '1'};
+    byte[] value = new byte[] {'v', '1'};
+    jedis.set(stringKey, value);
+    byte[] setKey = new byte[] {(byte) 0xac, (byte) 0xed, 0, 4, 0, 5, 's', 'e', 't', '1'};
+    byte[] member = new byte[] {'m', '1'};
+    jedis.sadd(setKey, member);
+    byte[] hashKey = new byte[] {(byte) 0xac, (byte) 0xed, 0, 4, 0, 5, 'h', 'a', 's', 'h', '1'};
+    byte[] key = new byte[] {'k', 'e', 'y', '1'};
+    jedis.hset(hashKey, key, value);
+    assertThat(jedis.exists(stringKey));
+    assertThat(jedis.exists(setKey));
+    assertThat(jedis.exists(hashKey));
+    assertThat(jedis.keys(new byte[] {'*'})).containsExactlyInAnyOrder(stringKey, setKey, hashKey);
+    assertThat(jedis.keys(new byte[] {(byte) 0xac, (byte) 0xed, 0, 4, 0, 5, 's', '*'}))
+        .containsExactlyInAnyOrder(stringKey, setKey);
+    assertThat(jedis.keys(new byte[] {(byte) 0xac, (byte) 0xed, 0, 4, 0, 5, 'h', '*'}))
+        .containsExactlyInAnyOrder(hashKey);
+    assertThat(jedis.keys(new byte[] {'f', '*'})).isEmpty();
+  }
+
+  @Test
+  public void keys_givenBinaryValue_withExactMatch_preservesBinaryData() {
+    byte[] stringKey =
+        new byte[] {(byte) 0xac, (byte) 0xed, 0, 4, 0, 5, 's', 't', 'r', 'i', 'n', 'g', '1'};
+    jedis.set(stringKey, stringKey);
+    assertThat(jedis.keys(stringKey)).containsExactlyInAnyOrder(stringKey);
+  }
+
+}
diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/key/KeysExecutor.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/key/KeysExecutor.java
index 6ba0a59..fd30a15 100755
--- a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/key/KeysExecutor.java
+++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/key/KeysExecutor.java
@@ -44,7 +44,7 @@ public class KeysExecutor extends AbstractExecutor {
 
     String glob = Coder.bytesToString(commandElems.get(1));
     Set<ByteArrayWrapper> allKeys = getDataRegion(context).keySet();
-    List<String> matchingKeys = new ArrayList<String>();
+    List<ByteArrayWrapper> matchingKeys = new ArrayList<>();
 
     Pattern pattern;
     try {
@@ -56,7 +56,7 @@ public class KeysExecutor extends AbstractExecutor {
     for (ByteArrayWrapper bytesKey : allKeys) {
       String key = bytesKey.toString();
       if (pattern.matcher(key).matches()) {
-        matchingKeys.add(key);
+        matchingKeys.add(bytesKey);
       }
     }