private static void testSendGetSGRequests(ScatterGatherBuilder<Greeting> sg, Long[] requestIds)
      throws ServiceUnavailableException, InterruptedException {
    Collection<ScatterGatherBuilder.RequestInfo<Greeting>> scatterGatherRequests =
        buildScatterGatherGetRequests(sg, requestIds);

    final Map<String, Greeting> results = new ConcurrentHashMap<String, Greeting>();
    final CountDownLatch latch = new CountDownLatch(scatterGatherRequests.size());
    final List<Throwable> errors = new ArrayList<Throwable>();

    final List<BatchResponse<Greeting>> responses = new ArrayList<BatchResponse<Greeting>>();
    for (ScatterGatherBuilder.RequestInfo<Greeting> requestInfo : scatterGatherRequests) {
      Callback<Response<BatchResponse<Greeting>>> cb =
          new Callback<Response<BatchResponse<Greeting>>>() {
            @Override
            public void onSuccess(Response<BatchResponse<Greeting>> response) {
              results.putAll(response.getEntity().getResults());
              synchronized (responses) {
                responses.add(response.getEntity());
              }
              latch.countDown();
            }

            @Override
            public void onError(Throwable e) {
              synchronized (errors) {
                errors.add(e);
              }
              latch.countDown();
            }
          };

      REST_CLIENT.sendRequest(requestInfo.getRequest(), requestInfo.getRequestContext(), cb);
    }
    latch.await();

    if (!errors.isEmpty()) {
      Assert.fail("Errors in scatter/gather: " + errors.toString());
    }

    Assert.assertEquals(results.values().size(), requestIds.length);

    Set<Set<String>> responseIdSets = new HashSet<Set<String>>();
    Set<Long> responseIds = new HashSet<Long>();
    for (BatchResponse<Greeting> response : responses) {
      Set<String> theseIds = response.getResults().keySet();
      Assert.assertFalse(responseIdSets.contains(theseIds)); // no duplicate requests
      for (String id : theseIds) {
        Assert.assertFalse(responseIds.contains(Long.parseLong(id))); // no duplicate ids
        responseIds.add(Long.parseLong(id));
      }
      responseIdSets.add(theseIds);
    }
    Assert.assertTrue(responseIds.containsAll(Arrays.asList(requestIds)));
    Assert.assertEquals(responseIds.size(), requestIds.length);
  }
  private static void testBuildSGGetRequests(
      int numEndpoints, ScatterGatherBuilder<Greeting> sg, Long[] ids)
      throws ServiceUnavailableException {
    Collection<ScatterGatherBuilder.RequestInfo<Greeting>> requests =
        buildScatterGatherGetRequests(sg, ids);
    Assert.assertEquals(requests.size(), numEndpoints);

    Set<Set<String>> requestIdSets = new HashSet<Set<String>>();
    Set<Long> requestIds = new HashSet<Long>();
    for (ScatterGatherBuilder.RequestInfo<Greeting> requestInfo : requests) {
      // URI will be something like
      // "greetings/?ids=21&ids=4&ids=53&ids=60&ids=66&ids=88&ids=93&foo=bar"
      BatchRequest<BatchResponse<Greeting>> request = requestInfo.getBatchRequest();
      Set<String> expectedParams = new HashSet<String>();
      expectedParams.add(RestConstants.QUERY_BATCH_IDS_PARAM);
      expectedParams.add("foo");
      expectedParams.add(RestConstants.FIELDS_PARAM);
      Set<String> expectedFields = Collections.singleton("message");

      testRequest(request, expectedParams, expectedFields, null, requestIdSets, requestIds);
    }
    Assert.assertTrue(requestIds.containsAll(Arrays.asList(ids)));
    Assert.assertEquals(requestIds.size(), ids.length);
  }