@Test
  public void testCoprocessorService() throws Throwable {
    Table table = util.getConnection().getTable(TEST_TABLE);

    List<HRegionLocation> regions;
    try (RegionLocator rl = util.getConnection().getRegionLocator(TEST_TABLE)) {
      regions = rl.getAllRegionLocations();
    }
    final TestProtos.EchoRequestProto request =
      TestProtos.EchoRequestProto.newBuilder().setMessage("hello").build();
    final Map<byte[], String> results =
      Collections.synchronizedMap(new TreeMap<byte[], String>(Bytes.BYTES_COMPARATOR));
    try {
      // scan: for all regions
      final RpcController controller = new ServerRpcController();
      table.coprocessorService(TestRpcServiceProtos.TestProtobufRpcProto.class, ROWS[0],
        ROWS[ROWS.length - 1],
        new Batch.Call<TestRpcServiceProtos.TestProtobufRpcProto, TestProtos.EchoResponseProto>() {
          @Override
          public TestProtos.EchoResponseProto
            call(TestRpcServiceProtos.TestProtobufRpcProto instance) throws IOException {
            LOG.debug("Default response is " + TestProtos.EchoRequestProto.getDefaultInstance());
            CoprocessorRpcUtils.BlockingRpcCallback<TestProtos.EchoResponseProto> callback =
              new CoprocessorRpcUtils.BlockingRpcCallback<>();
            instance.echo(controller, request, callback);
            TestProtos.EchoResponseProto response = callback.get();
            LOG.debug("Batch.Call returning result " + response);
            return response;
          }
        }, new Batch.Callback<TestProtos.EchoResponseProto>() {
          @Override
          public void update(byte[] region, byte[] row, TestProtos.EchoResponseProto result) {
            assertNotNull(result);
            assertEquals("hello", result.getMessage());
            results.put(region, result.getMessage());
          }
        });
      for (Map.Entry<byte[], String> e : results.entrySet()) {
        LOG.info("Got value " + e.getValue() + " for region " + Bytes.toStringBinary(e.getKey()));
      }
      assertEquals(3, results.size());
      for (HRegionLocation info : regions) {
        LOG.info("Region info is " + info.getRegion().getRegionNameAsString());
        assertTrue(results.containsKey(info.getRegion().getRegionName()));
      }
      results.clear();

      // scan: for region 2 and region 3
      table.coprocessorService(TestRpcServiceProtos.TestProtobufRpcProto.class, ROWS[rowSeperator1],
        ROWS[ROWS.length - 1],
        new Batch.Call<TestRpcServiceProtos.TestProtobufRpcProto, TestProtos.EchoResponseProto>() {
          @Override
          public TestProtos.EchoResponseProto
            call(TestRpcServiceProtos.TestProtobufRpcProto instance) throws IOException {
            LOG.debug("Default response is " + TestProtos.EchoRequestProto.getDefaultInstance());
            CoprocessorRpcUtils.BlockingRpcCallback<TestProtos.EchoResponseProto> callback =
              new CoprocessorRpcUtils.BlockingRpcCallback<>();
            instance.echo(controller, request, callback);
            TestProtos.EchoResponseProto response = callback.get();
            LOG.debug("Batch.Call returning result " + response);
            return response;
          }
        }, new Batch.Callback<TestProtos.EchoResponseProto>() {
          @Override
          public void update(byte[] region, byte[] row, TestProtos.EchoResponseProto result) {
            assertNotNull(result);
            assertEquals("hello", result.getMessage());
            results.put(region, result.getMessage());
          }
        });
      for (Map.Entry<byte[], String> e : results.entrySet()) {
        LOG.info("Got value " + e.getValue() + " for region " + Bytes.toStringBinary(e.getKey()));
      }
      assertEquals(2, results.size());
    } finally {
      table.close();
    }
  }
TestEndpoint: test cases to verify coprocessor Endpoint
hbase-endpoint/src/test/java/org/apache/hadoop/hbase/coprocessor/TestCoprocessorEndpoint.java