public void testSubscription() throws Exception {
    // Subscribe
    ParamsSubscriptionSubscribeCollection paramsSubscriptionSubscribeCollection =
        new ParamsSubscriptionSubscribeCollection(projectId, collectionId);
    lock = new CountDownLatch(1);
    response = null;
    conn.call(
        paramsSubscriptionSubscribeCollection,
        new SyncServerCallback() {
          @Override
          public void result(Response response) {
            SyncServerTest.this.response = response;
            lock.countDown();
          }
        });
    lock.await(WAITING_MILLIS, TimeUnit.MILLISECONDS);
    assertNotNull(response);
    assertEquals(Response.CODE_SUCCESS, (int) response.getResultCode());

    // Data New
    subscriptionLock = new CountDownLatch(1);
    success = false;
    conn.setSubscriptionListener(
        new SubscriptionListenerImpl() {
          @Override
          public void onAdded(Data data, Channel channel) {
            assertNotNull(data);
            assertEquals(DATA_TEXT, data.getText());
            success = true;
            subscriptionLock.countDown();
          }
        });

    ParamsDataNew paramsDataNew = new ParamsDataNew(projectId, collectionId, null, Data.PENDING);
    paramsDataNew.setText(DATA_TEXT);
    lock = new CountDownLatch(1);
    response = null;
    conn.call(
        paramsDataNew,
        new SyncServerCallback() {
          @Override
          public void result(Response response) {
            SyncServerTest.this.response = response;
            lock.countDown();
          }
        });
    lock.await(WAITING_MILLIS, TimeUnit.MILLISECONDS);
    assertNotNull(response);
    assertEquals(Response.CODE_SUCCESS, (int) response.getResultCode());
    String dataId = ((ResponseDataNew) response).getData().getId();

    // Check for subscription success
    subscriptionLock.await(WAITING_MILLIS, TimeUnit.MILLISECONDS);
    assertTrue(success);

    // Data Update
    subscriptionLock = new CountDownLatch(1);
    success = false;
    conn.setSubscriptionListener(
        new SubscriptionListenerImpl() {
          @Override
          public void onChanged(ArrayList<DataChanges> changes, Channel channel) {
            assertNotNull(changes);
            success = true;
            subscriptionLock.countDown();
          }
        });

    ParamsDataUpdate paramsDataUpdate =
        new ParamsDataUpdate(projectId, collectionId, null, dataId, null);
    paramsDataUpdate.setText(UPDATED_TEXT);
    lock = new CountDownLatch(1);
    response = null;
    conn.call(
        paramsDataUpdate,
        new SyncServerCallback() {
          @Override
          public void result(Response response) {
            SyncServerTest.this.response = response;
            lock.countDown();
          }
        });
    lock.await(WAITING_MILLIS, TimeUnit.MILLISECONDS);
    assertNotNull(response);
    assertEquals(Response.CODE_SUCCESS, (int) response.getResultCode());

    // Check for subscription success
    subscriptionLock.await(WAITING_MILLIS, TimeUnit.MILLISECONDS);
    assertTrue(success);

    // Data Delete
    subscriptionLock = new CountDownLatch(1);
    success = false;
    conn.setSubscriptionListener(
        new SubscriptionListenerImpl() {
          @Override
          public void onDeleted(String[] ids, Channel channel) {
            assertNotNull(ids);
            assertTrue(ids.length > 0);
            success = true;
            ;
            subscriptionLock.countDown();
          }
        });

    ParamsDataDelete paramsDataDelete = new ParamsDataDelete(projectId, collectionId, null);
    paramsDataDelete.setDataIds(new String[] {dataId});
    lock = new CountDownLatch(1);
    response = null;
    conn.call(
        paramsDataDelete,
        new SyncServerCallback() {
          @Override
          public void result(Response response) {
            SyncServerTest.this.response = response;
            lock.countDown();
          }
        });
    lock.await(WAITING_MILLIS, TimeUnit.MILLISECONDS);
    assertNotNull(response);
    assertEquals(Response.CODE_SUCCESS, (int) response.getResultCode());

    // Check for subscription success
    subscriptionLock.await(WAITING_MILLIS, TimeUnit.MILLISECONDS);
    assertTrue(success);
  }