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

ringles pushed a commit to branch 
GEODE-9892-Create-Infrastructure-for-Redis-Lists
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to 
refs/heads/GEODE-9892-Create-Infrastructure-for-Redis-Lists by this push:
     new 0ea15f8  Some sizing dev, native list integration tests running
0ea15f8 is described below

commit 0ea15f8be04c7a26ca2c965b1c0f731f7917c7a6
Author: Ray Ingles <[email protected]>
AuthorDate: Thu Jan 6 16:40:25 2022 -0500

    Some sizing dev, native list integration tests running
---
 .../list/ListsNativeRedisAcceptanceTest.java       |  38 ++++++
 .../list/AbstractListsIntegrationTest.java         | 136 +++++++++++++++++++++
 .../executor/list/ListsIntegrationTest.java        |  31 +++++
 .../geode/redis/internal/data/RedisList.java       |   4 +-
 .../internal/data/collections/SizeableList.java    |  15 ++-
 .../data/collections/SizeableListTest.java         |  83 +++++++++++++
 6 files changed, 300 insertions(+), 7 deletions(-)

diff --git 
a/geode-for-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/commands/executor/list/ListsNativeRedisAcceptanceTest.java
 
b/geode-for-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/commands/executor/list/ListsNativeRedisAcceptanceTest.java
new file mode 100755
index 0000000..37df9b2
--- /dev/null
+++ 
b/geode-for-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/commands/executor/list/ListsNativeRedisAcceptanceTest.java
@@ -0,0 +1,38 @@
+/*
+ * 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.commands.executor.list;
+
+
+import org.junit.ClassRule;
+
+import org.apache.geode.redis.NativeRedisClusterTestRule;
+import 
org.apache.geode.redis.internal.commands.executor.set.AbstractSetsIntegrationTest;
+
+public class ListsNativeRedisAcceptanceTest extends 
AbstractListsIntegrationTest {
+
+  @ClassRule
+  public static NativeRedisClusterTestRule redis = new 
NativeRedisClusterTestRule();
+
+  @Override
+  public int getPort() {
+    return redis.getExposedPorts().get(0);
+  }
+
+  @Override
+  public void flushAll() {
+    redis.flushAll();
+  }
+
+}
diff --git 
a/geode-for-redis/src/integrationTest/java/org/apache/geode/redis/internal/commands/executor/list/AbstractListsIntegrationTest.java
 
b/geode-for-redis/src/integrationTest/java/org/apache/geode/redis/internal/commands/executor/list/AbstractListsIntegrationTest.java
new file mode 100755
index 0000000..04e1244
--- /dev/null
+++ 
b/geode-for-redis/src/integrationTest/java/org/apache/geode/redis/internal/commands/executor/list/AbstractListsIntegrationTest.java
@@ -0,0 +1,136 @@
+/*
+ * 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.commands.executor.list;
+
+import static 
org.apache.geode.redis.RedisCommandArgumentsTestHelper.assertAtLeastNArgs;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import redis.clients.jedis.HostAndPort;
+import redis.clients.jedis.JedisCluster;
+import redis.clients.jedis.Protocol;
+import redis.clients.jedis.exceptions.JedisDataException;
+
+import org.apache.geode.redis.RedisIntegrationTest;
+import org.apache.geode.test.awaitility.GeodeAwaitility;
+
+public abstract class AbstractListsIntegrationTest implements 
RedisIntegrationTest {
+
+  private JedisCluster jedis;
+  private static final int REDIS_CLIENT_TIMEOUT =
+      Math.toIntExact(GeodeAwaitility.getTimeout().toMillis());
+
+  @Before
+  public void setUp() {
+    jedis = new JedisCluster(new HostAndPort("localhost", getPort()), 
REDIS_CLIENT_TIMEOUT);
+  }
+
+  @After
+  public void tearDown() {
+    flushAll();
+    jedis.close();
+  }
+
+  @Test
+  public void lpushErrors_givenTooFewArguments() {
+    assertAtLeastNArgs(jedis, Protocol.Command.LPUSH, 2);
+  }
+
+  @Test
+  public void testLPush_withExistingKey_ofWrongType_shouldReturnError() {
+    String key = "key";
+    String stringValue = "preexistingValue";
+    String[] setValue = new String[1];
+    setValue[0] = "set value that should never get added";
+
+    jedis.set(key, stringValue);
+    assertThatThrownBy(() -> jedis.lpush(key, setValue))
+        .hasMessageContaining("Operation against a key holding the wrong kind 
of value");
+  }
+
+  @Test
+  public void 
testLPush_withExistingKey_ofWrongType_shouldNotOverWriteExistingKey() {
+    String key = "key";
+    String stringValue = "preexistingValue";
+    String[] setValue = new String[1];
+    setValue[0] = "set value that should never get added";
+
+    jedis.set(key, stringValue);
+
+    assertThatThrownBy(() -> jedis.lpush(key, 
setValue)).isInstanceOf(JedisDataException.class);
+
+    String result = jedis.get(key);
+
+    assertThat(result).isEqualTo(stringValue);
+  }
+
+  @Test
+  public void testLPush_canStoreBinaryData() {
+    byte[] blob = new byte[256];
+    for (int i = 0; i < 256; i++) {
+      blob[i] = (byte) i;
+    }
+
+    jedis.lpush("key".getBytes(), blob, blob);
+
+    byte[] result = jedis.lpop("key".getBytes());
+    assertThat(result).containsExactly(blob);
+    result = jedis.lpop("key".getBytes());
+    assertThat(result).containsExactly(blob);
+  }
+
+  @Test
+  public void lpop_withStringFails() {
+    jedis.set("string", "value");
+    assertThatThrownBy(() -> 
jedis.lpop("string")).hasMessageContaining("WRONGTYPE");
+  }
+
+  @Test
+  public void lpop_withNonExistentKey_returnsNull() {
+    assertThat(jedis.lpop("non existent")).isNull();
+  }
+
+  @Test
+  public void lpopCount_withNonExistentKey_returnsNull() {
+    assertThat(jedis.lpop("non existent", 3)).isNull();
+  }
+
+  @Test
+  public void lpop_returnsOneMember() {
+    jedis.lpush("key", "m1", "m2");
+    String result = jedis.lpop("key");
+    assertThat(result).isIn("m1", "m2");
+  }
+
+  @Test
+  public void lpopCount_returnsTwoUniqueMembers() {
+    jedis.lpush("key", "m1", "m2", "m3");
+    List<String> results = jedis.lpop("key", 2);
+    assertThat(results).hasSize(2);
+    assertThat(results).containsAnyOf("m1", "m2", "m3");
+    assertThat(results.get(0)).isNotEqualTo(results.get(1));
+  }
+
+  @Test
+  public void lpopNegativeCount_returnsError() {
+    jedis.lpush("key", "m1", "m2", "m3");
+    assertThatThrownBy(() -> jedis.lpop("key", 
-3)).hasMessageContaining("value is out of range, must be positive");
+  }
+}
diff --git 
a/geode-for-redis/src/integrationTest/java/org/apache/geode/redis/internal/commands/executor/list/ListsIntegrationTest.java
 
b/geode-for-redis/src/integrationTest/java/org/apache/geode/redis/internal/commands/executor/list/ListsIntegrationTest.java
new file mode 100755
index 0000000..d5fd0de
--- /dev/null
+++ 
b/geode-for-redis/src/integrationTest/java/org/apache/geode/redis/internal/commands/executor/list/ListsIntegrationTest.java
@@ -0,0 +1,31 @@
+/*
+ * 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.commands.executor.list;
+
+import org.junit.ClassRule;
+
+import org.apache.geode.redis.GeodeRedisServerRule;
+
+public class ListsIntegrationTest extends AbstractListsIntegrationTest {
+
+  @ClassRule
+  public static GeodeRedisServerRule server = new GeodeRedisServerRule();
+
+  @Override
+  public int getPort() {
+    return server.getPort();
+  }
+
+}
diff --git 
a/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/RedisList.java
 
b/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/RedisList.java
index a4a2e89..ae05e1e 100644
--- 
a/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/RedisList.java
+++ 
b/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/RedisList.java
@@ -23,8 +23,8 @@ import static 
org.apache.geode.redis.internal.data.RedisDataType.REDIS_LIST;
 import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.Collection;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Objects;
 
@@ -87,7 +87,7 @@ public class RedisList extends AbstractRedisData {
       return this.elements;
     }
 
-    List<byte[]> popped = new ArrayList<>();
+    List<byte[]> popped = new LinkedList<>();
     while (popped.size() < popCount) {
       popped.add(elements.remove(0));
     }
diff --git 
a/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/collections/SizeableList.java
 
b/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/collections/SizeableList.java
index 4f72243..7249f5e 100644
--- 
a/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/collections/SizeableList.java
+++ 
b/geode-for-redis/src/main/java/org/apache/geode/redis/internal/data/collections/SizeableList.java
@@ -19,11 +19,12 @@ import static 
org.apache.geode.internal.JvmSizeUtils.memoryOverhead;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.LinkedList;
 import java.util.List;
 
 import org.apache.geode.internal.size.Sizeable;
 
-public abstract class SizeableList<K> extends ArrayList<K> implements Sizeable 
{
+public abstract class SizeableList<K> extends LinkedList<K> implements 
Sizeable {
   private static final long serialVersionUID = 9174920505089089517L;
   private static final int SIZEABLE_LIST_OVERHEAD =
       memoryOverhead(SizeableList.class);
@@ -32,18 +33,22 @@ public abstract class SizeableList<K> extends ArrayList<K> 
implements Sizeable {
   private List<K> elements;
 
   public SizeableList(Collection<K> collection) {
-    elements = new ArrayList<>(collection);
+    elements = new ArrayList<>(collection.size());
+    for (K element: collection) {
+      add(element);
+    }
   }
 
+
   public SizeableList(int size) {
-    elements = new ArrayList<>(size);
+    elements = new LinkedList<>();
   }
 
   @Override
   public boolean add(K k) {
     boolean added = elements.add(k);
     if (added) {
-      memberOverhead += sizeElement(k);
+      memberOverhead += sizeElement(k) + 4; // TODO: Figure out sizing.
     }
     return added;
   }
@@ -66,4 +71,4 @@ public abstract class SizeableList<K> extends ArrayList<K> 
implements Sizeable {
   }
 
   protected abstract int sizeElement(K element);
-}
+}
\ No newline at end of file
diff --git 
a/geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/collections/SizeableListTest.java
 
b/geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/collections/SizeableListTest.java
new file mode 100644
index 0000000..d18ebbb
--- /dev/null
+++ 
b/geode-for-redis/src/test/java/org/apache/geode/redis/internal/data/collections/SizeableListTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.data.collections;
+
+import it.unimi.dsi.fastutil.bytes.ByteArrays;
+import org.apache.geode.cache.util.ObjectSizer;
+import org.apache.geode.internal.size.ReflectionObjectSizer;
+import org.apache.geode.redis.internal.data.RedisList;
+import org.apache.geode.redis.internal.data.RedisSet;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class SizeableListTest {
+  private final ObjectSizer sizer = ReflectionObjectSizer.getInstance();
+
+  private int expectedSize(SizeableList list) {
+    return sizer.sizeof(list);
+  }
+
+  private RedisList.ElementList createTestElementList(int size) {
+    List<byte[]> initialElements = new ArrayList<>(size);
+    for (int i = 0; i < size; ++i) {
+      initialElements.add(new byte[] {(byte) i});
+    }
+    RedisList.ElementList list = new RedisList.ElementList(0);
+    return list;
+  }
+
+  @Test
+  public void getSizeInBytesForEmptyElementList() {
+    RedisList.ElementList list = createTestElementList(0);
+    assertThat(list.getSizeInBytes()).isEqualTo(expectedSize(list));
+  }
+
+  @Test
+  public void getSizeInBytesForSingleElementList() {
+    RedisList.ElementList list = createTestElementList(1);
+    assertThat(list.getSizeInBytes()).isEqualTo(expectedSize(list));
+  }
+
+  @Test
+  public void getSizeInBytesIsAccurateForByteArrays() {
+    List<byte[]> initialElements = new ArrayList<>();
+    int initialNumberOfElements = 100;
+    int elementsToAdd = 100;
+    for (int i = 0; i < initialNumberOfElements; ++i) {
+      initialElements.add(new byte[] {(byte) i});
+    }
+    // Create a set with an initial size and confirm that it correctly reports 
its size
+    RedisList.ElementList list = new RedisList.ElementList(initialElements);
+    assertThat(list.getSizeInBytes()).isEqualTo(expectedSize(list));
+
+    // Add enough members to force a resize and assert that the size is 
correct after each add
+    for (int i = initialNumberOfElements; i < initialNumberOfElements + 
elementsToAdd; ++i) {
+      list.add(new byte[] {(byte) i});
+      assertThat(list.getSizeInBytes()).isEqualTo(expectedSize(list));
+    }
+    assertThat(list.size()).isEqualTo(initialNumberOfElements + elementsToAdd);
+
+    // Remove all the members and assert that the size is correct after each 
remove
+    for (int i = 0; i < initialNumberOfElements + elementsToAdd; ++i) {
+      list.remove(new byte[] {(byte) i});
+      assertThat(list.getSizeInBytes()).isEqualTo(expectedSize(list));
+    }
+    assertThat(list.size()).isEqualTo(0);
+  }
+}

Reply via email to