content: package redis.clients.jedis.tests;
  
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.List;
  
  import org.junit.Assert;
  import org.junit.Test;
  
  import redis.clients.jedis.HostAndPort;
  import redis.clients.jedis.Jedis;
  import redis.clients.jedis.JedisShardInfo;
  import redis.clients.jedis.Protocol;
  import redis.clients.jedis.ShardedJedis;
  import redis.clients.jedis.tests.utils.ClientKillerUtil;
  import redis.clients.util.Hashing;
  import redis.clients.util.Sharded;
  
  public class ShardedJedisTest extends Assert {
    private static HostAndPort redis1 = HostAndPortUtil.getRedisServers().get(0);
    private static HostAndPort redis2 = HostAndPortUtil.getRedisServers().get(1);
  
    /**
     * Test for "Issue - BinaryShardedJedis.disconnect() may occur memory leak". You can find more
     * detailed information at https://github.com/xetorthio/jedis/issues/808
     * @throws InterruptedException
     */
    @Test
    public void testAvoidLeaksUponDisconnect() throws InterruptedException {
      List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>(2);
      // 6379
      JedisShardInfo shard1 = new JedisShardInfo(redis1.getHost(), redis1.getPort());
      shard1.setPassword("foobared");
      shards.add(shard1);
      // 6380
      JedisShardInfo shard2 = new JedisShardInfo(redis2.getHost(), redis2.getPort());
      shard2.setPassword("foobared");
      shards.add(shard2);
  
      @SuppressWarnings("resource")
      ShardedJedis shardedJedis = new ShardedJedis(shards);
      // establish the connection for two redis servers
      shardedJedis.set("a", "bar");
      JedisShardInfo ak = shardedJedis.getShardInfo("a");
      assertEquals(shard2, ak);
      shardedJedis.set("b", "bar1");
      JedisShardInfo bk = shardedJedis.getShardInfo("b");
      assertEquals(shard1, bk);
  
      // We set a name to the instance so it's easy to find it
      Iterator<Jedis> it = shardedJedis.getAllShards().iterator();
      Jedis deadClient = it.next();
      deadClient.clientSetname("DEAD");
  
      ClientKillerUtil.killClient(deadClient, "DEAD");
  
      assertEquals(true, deadClient.isConnected());
      assertEquals(false, deadClient.getClient().getSocket().isClosed());
      assertEquals(false, deadClient.getClient().isBroken()); // normal - not found
  
      shardedJedis.disconnect();
  
      assertEquals(false, deadClient.isConnected());
      assertEquals(true, deadClient.getClient().getSocket().isClosed());
      assertEquals(true, deadClient.getClient().isBroken());
  
      Jedis jedis2 = it.next();
      assertEquals(false, jedis2.isConnected());
      assertEquals(true, jedis2.getClient().getSocket().isClosed());
      assertEquals(false, jedis2.getClient().isBroken());
  
    }
  
    private List<String> getKeysDifferentShard(ShardedJedis jedis) {
      List<String> ret = new ArrayList<String>();
      JedisShardInfo first = jedis.getShardInfo("a0");
      ret.add("a0");
      for (int i = 1; i < 100; ++i) {
        JedisShardInfo actual = jedis.getShardInfo("a" + i);
        if (actual != first) {
          ret.add("a" + i);
          break;
  
        }
  
      }
      return ret;
    }
  
    @Test
    public void checkSharding() {
      List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
      shards.add(new JedisShardInfo(redis1.getHost(), redis1.getPort()));
      shards.add(new JedisShardInfo(redis2.getHost(), redis2.getPort()));
      ShardedJedis jedis = new ShardedJedis(shards);
      List<String> keys = getKeysDifferentShard(jedis);
      JedisShardInfo s1 = jedis.getShardInfo(keys.get(0));
      JedisShardInfo s2 = jedis.getShardInfo(keys.get(1));
      assertNotSame(s1, s2);
    }
  
    @Test
    public void trySharding() {
      List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
      JedisShardInfo si = new JedisShardInfo(redis1.getHost(), redis1.getPort());
      si.setPassword("foobared");
      shards.add(si);
      si = new JedisShardInfo(redis2.getHost(), redis2.getPort());
      si.setPassword("foobared");
      shards.add(si);
      ShardedJedis jedis = new ShardedJedis(shards);
      jedis.set("a", "bar");
      JedisShardInfo s1 = jedis.getShardInfo("a");
      jedis.set("b", "bar1");
      JedisShardInfo s2 = jedis.getShardInfo("b");
      jedis.disconnect();
  
      Jedis j = new Jedis(s1.getHost(), s1.getPort());
      j.auth("foobared");
      assertEquals("bar", j.get("a"));
      j.disconnect();
  
      j = new Jedis(s2.getHost(), s2.getPort());
      j.auth("foobared");
      assertEquals("bar1", j.get("b"));
      j.disconnect();
    }
  
    @Test
    public void tryShardingWithMurmure() {
      List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
      JedisShardInfo si = new JedisShardInfo(redis1.getHost(), redis1.getPort());
      si.setPassword("foobared");
      shards.add(si);
      si = new JedisShardInfo(redis2.getHost(), redis2.getPort());
      si.setPassword("foobared");
      shards.add(si);
      ShardedJedis jedis = new ShardedJedis(shards, Hashing.MURMUR_HASH);
      jedis.set("a", "bar");
      JedisShardInfo s1 = jedis.getShardInfo("a");
      jedis.set("b", "bar1");
      JedisShardInfo s2 = jedis.getShardInfo("b");
      jedis.disconnect();
  
      Jedis j = new Jedis(s1.getHost(), s1.getPort());
      j.auth("foobared");
      assertEquals("bar", j.get("a"));
      j.disconnect();
  
      j = new Jedis(s2.getHost(), s2.getPort());
      j.auth("foobared");
      assertEquals("bar1", j.get("b"));
      j.disconnect();
    }
  
    @Test
    public void checkKeyTags() {
      List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
      shards.add(new JedisShardInfo(redis1.getHost(), redis1.getPort()));
      shards.add(new JedisShardInfo(redis2.getHost(), redis2.getPort()));
      ShardedJedis jedis = new ShardedJedis(shards, ShardedJedis.DEFAULT_KEY_TAG_PATTERN);
  
      assertEquals(jedis.getKeyTag("foo"), "foo");
      assertEquals(jedis.getKeyTag("foo{bar}"), "bar");
      assertEquals(jedis.getKeyTag("foo{bar}}"), "bar"); // default pattern is
      // non greedy
      assertEquals(jedis.getKeyTag("{bar}foo"), "bar"); // Key tag may appear
      // anywhere
      assertEquals(jedis.getKeyTag("f{bar}oo"), "bar"); // Key tag may appear
      // anywhere
  
      JedisShardInfo s1 = jedis.getShardInfo("abc{bar}");
      JedisShardInfo s2 = jedis.getShardInfo("foo{bar}");
      assertSame(s1, s2);
  
      List<String> keys = getKeysDifferentShard(jedis);
      JedisShardInfo s3 = jedis.getShardInfo(keys.get(0));
      JedisShardInfo s4 = jedis.getShardInfo(keys.get(1));
      assertNotSame(s3, s4);
  
      ShardedJedis jedis2 = new ShardedJedis(shards);
  
      assertEquals(jedis2.getKeyTag("foo"), "foo");
      assertNotSame(jedis2.getKeyTag("foo{bar}"), "bar");
  
      JedisShardInfo s5 = jedis2.getShardInfo(keys.get(0) + "{bar}");
      JedisShardInfo s6 = jedis2.getShardInfo(keys.get(1) + "{bar}");
      assertNotSame(s5, s6);
    }
  
    @Test
    public void testMD5Sharding() {
      List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>(3);
      shards.add(new JedisShardInfo("localhost", Protocol.DEFAULT_PORT));
      shards.add(new JedisShardInfo("localhost", Protocol.DEFAULT_PORT + 1));
      shards.add(new JedisShardInfo("localhost", Protocol.DEFAULT_PORT + 2));
      Sharded<Jedis, JedisShardInfo> sharded = new Sharded<Jedis, JedisShardInfo>(shards, Hashing.MD5);
      int shard_6379 = 0;
      int shard_6380 = 0;
      int shard_6381 = 0;
      for (int i = 0; i < 1000; i++) {
        JedisShardInfo jedisShardInfo = sharded.getShardInfo(Integer.toString(i));
        switch (jedisShardInfo.getPort()) {
        case 6379:
          shard_6379++;
          break;
        case 6380:
          shard_6380++;
          break;
        case 6381:
          shard_6381++;
          break;
        default:
          fail("Attempting to use a non-defined shard!!:" + jedisShardInfo);
          break;
        }
      }
      assertTrue(shard_6379 > 300 && shard_6379 < 400);
      assertTrue(shard_6380 > 300 && shard_6380 < 400);
      assertTrue(shard_6381 > 300 && shard_6381 < 400);
    }
  
    @Test
    public void testMurmurSharding() {
      List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>(3);
      shards.add(new JedisShardInfo("localhost", Protocol.DEFAULT_PORT));
      shards.add(new JedisShardInfo("localhost", Protocol.DEFAULT_PORT + 1));
      shards.add(new JedisShardInfo("localhost", Protocol.DEFAULT_PORT + 2));
      Sharded<Jedis, JedisShardInfo> sharded = new Sharded<Jedis, JedisShardInfo>(shards,
          Hashing.MURMUR_HASH);
      int shard_6379 = 0;
      int shard_6380 = 0;
      int shard_6381 = 0;
      for (int i = 0; i < 1000; i++) {
        JedisShardInfo jedisShardInfo = sharded.getShardInfo(Integer.toString(i));
        switch (jedisShardInfo.getPort()) {
        case 6379:
          shard_6379++;
          break;
        case 6380:
          shard_6380++;
          break;
        case 6381:
          shard_6381++;
          break;
        default:
          fail("Attempting to use a non-defined shard!!:" + jedisShardInfo);
          break;
        }
      }
      assertTrue(shard_6379 > 300 && shard_6379 < 400);
      assertTrue(shard_6380 > 300 && shard_6380 < 400);
      assertTrue(shard_6381 > 300 && shard_6381 < 400);
    }
  
    @Test
    public void testMasterSlaveShardingConsistency() {
      List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>(3);
      shards.add(new JedisShardInfo("localhost", Protocol.DEFAULT_PORT));
      shards.add(new JedisShardInfo("localhost", Protocol.DEFAULT_PORT + 1));
      shards.add(new JedisShardInfo("localhost", Protocol.DEFAULT_PORT + 2));
      Sharded<Jedis, JedisShardInfo> sharded = new Sharded<Jedis, JedisShardInfo>(shards,
          Hashing.MURMUR_HASH);
  
      List<JedisShardInfo> otherShards = new ArrayList<JedisShardInfo>(3);
      otherShards.add(new JedisShardInfo("otherhost", Protocol.DEFAULT_PORT));
      otherShards.add(new JedisShardInfo("otherhost", Protocol.DEFAULT_PORT + 1));
      otherShards.add(new JedisShardInfo("otherhost", Protocol.DEFAULT_PORT + 2));
      Sharded<Jedis, JedisShardInfo> sharded2 = new Sharded<Jedis, JedisShardInfo>(otherShards,
          Hashing.MURMUR_HASH);
  
      for (int i = 0; i < 1000; i++) {
        JedisShardInfo jedisShardInfo = sharded.getShardInfo(Integer.toString(i));
        JedisShardInfo jedisShardInfo2 = sharded2.getShardInfo(Integer.toString(i));
        assertEquals(shards.indexOf(jedisShardInfo), otherShards.indexOf(jedisShardInfo2));
      }
  
    }
  
    @Test
    public void testMasterSlaveShardingConsistencyWithShardNaming() {
      List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>(3);
      shards.add(new JedisShardInfo("localhost", Protocol.DEFAULT_PORT, "HOST1:1234"));
      shards.add(new JedisShardInfo("localhost", Protocol.DEFAULT_PORT + 1, "HOST2:1234"));
      shards.add(new JedisShardInfo("localhost", Protocol.DEFAULT_PORT + 2, "HOST3:1234"));
      Sharded<Jedis, JedisShardInfo> sharded = new Sharded<Jedis, JedisShardInfo>(shards,
          Hashing.MURMUR_HASH);
  
      List<JedisShardInfo> otherShards = new ArrayList<JedisShardInfo>(3);
      otherShards.add(new JedisShardInfo("otherhost", Protocol.DEFAULT_PORT, "HOST2:1234"));
      otherShards.add(new JedisShardInfo("otherhost", Protocol.DEFAULT_PORT + 1, "HOST3:1234"));
      otherShards.add(new JedisShardInfo("otherhost", Protocol.DEFAULT_PORT + 2, "HOST1:1234"));
      Sharded<Jedis, JedisShardInfo> sharded2 = new Sharded<Jedis, JedisShardInfo>(otherShards,
          Hashing.MURMUR_HASH);
  
      for (int i = 0; i < 1000; i++) {
        JedisShardInfo jedisShardInfo = sharded.getShardInfo(Integer.toString(i));
        JedisShardInfo jedisShardInfo2 = sharded2.getShardInfo(Integer.toString(i));
        assertEquals(jedisShardInfo.getName(), jedisShardInfo2.getName());
      }
    }
  
    @Test
    public void checkCloseable() {
      List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
      shards.add(new JedisShardInfo(redis1.getHost(), redis1.getPort()));
      shards.add(new JedisShardInfo(redis2.getHost(), redis2.getPort()));
      shards.get(0).setPassword("foobared");
      shards.get(1).setPassword("foobared");
  
      ShardedJedis jedisShard = new ShardedJedis(shards);
      try {
        jedisShard.set("shard_closeable", "true");
      } finally {
        jedisShard.close();
      }
  
      for (Jedis jedis : jedisShard.getAllShards()) {
        assertTrue(!jedis.isConnected());
      }
    }
  
  }