/* * 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.*; import static org.junit.Assert.*; import java.util.Random; import org.junit.Test; import org.junit.experimental.categories.Category; import redis.clients.jedis.Jedis; 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; @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())); } }