http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/hll/IBuilder.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/hll/IBuilder.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/hll/IBuilder.java new file mode 100644 index 0000000..28340c6 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/hll/IBuilder.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2011 Clearspring Technologies, Inc. + * + * Licensed 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.hll; + + +public interface IBuilder<T> { + + T build(); + + int sizeof(); +}
http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/hll/ICardinality.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/hll/ICardinality.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/hll/ICardinality.java new file mode 100644 index 0000000..71369b1 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/hll/ICardinality.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2011 Clearspring Technologies, Inc. + * + * Licensed 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.hll; + + +import java.io.IOException; + + +public interface ICardinality { + + /** + * @param o stream element + * @return false if the value returned by cardinality() is unaffected by the appearance of o in + * the stream. + */ + boolean offer(Object o); + + /** + * Offer the value as a hashed long value + * + * @param hashedLong - the hash of the item to offer to the estimator + * @return false if the value returned by cardinality() is unaffected by the appearance of + * hashedLong in the stream + */ + boolean offerHashed(long hashedLong); + + /** + * Offer the value as a hashed long value + * + * @param hashedInt - the hash of the item to offer to the estimator + * @return false if the value returned by cardinality() is unaffected by the appearance of + * hashedInt in the stream + */ + boolean offerHashed(int hashedInt); + + /** + * @return the number of unique elements in the stream or an estimate thereof + */ + long cardinality(); + + /** + * @return size in bytes needed for serialization + */ + int sizeof(); + + /** + * @return byte[] + * @throws IOException + */ + byte[] getBytes() throws IOException; + + /** + * Merges estimators to produce a new estimator for the combined streams of this estimator and + * those passed as arguments. + * <p/> + * Nor this estimator nor the one passed as parameters are modified. + * + * @param estimators Zero or more compatible estimators + * @throws CardinalityMergeException If at least one of the estimators is not compatible with this + * one + */ + ICardinality merge(ICardinality... estimators) throws CardinalityMergeException; +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/hll/MurmurHash.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/hll/MurmurHash.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/hll/MurmurHash.java new file mode 100644 index 0000000..e5c1b1a --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/hll/MurmurHash.java @@ -0,0 +1,214 @@ +/* + * 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.hll; + + +/** + * This is a very fast, non-cryptographic hash suitable for general hash-based lookup. See + * http://murmurhash.googlepages.com/ for more details. + * <p/> + * <p> + * The C version of MurmurHash 2.0 found at that site was ported to Java by Andrzej Bialecki (ab at + * getopt org). + * </p> + */ +public class MurmurHash { + public static int hash(Object o) { + if (o == null) { + return 0; + } + if (o instanceof Long) { + return hashLong((Long) o); + } + if (o instanceof Integer) { + return hashLong((Integer) o); + } + if (o instanceof Double) { + return hashLong(Double.doubleToRawLongBits((Double) o)); + } + if (o instanceof Float) { + return hashLong(Float.floatToRawIntBits((Float) o)); + } + if (o instanceof String) { + return hash(((String) o).getBytes()); + } + if (o instanceof byte[]) { + return hash((byte[]) o); + } + return hash(o.toString()); + } + + public static int hash(byte[] data) { + return hash(data, 0, data.length, -1); + } + + public static int hash(byte[] data, int seed) { + return hash(data, 0, data.length, seed); + } + + public static int hash(byte[] data, int offset, int length, int seed) { + int m = 0x5bd1e995; + int r = 24; + + int h = seed ^ length; + + int len_4 = length >> 2; + + for (int i = 0; i < len_4; i++) { + int i_4 = i << 2; + int k = data[offset + i_4 + 3]; + k = k << 8; + k = k | (data[offset + i_4 + 2] & 0xff); + k = k << 8; + k = k | (data[offset + i_4 + 1] & 0xff); + k = k << 8; + k = k | (data[offset + i_4 + 0] & 0xff); + k *= m; + k ^= k >>> r; + k *= m; + h *= m; + h ^= k; + } + + // avoid calculating modulo + int len_m = len_4 << 2; + int left = length - len_m; + + if (left != 0) { + if (left >= 3) { + h ^= (int) data[offset + length - 3] << 16; + } + if (left >= 2) { + h ^= (int) data[offset + length - 2] << 8; + } + if (left >= 1) { + h ^= (int) data[offset + length - 1]; + } + + h *= m; + } + + h ^= h >>> 13; + h *= m; + h ^= h >>> 15; + + return h; + } + + public static int hashLong(long data) { + int m = 0x5bd1e995; + int r = 24; + + int h = 0; + + int k = (int) data * m; + k ^= k >>> r; + h ^= k * m; + + k = (int) (data >> 32) * m; + k ^= k >>> r; + h *= m; + h ^= k * m; + + h ^= h >>> 13; + h *= m; + h ^= h >>> 15; + + return h; + } + + public static long hash64(Object o) { + if (o == null) { + return 0l; + } else if (o instanceof String) { + final byte[] bytes = ((String) o).getBytes(); + return hash64(bytes, bytes.length); + } else if (o instanceof byte[]) { + final byte[] bytes = (byte[]) o; + return hash64(bytes, bytes.length); + } + return hash64(o.toString()); + } + + // 64 bit implementation copied from here: https://github.com/tnm/murmurhash-java + + /** + * Generates 64 bit hash from byte array with default seed value. + * + * @param data byte array to hash + * @param length length of the array to hash + * @return 64 bit hash of the given string + */ + public static long hash64(final byte[] data, int length) { + return hash64(data, length, 0xe17a1465); + } + + + /** + * Generates 64 bit hash from byte array of the given length and seed. + * + * @param data byte array to hash + * @param length length of the array to hash + * @param seed initial seed value + * @return 64 bit hash of the given array + */ + public static long hash64(final byte[] data, int length, int seed) { + final long m = 0xc6a4a7935bd1e995L; + final int r = 47; + + long h = (seed & 0xffffffffl) ^ (length * m); + + int length8 = length / 8; + + for (int i = 0; i < length8; i++) { + final int i8 = i * 8; + long k = ((long) data[i8 + 0] & 0xff) + (((long) data[i8 + 1] & 0xff) << 8) + + (((long) data[i8 + 2] & 0xff) << 16) + (((long) data[i8 + 3] & 0xff) << 24) + + (((long) data[i8 + 4] & 0xff) << 32) + (((long) data[i8 + 5] & 0xff) << 40) + + (((long) data[i8 + 6] & 0xff) << 48) + (((long) data[i8 + 7] & 0xff) << 56); + + k *= m; + k ^= k >>> r; + k *= m; + + h ^= k; + h *= m; + } + + switch (length % 8) { + case 7: + h ^= (long) (data[(length & ~7) + 6] & 0xff) << 48; + case 6: + h ^= (long) (data[(length & ~7) + 5] & 0xff) << 40; + case 5: + h ^= (long) (data[(length & ~7) + 4] & 0xff) << 32; + case 4: + h ^= (long) (data[(length & ~7) + 3] & 0xff) << 24; + case 3: + h ^= (long) (data[(length & ~7) + 2] & 0xff) << 16; + case 2: + h ^= (long) (data[(length & ~7) + 1] & 0xff) << 8; + case 1: + h ^= (long) (data[length & ~7] & 0xff); + h *= m; + }; + + h ^= h >>> r; + h *= m; + h ^= h >>> r; + + return h; + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/hll/RegisterSet.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/hll/RegisterSet.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/hll/RegisterSet.java new file mode 100644 index 0000000..97ac98d --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/hll/RegisterSet.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2012 Clearspring Technologies, Inc. + * + * Licensed 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.hll; + + +public class RegisterSet { + + public final static int LOG2_BITS_PER_WORD = 6; + public final static int REGISTER_SIZE = 5; + + public final int count; + public final int size; + + private final int[] M; + + public RegisterSet(int count) { + this(count, null); + } + + public RegisterSet(int count, int[] initialValues) { + this.count = count; + + if (initialValues == null) { + this.M = new int[getSizeForCount(count)]; + } else { + this.M = initialValues; + } + this.size = this.M.length; + } + + public static int getBits(int count) { + return count / LOG2_BITS_PER_WORD; + } + + public static int getSizeForCount(int count) { + int bits = getBits(count); + if (bits == 0) { + return 1; + } else if (bits % Integer.SIZE == 0) { + return bits; + } else { + return bits + 1; + } + } + + public void set(int position, int value) { + int bucketPos = position / LOG2_BITS_PER_WORD; + int shift = REGISTER_SIZE * (position - (bucketPos * LOG2_BITS_PER_WORD)); + this.M[bucketPos] = (this.M[bucketPos] & ~(0x1f << shift)) | (value << shift); + } + + public int get(int position) { + int bucketPos = position / LOG2_BITS_PER_WORD; + int shift = REGISTER_SIZE * (position - (bucketPos * LOG2_BITS_PER_WORD)); + return (this.M[bucketPos] & (0x1f << shift)) >>> shift; + } + + public boolean updateIfGreater(int position, int value) { + int bucket = position / LOG2_BITS_PER_WORD; + int shift = REGISTER_SIZE * (position - (bucket * LOG2_BITS_PER_WORD)); + int mask = 0x1f << shift; + + // Use long to avoid sign issues with the left-most shift + long curVal = this.M[bucket] & mask; + long newVal = value << shift; + if (curVal < newVal) { + this.M[bucket] = (int) ((this.M[bucket] & ~mask) | newVal); + return true; + } else { + return false; + } + } + + public void merge(RegisterSet that) { + for (int bucket = 0; bucket < M.length; bucket++) { + int word = 0; + for (int j = 0; j < LOG2_BITS_PER_WORD; j++) { + int mask = 0x1f << (REGISTER_SIZE * j); + + int thisVal = (this.M[bucket] & mask); + int thatVal = (that.M[bucket] & mask); + word |= (thisVal < thatVal) ? thatVal : thisVal; + } + this.M[bucket] = word; + } + } + + int[] readOnlyBits() { + return M; + } + + public int[] bits() { + int[] copy = new int[size]; + System.arraycopy(M, 0, copy, 0, M.length); + return copy; + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/java/org/apache/geode/redis/internal/org/apache/hadoop/fs/GlobPattern.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/java/org/apache/geode/redis/internal/org/apache/hadoop/fs/GlobPattern.java b/geode-redis/src/main/java/org/apache/geode/redis/internal/org/apache/hadoop/fs/GlobPattern.java new file mode 100644 index 0000000..b0190f6 --- /dev/null +++ b/geode-redis/src/main/java/org/apache/geode/redis/internal/org/apache/hadoop/fs/GlobPattern.java @@ -0,0 +1,165 @@ +/** + * 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.org.apache.hadoop.fs; + +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +/** + * A class for POSIX glob pattern with brace expansions. + */ +public class GlobPattern { + private static final char BACKSLASH = '\\'; + private Pattern compiled; + private boolean hasWildcard = false; + + /** + * Construct the glob pattern object with a glob pattern string + * + * @param globPattern the glob pattern string + */ + public GlobPattern(String globPattern) { + set(globPattern); + } + + /** + * @return the compiled pattern + */ + public Pattern compiled() { + return compiled; + } + + /** + * Compile glob pattern string + * + * @param globPattern the glob pattern + * @return the pattern object + */ + public static Pattern compile(String globPattern) { + return new GlobPattern(globPattern).compiled(); + } + + /** + * Match input against the compiled glob pattern + * + * @param s input chars + * @return true for successful matches + */ + public boolean matches(CharSequence s) { + return compiled.matcher(s).matches(); + } + + /** + * Set and compile a glob pattern + * + * @param glob the glob pattern string + */ + public void set(String glob) { + StringBuilder regex = new StringBuilder(); + int setOpen = 0; + int curlyOpen = 0; + int len = glob.length(); + hasWildcard = false; + + for (int i = 0; i < len; i++) { + char c = glob.charAt(i); + + switch (c) { + case BACKSLASH: + if (++i >= len) { + error("Missing escaped character", glob, i); + } + regex.append(c).append(glob.charAt(i)); + continue; + case '.': + case '$': + case '(': + case ')': + case '|': + case '+': + // escape regex special chars that are not glob special chars + regex.append(BACKSLASH); + break; + case '*': + regex.append('.'); + hasWildcard = true; + break; + case '?': + regex.append('.'); + hasWildcard = true; + continue; + case '{': // start of a group + regex.append("(?:"); // non-capturing + curlyOpen++; + hasWildcard = true; + continue; + case ',': + regex.append(curlyOpen > 0 ? '|' : c); + continue; + case '}': + if (curlyOpen > 0) { + // end of a group + curlyOpen--; + regex.append(")"); + continue; + } + break; + case '[': + if (setOpen > 0) { + error("Unclosed character class", glob, i); + } + setOpen++; + hasWildcard = true; + break; + case '^': // ^ inside [...] can be unescaped + if (setOpen == 0) { + regex.append(BACKSLASH); + } + break; + case '!': // [! needs to be translated to [^ + regex.append(setOpen > 0 && '[' == glob.charAt(i - 1) ? '^' : '!'); + continue; + case ']': + // Many set errors like [][] could not be easily detected here, + // as []], []-] and [-] are all valid POSIX glob and java regex. + // We'll just let the regex compiler do the real work. + setOpen = 0; + break; + default: + } + regex.append(c); + } + + if (setOpen > 0) { + error("Unclosed character class", glob, len); + } + if (curlyOpen > 0) { + error("Unclosed group", glob, len); + } + compiled = Pattern.compile(regex.toString()); + } + + /** + * @return true if this is a wildcard pattern (with special chars) + */ + public boolean hasWildcard() { + return hasWildcard; + } + + private static void error(String message, String pattern, int pos) { + throw new PatternSyntaxException(message, pattern, pos); + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/main/resources/META-INF/services/org.apache.geode.internal.cache.CacheService ---------------------------------------------------------------------- diff --git a/geode-redis/src/main/resources/META-INF/services/org.apache.geode.internal.cache.CacheService b/geode-redis/src/main/resources/META-INF/services/org.apache.geode.internal.cache.CacheService new file mode 100644 index 0000000..efda3a9 --- /dev/null +++ b/geode-redis/src/main/resources/META-INF/services/org.apache.geode.internal.cache.CacheService @@ -0,0 +1 @@ +org.apache.geode.redis.GeodeRedisServiceImpl \ No newline at end of file http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/test/java/org/apache/geode/redis/AuthJUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/test/java/org/apache/geode/redis/AuthJUnitTest.java b/geode-redis/src/test/java/org/apache/geode/redis/AuthJUnitTest.java new file mode 100644 index 0000000..753bc9e --- /dev/null +++ b/geode-redis/src/test/java/org/apache/geode/redis/AuthJUnitTest.java @@ -0,0 +1,120 @@ +/* + * 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import org.apache.geode.distributed.ConfigurationProperties; +import org.apache.geode.distributed.internal.InternalDistributedSystem; +import org.apache.geode.internal.cache.GemFireCacheImpl; +import org.apache.geode.test.junit.categories.IntegrationTest; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.util.Properties; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.exceptions.JedisConnectionException; +import redis.clients.jedis.exceptions.JedisDataException; + +@Category(IntegrationTest.class) +public class AuthJUnitTest extends RedisTestBase { + + private static final String PASSWORD = "pwd"; + + private void setupCacheWithPassword() { + if (cache != null) { + cache.close(); + } + Properties redisCacheProperties = getDefaultRedisCacheProperties(); + redisCacheProperties.setProperty(ConfigurationProperties.REDIS_PASSWORD, PASSWORD); + cache = (GemFireCacheImpl) createCacheInstance(redisCacheProperties); + } + + @Test + public void testAuthConfig() { + setupCacheWithPassword(); + InternalDistributedSystem distributedSystem = cache.getDistributedSystem(); + assert (distributedSystem.getConfig().getRedisPassword().equals(PASSWORD)); + cache.close(); + } + + @Test + public void testAuthRejectAccept() { + setupCacheWithPassword(); + try (Jedis jedis = defaultJedisInstance()) { + Exception ex = null; + try { + jedis.auth("wrongpwd"); + } catch (JedisDataException e) { + ex = e; + } + assertNotNull(ex); + + String res = jedis.auth(PASSWORD); + assertEquals(res, "OK"); + } + } + + @Test + public void testAuthNoPwd() { + try (Jedis jedis = defaultJedisInstance()) { + jedis.auth(PASSWORD); + fail( + "We expecting either a JedisConnectionException or JedisDataException to be thrown here"); + } catch (JedisConnectionException | JedisDataException exception) { + } + } + + @Test + public void testAuthAcceptRequests() { + setupCacheWithPassword(); + Exception ex = null; + try (Jedis jedis = defaultJedisInstance()) { + try { + jedis.set("foo", "bar"); + } catch (JedisDataException e) { + ex = e; + } + assertNotNull(ex); + + String res = jedis.auth(PASSWORD); + assertEquals(res, "OK"); + + jedis.set("foo", "bar"); // No exception + } + } + + @Test + public void testSeparateClientRequests() { + setupCacheWithPassword(); + try (Jedis authorizedJedis = new Jedis(hostName, Integer.parseInt(redisPort), 100000); + Jedis nonAuthorizedJedis = new Jedis(hostName, Integer.parseInt(redisPort), 100000)) { + String res = authorizedJedis.auth(PASSWORD); + assertEquals(res, "OK"); + authorizedJedis.set("foo", "bar"); // No exception for authorized client + + authorizedJedis.auth(PASSWORD); + Exception ex = null; + try { + nonAuthorizedJedis.set("foo", "bar"); + } catch (JedisDataException e) { + ex = e; + } + assertNotNull(ex); + } + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/test/java/org/apache/geode/redis/ConcurrentStartTest.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/test/java/org/apache/geode/redis/ConcurrentStartTest.java b/geode-redis/src/test/java/org/apache/geode/redis/ConcurrentStartTest.java new file mode 100644 index 0000000..7ada70c --- /dev/null +++ b/geode-redis/src/test/java/org/apache/geode/redis/ConcurrentStartTest.java @@ -0,0 +1,85 @@ +/* + * 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; + +import org.apache.geode.test.junit.categories.IntegrationTest; +import org.junit.experimental.categories.Category; + +//TODO I think this test can now be removed +@Category(IntegrationTest.class) +public class ConcurrentStartTest extends RedisTestBase { + +// private Cache cache; +// private int numServers = 10; +// +// @Rule +// public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); +// +// @Before +// public void setUp() { +// System.setProperty(DistributedSystem.PROPERTIES_FILE_PROPERTY, +// getClass().getSimpleName() + ".properties"); +// } +// +// @After +// public void tearDown() { +// if (this.cache != null) { +// this.cache.close(); +// this.cache = null; +// } +// } +// +// @Test +// public void testCachelessStart() throws InterruptedException { +// runNServers(numServers); +// GemFireCacheImpl.getInstance().close(); +// } +// +// @Test +// public void testCachefulStart() throws InterruptedException { +// CacheFactory cf = new CacheFactory(); +// cf.set(MCAST_PORT, "0"); +// cf.set(LOCATORS, ""); +// this.cache = cf.create(); +// +// runNServers(numServers); +// } +// +// private void runNServers(int n) throws InterruptedException { +// final int[] ports = AvailablePortHelper.getRandomAvailableTCPPorts(numServers); +// final Thread[] threads = new Thread[n]; +// for (int i = 0; i < n; i++) { +// final int j = i; +// Runnable r = new Runnable() { +// +// @Override +// public void run() { +// GeodeRedisServiceImpl s = new GeodeRedisServiceImpl(ports[j]); +// s.start(); +// s.stop(); +// } +// }; +// +// Thread t = new Thread(r); +// t.setDaemon(true); +// t.start(); +// threads[i] = t; +// } +// for (Thread t : threads) +// t.join(); +// this.cache = GemFireCacheImpl.getInstance(); +// assertFalse(this.cache.isClosed()); +// } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/test/java/org/apache/geode/redis/HashesJUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/test/java/org/apache/geode/redis/HashesJUnitTest.java b/geode-redis/src/test/java/org/apache/geode/redis/HashesJUnitTest.java new file mode 100644 index 0000000..f8fad9e --- /dev/null +++ b/geode-redis/src/test/java/org/apache/geode/redis/HashesJUnitTest.java @@ -0,0 +1,147 @@ +/* + * 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.apache.geode.test.junit.categories.FlakyTest; +import org.apache.geode.test.junit.categories.IntegrationTest; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import redis.clients.jedis.Jedis; + +@Category(IntegrationTest.class) +public class HashesJUnitTest extends RedisTestBase { + + @Test + public void testHMSetHSetHLen() { + try (Jedis jedis = defaultJedisInstance()) { + int num = 10; + String key = randString(); + Map<String, String> hash = new HashMap<String, String>(); + for (int i = 0; i < num; i++) { + hash.put(randString(), randString()); + } + String response = jedis.hmset(key, hash); + assertTrue(response.equals("OK")); + assertEquals(new Long(hash.size()), jedis.hlen(key)); + + key = randString(); + hash = new HashMap<String, String>(); + for (int i = 0; i < num; i++) { + hash.put(randString(), randString()); + } + Set<String> keys = hash.keySet(); + Long count = 1L; + for (String field : keys) { + Long res = jedis.hset(key, field, hash.get(field)); + assertTrue(res == 1L); + assertEquals(count++, jedis.hlen(key)); + } + } + } + + @Test + public void testHMGetHDelHGetAllHVals() { + try (Jedis jedis = defaultJedisInstance()) { + String key = randString(); + Map<String, String> hash = new HashMap<String, String>(); + for (int i = 0; i < 10; i++) { + String m = randString(); + String f = randString(); + hash.put(m, f); + } + jedis.hmset(key, hash); + Set<String> keys = hash.keySet(); + String[] keyArray = keys.toArray(new String[keys.size()]); + List<String> retList = jedis.hmget(key, keyArray); + + for (int i = 0; i < keys.size(); i++) { + assertEquals(retList.get(i), hash.get(keyArray[i])); + } + + Map<String, String> retMap = jedis.hgetAll(key); + + assertEquals(retMap, hash); + + List<String> retVals = jedis.hvals(key); + Set<String> retSet = new HashSet<String>(retVals); + + assertTrue(retSet.containsAll(hash.values())); + + jedis.hdel(key, keyArray); + assertTrue(jedis.hlen(key) == 0); + } + } + + @Test + public void testHkeys() { + try (Jedis jedis = defaultJedisInstance()) { + String key = randString(); + Map<String, String> hash = new HashMap<String, String>(); + for (int i = 0; i < 10; i++) { + hash.put(randString(), randString()); + } + String response = jedis.hmset(key, hash); + + Set<String> keys = hash.keySet(); + Set<String> retSet = jedis.hkeys(key); + + assertTrue(retSet.containsAll(keys)); + } + } + + @Category(FlakyTest.class) // GEODE-1942 + @Test + public void testHIncrBy() { + try (Jedis jedis = defaultJedisInstance()) { + String key = randString(); + String field = randString(); + + Long incr = (long) rand.nextInt(50); + if (incr == 0) { + incr++; + } + + long response1 = jedis.hincrBy(key, field, incr); + assertTrue(response1 == incr); + + long response2 = jedis.hincrBy(randString(), randString(), incr); + assertTrue(response2 == incr); + + long response3 = jedis.hincrBy(key, field, incr); + assertTrue(response3 == 2 * incr); + + String field1 = randString(); + Exception ex = null; + try { + jedis.hincrBy(key, field1, Long.MAX_VALUE); + jedis.hincrBy(key, field1, incr); + } catch (Exception e) { + ex = e; + } + + assertNotNull(ex); + } + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/test/java/org/apache/geode/redis/ListsJUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/test/java/org/apache/geode/redis/ListsJUnitTest.java b/geode-redis/src/test/java/org/apache/geode/redis/ListsJUnitTest.java new file mode 100644 index 0000000..484224f --- /dev/null +++ b/geode-redis/src/test/java/org/apache/geode/redis/ListsJUnitTest.java @@ -0,0 +1,212 @@ +/* + * 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.apache.geode.test.junit.categories.IntegrationTest; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.util.ArrayList; +import java.util.List; +import redis.clients.jedis.Jedis; + +@Category(IntegrationTest.class) +public class ListsJUnitTest extends RedisTestBase { + @Test + public void testLindex() { + try (Jedis jedis = defaultJedisInstance()) { + int elements = 50; + ArrayList<String> strings = new ArrayList<String>(); + String key = randString(); + for (int i = 0; i < elements; i++) { + String elem = randString(); + strings.add(elem); + } + String[] stringArray = strings.toArray(new String[strings.size()]); + jedis.rpush(key, stringArray); + + for (int i = 0; i < elements; i++) { + String gemString = jedis.lindex(key, i); + String s = strings.get(i); + assertEquals(gemString, s); + } + } + } + + @Test + public void testLPopRPush() { + try (Jedis jedis = defaultJedisInstance()) { + int elements = 50; + ArrayList<String> strings = new ArrayList<String>(); + String key = randString(); + for (int i = 0; i < elements; i++) { + String elem = randString(); + strings.add(elem); + } + String[] stringArray = strings.toArray(new String[strings.size()]); + jedis.rpush(key, stringArray); + + for (int i = 0; i < elements; i++) { + String gemString = jedis.lpop(key); + String s = strings.get(i); + assertEquals(s, gemString); + } + } + } + + @Test + public void testRPopLPush() { + try (Jedis jedis = defaultJedisInstance()) { + int elements = 500; + ArrayList<String> strings = new ArrayList<String>(); + String key = randString(); + for (int i = 0; i < elements; i++) { + String elem = randString(); + strings.add(elem); + } + String[] stringArray = strings.toArray(new String[strings.size()]); + jedis.lpush(key, stringArray); + + for (int i = 0; i < elements; i++) { + String gemString = jedis.rpop(key); + String s = strings.get(i); + assertEquals(gemString, s); + } + } + } + + @Test + public void testLRange() { + try (Jedis jedis = defaultJedisInstance()) { + int elements = 10; + ArrayList<String> strings = new ArrayList<String>(); + String key = randString(); + for (int i = 0; i < elements; i++) { + String elem = randString(); + strings.add(elem); + } + String[] stringArray = strings.toArray(new String[strings.size()]); + jedis.rpush(key, stringArray); + + for (int i = 0; i < elements; i++) { + List<String> range = jedis.lrange(key, 0, i); + assertEquals(range, strings.subList(0, i + 1)); + } + + for (int i = 0; i < elements; i++) { + List<String> range = jedis.lrange(key, i, -1); + assertEquals(range, strings.subList(i, strings.size())); + } + } + } + + @Test + public void testLTrim() { + try (Jedis jedis = defaultJedisInstance()) { + int elements = 5; + ArrayList<String> strings = new ArrayList<String>(); + String key = randString(); + for (int i = 0; i < elements; i++) { + String elem = randString(); + strings.add(elem); + } + String[] stringArray = strings.toArray(new String[strings.size()]); + jedis.rpush(key, stringArray); + // Take off last element one at a time + for (int i = elements - 1; i >= 0; i--) { + jedis.ltrim(key, 0, i); + List<String> range = jedis.lrange(key, 0, -1); + assertEquals(range, strings.subList(0, i + 1)); + } + jedis.rpop(key); + jedis.rpush(key, stringArray); + // Take off first element one at a time + for (int i = 1; i < elements; i++) { + jedis.ltrim(key, 1, -1); + List<String> range = jedis.lrange(key, 0, -1); + List<String> expected = strings.subList(i, strings.size()); + assertEquals(range, expected); + } + } + } + + @Test + public void testLRPushX() { + try (Jedis jedis = defaultJedisInstance()) { + String key = randString(); + String otherKey = "Other key"; + jedis.lpush(key, randString()); + assertTrue(jedis.lpushx(key, randString()) > 0); + assertTrue(jedis.rpushx(key, randString()) > 0); + + assertTrue(jedis.lpushx(otherKey, randString()) == 0); + assertTrue(jedis.rpushx(otherKey, randString()) == 0); + + jedis.del(key); + + assertTrue(jedis.lpushx(key, randString()) == 0); + assertTrue(jedis.rpushx(key, randString()) == 0); + } + } + + @Test + public void testLRem() { + try (Jedis jedis = defaultJedisInstance()) { + int elements = 5; + ArrayList<String> strings = new ArrayList<String>(); + String key = randString(); + for (int i = 0; i < elements; i++) { + String elem = randString(); + strings.add(elem); + } + String[] stringArray = strings.toArray(new String[strings.size()]); + jedis.rpush(key, stringArray); + + for (int i = 0; i < elements; i++) { + String remove = strings.remove(0); + jedis.lrem(key, 0, remove); + List<String> range = jedis.lrange(key, 0, -1); + assertEquals(strings, range); + } + } + } + + @Test + public void testLSet() { + try (Jedis jedis = defaultJedisInstance()) { + int elements = 10; + ArrayList<String> strings = new ArrayList<String>(); + String key = randString(); + for (int i = 0; i < elements; i++) { + String elem = randString(); + strings.add(elem); + } + String[] stringArray = strings.toArray(new String[strings.size()]); + jedis.rpush(key, stringArray); + + for (int i = 0; i < elements; i++) { + String s = randString(); + strings.set(i, s); + jedis.lset(key, i, s); + List<String> range = jedis.lrange(key, 0, -1); + assertEquals(range, strings); + } + } + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/test/java/org/apache/geode/redis/RedisDistDUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/test/java/org/apache/geode/redis/RedisDistDUnitTest.java b/geode-redis/src/test/java/org/apache/geode/redis/RedisDistDUnitTest.java new file mode 100644 index 0000000..f76b4f8 --- /dev/null +++ b/geode-redis/src/test/java/org/apache/geode/redis/RedisDistDUnitTest.java @@ -0,0 +1,266 @@ +/* + * 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; + +import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; +import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL; +import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT; +import static org.junit.Assert.assertEquals; + +import org.apache.geode.cache.CacheFactory; +import org.apache.geode.distributed.ConfigurationProperties; +import org.apache.geode.internal.AvailablePortHelper; +import org.apache.geode.internal.net.SocketCreator; +import org.apache.geode.test.dunit.AsyncInvocation; +import org.apache.geode.test.dunit.DistributedTestUtils; +import org.apache.geode.test.dunit.Host; +import org.apache.geode.test.dunit.IgnoredException; +import org.apache.geode.test.dunit.LogWriterUtils; +import org.apache.geode.test.dunit.SerializableCallable; +import org.apache.geode.test.dunit.VM; +import org.apache.geode.test.dunit.internal.JUnit4DistributedTestCase; +import org.apache.geode.test.junit.categories.DistributedTest; +import org.apache.geode.test.junit.categories.FlakyTest; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.util.Random; +import redis.clients.jedis.Jedis; + +@Category(DistributedTest.class) +public class RedisDistDUnitTest extends JUnit4DistributedTestCase { + + public static final String TEST_KEY = "key"; + public static int pushes = 200; + int redisPort = 6379; + private Host host; + private VM server1; + private VM server2; + private VM client1; + private VM client2; + + private int server1Port; + private int server2Port; + + private String localHost; + + private static final int JEDIS_TIMEOUT = 20 * 1000; + + private abstract class ClientTestBase extends SerializableCallable { + + int port; + + protected ClientTestBase(int port) { + this.port = port; + } + } + + @Override + public final void postSetUp() throws Exception { + disconnectAllFromDS(); + + localHost = SocketCreator.getLocalHost().getHostName(); + + host = Host.getHost(0); + server1 = host.getVM(0); + server2 = host.getVM(1); + client1 = host.getVM(2); + client2 = host.getVM(3); + final int[] ports = AvailablePortHelper.getRandomAvailableTCPPorts(2); + final int locatorPort = DistributedTestUtils.getDUnitLocatorPort(); + final SerializableCallable<Object> startRedisAdapter = new SerializableCallable<Object>() { + + @Override + public Object call() throws Exception { + int port = ports[VM.getCurrentVMNum()]; + CacheFactory cF = new CacheFactory(); + String locator = SocketCreator.getLocalHost().getHostName() + "[" + locatorPort + "]"; + cF.set(LOG_LEVEL, LogWriterUtils.getDUnitLogLevel()); + cF.set(ConfigurationProperties.REDIS_BIND_ADDRESS, localHost); + cF.set(ConfigurationProperties.REDIS_PORT, "" + port); + cF.set(MCAST_PORT, "0"); + cF.set(LOCATORS, locator); + cF.create(); + return Integer.valueOf(port); + } + }; + AsyncInvocation i = server1.invokeAsync(startRedisAdapter); + server2Port = (Integer) server2.invoke(startRedisAdapter); + server1Port = (Integer) i.getResult(); + } + + @Override + public final void preTearDown() throws Exception { + disconnectAllFromDS(); + } + + @Category(FlakyTest.class) // GEODE-1092: random ports, failure stack involves TCPTransport + // ConnectionHandler (are we eating BindExceptions somewhere?), uses + // Random, async actions + @Test + public void testConcListOps() throws Exception { + final Jedis jedis1 = new Jedis(localHost, server1Port, JEDIS_TIMEOUT); + final Jedis jedis2 = new Jedis(localHost, server2Port, JEDIS_TIMEOUT); + final int pushes = 20; + class ConcListOps extends ClientTestBase { + protected ConcListOps(int port) { + super(port); + } + + @Override + public Object call() throws Exception { + Jedis jedis = new Jedis(localHost, port, JEDIS_TIMEOUT); + Random r = new Random(); + for (int i = 0; i < pushes; i++) { + if (r.nextBoolean()) { + jedis.lpush(TEST_KEY, randString()); + } else { + jedis.rpush(TEST_KEY, randString()); + } + } + return null; + } + }; + + AsyncInvocation i = client1.invokeAsync(new ConcListOps(server1Port)); + client2.invoke(new ConcListOps(server2Port)); + i.getResult(); + long expected = 2 * pushes; + long result1 = jedis1.llen(TEST_KEY); + long result2 = jedis2.llen(TEST_KEY); + assertEquals(expected, result1); + assertEquals(result1, result2); + } + + @Category(FlakyTest.class) // GEODE-717: random ports, BindException in failure stack, async + // actions + @Test + public void testConcCreateDestroy() throws Exception { + IgnoredException.addIgnoredException("RegionDestroyedException"); + IgnoredException.addIgnoredException("IndexInvalidException"); + final int ops = 40; + final String hKey = TEST_KEY + "hash"; + final String lKey = TEST_KEY + "list"; + final String zKey = TEST_KEY + "zset"; + final String sKey = TEST_KEY + "set"; + + class ConcCreateDestroy extends ClientTestBase { + protected ConcCreateDestroy(int port) { + super(port); + } + + @Override + public Object call() throws Exception { + Jedis jedis = new Jedis(localHost, port, JEDIS_TIMEOUT); + Random r = new Random(); + for (int i = 0; i < ops; i++) { + int n = r.nextInt(4); + if (n == 0) { + if (r.nextBoolean()) { + jedis.hset(hKey, randString(), randString()); + } else { + jedis.del(hKey); + } + } else if (n == 1) { + if (r.nextBoolean()) { + jedis.lpush(lKey, randString()); + } else { + jedis.del(lKey); + } + } else if (n == 2) { + if (r.nextBoolean()) { + jedis.zadd(zKey, r.nextDouble(), randString()); + } else { + jedis.del(zKey); + } + } else { + if (r.nextBoolean()) { + jedis.sadd(sKey, randString()); + } else { + jedis.del(sKey); + } + } + } + return null; + } + } + + // Expect to run with no exception + AsyncInvocation i = client1.invokeAsync(new ConcCreateDestroy(server1Port)); + client2.invoke(new ConcCreateDestroy(server2Port)); + i.getResult(); + } + + /** + * Just make sure there are no unexpected server crashes + */ + @Category(FlakyTest.class) // GEODE-1697 + @Test + public void testConcOps() throws Exception { + + final int ops = 100; + final String hKey = TEST_KEY + "hash"; + final String lKey = TEST_KEY + "list"; + final String zKey = TEST_KEY + "zset"; + final String sKey = TEST_KEY + "set"; + + class ConcOps extends ClientTestBase { + + protected ConcOps(int port) { + super(port); + } + + @Override + public Object call() throws Exception { + Jedis jedis = new Jedis(localHost, port, JEDIS_TIMEOUT); + Random r = new Random(); + for (int i = 0; i < ops; i++) { + int n = r.nextInt(4); + if (n == 0) { + jedis.hset(hKey, randString(), randString()); + jedis.hgetAll(hKey); + jedis.hvals(hKey); + } else if (n == 1) { + jedis.lpush(lKey, randString()); + jedis.rpush(lKey, randString()); + jedis.ltrim(lKey, 0, 100); + jedis.lrange(lKey, 0, -1); + } else if (n == 2) { + jedis.zadd(zKey, r.nextDouble(), randString()); + jedis.zrangeByLex(zKey, "(a", "[z"); + jedis.zrangeByScoreWithScores(zKey, 0, 1, 0, 100); + jedis.zremrangeByScore(zKey, r.nextDouble(), r.nextDouble()); + } else { + jedis.sadd(sKey, randString()); + jedis.smembers(sKey); + jedis.sdiff(sKey, "afd"); + jedis.sunionstore("dst", sKey, "afds"); + } + } + return null; + } + } + + // Expect to run with no exception + AsyncInvocation i = client1.invokeAsync(new ConcOps(server1Port)); + client2.invoke(new ConcOps(server2Port)); + i.getResult(); + } + + private String randString() { + return Long.toHexString(Double.doubleToLongBits(Math.random())); + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/test/java/org/apache/geode/redis/RedisServerTest.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/test/java/org/apache/geode/redis/RedisServerTest.java b/geode-redis/src/test/java/org/apache/geode/redis/RedisServerTest.java new file mode 100644 index 0000000..b8387e1 --- /dev/null +++ b/geode-redis/src/test/java/org/apache/geode/redis/RedisServerTest.java @@ -0,0 +1,54 @@ +/* + * 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; + +import org.apache.geode.cache.DataPolicy; +import org.apache.geode.cache.Region; +import org.apache.geode.internal.cache.GemFireCacheImpl; +import org.apache.geode.test.junit.categories.IntegrationTest; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.RestoreSystemProperties; +import org.junit.experimental.categories.Category; + + +@Category(IntegrationTest.class) +public class RedisServerTest extends RedisTestBase { + @Rule + public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); + + @Test + public void initializeRedisCreatesThreeRegions() { + Assert.assertEquals(2, cache.rootRegions().size()); + Assert.assertTrue(cache.getRegion(GeodeRedisServiceImpl.REDIS_META_DATA_REGION) != null); + } + + @Test + public void initializeRedisCreatesPartitionedRegionByDefault() { + Region redisStringRegion = cache.getRegion(GeodeRedisServiceImpl.STRING_REGION); + Assert.assertEquals(DataPolicy.PARTITION, redisStringRegion.getAttributes().getDataPolicy()); + } + + @Test + public void initializeRedisCreatesRegionsUsingSystemProperty() { + shutdownCache(); + System.setProperty("gemfireredis.regiontype", "REPLICATE"); + cache = (GemFireCacheImpl) createCacheInstance(getDefaultRedisCacheProperties()); + Region redisStringRegion = cache.getRegion(GeodeRedisServiceImpl.STRING_REGION); + Assert.assertEquals(DataPolicy.REPLICATE, redisStringRegion.getAttributes().getDataPolicy()); + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/test/java/org/apache/geode/redis/RedisTestBase.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/test/java/org/apache/geode/redis/RedisTestBase.java b/geode-redis/src/test/java/org/apache/geode/redis/RedisTestBase.java new file mode 100644 index 0000000..b111fbc --- /dev/null +++ b/geode-redis/src/test/java/org/apache/geode/redis/RedisTestBase.java @@ -0,0 +1,103 @@ +/* + * 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; + +import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; +import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL; +import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT; +import static org.apache.geode.distributed.ConfigurationProperties.REDIS_PORT; + +import org.apache.geode.cache.Cache; +import org.apache.geode.cache.CacheFactory; +import org.apache.geode.internal.AvailablePortHelper; +import org.apache.geode.internal.cache.GemFireCacheImpl; +import org.apache.geode.internal.net.SocketCreator; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; + +import java.io.IOException; +import java.util.Properties; +import java.util.Random; +import redis.clients.jedis.Jedis; + +public class RedisTestBase { + // protected Jedis jedis; + protected GemFireCacheImpl cache; + protected static String redisPort; + protected Random rand; + protected String hostName; + + @BeforeClass + public static void setupBeforeClass() { + redisPort = String.valueOf(AvailablePortHelper.getRandomAvailableTCPPort()); + } + + protected Jedis defaultJedisInstance() { + return new Jedis(hostName, Integer.parseInt(redisPort), 100000); + } + + @Before + public void setUp() throws IOException { + hostName = SocketCreator.getLocalHost().getHostName(); + cache = (GemFireCacheImpl) createCacheInstance(getDefaultRedisCacheProperties()); + rand = new Random(System.nanoTime()); + } + + protected Properties getDefaultRedisCacheProperties() { + Properties properties = new Properties(); + properties.setProperty(LOG_LEVEL, "config"); + properties.setProperty(MCAST_PORT, "0"); + properties.setProperty(LOCATORS, ""); + properties.setProperty(REDIS_PORT, redisPort); + return properties; + } + + protected Cache createCacheInstance(Properties properties) { + CacheFactory cacheFactory = new CacheFactory(properties); + return cacheFactory.create(); + } + + @After + public void tearDown() throws InterruptedException { +// if (jedis != null) { +// jedis.flushAll(); +// jedis.shutdown(); +// } +// GeodeRedisService service = cache.getService(GeodeRedisService.class); +// service.stop(); + if (cache != null) { + cache.close(); + } + } + + protected String randString() { + int length = rand.nextInt(8) + 5; + StringBuilder rString = new StringBuilder(); + for (int i = 0; i < length; i++) { + rString.append((char) (rand.nextInt(57) + 65)); + } + // return rString.toString(); + return Long.toHexString(Double.doubleToLongBits(Math.random())); + } + + protected void shutdownCache() { + if (cache != null) { + cache.close(); + } + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/test/java/org/apache/geode/redis/SetsJUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/test/java/org/apache/geode/redis/SetsJUnitTest.java b/geode-redis/src/test/java/org/apache/geode/redis/SetsJUnitTest.java new file mode 100644 index 0000000..d979947 --- /dev/null +++ b/geode-redis/src/test/java/org/apache/geode/redis/SetsJUnitTest.java @@ -0,0 +1,194 @@ +/* + * 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.apache.geode.test.junit.categories.IntegrationTest; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; +import redis.clients.jedis.Jedis; + +@Category(IntegrationTest.class) +public class SetsJUnitTest extends RedisTestBase { + + @Test + public void testSAddScard() { + try (Jedis jedis = defaultJedisInstance()) { + int elements = 10; + Set<String> strings = new HashSet<String>(); + String key = randString(); + for (int i = 0; i < elements; i++) { + String elem = randString(); + strings.add(elem); + } + String[] stringArray = strings.toArray(new String[strings.size()]); + Long response = jedis.sadd(key, stringArray); + assertEquals(response, new Long(strings.size())); + + assertEquals(jedis.scard(key), new Long(strings.size())); + } + } + + @Test + public void testSMembersIsMember() { + try (Jedis jedis = defaultJedisInstance()) { + int elements = 10; + Set<String> strings = new HashSet<String>(); + String key = randString(); + for (int i = 0; i < elements; i++) { + String elem = randString(); + strings.add(elem); + } + String[] stringArray = strings.toArray(new String[strings.size()]); + jedis.sadd(key, stringArray); + + Set<String> returnedSet = jedis.smembers(key); + + assertEquals(returnedSet, new HashSet<String>(strings)); + + for (String entry : strings) { + boolean exists = jedis.sismember(key, entry); + assertTrue(exists); + } + } + } + + @Test + public void testSMove() { + try (Jedis jedis = defaultJedisInstance()) { + String source = randString(); + String dest = randString(); + String test = randString(); + int elements = 10; + Set<String> strings = new HashSet<String>(); + for (int i = 0; i < elements; i++) { + String elem = randString(); + strings.add(elem); + } + String[] stringArray = strings.toArray(new String[strings.size()]); + jedis.sadd(source, stringArray); + + long i = 1; + for (String entry : strings) { + assertTrue(jedis.smove(source, dest, entry) == 1); + assertTrue(jedis.sismember(dest, entry)); + assertTrue(jedis.scard(source) == strings.size() - i); + assertTrue(jedis.scard(dest) == i); + i++; + } + assertTrue(jedis.smove(test, dest, randString()) == 0); + } + } + + @Test + public void testSDiffAndStore() { + try (Jedis jedis = defaultJedisInstance()) { + int numSets = 3; + int elements = 10; + String[] keys = new String[numSets]; + ArrayList<Set<String>> sets = new ArrayList<Set<String>>(); + populateListRandomData(numSets, elements, keys, sets); + + for (int i = 0; i < numSets; i++) { + Set<String> s = sets.get(i); + String[] stringArray = s.toArray(new String[s.size()]); + jedis.sadd(keys[i], stringArray); + } + + Set<String> result = sets.get(0); + for (int i = 1; i < numSets; i++) { + result.removeAll(sets.get(i)); + } + assertEquals(result, jedis.sdiff(keys)); + String destination = randString(); + jedis.sdiffstore(destination, keys); + Set<String> destResult = jedis.smembers(destination); + assertEquals(result, destResult); + } + } + + @Test + public void testSUnionAndStore() { + try (Jedis jedis = defaultJedisInstance()) { + int numSets = 3; + int elements = 10; + String[] keys = new String[numSets]; + ArrayList<Set<String>> sets = new ArrayList<Set<String>>(); + populateListRandomData(numSets, elements, keys, sets); + + for (int i = 0; i < numSets; i++) { + Set<String> s = sets.get(i); + String[] stringArray = s.toArray(new String[s.size()]); + jedis.sadd(keys[i], stringArray); + } + + Set<String> result = sets.get(0); + for (int i = 1; i < numSets; i++) { + result.addAll(sets.get(i)); + } + assertEquals(result, jedis.sunion(keys)); + String destination = randString(); + jedis.sunionstore(destination, keys); + Set<String> destResult = jedis.smembers(destination); + assertEquals(result, destResult); + } + } + + @Test + public void testSInterAndStore() { + try (Jedis jedis = defaultJedisInstance()) { + int numSets = 3; + int elements = 10; + String[] keys = new String[numSets]; + ArrayList<Set<String>> sets = new ArrayList<Set<String>>(); + populateListRandomData(numSets, elements, keys, sets); + + for (int i = 0; i < numSets; i++) { + Set<String> s = sets.get(i); + String[] stringArray = s.toArray(new String[s.size()]); + jedis.sadd(keys[i], stringArray); + } + + Set<String> result = sets.get(0); + for (int i = 1; i < numSets; i++) { + result.retainAll(sets.get(i)); + } + assertEquals(result, jedis.sinter(keys)); + String destination = randString(); + jedis.sinterstore(destination, keys); + Set<String> destResult = jedis.smembers(destination); + assertEquals(result, destResult); + } + + } + + private void populateListRandomData(int numSets, int elements, String[] keys, + ArrayList<Set<String>> sets) { + for (int j = 0; j < numSets; j++) { + keys[j] = randString(); + Set<String> newSet = new HashSet<>(); + for (int i = 0; i < elements; i++) { + newSet.add(randString()); + } + sets.add(newSet); + } + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/test/java/org/apache/geode/redis/SortedSetsJUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/test/java/org/apache/geode/redis/SortedSetsJUnitTest.java b/geode-redis/src/test/java/org/apache/geode/redis/SortedSetsJUnitTest.java new file mode 100644 index 0000000..9f07f00 --- /dev/null +++ b/geode-redis/src/test/java/org/apache/geode/redis/SortedSetsJUnitTest.java @@ -0,0 +1,417 @@ +/* + * 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import org.apache.geode.test.junit.categories.IntegrationTest; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.Tuple; + +@Category(IntegrationTest.class) +public class SortedSetsJUnitTest extends RedisTestBase { + + @Test + public void testZAddZRange() { + try (Jedis jedis = defaultJedisInstance()) { + int numMembers = 10; + String key = randString(); + Map<String, Double> scoreMembers = new HashMap<String, Double>(); + + for (int i = 0; i < numMembers; i++) { + scoreMembers.put(randString(), rand.nextDouble()); + } + + jedis.zadd(key, scoreMembers); + int k = 0; + for (String entry : scoreMembers.keySet()) { + assertNotNull(jedis.zscore(key, entry)); + } + + Set<Tuple> results = jedis.zrangeWithScores(key, 0, -1); + Map<String, Double> resultMap = new HashMap<String, Double>(); + for (Tuple t : results) { + resultMap.put(t.getElement(), t.getScore()); + } + + assertEquals(scoreMembers, resultMap); + + for (int i = 0; i < 10; i++) { + int start; + int stop; + do { + start = rand.nextInt(numMembers); + stop = rand.nextInt(numMembers); + } while (start > stop); + results = jedis.zrangeWithScores(key, start, stop); + List<Entry<String, Double>> resultList = new ArrayList<Entry<String, Double>>(); + for (Tuple t : results) { + resultList.add(new AbstractMap.SimpleEntry<String, Double>(t.getElement(), t.getScore())); + } + List<Entry<String, Double>> list = + new ArrayList<Entry<String, Double>>(scoreMembers.entrySet()); + Collections.sort(list, new EntryCmp()); + list = list.subList(start, stop + 1); + assertEquals(list, resultList); + } + } + } + + @Test + public void testZRevRange() { + try (Jedis jedis = defaultJedisInstance()) { + int numMembers = 10; + String key = randString(); + + Map<String, Double> scoreMembers = new HashMap<String, Double>(); + + for (int i = 0; i < numMembers; i++) { + scoreMembers.put(randString(), rand.nextDouble()); + } + + jedis.zadd(key, scoreMembers); + + Set<Tuple> results; + + for (int i = 0; i < 10; i++) { + int start; + int stop; + do { + start = rand.nextInt(numMembers); + stop = rand.nextInt(numMembers); + } while (start > stop); + results = jedis.zrevrangeWithScores(key, start, stop); + List<Entry<String, Double>> resultList = new ArrayList<Entry<String, Double>>(); + for (Tuple t : results) { + resultList.add(new AbstractMap.SimpleEntry<String, Double>(t.getElement(), t.getScore())); + } + List<Entry<String, Double>> list = + new ArrayList<Entry<String, Double>>(scoreMembers.entrySet()); + Collections.sort(list, new EntryRevCmp()); + list = list.subList(start, stop + 1); + assertEquals(list, resultList); + } + } + } + + @Test + public void testZCount() { + try (Jedis jedis = defaultJedisInstance()) { + int num = 10; + int runs = 2; + for (int i = 0; i < runs; i++) { + Double min; + Double max; + do { + min = rand.nextDouble(); + max = rand.nextDouble(); + } while (min > max); + + int count = 0; + + String key = randString(); + Map<String, Double> scoreMembers = new HashMap<String, Double>(); + + for (int j = 0; j < num; j++) { + Double nextDouble = rand.nextDouble(); + if (nextDouble >= min && nextDouble <= max) { + count++; + } + scoreMembers.put(randString(), nextDouble); + } + + jedis.zadd(key, scoreMembers); + Long countResult = jedis.zcount(key, min, max); + assertTrue(count == countResult); + } + } + } + + @Test + public void testZIncrBy() { + try (Jedis jedis = defaultJedisInstance()) { + String key = randString(); + String member = randString(); + Double score = 0.0; + for (int i = 0; i < 20; i++) { + Double incr = rand.nextDouble(); + Double result = jedis.zincrby(key, incr, member); + score += incr; + assertEquals(score, result, 1.0 / 100000000.0); + } + + jedis.zincrby(key, Double.MAX_VALUE, member); + Double infResult = jedis.zincrby(key, Double.MAX_VALUE, member); + + assertEquals(infResult, Double.valueOf(Double.POSITIVE_INFINITY)); + } + } + + public void testZRangeByScore() { + try (Jedis jedis = defaultJedisInstance()) { + Double min; + Double max; + for (int j = 0; j < 2; j++) { + do { + min = rand.nextDouble(); + max = rand.nextDouble(); + } while (min > max); + int numMembers = 500; + String key = randString(); + Map<String, Double> scoreMembers = new HashMap<String, Double>(); + List<Entry<String, Double>> expected = new ArrayList<Entry<String, Double>>(); + for (int i = 0; i < numMembers; i++) { + String s = randString(); + Double d = rand.nextDouble(); + scoreMembers.put(s, d); + if (d > min && d < max) { + expected.add(new AbstractMap.SimpleEntry<String, Double>(s, d)); + } + } + jedis.zadd(key, scoreMembers); + Set<Tuple> results = jedis.zrangeByScoreWithScores(key, min, max); + List<Entry<String, Double>> resultList = new ArrayList<Entry<String, Double>>(); + for (Tuple t : results) { + resultList.add(new AbstractMap.SimpleEntry<String, Double>(t.getElement(), t.getScore())); + } + Collections.sort(expected, new EntryCmp()); + + assertEquals(expected, resultList); + jedis.del(key); + } + } + } + + public void testZRevRangeByScore() { + try (Jedis jedis = defaultJedisInstance()) { + Double min; + Double max; + for (int j = 0; j < 2; j++) { + do { + min = rand.nextDouble(); + max = rand.nextDouble(); + } while (min > max); + int numMembers = 500; + String key = randString(); + Map<String, Double> scoreMembers = new HashMap<String, Double>(); + List<Entry<String, Double>> expected = new ArrayList<Entry<String, Double>>(); + for (int i = 0; i < numMembers; i++) { + String s = randString(); + Double d = rand.nextDouble(); + scoreMembers.put(s, d); + if (d > min && d < max) { + expected.add(new AbstractMap.SimpleEntry<String, Double>(s, d)); + } + } + jedis.zadd(key, scoreMembers); + Set<Tuple> results = jedis.zrevrangeByScoreWithScores(key, max, min); + List<Entry<String, Double>> resultList = new ArrayList<Entry<String, Double>>(); + for (Tuple t : results) { + resultList.add(new AbstractMap.SimpleEntry<String, Double>(t.getElement(), t.getScore())); + } + Collections.sort(expected, new EntryRevCmp()); + + assertEquals(expected, resultList); + jedis.del(key); + } + } + } + + @Test + public void testZRemZScore() { + try (Jedis jedis = defaultJedisInstance()) { + Double min; + Double max; + for (int j = 0; j < 2; j++) { + do { + min = rand.nextDouble(); + max = rand.nextDouble(); + } while (min > max); + int numMembers = 5000; + String key = randString(); + Map<String, Double> scoreMembers = new HashMap<String, Double>(); + List<Entry<String, Double>> expected = new ArrayList<Entry<String, Double>>(); + for (int i = 0; i < numMembers; i++) { + String s = randString(); + Double d = rand.nextDouble(); + scoreMembers.put(s, d); + if (d > min && d < max) { + expected.add(new AbstractMap.SimpleEntry<String, Double>(s, d)); + } + } + jedis.zadd(key, scoreMembers); + Collections.sort(expected, new EntryCmp()); + for (int i = expected.size(); i > 0; i--) { + Entry<String, Double> remEntry = expected.remove(i - 1); + String rem = remEntry.getKey(); + Double val = remEntry.getValue(); + assertEquals(val, jedis.zscore(key, rem)); + + assertTrue(jedis.zrem(key, rem) == 1); + } + String s = randString(); + if (!expected.contains(s)) { + assertTrue(jedis.zrem(key, s) == 0); + } + jedis.del(key); + } + } + } + + @Test + public void testZRank() { + try (Jedis jedis = defaultJedisInstance()) { + for (int j = 0; j < 2; j++) { + int numMembers = 10; + String key = randString(); + Map<String, Double> scoreMembers = new HashMap<String, Double>(); + List<Entry<String, Double>> expected = new ArrayList<Entry<String, Double>>(); + for (int i = 0; i < numMembers; i++) { + String s = randString(); + Double d = rand.nextDouble(); + scoreMembers.put(s, d); + expected.add(new AbstractMap.SimpleEntry<String, Double>(s, d)); + } + Collections.sort(expected, new EntryCmp()); + jedis.zadd(key, scoreMembers); + for (int i = 0; i < expected.size(); i++) { + Entry<String, Double> en = expected.get(i); + String field = en.getKey(); + Long rank = jedis.zrank(key, field); + assertEquals(new Long(i), rank); + } + String field = randString(); + if (!expected.contains(field)) { + assertNull(jedis.zrank(key, field)); + } + jedis.del(key); + } + } + } + + @Test + public void testZRevRank() { + try (Jedis jedis = defaultJedisInstance()) { + for (int j = 0; j < 2; j++) { + int numMembers = 10; + String key = randString(); + Map<String, Double> scoreMembers = new HashMap<String, Double>(); + List<Entry<String, Double>> expected = new ArrayList<Entry<String, Double>>(); + for (int i = 0; i < numMembers; i++) { + String s = randString(); + Double d = rand.nextDouble(); + scoreMembers.put(s, d); + expected.add(new AbstractMap.SimpleEntry<String, Double>(s, d)); + } + Collections.sort(expected, new EntryRevCmp()); + jedis.zadd(key, scoreMembers); + for (int i = 0; i < expected.size(); i++) { + Entry<String, Double> en = expected.get(i); + String field = en.getKey(); + Long rank = jedis.zrevrank(key, field); + assertEquals(new Long(i), rank); + } + String field = randString(); + if (!expected.contains(field)) { + assertNull(jedis.zrank(key, field)); + } + jedis.del(key); + } + } + } + + private class EntryCmp implements Comparator<Entry<String, Double>> { + + @Override + public int compare(Entry<String, Double> o1, Entry<String, Double> o2) { + Double diff = o1.getValue() - o2.getValue(); + if (diff == 0) { + return o2.getKey().compareTo(o1.getKey()); + } else { + return diff > 0 ? 1 : -1; + } + } + + } + + private class EntryRevCmp implements Comparator<Entry<String, Double>> { + + @Override + public int compare(Entry<String, Double> o1, Entry<String, Double> o2) { + Double diff = o2.getValue() - o1.getValue(); + if (diff == 0) { + return o1.getKey().compareTo(o2.getKey()); + } else { + return diff > 0 ? 1 : -1; + } + } + + } + + @Test + public void testZRemRangeByScore() { + try (Jedis jedis = defaultJedisInstance()) { + Double min; + Double max; + for (int j = 0; j < 3; j++) { + do { + min = rand.nextDouble(); + max = rand.nextDouble(); + } while (min > max); + int numMembers = 10; + String key = randString(); + Map<String, Double> scoreMembers = new HashMap<String, Double>(); + List<Entry<String, Double>> fullList = new ArrayList<Entry<String, Double>>(); + List<Entry<String, Double>> toRemoveList = new ArrayList<Entry<String, Double>>(); + for (int i = 0; i < numMembers; i++) { + String s = randString(); + Double d = rand.nextDouble(); + scoreMembers.put(s, d); + fullList.add(new AbstractMap.SimpleEntry<String, Double>(s, d)); + if (d > min && d < max) { + toRemoveList.add(new AbstractMap.SimpleEntry<String, Double>(s, d)); + } + } + jedis.zadd(key, scoreMembers); + Long numRemoved = jedis.zremrangeByScore(key, min, max); + List<Entry<String, Double>> expectedList = new ArrayList<Entry<String, Double>>(fullList); + expectedList.removeAll(toRemoveList); + Collections.sort(expectedList, new EntryCmp()); + Set<Tuple> result = jedis.zrangeWithScores(key, 0, -1); + List<Entry<String, Double>> resultList = new ArrayList<Entry<String, Double>>(); + for (Tuple t : result) { + resultList.add(new AbstractMap.SimpleEntry<String, Double>(t.getElement(), t.getScore())); + } + assertEquals(expectedList, resultList); + jedis.del(key); + } + } + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/geode-redis/src/test/java/org/apache/geode/redis/StringsJunitTest.java ---------------------------------------------------------------------- diff --git a/geode-redis/src/test/java/org/apache/geode/redis/StringsJunitTest.java b/geode-redis/src/test/java/org/apache/geode/redis/StringsJunitTest.java new file mode 100644 index 0000000..7465576 --- /dev/null +++ b/geode-redis/src/test/java/org/apache/geode/redis/StringsJunitTest.java @@ -0,0 +1,287 @@ +/* + * 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import org.apache.geode.test.junit.categories.IntegrationTest; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; +import redis.clients.jedis.Jedis; + +@Category(IntegrationTest.class) +public class StringsJunitTest extends RedisTestBase { + + @Test + public void testAppendAndStrlen() { + try (Jedis jedis = defaultJedisInstance()) { + String key = randString(); + int len = key.length(); + String full = key; + jedis.set(key, key); + for (int i = 0; i < 15; i++) { + String rand = randString(); + jedis.append(key, rand); + len += rand.length(); + full += rand; + } + String ret = jedis.get(key); + assertTrue(ret.length() == len); + assertTrue(full.equals(ret)); + assertTrue(full.length() == jedis.strlen(key)); + } + } + + @Test + public void testDecr() { + try (Jedis jedis = defaultJedisInstance()) { + String key1 = randString(); + String key2 = randString(); + String key3 = randString(); + int num1 = 100; + int num2 = -100; + jedis.set(key1, "" + num1); + // jedis.set(key3, "-100"); + jedis.set(key2, "" + num2); + + jedis.decr(key1); + jedis.decr(key3); + jedis.decr(key2); + assertTrue(jedis.get(key1).equals("" + (num1 - 1))); + assertTrue(jedis.get(key2).equals("" + (num2 - 1))); + assertTrue(jedis.get(key3).equals("" + (-1))); + } + } + + @Test + public void testIncr() { + try (Jedis jedis = defaultJedisInstance()) { + String key1 = randString(); + String key2 = randString(); + String key3 = randString(); + int num1 = 100; + int num2 = -100; + jedis.set(key1, "" + num1); + // jedis.set(key3, "-100"); + jedis.set(key2, "" + num2); + + jedis.incr(key1); + jedis.incr(key3); + jedis.incr(key2); + + assertTrue(jedis.get(key1).equals("" + (num1 + 1))); + assertTrue(jedis.get(key2).equals("" + (num2 + 1))); + assertTrue(jedis.get(key3).equals("" + (+1))); + } + } + + @Test + public void testDecrBy() { + try (Jedis jedis = defaultJedisInstance()) { + String key1 = randString(); + String key2 = randString(); + String key3 = randString(); + int decr1 = rand.nextInt(100); + int decr2 = rand.nextInt(100); + Long decr3 = Long.MAX_VALUE / 2; + int num1 = 100; + int num2 = -100; + jedis.set(key1, "" + num1); + jedis.set(key2, "" + num2); + jedis.set(key3, "" + Long.MIN_VALUE); + + jedis.decrBy(key1, decr1); + jedis.decrBy(key2, decr2); + + assertTrue(jedis.get(key1).equals("" + (num1 - decr1 * 1))); + assertTrue(jedis.get(key2).equals("" + (num2 - decr2 * 1))); + + Exception ex = null; + try { + jedis.decrBy(key3, decr3); + } catch (Exception e) { + ex = e; + } + assertNotNull(ex); + } + } + + @Test + public void testIncrBy() { + try (Jedis jedis = defaultJedisInstance()) { + String key1 = randString(); + String key2 = randString(); + String key3 = randString(); + int incr1 = rand.nextInt(100); + int incr2 = rand.nextInt(100); + Long incr3 = Long.MAX_VALUE / 2; + int num1 = 100; + int num2 = -100; + jedis.set(key1, "" + num1); + jedis.set(key2, "" + num2); + jedis.set(key3, "" + Long.MAX_VALUE); + + jedis.incrBy(key1, incr1); + jedis.incrBy(key2, incr2); + assertTrue(jedis.get(key1).equals("" + (num1 + incr1 * 1))); + assertTrue(jedis.get(key2).equals("" + (num2 + incr2 * 1))); + + Exception ex = null; + try { + jedis.incrBy(key3, incr3); + } catch (Exception e) { + ex = e; + } + assertNotNull(ex); + } + } + + @Test + public void testGetRange() { + try (Jedis jedis = defaultJedisInstance()) { + String sent = randString(); + String contents = randString(); + jedis.set(sent, contents); + for (int i = 0; i < sent.length(); i++) { + String range = jedis.getrange(sent, i, -1); + assertTrue(contents.substring(i).equals(range)); + } + assertNull(jedis.getrange(sent, 2, 0)); + } + } + + @Test + public void testGetSet() { + try (Jedis jedis = defaultJedisInstance()) { + String key = randString(); + String contents = randString(); + jedis.set(key, contents); + String newContents = randString(); + String oldContents = jedis.getSet(key, newContents); + assertTrue(oldContents.equals(contents)); + contents = newContents; + } + } + + @Test + public void testMSetAndGet() { + try (Jedis jedis = defaultJedisInstance()) { + int r = 5; + String[] keyvals = new String[(r * 2)]; + String[] keys = new String[r]; + String[] vals = new String[r]; + for (int i = 0; i < r; i++) { + String key = randString(); + String val = randString(); + keyvals[2 * i] = key; + keyvals[2 * i + 1] = val; + keys[i] = key; + vals[i] = val; + } + + jedis.mset(keyvals); + + List<String> ret = jedis.mget(keys); + Object[] retArray = ret.toArray(); + + assertTrue(Arrays.equals(vals, retArray)); + } + } + + @Test + public void testMSetNX() { + try (Jedis jedis = defaultJedisInstance()) { + Set<String> strings = new HashSet<String>(); + for (int i = 0; i < 2 * 5; i++) { + strings.add(randString()); + } + String[] array = strings.toArray(new String[0]); + long response = jedis.msetnx(array); + + assertTrue(response == 1); + + long response2 = jedis.msetnx(array[0], randString()); + + assertTrue(response2 == 0); + assertEquals(array[1], jedis.get(array[0])); + } + } + + @Test + public void testSetNX() { + try (Jedis jedis = defaultJedisInstance()) { + String key1 = randString(); + String key2; + do { + key2 = randString(); + } while (key2.equals(key1)); + + long response1 = jedis.setnx(key1, key1); + long response2 = jedis.setnx(key2, key2); + long response3 = jedis.setnx(key1, key2); + + assertTrue(response1 == 1); + assertTrue(response2 == 1); + assertTrue(response3 == 0); + } + } + + @Test + public void testPAndSetex() { + try (Jedis jedis = defaultJedisInstance()) { + Random r = new Random(); + int setex = r.nextInt(5); + if (setex == 0) { + setex = 1; + } + String key = randString(); + jedis.setex(key, setex, randString()); + try { + Thread.sleep((setex + 5) * 1000); + } catch (InterruptedException e) { + return; + } + String result = jedis.get(key); + // System.out.println(result); + assertNull(result); + + int psetex = r.nextInt(5000); + if (psetex == 0) { + psetex = 1; + } + key = randString(); + jedis.psetex(key, psetex, randString()); + long start = System.currentTimeMillis(); + try { + Thread.sleep(psetex + 5000); + } catch (InterruptedException e) { + return; + } + long stop = System.currentTimeMillis(); + result = jedis.get(key); + assertTrue(stop - start >= psetex); + assertNull(result); + } + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/c6dbc6d4/gradle/dependency-versions.properties ---------------------------------------------------------------------- diff --git a/gradle/dependency-versions.properties b/gradle/dependency-versions.properties index a0b291e..e019673 100644 --- a/gradle/dependency-versions.properties +++ b/gradle/dependency-versions.properties @@ -61,7 +61,7 @@ javax.persistence-api.version = 2.0.0 javax.resource-api.version = 1.7 javax.servlet-api.version = 3.1.0 javax.transaction-api.version = 1.2 -jedis.version = 2.7.2 +jedis.version = 2.9.0 jetty.version = 9.3.6.v20151106 jgroups.version = 3.6.10.Final jline.version = 2.12 @@ -84,7 +84,7 @@ multithreadedtc.version = 1.01 mx4j.version = 3.0.1 mx4j-remote.version = 3.0.1 mx4j-tools.version = 3.0.1 -netty-all.version = 4.0.4.Final +netty-all.version = 4.1.8.Final open-json.version = 1.7 paranamer.version = 2.3 phantomjsdriver.version=1.2.1
