@Override
  protected void setUp() throws Exception {
    syncano = new Syncano(mContext, Constants.INSTANCE_NAME, Constants.API_KEY);
    assertTrue(
        "Device should be connected to internet before test",
        DownloadTool.connectionAvailable(mContext));

    // Create test project
    ParamsProjectNew paramsProjectNew = new ParamsProjectNew("CI Test Project");
    ResponseProjectNew responseProjectNew = syncano.projectNew(paramsProjectNew);
    assertEquals(
        "Failed to create test project",
        Response.CODE_SUCCESS,
        (int) responseProjectNew.getResultCode());
    projectId = responseProjectNew.getProject().getId();

    // Create test collection
    ParamsCollectionNew paramsCollectionNew =
        new ParamsCollectionNew(projectId, "CI Test Collection");
    ResponseCollectionNew responseCollectionNew = syncano.collectionNew(paramsCollectionNew);
    assertEquals(
        "Failed to create test collection",
        Response.CODE_SUCCESS,
        (int) responseCollectionNew.getResultCode());
    collectionId = responseCollectionNew.getCollection().getId();

    lock = new CountDownLatch(1);
    conn =
        new SyncServerConnection(
            mContext,
            Constants.INSTANCE_NAME,
            Constants.API_KEY,
            new SyncServerListener() {
              @Override
              public void onMessage(String object, JsonObject message) {
                Log.d(TAG, "message " + object + " " + message);
              }

              @Override
              public void onError(String why) {
                Log.d(TAG, "error: " + why);
              }

              @Override
              public void onDisconnected() {
                Log.d(TAG, "disconnected");
                lock.countDown();
              }

              @Override
              public void onConnected() {
                Log.d(TAG, "connected");
                lock.countDown();
              }
            });

    conn.start();
    lock.await(WAITING_MILLIS, TimeUnit.MILLISECONDS);
    assertTrue(conn.isConnected());
  }
  public void testNotifications() throws Exception {
    notificationLock = new CountDownLatch(1);
    success = false;
    conn.setSyncServerListener(
        new SyncServerListenerImpl() {
          @Override
          public void onMessage(String object, JsonObject message) {
            assertNotNull(object);
            assertNotNull(message);
            assertEquals(NOTIFICATION_TEXT, message.get(PARAM_NOTIFICATION_TEXT).getAsString());
            success = true;
            notificationLock.countDown();
          }
        });

    ParamsNotificationSend paramsNotificationSend = new ParamsNotificationSend(null);
    paramsNotificationSend.addParam(PARAM_NOTIFICATION_TEXT, NOTIFICATION_TEXT);

    lock = new CountDownLatch(1);
    response = null;
    conn.call(
        paramsNotificationSend,
        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 notification success
    notificationLock.await(WAITING_MILLIS, TimeUnit.MILLISECONDS);
    assertTrue(success);
  }
  @Override
  protected void tearDown() throws Exception {

    conn.stop();

    // Clean test collection (called before project is deleted)
    ParamsCollectionDelete paramsCollectionDelete =
        new ParamsCollectionDelete(projectId, collectionId);
    Response responseCollectionDelete = syncano.collectionDelete(paramsCollectionDelete);
    assertEquals(
        "Failed to clean test collection",
        Response.CODE_SUCCESS,
        (int) responseCollectionDelete.getResultCode());

    // Clean test project
    ParamsProjectDelete paramsProjectDelete = new ParamsProjectDelete(projectId);
    Response responseProjectDelete = syncano.projectDelete(paramsProjectDelete);
    assertEquals(
        "Failed to clean test project",
        Response.CODE_SUCCESS,
        (int) responseProjectDelete.getResultCode());
  }
  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);
  }