Merging with upstream, necessary changes, shifting poolConfig as private instance variable from JedisClusterConnectionHandler to JedisClusterInfoCache due to design change in previous commits.
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
package redis.clients.jedis.tests;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import redis.clients.jedis.Connection;
|
||||
import redis.clients.jedis.exceptions.JedisConnectionException;
|
||||
|
||||
public class ConnectionCloseTest extends Assert {
|
||||
|
||||
private Connection client;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
client = new Connection();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
client.close();
|
||||
}
|
||||
|
||||
@Test(expected = JedisConnectionException.class)
|
||||
public void checkUnkownHost() {
|
||||
client.setHost("someunknownhost");
|
||||
client.connect();
|
||||
}
|
||||
|
||||
@Test(expected = JedisConnectionException.class)
|
||||
public void checkWrongPort() {
|
||||
client.setHost("localhost");
|
||||
client.setPort(55665);
|
||||
client.connect();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectIfNotConnectedWhenSettingTimeoutInfinite() {
|
||||
client.setHost("localhost");
|
||||
client.setPort(6379);
|
||||
client.setTimeoutInfinite();
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ public class HostAndPortUtil {
|
||||
sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT));
|
||||
sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 1));
|
||||
sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 2));
|
||||
sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 3));
|
||||
|
||||
clusterHostAndPortList.add(new HostAndPort("localhost", 7379));
|
||||
clusterHostAndPortList.add(new HostAndPort("localhost", 7380));
|
||||
|
||||
@@ -17,7 +17,7 @@ public class JedisClusterNodeInformationParserTest extends Assert {
|
||||
|
||||
@Test
|
||||
public void testParseNodeMyself() {
|
||||
String nodeInfo = "9b0d2ab38ee31482c95fdb2c7847a0d40e88d518 :0 myself,master - 0 0 1 connected 0-5460";
|
||||
String nodeInfo = "9b0d2ab38ee31482c95fdb2c7847a0d40e88d518 :7379 myself,master - 0 0 1 connected 0-5460";
|
||||
HostAndPort current = new HostAndPort("localhost", 7379);
|
||||
ClusterNodeInformation clusterNodeInfo = parser
|
||||
.parse(nodeInfo, current);
|
||||
@@ -44,7 +44,7 @@ public class JedisClusterNodeInformationParserTest extends Assert {
|
||||
|
||||
@Test
|
||||
public void testParseSlotBeingMigrated() {
|
||||
String nodeInfo = "5f4a2236d00008fba7ac0dd24b95762b446767bd :0 myself,master - 0 0 1 connected 0-5459 [5460->-5f4a2236d00008fba7ac0dd24b95762b446767bd] [5461-<-5f4a2236d00008fba7ac0dd24b95762b446767bd]";
|
||||
String nodeInfo = "5f4a2236d00008fba7ac0dd24b95762b446767bd :7379 myself,master - 0 0 1 connected 0-5459 [5460->-5f4a2236d00008fba7ac0dd24b95762b446767bd] [5461-<-5f4a2236d00008fba7ac0dd24b95762b446767bd]";
|
||||
HostAndPort current = new HostAndPort("localhost", 7379);
|
||||
ClusterNodeInformation clusterNodeInfo = parser
|
||||
.parse(nodeInfo, current);
|
||||
|
||||
@@ -2,6 +2,7 @@ package redis.clients.jedis.tests;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -15,7 +16,13 @@ import org.junit.Test;
|
||||
import redis.clients.jedis.HostAndPort;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisCluster;
|
||||
import redis.clients.jedis.exceptions.*;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
import redis.clients.jedis.exceptions.JedisAskDataException;
|
||||
import redis.clients.jedis.exceptions.JedisClusterException;
|
||||
import redis.clients.jedis.exceptions.JedisClusterMaxRedirectionsException;
|
||||
import redis.clients.jedis.exceptions.JedisConnectionException;
|
||||
import redis.clients.jedis.exceptions.JedisException;
|
||||
import redis.clients.jedis.exceptions.JedisMovedDataException;
|
||||
import redis.clients.jedis.tests.utils.JedisClusterTestUtil;
|
||||
import redis.clients.util.JedisClusterCRC16;
|
||||
|
||||
@@ -329,6 +336,33 @@ public class JedisClusterTest extends Assert {
|
||||
jc.set("52", "poolTestValue");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloseable() {
|
||||
Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>();
|
||||
jedisClusterNode.add(new HostAndPort(nodeInfo1.getHost(), nodeInfo1.getPort()));
|
||||
|
||||
JedisCluster jc = null;
|
||||
try {
|
||||
jc = new JedisCluster(jedisClusterNode);
|
||||
jc.set("51", "foo");
|
||||
} finally {
|
||||
if (jc != null) {
|
||||
jc.close();
|
||||
}
|
||||
}
|
||||
|
||||
Iterator<JedisPool> poolIterator = jc.getClusterNodes().values().iterator();
|
||||
while (poolIterator.hasNext()) {
|
||||
JedisPool pool = poolIterator.next();
|
||||
try {
|
||||
pool.getResource();
|
||||
fail("JedisCluster's internal pools should be already destroyed");
|
||||
} catch (JedisConnectionException e) {
|
||||
// ok to go...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getNodeServingSlotRange(String infoOutput) {
|
||||
// f4f3dc4befda352a4e0beccf29f5e8828438705d 127.0.0.1:7380 master - 0 1394372400827 0 connected 5461-10922
|
||||
for (String infoLine : infoOutput.split("\n")) {
|
||||
|
||||
@@ -27,6 +27,20 @@ public class JedisPoolTest extends Assert {
|
||||
assertEquals("bar", jedis.get("foo"));
|
||||
pool.returnResource(jedis);
|
||||
pool.destroy();
|
||||
assertTrue(pool.isClosed());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkCloseableConnections() throws Exception {
|
||||
JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(),
|
||||
hnp.getPort(), 2000);
|
||||
Jedis jedis = pool.getResource();
|
||||
jedis.auth("foobared");
|
||||
jedis.set("foo", "bar");
|
||||
assertEquals("bar", jedis.get("foo"));
|
||||
pool.returnResource(jedis);
|
||||
pool.close();
|
||||
assertTrue(pool.isClosed());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -39,6 +53,7 @@ public class JedisPoolTest extends Assert {
|
||||
assertEquals("bar", jedis.get("foo"));
|
||||
pool.returnResource(jedis);
|
||||
pool.destroy();
|
||||
assertTrue(pool.isClosed());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -56,6 +71,7 @@ public class JedisPoolTest extends Assert {
|
||||
jedis.incr("foo");
|
||||
pool.returnResource(jedis);
|
||||
pool.destroy();
|
||||
assertTrue(pool.isClosed());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -72,6 +88,7 @@ public class JedisPoolTest extends Assert {
|
||||
jedis.incr("foo");
|
||||
pool.returnResource(jedis);
|
||||
pool.destroy();
|
||||
assertTrue(pool.isClosed());
|
||||
}
|
||||
|
||||
@Test(expected = JedisConnectionException.class)
|
||||
@@ -99,6 +116,7 @@ public class JedisPoolTest extends Assert {
|
||||
jedis.set("foo", "bar");
|
||||
pool.returnResource(jedis);
|
||||
pool.destroy();
|
||||
assertTrue(pool.isClosed());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -110,6 +128,7 @@ public class JedisPoolTest extends Assert {
|
||||
assertEquals("bar", jedis0.get("foo"));
|
||||
pool0.returnResource(jedis0);
|
||||
pool0.destroy();
|
||||
assertTrue(pool0.isClosed());
|
||||
|
||||
JedisPool pool1 = new JedisPool(new JedisPoolConfig(), hnp.getHost(),
|
||||
hnp.getPort(), 2000, "foobared", 1);
|
||||
@@ -117,6 +136,7 @@ public class JedisPoolTest extends Assert {
|
||||
assertNull(jedis1.get("foo"));
|
||||
pool1.returnResource(jedis1);
|
||||
pool1.destroy();
|
||||
assertTrue(pool1.isClosed());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -144,6 +164,12 @@ public class JedisPoolTest extends Assert {
|
||||
assertEquals("bar", jedis.get("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allowUrlWithNoDBAndNoPassword() throws URISyntaxException {
|
||||
new JedisPool("redis://localhost:6380");
|
||||
new JedisPool(new URI("redis://localhost:6380"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void selectDatabaseOnActivation() {
|
||||
JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(),
|
||||
@@ -163,6 +189,7 @@ public class JedisPoolTest extends Assert {
|
||||
|
||||
pool.returnResource(jedis1);
|
||||
pool.destroy();
|
||||
assertTrue(pool.isClosed());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -176,6 +203,7 @@ public class JedisPoolTest extends Assert {
|
||||
|
||||
pool0.returnResource(jedis);
|
||||
pool0.destroy();
|
||||
assertTrue(pool0.isClosed());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -204,6 +232,7 @@ public class JedisPoolTest extends Assert {
|
||||
}
|
||||
|
||||
pool.destroy();
|
||||
assertTrue(pool.isClosed());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -238,4 +267,40 @@ public class JedisPoolTest extends Assert {
|
||||
pool.returnResource(null);
|
||||
pool.returnResourceObject(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNumActiveIsNegativeWhenPoolIsClosed() {
|
||||
JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(),
|
||||
hnp.getPort(), 2000, "foobared", 0, "my_shiny_client_name");
|
||||
|
||||
pool.destroy();
|
||||
assertTrue(pool.getNumActive() < 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNumActiveReturnsTheCorrectNumber() {
|
||||
JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(),
|
||||
hnp.getPort(), 2000);
|
||||
Jedis jedis = pool.getResource();
|
||||
jedis.auth("foobared");
|
||||
jedis.set("foo", "bar");
|
||||
assertEquals("bar", jedis.get("foo"));
|
||||
|
||||
assertEquals(1, pool.getNumActive());
|
||||
|
||||
Jedis jedis2 = pool.getResource();
|
||||
jedis.auth("foobared");
|
||||
jedis.set("foo", "bar");
|
||||
|
||||
assertEquals(2, pool.getNumActive());
|
||||
|
||||
pool.returnResource(jedis);
|
||||
assertEquals(1, pool.getNumActive());
|
||||
|
||||
pool.returnResource(jedis2);
|
||||
|
||||
assertEquals(0, pool.getNumActive());
|
||||
|
||||
pool.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package redis.clients.jedis.tests;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
|
||||
import org.junit.Before;
|
||||
@@ -21,18 +22,63 @@ public class JedisSentinelPoolTest extends JedisTestBase {
|
||||
.get(2);
|
||||
protected static HostAndPort slave1 = HostAndPortUtil.getRedisServers()
|
||||
.get(3);
|
||||
|
||||
protected static HostAndPort sentinel1 = HostAndPortUtil
|
||||
.getSentinelServers().get(1);
|
||||
protected static HostAndPort sentinel2 = HostAndPortUtil
|
||||
.getSentinelServers().get(3);
|
||||
|
||||
protected static Jedis sentinelJedis1;
|
||||
protected static Jedis sentinelJedis2;
|
||||
|
||||
protected Set<String> sentinels = new HashSet<String>();
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
sentinels.add(sentinel1.toString());
|
||||
sentinels.add(sentinel2.toString());
|
||||
|
||||
sentinelJedis1 = new Jedis(sentinel1.getHost(), sentinel1.getPort());
|
||||
sentinelJedis2 = new Jedis(sentinel2.getHost(), sentinel2.getPort());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void errorMasterNameNotThrowException() throws InterruptedException {
|
||||
final String wrongMasterName = "wrongMasterName";
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(3);
|
||||
sentinelJedis1.sentinelMonitor(wrongMasterName,
|
||||
"127.0.0.1", master.getPort(), 2);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
|
||||
JedisSentinelPool pool = new JedisSentinelPool(wrongMasterName,
|
||||
sentinels);
|
||||
pool.destroy();
|
||||
sentinelJedis1.sentinelRemove(wrongMasterName);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void checkCloseableConnections() throws Exception {
|
||||
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
|
||||
|
||||
JedisSentinelPool pool = new JedisSentinelPool(
|
||||
MASTER_NAME, sentinels, config, 1000, "foobared", 2);
|
||||
Jedis jedis = pool.getResource();
|
||||
jedis.auth("foobared");
|
||||
jedis.set("foo", "bar");
|
||||
assertEquals("bar", jedis.get("foo"));
|
||||
pool.returnResource(jedis);
|
||||
pool.close();
|
||||
assertTrue(pool.isClosed());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -41,6 +87,8 @@ public class JedisSentinelPoolTest extends JedisTestBase {
|
||||
new GenericObjectPoolConfig(), 1000, "foobared", 2);
|
||||
|
||||
forceFailover(pool);
|
||||
// after failover sentinel needs a bit of time to stabilize before a new failover
|
||||
Thread.sleep(100);
|
||||
forceFailover(pool);
|
||||
|
||||
// you can test failover as much as possible
|
||||
@@ -134,29 +182,25 @@ public class JedisSentinelPoolTest extends JedisTestBase {
|
||||
HostAndPort oldMaster = pool.getCurrentHostMaster();
|
||||
|
||||
// jedis connection should be master
|
||||
Jedis jedis = pool.getResource();
|
||||
assertEquals("PONG", jedis.ping());
|
||||
Jedis beforeFailoverJedis = pool.getResource();
|
||||
assertEquals("PONG", beforeFailoverJedis.ping());
|
||||
|
||||
// It can throw JedisDataException while there's no slave to promote
|
||||
// There's nothing we can do, so we just pass Exception to make test
|
||||
// fail fast
|
||||
sentinelJedis1.sentinelFailover(MASTER_NAME);
|
||||
|
||||
waitForFailover(pool, oldMaster);
|
||||
// JedisSentinelPool recognize master but may not changed internal pool
|
||||
// yet
|
||||
Thread.sleep(100);
|
||||
|
||||
Jedis afterFailoverJedis = pool.getResource();
|
||||
assertEquals("PONG", afterFailoverJedis.ping());
|
||||
assertEquals("foobared", afterFailoverJedis.configGet("requirepass").get(1));
|
||||
assertEquals(2, afterFailoverJedis.getDB().intValue());
|
||||
|
||||
jedis = pool.getResource();
|
||||
assertEquals("PONG", jedis.ping());
|
||||
assertEquals("foobared", jedis.configGet("requirepass").get(1));
|
||||
assertEquals(2, jedis.getDB().intValue());
|
||||
// returning both connections to the pool should not throw
|
||||
beforeFailoverJedis.close();
|
||||
afterFailoverJedis.close();
|
||||
}
|
||||
|
||||
private void waitForFailover(JedisSentinelPool pool, HostAndPort oldMaster)
|
||||
throws InterruptedException {
|
||||
HostAndPort newMaster = JedisSentinelTestUtil
|
||||
.waitForNewPromotedMaster(sentinelJedis1);
|
||||
.waitForNewPromotedMaster(MASTER_NAME, sentinelJedis1, sentinelJedis2);
|
||||
|
||||
waitForJedisSentinelPoolRecognizeNewMaster(pool, newMaster);
|
||||
}
|
||||
@@ -166,10 +210,9 @@ public class JedisSentinelPoolTest extends JedisTestBase {
|
||||
throws InterruptedException {
|
||||
|
||||
while (true) {
|
||||
String host = pool.getCurrentHostMaster().getHost();
|
||||
int port = pool.getCurrentHostMaster().getPort();
|
||||
HostAndPort currentHostMaster = pool.getCurrentHostMaster();
|
||||
|
||||
if (host.equals(newMaster.getHost()) && port == newMaster.getPort())
|
||||
if (newMaster.equals(currentHostMaster))
|
||||
break;
|
||||
|
||||
System.out
|
||||
@@ -179,4 +222,4 @@ public class JedisSentinelPoolTest extends JedisTestBase {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -85,16 +85,16 @@ public class JedisSentinelTest extends JedisTestBase {
|
||||
public void sentinelFailover() throws InterruptedException {
|
||||
Jedis j = new Jedis(sentinelForFailover.getHost(),
|
||||
sentinelForFailover.getPort());
|
||||
Jedis j2 = new Jedis(sentinelForFailover.getHost(),
|
||||
sentinelForFailover.getPort());
|
||||
|
||||
try {
|
||||
List<String> masterHostAndPort = j
|
||||
.sentinelGetMasterAddrByName(FAILOVER_MASTER_NAME);
|
||||
HostAndPort currentMaster = new HostAndPort(masterHostAndPort.get(0),
|
||||
Integer.parseInt(masterHostAndPort.get(1)));
|
||||
String result = j.sentinelFailover(FAILOVER_MASTER_NAME);
|
||||
assertEquals("OK", result);
|
||||
|
||||
JedisSentinelTestUtil.waitForNewPromotedMaster(j);
|
||||
JedisSentinelTestUtil.waitForNewPromotedMaster(FAILOVER_MASTER_NAME, j, j2);
|
||||
|
||||
masterHostAndPort = j
|
||||
.sentinelGetMasterAddrByName(FAILOVER_MASTER_NAME);
|
||||
|
||||
@@ -57,6 +57,14 @@ public class JedisTest extends JedisCommandTestBase {
|
||||
jedis.hmget("foobar", "foo");
|
||||
}
|
||||
|
||||
@Test(expected = JedisConnectionException.class)
|
||||
public void timeoutConnectionWithURI() throws Exception {
|
||||
jedis = new Jedis(new URI("redis://:foobared@localhost:6380/2"), 15000);
|
||||
jedis.configSet("timeout", "1");
|
||||
Thread.sleep(2000);
|
||||
jedis.hmget("foobar", "foo");
|
||||
}
|
||||
|
||||
@Test(expected = JedisDataException.class)
|
||||
public void failWhenSendingNullValues() {
|
||||
jedis.set("foo", null);
|
||||
@@ -92,7 +100,22 @@ public class JedisTest extends JedisCommandTestBase {
|
||||
assertEquals("PONG", jedis.ping());
|
||||
assertEquals("bar", jedis.get("foo"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void allowUrlWithNoDBAndNoPassword() {
|
||||
Jedis jedis = new Jedis("redis://localhost:6380");
|
||||
jedis.auth("foobared");
|
||||
assertEquals(jedis.getClient().getHost(), "localhost");
|
||||
assertEquals(jedis.getClient().getPort(), 6380);
|
||||
assertEquals(jedis.getDB(), (Long) 0L);
|
||||
|
||||
jedis = new Jedis("redis://localhost:6380/");
|
||||
jedis.auth("foobared");
|
||||
assertEquals(jedis.getClient().getHost(), "localhost");
|
||||
assertEquals(jedis.getClient().getPort(), 6380);
|
||||
assertEquals(jedis.getDB(), (Long) 0L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkCloseable() {
|
||||
jedis.close();
|
||||
|
||||
@@ -1,24 +1,14 @@
|
||||
package redis.clients.jedis.tests;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import redis.clients.jedis.HostAndPort;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.Pipeline;
|
||||
import redis.clients.jedis.Response;
|
||||
import redis.clients.jedis.Tuple;
|
||||
import redis.clients.jedis.*;
|
||||
import redis.clients.jedis.exceptions.JedisDataException;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.*;
|
||||
|
||||
public class PipeliningTest extends Assert {
|
||||
private static HostAndPort hnp = HostAndPortUtil.getRedisServers().get(0);
|
||||
|
||||
@@ -52,6 +42,9 @@ public class PipeliningTest extends Assert {
|
||||
jedis.hset("hash", "foo", "bar");
|
||||
jedis.zadd("zset", 1, "foo");
|
||||
jedis.sadd("set", "foo");
|
||||
jedis.setrange("setrange", 0, "0123456789");
|
||||
byte[] bytesForSetRange = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
jedis.setrange("setrangebytes".getBytes(), 0, bytesForSetRange);
|
||||
|
||||
Pipeline p = jedis.pipelined();
|
||||
Response<String> string = p.get("string");
|
||||
@@ -68,8 +61,10 @@ public class PipeliningTest extends Assert {
|
||||
p.sadd("set", "foo");
|
||||
Response<Set<String>> smembers = p.smembers("set");
|
||||
Response<Set<Tuple>> zrangeWithScores = p.zrangeWithScores("zset", 0,
|
||||
-1);
|
||||
p.sync();
|
||||
-1);
|
||||
Response<String> getrange = p.getrange("setrange", 1, 3);
|
||||
Response<byte[]> getrangeBytes = p.getrange("setrangebytes".getBytes(), 6, 8);
|
||||
p.sync();
|
||||
|
||||
assertEquals("foo", string.get());
|
||||
assertEquals("foo", list.get());
|
||||
@@ -83,6 +78,9 @@ public class PipeliningTest extends Assert {
|
||||
assertNotNull(hgetAll.get().get("foo"));
|
||||
assertEquals(1, smembers.get().size());
|
||||
assertEquals(1, zrangeWithScores.get().size());
|
||||
assertEquals("123", getrange.get());
|
||||
byte[] expectedGetRangeBytes = {6, 7, 8};
|
||||
assertArrayEquals(expectedGetRangeBytes, getrangeBytes.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -373,4 +371,79 @@ public class PipeliningTest extends Assert {
|
||||
assertNull(result1.get());
|
||||
assertEquals("13", result2.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPipelinedTransactionResponse() {
|
||||
|
||||
String key1 = "key1";
|
||||
String val1 = "val1";
|
||||
|
||||
String key2 = "key2";
|
||||
String val2 = "val2";
|
||||
|
||||
String key3 = "key3";
|
||||
String field1 = "field1";
|
||||
String field2 = "field2";
|
||||
String field3 = "field3";
|
||||
String field4 = "field4";
|
||||
|
||||
String value1 = "value1";
|
||||
String value2 = "value2";
|
||||
String value3 = "value3";
|
||||
String value4 = "value4";
|
||||
|
||||
Map<String, String> hashMap = new HashMap<String, String>();
|
||||
hashMap.put(field1, value1);
|
||||
hashMap.put(field2, value2);
|
||||
|
||||
String key4 = "key4";
|
||||
Map<String, String> hashMap1 = new HashMap<String, String>();
|
||||
hashMap1.put(field3, value3);
|
||||
hashMap1.put(field4, value4);
|
||||
|
||||
|
||||
jedis.set(key1, val1);
|
||||
jedis.set(key2, val2);
|
||||
jedis.hmset(key3, hashMap);
|
||||
jedis.hmset(key4, hashMap1);
|
||||
|
||||
Pipeline pipeline = jedis.pipelined();
|
||||
pipeline.multi();
|
||||
|
||||
pipeline.get(key1);
|
||||
pipeline.hgetAll(key2);
|
||||
pipeline.hgetAll(key3);
|
||||
pipeline.get(key4);
|
||||
|
||||
Response<List<Object> > response = pipeline.exec();
|
||||
pipeline.sync();
|
||||
|
||||
List<Object> result = response.get();
|
||||
|
||||
assertEquals(4, result.size());
|
||||
|
||||
assertEquals("val1", result.get(0));
|
||||
|
||||
assertTrue(result.get(1) instanceof JedisDataException);
|
||||
|
||||
Map<String, String> hashMapReceived = (Map<String, String>)result.get(2);
|
||||
Iterator<String> iterator = hashMapReceived.keySet().iterator();
|
||||
String mapKey1 = iterator.next();
|
||||
String mapKey2 = iterator.next();
|
||||
assertFalse(iterator.hasNext());
|
||||
verifyHasBothValues(mapKey1, mapKey2, field1, field2);
|
||||
String mapValue1 = hashMapReceived.get(mapKey1);
|
||||
String mapValue2 = hashMapReceived.get(mapKey2);
|
||||
verifyHasBothValues(mapValue1, mapValue2, value1, value2);
|
||||
|
||||
assertTrue(result.get(3) instanceof JedisDataException);
|
||||
}
|
||||
|
||||
private void verifyHasBothValues(String firstKey, String secondKey, String value1, String value2) {
|
||||
assertFalse(firstKey.equals(secondKey));
|
||||
assertTrue(firstKey.equals(value1)
|
||||
|| firstKey.equals(value2));
|
||||
assertTrue(secondKey.equals(value1)
|
||||
|| secondKey.equals(value2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,18 @@ public class ShardedJedisPoolTest extends Assert {
|
||||
pool.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkCloseableConnections() throws Exception {
|
||||
ShardedJedisPool pool = new ShardedJedisPool(
|
||||
new GenericObjectPoolConfig(), shards);
|
||||
ShardedJedis jedis = pool.getResource();
|
||||
jedis.set("foo", "bar");
|
||||
assertEquals("bar", jedis.get("foo"));
|
||||
pool.returnResource(jedis);
|
||||
pool.close();
|
||||
assertTrue(pool.isClosed());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkConnectionWithDefaultPort() {
|
||||
ShardedJedisPool pool = new ShardedJedisPool(
|
||||
|
||||
@@ -521,7 +521,7 @@ public class AllKindOfValuesCommandsTest extends JedisCommandTestBase {
|
||||
|
||||
ScanResult<String> result = jedis.scan(SCAN_POINTER_START);
|
||||
|
||||
assertEquals(SCAN_POINTER_START, result.getStringCursor());
|
||||
assertEquals(SCAN_POINTER_START, result.getCursor());
|
||||
assertFalse(result.getResult().isEmpty());
|
||||
|
||||
// binary
|
||||
@@ -541,7 +541,7 @@ public class AllKindOfValuesCommandsTest extends JedisCommandTestBase {
|
||||
jedis.set("aa", "aa");
|
||||
ScanResult<String> result = jedis.scan(SCAN_POINTER_START, params);
|
||||
|
||||
assertEquals(SCAN_POINTER_START, result.getStringCursor());
|
||||
assertEquals(SCAN_POINTER_START, result.getCursor());
|
||||
assertFalse(result.getResult().isEmpty());
|
||||
|
||||
// binary
|
||||
|
||||
@@ -45,6 +45,8 @@ public class ClusterCommandsTest extends JedisTestBase {
|
||||
node1.clusterDelSlots(1, 2, 3, 4, 5, 500);
|
||||
node1.clusterSetSlotNode(5000, node1Id);
|
||||
node1.clusterDelSlots(5000, 10000);
|
||||
node1.clusterDelSlots(3000, 3001, 3002);
|
||||
node2.clusterDelSlots(4000, 4001, 4002);
|
||||
node1.clusterAddSlots(6000);
|
||||
node1.clusterDelSlots(6000);
|
||||
waitForGossip();
|
||||
@@ -134,5 +136,34 @@ public class ClusterCommandsTest extends JedisTestBase {
|
||||
String status = node1.clusterSetSlotMigrating(5000, nodeId);
|
||||
assertEquals("OK", status);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clusterSlots() {
|
||||
// please see cluster slot output format from below commit
|
||||
// @see:
|
||||
// https://github.com/antirez/redis/commit/e14829de3025ffb0d3294e5e5a1553afd9f10b60
|
||||
String status = node1.clusterAddSlots(3000, 3001, 3002);
|
||||
assertEquals("OK", status);
|
||||
status = node2.clusterAddSlots(4000, 4001, 4002);
|
||||
assertEquals("OK", status);
|
||||
|
||||
List<Object> slots = node1.clusterSlots();
|
||||
assertNotNull(slots);
|
||||
assertTrue(slots.size() > 0);
|
||||
|
||||
for (Object slotInfoObj : slots) {
|
||||
List<Object> slotInfo = (List<Object>) slotInfoObj;
|
||||
assertNotNull(slots);
|
||||
assertTrue(slots.size() >= 2);
|
||||
|
||||
assertTrue(slotInfo.get(0) instanceof Long);
|
||||
assertTrue(slotInfo.get(1) instanceof Long);
|
||||
|
||||
if (slots.size() > 2) {
|
||||
// assigned slots
|
||||
assertTrue(slotInfo.get(2) instanceof List);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,9 +9,11 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import redis.clients.jedis.Pipeline;
|
||||
import redis.clients.jedis.Response;
|
||||
import redis.clients.jedis.ScanParams;
|
||||
import redis.clients.jedis.ScanResult;
|
||||
|
||||
import static redis.clients.jedis.ScanParams.SCAN_POINTER_START;
|
||||
import static redis.clients.jedis.ScanParams.SCAN_POINTER_START_BINARY;
|
||||
|
||||
@@ -316,6 +318,22 @@ public class HashesCommandsTest extends JedisCommandTestBase {
|
||||
assertArrayEquals(bbar, bhash.get(bcar));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hgetAllPipeline() {
|
||||
Map<byte[], byte[]> bh = new HashMap<byte[], byte[]>();
|
||||
bh.put(bbar, bcar);
|
||||
bh.put(bcar, bbar);
|
||||
jedis.hmset(bfoo, bh);
|
||||
Pipeline pipeline = jedis.pipelined();
|
||||
Response<Map<byte[], byte[]>> bhashResponse = pipeline.hgetAll(bfoo);
|
||||
pipeline.sync();
|
||||
Map<byte[], byte[]> bhash = bhashResponse.get();
|
||||
|
||||
assertEquals(2, bhash.size());
|
||||
assertArrayEquals(bcar, bhash.get(bbar));
|
||||
assertArrayEquals(bbar, bhash.get(bcar));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hscan() {
|
||||
jedis.hset("foo", "b", "b");
|
||||
@@ -323,7 +341,7 @@ public class HashesCommandsTest extends JedisCommandTestBase {
|
||||
|
||||
ScanResult<Map.Entry<String, String>> result = jedis.hscan("foo", SCAN_POINTER_START);
|
||||
|
||||
assertEquals(SCAN_POINTER_START, result.getStringCursor());
|
||||
assertEquals(SCAN_POINTER_START, result.getCursor());
|
||||
assertFalse(result.getResult().isEmpty());
|
||||
|
||||
// binary
|
||||
@@ -346,7 +364,7 @@ public class HashesCommandsTest extends JedisCommandTestBase {
|
||||
ScanResult<Map.Entry<String, String>> result = jedis.hscan("foo",
|
||||
SCAN_POINTER_START, params);
|
||||
|
||||
assertEquals(SCAN_POINTER_START, result.getStringCursor());
|
||||
assertEquals(SCAN_POINTER_START, result.getCursor());
|
||||
assertFalse(result.getResult().isEmpty());
|
||||
|
||||
// binary
|
||||
|
||||
@@ -466,7 +466,7 @@ public class SetCommandsTest extends JedisCommandTestBase {
|
||||
|
||||
ScanResult<String> result = jedis.sscan("foo", SCAN_POINTER_START);
|
||||
|
||||
assertEquals(SCAN_POINTER_START, result.getStringCursor());
|
||||
assertEquals(SCAN_POINTER_START, result.getCursor());
|
||||
assertFalse(result.getResult().isEmpty());
|
||||
|
||||
// binary
|
||||
@@ -486,7 +486,7 @@ public class SetCommandsTest extends JedisCommandTestBase {
|
||||
jedis.sadd("foo", "b", "a", "aa");
|
||||
ScanResult<String> result = jedis.sscan("foo", SCAN_POINTER_START, params);
|
||||
|
||||
assertEquals(SCAN_POINTER_START, result.getStringCursor());
|
||||
assertEquals(SCAN_POINTER_START, result.getCursor());
|
||||
assertFalse(result.getResult().isEmpty());
|
||||
|
||||
// binary
|
||||
|
||||
@@ -20,6 +20,10 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
|
||||
final byte[] ba = { 0x0A };
|
||||
final byte[] bb = { 0x0B };
|
||||
final byte[] bc = { 0x0C };
|
||||
final byte[] bInclusiveB = { 0x5B, 0x0B };
|
||||
final byte[] bExclusiveC = { 0x28, 0x0C };
|
||||
final byte[] bLexMinusInf = { 0x2D };
|
||||
final byte[] bLexPlusInf = { 0x2B };
|
||||
|
||||
final byte[] bbar1 = { 0x05, 0x06, 0x07, 0x08, 0x0A };
|
||||
final byte[] bbar2 = { 0x05, 0x06, 0x07, 0x08, 0x0B };
|
||||
@@ -54,7 +58,7 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
|
||||
assertEquals(0, bstatus);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void zrange() {
|
||||
jedis.zadd("foo", 1d, "a");
|
||||
@@ -91,6 +95,48 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
|
||||
assertEquals(bexpected, brange);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void zrangeByLex() {
|
||||
jedis.zadd("foo", 1, "aa");
|
||||
jedis.zadd("foo", 1, "c");
|
||||
jedis.zadd("foo", 1, "bb");
|
||||
jedis.zadd("foo", 1, "d");
|
||||
|
||||
Set<String> expected = new LinkedHashSet<String>();
|
||||
expected.add("bb");
|
||||
expected.add("c");
|
||||
|
||||
// exclusive aa ~ inclusive c
|
||||
assertEquals(expected, jedis.zrangeByLex("foo", "(aa", "[c"));
|
||||
|
||||
expected.clear();
|
||||
expected.add("bb");
|
||||
expected.add("c");
|
||||
|
||||
// with LIMIT
|
||||
assertEquals(expected, jedis.zrangeByLex("foo", "-", "+", 1, 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void zrangeByLexBinary() {
|
||||
// binary
|
||||
jedis.zadd(bfoo, 1, ba);
|
||||
jedis.zadd(bfoo, 1, bc);
|
||||
jedis.zadd(bfoo, 1, bb);
|
||||
|
||||
Set<byte[]> bExpected = new LinkedHashSet<byte[]>();
|
||||
bExpected.add(bb);
|
||||
|
||||
assertEquals(bExpected, jedis.zrangeByLex(bfoo, bInclusiveB, bExclusiveC));
|
||||
|
||||
bExpected.clear();
|
||||
bExpected.add(ba);
|
||||
bExpected.add(bb);
|
||||
|
||||
// with LIMIT
|
||||
assertEquals(bExpected, jedis.zrangeByLex(bfoo, bLexMinusInf, bLexPlusInf, 0, 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void zrevrange() {
|
||||
@@ -401,6 +447,40 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
|
||||
|
||||
assertEquals(3, bresult);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void zlexcount() {
|
||||
jedis.zadd("foo", 1, "a");
|
||||
jedis.zadd("foo", 1, "b");
|
||||
jedis.zadd("foo", 1, "c");
|
||||
jedis.zadd("foo", 1, "aa");
|
||||
|
||||
long result = jedis.zlexcount("foo", "[aa", "(c");
|
||||
assertEquals(2, result);
|
||||
|
||||
result = jedis.zlexcount("foo", "-", "+");
|
||||
assertEquals(4, result);
|
||||
|
||||
result = jedis.zlexcount("foo", "-", "(c");
|
||||
assertEquals(3, result);
|
||||
|
||||
result = jedis.zlexcount("foo", "[aa", "+");
|
||||
assertEquals(3, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void zlexcountBinary() {
|
||||
// Binary
|
||||
jedis.zadd(bfoo, 1, ba);
|
||||
jedis.zadd(bfoo, 1, bc);
|
||||
jedis.zadd(bfoo, 1, bb);
|
||||
|
||||
long result = jedis.zlexcount(bfoo, bInclusiveB, bExclusiveC);
|
||||
assertEquals(1, result);
|
||||
|
||||
result = jedis.zlexcount(bfoo, bLexMinusInf, bLexPlusInf);
|
||||
assertEquals(3, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void zrangebyscore() {
|
||||
@@ -739,6 +819,41 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
|
||||
|
||||
assertEquals(bexpected, jedis.zrange(bfoo, 0, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void zremrangeByLex() {
|
||||
jedis.zadd("foo", 1, "a");
|
||||
jedis.zadd("foo", 1, "b");
|
||||
jedis.zadd("foo", 1, "c");
|
||||
jedis.zadd("foo", 1, "aa");
|
||||
|
||||
long result = jedis.zremrangeByLex("foo", "[aa", "(c");
|
||||
|
||||
assertEquals(2, result);
|
||||
|
||||
Set<String> expected = new LinkedHashSet<String>();
|
||||
expected.add("a");
|
||||
expected.add("c");
|
||||
|
||||
assertEquals(expected, jedis.zrangeByLex("foo", "-", "+"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void zremrangeByLexBinary() {
|
||||
jedis.zadd(bfoo, 1, ba);
|
||||
jedis.zadd(bfoo, 1, bc);
|
||||
jedis.zadd(bfoo, 1, bb);
|
||||
|
||||
long bresult = jedis.zremrangeByLex(bfoo, bInclusiveB, bExclusiveC);
|
||||
|
||||
assertEquals(1, bresult);
|
||||
|
||||
Set<byte[]> bexpected = new LinkedHashSet<byte[]>();
|
||||
bexpected.add(ba);
|
||||
bexpected.add(bc);
|
||||
|
||||
assertEquals(bexpected, jedis.zrangeByLex(bfoo, bLexMinusInf, bLexPlusInf));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void zunionstore() {
|
||||
@@ -783,15 +898,15 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
|
||||
jedis.zadd("bar", 2, "b");
|
||||
|
||||
ZParams params = new ZParams();
|
||||
params.weights(2, 2);
|
||||
params.weights(2, 2.5);
|
||||
params.aggregate(ZParams.Aggregate.SUM);
|
||||
long result = jedis.zunionstore("dst", params, "foo", "bar");
|
||||
|
||||
assertEquals(2, result);
|
||||
|
||||
Set<Tuple> expected = new LinkedHashSet<Tuple>();
|
||||
expected.add(new Tuple("b", new Double(8)));
|
||||
expected.add(new Tuple("a", new Double(6)));
|
||||
expected.add(new Tuple("b", new Double(9)));
|
||||
expected.add(new Tuple("a", new Double(7)));
|
||||
|
||||
assertEquals(expected, jedis.zrangeWithScores("dst", 0, 100));
|
||||
|
||||
@@ -802,7 +917,7 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
|
||||
jedis.zadd(bbar, 2, bb);
|
||||
|
||||
ZParams bparams = new ZParams();
|
||||
bparams.weights(2, 2);
|
||||
bparams.weights(2, 2.5);
|
||||
bparams.aggregate(ZParams.Aggregate.SUM);
|
||||
long bresult = jedis.zunionstore(SafeEncoder.encode("dst"), bparams,
|
||||
bfoo, bbar);
|
||||
@@ -810,8 +925,8 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
|
||||
assertEquals(2, bresult);
|
||||
|
||||
Set<Tuple> bexpected = new LinkedHashSet<Tuple>();
|
||||
bexpected.add(new Tuple(bb, new Double(8)));
|
||||
bexpected.add(new Tuple(ba, new Double(6)));
|
||||
bexpected.add(new Tuple(bb, new Double(9)));
|
||||
bexpected.add(new Tuple(ba, new Double(7)));
|
||||
|
||||
assertEquals(bexpected,
|
||||
jedis.zrangeWithScores(SafeEncoder.encode("dst"), 0, 100));
|
||||
@@ -855,14 +970,14 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
|
||||
jedis.zadd("bar", 2, "a");
|
||||
|
||||
ZParams params = new ZParams();
|
||||
params.weights(2, 2);
|
||||
params.weights(2, 2.5);
|
||||
params.aggregate(ZParams.Aggregate.SUM);
|
||||
long result = jedis.zinterstore("dst", params, "foo", "bar");
|
||||
|
||||
assertEquals(1, result);
|
||||
|
||||
Set<Tuple> expected = new LinkedHashSet<Tuple>();
|
||||
expected.add(new Tuple("a", new Double(6)));
|
||||
expected.add(new Tuple("a", new Double(7)));
|
||||
|
||||
assertEquals(expected, jedis.zrangeWithScores("dst", 0, 100));
|
||||
|
||||
@@ -872,7 +987,7 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
|
||||
jedis.zadd(bbar, 2, ba);
|
||||
|
||||
ZParams bparams = new ZParams();
|
||||
bparams.weights(2, 2);
|
||||
bparams.weights(2, 2.5);
|
||||
bparams.aggregate(ZParams.Aggregate.SUM);
|
||||
long bresult = jedis.zinterstore(SafeEncoder.encode("dst"), bparams,
|
||||
bfoo, bbar);
|
||||
@@ -880,7 +995,7 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
|
||||
assertEquals(1, bresult);
|
||||
|
||||
Set<Tuple> bexpected = new LinkedHashSet<Tuple>();
|
||||
bexpected.add(new Tuple(ba, new Double(6)));
|
||||
bexpected.add(new Tuple(ba, new Double(7)));
|
||||
|
||||
assertEquals(bexpected,
|
||||
jedis.zrangeWithScores(SafeEncoder.encode("dst"), 0, 100));
|
||||
@@ -903,7 +1018,7 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
|
||||
|
||||
ScanResult<Tuple> result = jedis.zscan("foo", SCAN_POINTER_START);
|
||||
|
||||
assertEquals(SCAN_POINTER_START, result.getStringCursor());
|
||||
assertEquals(SCAN_POINTER_START, result.getCursor());
|
||||
assertFalse(result.getResult().isEmpty());
|
||||
|
||||
// binary
|
||||
@@ -926,7 +1041,7 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
|
||||
jedis.zadd("foo", 11, "aa");
|
||||
ScanResult<Tuple> result = jedis.zscan("foo", SCAN_POINTER_START, params);
|
||||
|
||||
assertEquals(SCAN_POINTER_START, result.getStringCursor());
|
||||
assertEquals(SCAN_POINTER_START, result.getCursor());
|
||||
assertFalse(result.getResult().isEmpty());
|
||||
|
||||
// binary
|
||||
@@ -970,4 +1085,4 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
|
||||
|
||||
assertFalse(bResult.getResult().isEmpty());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@ import redis.clients.jedis.JedisPubSub;
|
||||
import redis.clients.jedis.tests.utils.FailoverAbortedException;
|
||||
|
||||
public class JedisSentinelTestUtil {
|
||||
public static HostAndPort waitForNewPromotedMaster(Jedis sentinelJedis)
|
||||
public static HostAndPort waitForNewPromotedMaster(final String masterName,
|
||||
final Jedis sentinelJedis, final Jedis commandJedis)
|
||||
throws InterruptedException {
|
||||
|
||||
final AtomicReference<String> newmaster = new AtomicReference<String>(
|
||||
@@ -47,6 +48,7 @@ public class JedisSentinelTestUtil {
|
||||
|
||||
@Override
|
||||
public void onPSubscribe(String pattern, int subscribedChannels) {
|
||||
commandJedis.sentinelFailover(masterName);
|
||||
}
|
||||
}, "*");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user