/**
   * Test compatability between version 4.1.0 and the current version.
   *
   * <p>A current server could read subscription data recorded by 4.1.0 server.
   */
  @Test(timeout = 60000)
  public void testSubscriptionDataCompat410() throws Exception {
    ByteString topic = ByteString.copyFromUtf8("TestCompat410");
    ByteString sub410 = ByteString.copyFromUtf8("sub410");
    ByteString subcur = ByteString.copyFromUtf8("subcur");

    // start bookkeeper 410
    BookKeeperCluster410 bkc410 = new BookKeeperCluster410(3);
    bkc410.start();

    int port = PortManager.nextFreePort();
    int sslPort = PortManager.nextFreePort();

    // start 410 server
    Server410 s410 = new Server410(zkUtil.getZooKeeperConnectString(), port, sslPort);
    s410.start();

    Client410 c410 = new Client410("localhost:" + port + ":" + sslPort);
    c410.subscribe(topic, sub410);
    c410.closeSubscription(topic, sub410);
    Thread.sleep(1000); // give server time to run disconnect logic (BOOKKEEPER-513)

    ClientCurrent ccur = new ClientCurrent("localhost:" + port + ":" + sslPort);
    ccur.subscribe(topic, subcur);
    ccur.closeSubscription(topic, subcur);

    // publish messages using old client
    c410.publishInts(topic, 0, 10);
    // stop 410 server
    s410.stop();

    // start 420 server
    Server420 s420 = new Server420(zkUtil.getZooKeeperConnectString(), port, sslPort);
    s420.start();

    c410.subscribe(topic, sub410);
    c410.receiveInts(topic, sub410, 0, 10);

    ccur.subscribe(topic, subcur);
    ccur.receiveInts(topic, subcur, 0, 10);

    // publish messages using current client
    ccur.publishInts(topic, 10, 10);

    c410.receiveInts(topic, sub410, 10, 10);
    ccur.receiveInts(topic, subcur, 10, 10);

    // stop 420 server
    s420.stop();

    c410.close();
    ccur.close();

    // stop bookkeeper cluster
    bkc410.stop();
  }
  /**
   * Test compatability between version 4.1.0 and the current version.
   *
   * <p>Server side throttling does't work when current client connects to old version server.
   */
  @Test(timeout = 60000)
  public void testServerSideThrottleCompat410() throws Exception {
    ByteString topic = ByteString.copyFromUtf8("TestServerSideThrottleCompat410");
    ByteString subid = ByteString.copyFromUtf8("mysub");

    // start bookkeeper
    BookKeeperCluster410 bkc410 = new BookKeeperCluster410(3);
    bkc410.start();

    int port = PortManager.nextFreePort();
    int sslPort = PortManager.nextFreePort();

    // start hub server 410
    Server410 s410 = new Server410(zkUtil.getZooKeeperConnectString(), port, sslPort);
    s410.start();

    ClientCurrent ccur = new ClientCurrent(false, "localhost:" + port + ":" + sslPort);
    ccur.throttleX41(topic, subid, 10);

    ccur.close();

    // stop 410 server
    s410.stop();
    // stop bookkeeper cluster
    bkc410.stop();
  }
  /**
   * Test compatability between version 4.1.0 and the current version.
   *
   * <p>A current client running message filter would fail on 4.1.0 hub servers.
   */
  @Test(timeout = 60000)
  public void testClientMessageFilterCompat410() throws Exception {
    ByteString topic = ByteString.copyFromUtf8("TestUpdateMessageBoundCompat410");
    ByteString subid = ByteString.copyFromUtf8("mysub");

    // start bookkeeper
    BookKeeperCluster410 bkc410 = new BookKeeperCluster410(3);
    bkc410.start();

    int port = PortManager.nextFreePort();
    int sslPort = PortManager.nextFreePort();

    // start hub server 410
    Server410 s410 = new Server410(zkUtil.getZooKeeperConnectString(), port, sslPort);
    s410.start();

    ClientCurrent ccur = new ClientCurrent("localhost:" + port + ":" + sslPort);
    ccur.subscribe(topic, subid);
    ccur.closeSubscription(topic, subid);

    ccur.publishInts(topic, 0, 100);
    try {
      ccur.receiveNumModM(topic, subid, 0, 50, 2);
      fail("client-side filter could not run on 4.1.0 hub server");
    } catch (Exception e) {
      logger.info("Should fail to run client-side message filter on 4.1.0 hub server.", e);
      ccur.closeSubscription(topic, subid);
    }

    // stop 410 server
    s410.stop();
    // stop bookkeeper cluster
    bkc410.stop();
  }
    public void stop() throws Exception {
      for (org.apache.hw_v4_0_0.bookkeeper.proto.BookieServer bs : bks) {
        bs.shutdown();
      }
      bks.clear();

      zkUtil.killServer();
    }
  /**
   * Test compatability of publish interface between version 4.1.0 and current verison.
   *
   * <p>1) 4.1.0 client could talk with current server. 2) current client could talk with 4.1.0
   * server, but no message seq id would be returned
   */
  @Test(timeout = 60000)
  public void testPublishCompat410() throws Exception {
    ByteString topic = ByteString.copyFromUtf8("TestPublishCompat410");
    ByteString data = ByteString.copyFromUtf8("testdata");

    // start bookkeeper 410
    BookKeeperCluster410 bkc410 = new BookKeeperCluster410(3);
    bkc410.start();

    int port = PortManager.nextFreePort();
    int sslPort = PortManager.nextFreePort();

    // start 410 server
    Server410 s410 = new Server410(zkUtil.getZooKeeperConnectString(), port, sslPort);
    s410.start();

    ClientCurrent ccur = new ClientCurrent("localhost:" + port + ":" + sslPort);
    Client410 c410 = new Client410("localhost:" + port + ":" + sslPort);

    // client c410 could publish message to 410 server
    assertNull(c410.publish(topic, data));
    // client ccur could publish message to 410 server
    // but no message seq id would be returned
    assertNull(ccur.publish(topic, data));

    // stop 410 server
    s410.stop();

    // start 420 server
    Server420 s420 = new Server420(zkUtil.getZooKeeperConnectString(), port, sslPort);
    s420.start();

    // client c410 could publish message to 410 server
    // but no message seq id would be returned
    assertNull(c410.publish(topic, data));
    // client ccur could publish message to current server
    assertNotNull(ccur.publish(topic, data));

    ccur.close();
    c410.close();

    // stop 420 server
    s420.stop();
    bkc410.stop();
  }
    public void start() throws Exception {
      zkUtil.startServer();

      bks = new LinkedList<org.apache.bookkeeper.proto.BookieServer>();
      bkConfs = new LinkedList<org.apache.bookkeeper.conf.ServerConfiguration>();

      for (int i = 0; i < numBookies; i++) {
        startBookieServer();
      }
    }
 protected void startBookieServer() throws Exception {
   int port = PortManager.nextFreePort();
   File tmpDir =
       org.apache.hw_v4_0_0.hedwig.util.FileUtils.createTempDirectory(
           getClass().getName() + port, "test");
   org.apache.hw_v4_0_0.bookkeeper.conf.ServerConfiguration conf =
       newServerConfiguration(
           port, zkUtil.getZooKeeperConnectString(), tmpDir, new File[] {tmpDir});
   bks.add(startBookie(conf));
   bkConfs.add(conf);
 }
    protected org.apache.bookkeeper.proto.BookieServer startBookie(
        org.apache.bookkeeper.conf.ServerConfiguration conf) throws Exception {
      org.apache.bookkeeper.proto.BookieServer server =
          new org.apache.bookkeeper.proto.BookieServer(conf);
      server.start();

      int port = conf.getBookiePort();
      while (zkUtil
              .getZooKeeperClient()
              .exists(
                  "/ledgers/available/" + InetAddress.getLocalHost().getHostAddress() + ":" + port,
                  false)
          == null) {
        Thread.sleep(500);
      }
      return server;
    }
  /**
   * Test compatability between version 4.1.0 and the current version.
   *
   * <p>A 4.1.0 client could not update message bound, while current could do it.
   */
  @Test(timeout = 60000)
  public void testUpdateMessageBoundCompat410() throws Exception {
    ByteString topic = ByteString.copyFromUtf8("TestUpdateMessageBoundCompat410");
    ByteString subid = ByteString.copyFromUtf8("mysub");

    // start bookkeeper
    BookKeeperCluster420 bkc420 = new BookKeeperCluster420(3);
    bkc420.start();

    int port = PortManager.nextFreePort();
    int sslPort = PortManager.nextFreePort();

    // start hub server
    Server420 s420 = new Server420(zkUtil.getZooKeeperConnectString(), port, sslPort);
    s420.start();

    org.apache.hedwig.protocol.PubSubProtocol.SubscriptionOptions options5cur =
        org.apache.hedwig.protocol.PubSubProtocol.SubscriptionOptions.newBuilder()
            .setCreateOrAttach(
                org.apache.hedwig.protocol.PubSubProtocol.SubscribeRequest.CreateOrAttach
                    .CREATE_OR_ATTACH)
            .setMessageBound(5)
            .build();
    org.apache.hw_v4_1_0.hedwig.protocol.PubSubProtocol.SubscriptionOptions options5v410 =
        org.apache.hw_v4_1_0.hedwig.protocol.PubSubProtocol.SubscriptionOptions.newBuilder()
            .setCreateOrAttach(
                org.apache.hw_v4_1_0.hedwig.protocol.PubSubProtocol.SubscribeRequest.CreateOrAttach
                    .CREATE_OR_ATTACH)
            .setMessageBound(5)
            .build();
    org.apache.hw_v4_1_0.hedwig.protocol.PubSubProtocol.SubscriptionOptions options20v410 =
        org.apache.hw_v4_1_0.hedwig.protocol.PubSubProtocol.SubscriptionOptions.newBuilder()
            .setCreateOrAttach(
                org.apache.hw_v4_1_0.hedwig.protocol.PubSubProtocol.SubscribeRequest.CreateOrAttach
                    .CREATE_OR_ATTACH)
            .setMessageBound(20)
            .build();

    Client410 c410 = new Client410("localhost:" + port + ":" + sslPort);
    c410.subscribe(topic, subid, options20v410);
    c410.closeSubscription(topic, subid);
    Thread.sleep(1000); // give server time to run disconnect logic (BOOKKEEPER-513)

    c410.sendXExpectLastY(topic, subid, 50, 20);

    c410.subscribe(topic, subid, options5v410);
    c410.closeSubscription(topic, subid);
    Thread.sleep(1000); // give server time to run disconnect logic (BOOKKEEPER-513)

    // the message bound isn't updated.
    c410.sendXExpectLastY(topic, subid, 50, 20);

    ClientCurrent ccur = new ClientCurrent("localhost:" + port + ":" + sslPort);
    ccur.subscribe(topic, subid, options5cur);
    ccur.closeSubscription(topic, subid);
    Thread.sleep(1000); // give server time to run disconnect logic (BOOKKEEPER-513)

    // the message bound should be updated.
    c410.sendXExpectLastY(topic, subid, 50, 5);

    // stop 420 server
    s420.stop();

    c410.close();
    ccur.close();

    // stop bookkeeper cluster
    bkc420.stop();
  }
  /**
   * Test compatability of message bound between version 4.0.0 and current version.
   *
   * <p>1) message bound doesn't take effects on 4.0.0 server. 2) message bound take effects on both
   * 4.1.0 and current server
   */
  @Test(timeout = 60000)
  public void testMessageBoundCompat() throws Exception {
    ByteString topic = ByteString.copyFromUtf8("testMessageBoundCompat");
    ByteString subid = ByteString.copyFromUtf8("mysub");

    int port = PortManager.nextFreePort();
    int sslPort = PortManager.nextFreePort();

    // start bookkeeper 400
    BookKeeperCluster400 bkc400 = new BookKeeperCluster400(3);
    bkc400.start();

    // start 400 server
    Server400 s400 = new Server400(zkUtil.getZooKeeperConnectString(), port, sslPort);
    s400.start();

    org.apache.hedwig.protocol.PubSubProtocol.SubscriptionOptions options5cur =
        org.apache.hedwig.protocol.PubSubProtocol.SubscriptionOptions.newBuilder()
            .setCreateOrAttach(
                org.apache.hedwig.protocol.PubSubProtocol.SubscribeRequest.CreateOrAttach
                    .CREATE_OR_ATTACH)
            .setMessageBound(5)
            .build();

    ClientCurrent ccur = new ClientCurrent("localhost:" + port + ":" + sslPort);
    ccur.subscribe(topic, subid, options5cur);
    ccur.closeSubscription(topic, subid);
    ccur.sendXExpectLastY(topic, subid, 50, 50);

    // stop 400 servers
    s400.stop();
    bkc400.stop();

    // start bookkeeper 410
    BookKeeperCluster410 bkc410 = new BookKeeperCluster410(3);
    bkc410.start();

    // start 410 server
    Server410 s410 = new Server410(zkUtil.getZooKeeperConnectString(), port, sslPort);
    s410.start();

    ccur.subscribe(topic, subid, options5cur);
    ccur.closeSubscription(topic, subid);
    ccur.sendXExpectLastY(topic, subid, 50, 5);

    // stop 410 servers
    s410.stop();
    bkc410.stop();

    // start bookkeeper current
    BookKeeperCluster420 bkc420 = new BookKeeperCluster420(3);
    bkc420.start();

    // start 420 server
    Server420 s420 = new Server420(zkUtil.getZooKeeperConnectString(), port, sslPort);
    s420.start();

    ccur.subscribe(topic, subid, options5cur);
    ccur.closeSubscription(topic, subid);
    ccur.sendXExpectLastY(topic, subid, 50, 5);

    // stop 420 server
    s420.stop();
    bkc420.stop();

    ccur.close();
  }