public LoginTests() {
    super("Login tests");

    this.addTest(createLogoutTest());
    this.addTest(
        createCRUDTest(
            APPLICATION_PERMISSION_TABLE_NAME, null, TablePermission.Application, false));
    this.addTest(createCRUDTest(USER_PERMISSION_TABLE_NAME, null, TablePermission.User, false));
    this.addTest(createCRUDTest(ADMIN_PERMISSION_TABLE_NAME, null, TablePermission.Admin, false));

    for (MobileServiceAuthenticationProvider provider :
        MobileServiceAuthenticationProvider.values()) {
      this.addTest(createLogoutTest());
      this.addTest(createLoginTest(provider));
      this.addTest(
          createCRUDTest(
              APPLICATION_PERMISSION_TABLE_NAME, provider, TablePermission.Application, true));
      this.addTest(
          createCRUDTest(USER_PERMISSION_TABLE_NAME, provider, TablePermission.User, true));
      this.addTest(
          createCRUDTest(ADMIN_PERMISSION_TABLE_NAME, provider, TablePermission.Admin, true));
    }
  }
  private TestCase createLoginTest(final MobileServiceAuthenticationProvider provider) {
    TestCase test =
        new TestCase() {

          @Override
          protected void executeTest(
              final MobileServiceClient client, final TestExecutionCallback callback) {
            final TestCase testCase = this;
            client.login(
                provider,
                new UserAuthenticationCallback() {

                  @Override
                  public void onCompleted(
                      MobileServiceUser user, Exception exception, ServiceFilterResponse response) {
                    TestResult result = new TestResult();
                    String userName;
                    if (user == null) {
                      userName = "******";
                    } else {
                      userName = user.getUserId();
                    }

                    log("Logged in as " + userName);
                    result.setStatus(
                        client.getCurrentUser() != null ? TestStatus.Passed : TestStatus.Failed);
                    result.setTestCase(testCase);

                    callback.onTestComplete(testCase, result);
                  }
                });
          }
        };

    test.setName("Login with " + provider.toString());
    return test;
  }
  private TestCase createCRUDTest(
      final String tableName,
      final MobileServiceAuthenticationProvider provider,
      final TablePermission tableType,
      final boolean userIsAuthenticated) {
    final TestCase test =
        new TestCase() {

          @Override
          protected void executeTest(
              MobileServiceClient client, final TestExecutionCallback callback) {

            final TestResult result = new TestResult();
            result.setStatus(TestStatus.Passed);
            result.setTestCase(this);
            final TestCase testCase = this;

            MobileServiceClient logClient = client.withFilter(new LogServiceFilter());

            final MobileServiceJsonTable table = logClient.getTable(tableName);
            final boolean crudShouldWork =
                tableType == TablePermission.Public
                    || tableType == TablePermission.Application
                    || (tableType == TablePermission.User && userIsAuthenticated);
            final JsonObject item = new JsonObject();
            item.addProperty("name", "John Doe");
            log("insert item");
            table.insert(
                item,
                new TableJsonOperationCallback() {

                  @Override
                  public void onCompleted(
                      JsonObject jsonEntity, Exception exception, ServiceFilterResponse response) {
                    int id = 1;
                    if (exception == null) {
                      id = jsonEntity.get("id").getAsInt();
                    }

                    item.addProperty("id", id);
                    if (!validateExecution(crudShouldWork, exception, result)) {
                      callback.onTestComplete(testCase, result);
                      return;
                    }

                    item.addProperty("name", "Jane Doe");
                    log("update item");
                    table.update(
                        item,
                        new TableJsonOperationCallback() {

                          @Override
                          public void onCompleted(
                              JsonObject jsonEntity,
                              Exception exception,
                              ServiceFilterResponse response) {

                            if (!validateExecution(crudShouldWork, exception, result)) {
                              callback.onTestComplete(testCase, result);
                              return;
                            }

                            log("lookup item");
                            table.lookUp(
                                item.get("id").getAsInt(),
                                new TableJsonOperationCallback() {

                                  @Override
                                  public void onCompleted(
                                      JsonObject jsonEntity,
                                      Exception exception,
                                      ServiceFilterResponse response) {
                                    if (!validateExecution(crudShouldWork, exception, result)) {
                                      callback.onTestComplete(testCase, result);
                                      return;
                                    }

                                    log("delete item");
                                    table.delete(
                                        item.get("id").getAsInt(),
                                        new TableDeleteCallback() {

                                          @Override
                                          public void onCompleted(
                                              Exception exception, ServiceFilterResponse response) {
                                            validateExecution(crudShouldWork, exception, result);

                                            callback.onTestComplete(testCase, result);
                                            return;
                                          }
                                        });
                                  }
                                });
                          }
                        });
                  }
                });
          }

          private boolean validateExecution(
              boolean crudShouldWork, Exception exception, TestResult result) {
            if (crudShouldWork && exception != null || !crudShouldWork && exception == null) {
              createResultFromException(result, exception);
              result.setStatus(TestStatus.Failed);
              return false;
            } else {
              return true;
            }
          }
        };

    String testKind;
    if (userIsAuthenticated) {
      testKind = "auth by " + provider.toString();
    } else {
      testKind = "unauthenticated";
    }

    String testName =
        String.format(
            Locale.getDefault(),
            "CRUD, %s, table with %s permissions",
            testKind,
            tableType.toString());
    test.setName(testName);

    return test;
  }