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;
  }
  public Response call(DB db, DBCollection coll, OutMessage m, int retries) throws MongoException {

    final MyPort mp = _threadPort.get();
    final DBPort port = mp.get(false);

    port.checkAuth(db);

    Response res = null;
    try {
      res = port.call(m, coll);
      mp.done(port);
    } catch (IOException ioe) {
      mp.error(ioe);
      if (_error(ioe) && retries > 0) {
        return call(db, coll, m, retries - 1);
      }
      throw new MongoException.Network("can't call something", ioe);
    } catch (RuntimeException re) {
      mp.error(re);
      throw re;
    }

    ServerError err = res.getError();

    if (err != null && err.isNotMasterError()) {
      _pickCurrent();
      if (retries <= 0) {
        throw new MongoException("not talking to master and retries used up");
      }
      return call(db, coll, m, retries - 1);
    }

    return res;
  }
  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;
    }
  }
  private void deleteTestAccount(String testAccountId, String appAccessToken) {
    Bundle parameters = new Bundle();
    parameters.putString("access_token", appAccessToken);

    Request request = new Request(null, testAccountId, parameters, HttpMethod.DELETE);
    Response response = request.executeAndWait();

    FacebookRequestError error = response.getError();
    GraphObject graphObject = response.getGraphObject();
    if (error != null) {
      Log.w(
          LOG_TAG,
          String.format(
              "Could not delete test account %s: %s",
              testAccountId, error.getException().toString()));
    } else if (graphObject.getProperty(Response.NON_JSON_RESPONSE_PROPERTY) == (Boolean) false) {
      Log.w(
          LOG_TAG,
          String.format("Could not delete test account %s: unknown reason", testAccountId));
    }
  }