@Test(
      dataProvider =
          com.linkedin.restli.internal.common.TestConstants.RESTLI_PROTOCOL_1_2_PREFIX
              + "clientDataDataProvider")
  public void testUpdate(RestClient restClient, RootBuilderWrapper<Long, Greeting> builders)
      throws RemoteInvocationException, CloneNotSupportedException {
    // GET
    Request<Greeting> request = builders.get().id(1L).build();
    Response<Greeting> greetingResponse1 = restClient.sendRequest(request).getResponse();

    String response1 = greetingResponse1.getEntity().getMessage();
    Assert.assertNotNull(response1);

    // POST
    Greeting greeting = new Greeting(greetingResponse1.getEntity().data().copy());
    greeting.setMessage(response1 + "Again");

    Request<EmptyRecord> writeRequest = builders.update().id(1L).input(greeting).build();
    Response<EmptyRecord> updateResponse = restClient.sendRequest(writeRequest).getResponse();
    Assert.assertNull(updateResponse.getHeader(RestConstants.HEADER_CONTENT_TYPE));

    // GET again, to verify that our POST worked.
    Request<Greeting> request2 = builders.get().id(1L).build();
    Response<Greeting> greetingResponse2 = restClient.sendRequest(request2).getResponse();

    String response2 = greetingResponse2.getEntity().getMessage();
    Assert.assertEquals(response2, response1 + "Again");
  }
  @Test(
      dataProvider =
          com.linkedin.restli.internal.common.TestConstants.RESTLI_PROTOCOL_1_2_PREFIX
              + "buildersClientDataDataProvider")
  public void testCreateId(RestClient restClient, RestliRequestOptions requestOptions)
      throws RemoteInvocationException {
    Greeting greeting = new Greeting();
    greeting.setMessage("Hello there!");
    greeting.setTone(Tone.FRIENDLY);

    final GreetingsRequestBuilders builders = new GreetingsRequestBuilders(requestOptions);

    CreateIdRequest<Long, Greeting> createRequest = builders.create().input(greeting).build();
    Response<IdResponse<Long>> response = restClient.sendRequest(createRequest).getResponse();
    Assert.assertNull(response.getHeader(RestConstants.HEADER_CONTENT_TYPE));
    @SuppressWarnings("unchecked")
    long id = response.getEntity().getId();
    @SuppressWarnings("deprecation")
    String stringId = response.getId();
    Assert.assertEquals(id, Long.parseLong(stringId));

    Request<Greeting> getRequest = builders.get().id(id).build();
    Response<Greeting> getResponse = restClient.sendRequest(getRequest).getResponse();
    Greeting responseGreeting = getResponse.getEntity();

    Assert.assertEquals(responseGreeting.getMessage(), greeting.getMessage());
    Assert.assertEquals(responseGreeting.getTone(), greeting.getTone());
  }
  private static void testSendSGKVRequests(
      Collection<ScatterGatherBuilder.KVRequestInfo<Long, UpdateStatus>> scatterGatherRequests,
      Long[] requestIds)
      throws InterruptedException {
    final Map<Long, UpdateStatus> results = new ConcurrentHashMap<Long, UpdateStatus>();
    final CountDownLatch latch = new CountDownLatch(scatterGatherRequests.size());
    final List<Throwable> errors = new ArrayList<Throwable>();

    final List<BatchKVResponse<Long, UpdateStatus>> responses =
        new ArrayList<BatchKVResponse<Long, UpdateStatus>>();
    for (ScatterGatherBuilder.KVRequestInfo<Long, UpdateStatus> requestInfo :
        scatterGatherRequests) {
      Callback<Response<BatchKVResponse<Long, UpdateStatus>>> cb =
          new Callback<Response<BatchKVResponse<Long, UpdateStatus>>>() {
            @Override
            public void onSuccess(Response<BatchKVResponse<Long, UpdateStatus>> 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();
            }
          };

      BatchRequest<BatchKVResponse<Long, UpdateStatus>> request = requestInfo.getRequest();
      RequestContext requestContext = requestInfo.getRequestContext();
      REST_CLIENT.sendRequest(request, requestContext, cb);
    }
    latch.await();

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

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

    Set<Set<Long>> responseIdSets = new HashSet<Set<Long>>();
    Set<Long> responseIds = new HashSet<Long>();
    for (BatchKVResponse<Long, UpdateStatus> response : responses) {
      Set<Long> theseIds = response.getResults().keySet();
      Assert.assertFalse(responseIdSets.contains(theseIds)); // no duplicate requests
      for (Long id : theseIds) {
        Assert.assertFalse(responseIds.contains(id)); // no duplicate ids
        responseIds.add(id);
      }
      responseIdSets.add(theseIds);
    }
    Assert.assertTrue(responseIds.containsAll(Arrays.asList(requestIds)));
    Assert.assertEquals(responseIds.size(), requestIds.length);
  }
 @Test(
     dataProvider =
         com.linkedin.restli.internal.common.TestConstants.RESTLI_PROTOCOL_1_2_PREFIX
             + "clientDataDataProvider")
 public void testGet(RestClient restClient, RootBuilderWrapper<Long, Greeting> builders)
     throws RemoteInvocationException {
   Request<Greeting> request = builders.get().id(1L).build();
   Response<Greeting> response = restClient.sendRequest(request).getResponse();
   Greeting greeting = response.getEntity();
   Assert.assertEquals(greeting.getId(), new Long(1));
 }
  @Test(
      dataProvider =
          com.linkedin.restli.internal.common.TestConstants.RESTLI_PROTOCOL_1_2_PREFIX
              + "requestBuilderDataProvider")
  public void testPostsWithCharset(RootBuilderWrapper<Long, Greeting> builders)
      throws RemoteInvocationException {
    RestClient restClient = new RestClient(CLIENT, URI_PREFIX);

    Request<Greeting> request =
        builders
            .<Greeting>action("SomeAction")
            .id(1L)
            .setActionParam("A", 1)
            .setActionParam("B", "")
            .setActionParam("C", new TransferOwnershipRequest())
            .setActionParam("D", new TransferOwnershipRequest())
            .setActionParam("E", 3)
            .setHeader("Content-Type", "application/json; charset=UTF-8")
            .build();

    Response<Greeting> response = restClient.sendRequest(request).getResponse();

    Greeting actionGreeting = response.getEntity();
    Assert.assertEquals(actionGreeting.getMessage(), "This is a newly created greeting");

    Greeting createGreeting = new Greeting();
    createGreeting.setMessage("Hello there!");
    createGreeting.setTone(Tone.FRIENDLY);

    Request<EmptyRecord> createRequest =
        builders
            .create()
            .input(createGreeting)
            .setHeader("Content-Type", "application/json; charset=UTF-8")
            .build();
    Response<EmptyRecord> emptyRecordResponse = restClient.sendRequest(createRequest).getResponse();
    Assert.assertNull(emptyRecordResponse.getHeader(RestConstants.HEADER_CONTENT_TYPE));
  }
 private static Long[] prepareData(List<Greeting> entities, RestliRequestOptions requestOptions)
     throws RemoteInvocationException {
   GreetingsRequestBuilders builders = new GreetingsRequestBuilders(requestOptions);
   BatchCreateIdRequest<Long, Greeting> request = builders.batchCreate().inputs(entities).build();
   Response<BatchCreateIdResponse<Long>> response = REST_CLIENT.sendRequest(request).getResponse();
   List<CreateIdStatus<Long>> statuses = response.getEntity().getElements();
   final Long[] requestIds = new Long[entities.size()];
   for (int i = 0; i < statuses.size(); ++i) {
     CreateIdStatus<Long> status = statuses.get(i);
     Assert.assertFalse(status.hasError());
     requestIds[i] = status.getKey();
   }
   return requestIds;
 }
  @Test(
      dataProvider =
          com.linkedin.restli.internal.common.TestConstants.RESTLI_PROTOCOL_1_2_PREFIX
              + "clientDataBatchDataProvider")
  public void testBatchGet(RestClient restClient, RestliRequestOptions requestOptions)
      throws RemoteInvocationException {
    List<Long> ids = Arrays.asList(1L, 2L, 3L, 4L);
    Request<BatchResponse<Greeting>> request =
        new GreetingsBuilders(requestOptions).batchGet().ids(ids).build();

    Response<BatchResponse<Greeting>> response = restClient.sendRequest(request).getResponse();
    BatchResponse<Greeting> batchResponse = response.getEntity();
    Assert.assertEquals(batchResponse.getResults().size(), ids.size());
  }
  @Test(
      dataProvider =
          com.linkedin.restli.internal.common.TestConstants.RESTLI_PROTOCOL_1_2_PREFIX
              + "clientDataDataProvider")
  public void testFinder(RestClient restClient, RootBuilderWrapper<Long, Greeting> builders)
      throws RemoteInvocationException {
    Request<CollectionResponse<Greeting>> request =
        builders.findBy("Search").setQueryParam("tone", Tone.SINCERE).paginate(1, 2).build();

    Response<CollectionResponse<Greeting>> response = restClient.sendRequest(request).getResponse();

    CollectionResponse<Greeting> collectionResponse = response.getEntity();
    List<Greeting> greetings = collectionResponse.getElements();

    for (Greeting g : greetings) {
      Assert.assertEquals(g.getTone(), Tone.SINCERE);
    }
    collectionResponse.getPaging().getLinks();
  }
  @Test(
      dataProvider =
          com.linkedin.restli.internal.common.TestConstants.RESTLI_PROTOCOL_1_2_PREFIX
              + "clientDataDataProvider")
  public void testAction(RestClient restClient, RootBuilderWrapper<Long, Greeting> builders)
      throws RemoteInvocationException {
    Request<Greeting> request =
        builders
            .<Greeting>action("SomeAction")
            .id(1L)
            .setActionParam("A", 1)
            .setActionParam("B", "")
            .setActionParam("C", new TransferOwnershipRequest())
            .setActionParam("D", new TransferOwnershipRequest())
            .setActionParam("E", 3)
            .build();

    Response<Greeting> response = restClient.sendRequest(request).getResponse();

    Greeting greeting = response.getEntity();
    Assert.assertEquals(greeting.getMessage(), "This is a newly created greeting");
  }
  @SuppressWarnings({"unchecked", "rawtypes"})
  private <T extends Request> RestRequest clientGeneratedRequest(
      Class<T> requestClass,
      ResourceMethod method,
      DataMap entityBody,
      RestClient.ContentType contentType,
      List<RestClient.AcceptType> acceptTypes)
      throws URISyntaxException {
    // massive setup...
    Client mockClient = EasyMock.createMock(Client.class);

    @SuppressWarnings({"rawtypes"})
    Request<?> mockRequest = EasyMock.createMock(requestClass);
    RecordTemplate mockRecordTemplate = EasyMock.createMock(RecordTemplate.class);
    @SuppressWarnings({"rawtypes"})
    RestResponseDecoder mockResponseDecoder = EasyMock.createMock(RestResponseDecoder.class);

    setCommonExpectations(mockRequest, method, mockRecordTemplate, mockResponseDecoder);

    if (method == ResourceMethod.BATCH_PARTIAL_UPDATE || method == ResourceMethod.BATCH_UPDATE) {
      buildInputForBatchPathAndUpdate(mockRequest);
    } else {
      EasyMock.expect(mockRequest.getInputRecord()).andReturn(mockRecordTemplate).times(2);
      EasyMock.expect(mockRequest.getResourceSpec()).andReturn(new ResourceSpecImpl()).once();
    }

    if (method == ResourceMethod.GET) {
      EasyMock.expect(((GetRequest) mockRequest).getObjectId()).andReturn(null).once();
      EasyMock.expect(((GetRequest) mockRequest).getResourceSpec())
          .andReturn(new ResourceSpecImpl())
          .once();
      EasyMock.expect(mockRequest.getMethodName()).andReturn(null);
    } else if (method == ResourceMethod.BATCH_GET) {
      EasyMock.expect(mockRequest.getMethodName()).andReturn(null);
    } else if (method == ResourceMethod.ACTION) {
      EasyMock.expect(((ActionRequest) mockRequest).getId()).andReturn(null);
      EasyMock.expect(mockRequest.getMethodName()).andReturn("testAction");
    } else if (method == ResourceMethod.FINDER) {
      EasyMock.expect(((FindRequest) mockRequest).getAssocKey()).andReturn(new CompoundKey());
      EasyMock.expect(mockRequest.getMethodName()).andReturn("testFinder");
    } else if (method == ResourceMethod.GET_ALL) {
      EasyMock.expect(((GetAllRequest) mockRequest).getAssocKey()).andReturn(new CompoundKey());
      EasyMock.expect(mockRequest.getMethodName()).andReturn(null);
    } else if (method == ResourceMethod.UPDATE) {
      EasyMock.expect(((UpdateRequest) mockRequest).getResourceSpec())
          .andReturn(new ResourceSpecImpl())
          .once();
      EasyMock.expect(((UpdateRequest) mockRequest).getId()).andReturn(null);
      EasyMock.expect(mockRequest.getMethodName()).andReturn(null);
    } else if (method == ResourceMethod.PARTIAL_UPDATE) {
      EasyMock.expect(mockRequest.getResourceSpec()).andReturn(new ResourceSpecImpl()).times(2);
      EasyMock.expect(((PartialUpdateRequest) mockRequest).getId()).andReturn(null);
      EasyMock.expect(mockRequest.getMethodName()).andReturn(null);
    } else if (method == ResourceMethod.DELETE) {
      EasyMock.expect(((DeleteRequest) mockRequest).getResourceSpec())
          .andReturn(new ResourceSpecImpl())
          .once();
      EasyMock.expect(((DeleteRequest) mockRequest).getId()).andReturn(null);
      EasyMock.expect(mockRequest.getMethodName()).andReturn(null);
    } else {
      EasyMock.expect(mockRequest.getMethodName()).andReturn(null);
    }

    EasyMock.expect(mockRecordTemplate.data()).andReturn(entityBody).once();

    Capture<RestRequest> restRequestCapture = new Capture<RestRequest>();

    EasyMock.expect(mockClient.getMetadata(new URI(HOST + SERVICE_NAME)))
        .andReturn(Collections.<String, Object>emptyMap())
        .once();

    mockClient.restRequest(
        EasyMock.capture(restRequestCapture),
        (RequestContext) EasyMock.anyObject(),
        (Callback<RestResponse>) EasyMock.anyObject());
    EasyMock.expectLastCall().once();

    EasyMock.replay(mockClient, mockRequest, mockRecordTemplate);

    // do work!
    RestClient restClient;
    if (acceptTypes == null) {
      restClient = new RestClient(mockClient, HOST);
    } else if (contentType == null) {
      restClient = new RestClient(mockClient, HOST, acceptTypes);
    } else {
      restClient = new RestClient(mockClient, HOST, contentType, acceptTypes);
    }

    restClient.sendRequest(mockRequest);

    return restRequestCapture.getValue();
  }