private static synchronized void retrieveTestAccountsForAppIfNeeded() {
    if (appTestAccounts != null) {
      return;
    }

    appTestAccounts = new HashMap<String, TestAccount>();

    // The data we need is split across two different FQL tables. We construct two queries, submit
    // them
    // together (the second one refers to the first one), then cross-reference the results.

    // Get the test accounts for this app.
    String testAccountQuery =
        String.format(
            "SELECT id,access_token FROM test_account WHERE app_id = %s", testApplicationId);
    // Get the user names for those accounts.
    String userQuery = "SELECT uid,name FROM user WHERE uid IN (SELECT id FROM #test_accounts)";

    Bundle parameters = new Bundle();

    // Build a JSON string that contains our queries and pass it as the 'q' parameter of the query.
    JSONObject multiquery;
    try {
      multiquery = new JSONObject();
      multiquery.put("test_accounts", testAccountQuery);
      multiquery.put("users", userQuery);
    } catch (JSONException exception) {
      throw new FacebookException(exception);
    }
    parameters.putString("q", multiquery.toString());

    // We need to authenticate as this app.
    parameters.putString("access_token", getAppAccessToken());

    Request request = new Request(null, "fql", parameters, null);
    Response response = request.executeAndWait();

    if (response.getError() != null) {
      throw response.getError().getException();
    }

    FqlResponse fqlResponse = response.getGraphObjectAs(FqlResponse.class);

    GraphObjectList<FqlResult> fqlResults = fqlResponse.getData();
    if (fqlResults == null || fqlResults.size() != 2) {
      throw new FacebookException("Unexpected number of results from FQL query");
    }

    // We get back two sets of results. The first is from the test_accounts query, the second from
    // the users query.
    Collection<TestAccount> testAccounts =
        fqlResults.get(0).getFqlResultSet().castToListOf(TestAccount.class);
    Collection<UserAccount> userAccounts =
        fqlResults.get(1).getFqlResultSet().castToListOf(UserAccount.class);

    // Use both sets of results to populate our static array of accounts.
    populateTestAccounts(testAccounts, userAccounts);

    return;
  }
  private TestAccount createTestAccountAndFinishAuth() {
    Bundle parameters = new Bundle();
    parameters.putString("installed", "true");
    parameters.putString("permissions", getPermissionsString());
    parameters.putString("access_token", getAppAccessToken());

    // If we're in shared mode, we want to rename this user to encode its permissions, so we can
    // find it later
    // in another shared session. If we're in private mode, don't bother renaming it since we're
    // just going to
    // delete it at the end of the session.
    if (mode == Mode.SHARED) {
      parameters.putString(
          "name", String.format("Shared %s Testuser", getSharedTestAccountIdentifier()));
    }

    String graphPath = String.format("%s/accounts/test-users", testApplicationId);
    Request createUserRequest = new Request(null, graphPath, parameters, HttpMethod.POST);
    Response response = createUserRequest.executeAndWait();

    FacebookRequestError error = response.getError();
    TestAccount testAccount = response.getGraphObjectAs(TestAccount.class);
    if (error != null) {
      finishAuthOrReauth(null, error.getException());
      return null;
    } else {
      assert testAccount != null;

      // If we are in shared mode, store this new account in the dictionary so we can re-use it
      // later.
      if (mode == Mode.SHARED) {
        // Remember the new name we gave it, since we didn't get it back in the results of the
        // create request.
        testAccount.setName(parameters.getString("name"));
        storeTestAccount(testAccount);
      }

      finishAuthWithTestAccount(testAccount);

      return testAccount;
    }
  }