@Override
    public void callMethod(MethodDescriptor method, RpcController controller, Message request,
      Message responsePrototype, RpcCallback<Message> done) {
      if (method.getService().equals(ConnectionRegistryService.getDescriptor())) {
        // this is for setting up the rpc client
        done.run(
          GetConnectionRegistryResponse.newBuilder().setClusterId(RESP.getClusterId()).build());
        return;
      }
      if (!method.getName().equals("GetClusterId")) {
        // On RPC failures, MasterRegistry internally runs getMasters() RPC to keep the master list
        // fresh. We do not want to intercept those RPCs here and double count.
        return;
      }
      // simulate the asynchronous behavior otherwise all logic will perform in the same thread...
      EXECUTOR.execute(() -> {
        int index = CALLED.getAndIncrement();
        if (index == BAD_RESP_INDEX) {
          done.run(GetClusterIdResponse.getDefaultInstance());
        } else if (GOOD_RESP_INDEXS.contains(index)) {
          done.run(RESP);
        } else {
          controller.setFailed("inject error");
          done.run(null);
        }
      });
    }
A dummy RpcChannel implementation that intercepts the GetClusterId() RPC calls and injects
errors. All other RPCs are ignored.
hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestRpcBasedRegistryHedgedReads.java