使用 Camouflage 模拟 Stream gRPC 响应

问题描述 投票:0回答:1

我最近将我的 gRPC 客户端迁移到 Stream 方法,之前使用 Camouflage 进行的模拟实现不再起作用。 我的客户(Java):

  private final TestAdapterStub testAdapterStub;
  private CompletableFuture<GetTestResponse> responseFuture;


  public GetTestResponse getTest(String id) {
    GetTestRequest request = GetTestRequest.newBuilder()
        .setId(id)
        .build();

    responseFuture = new CompletableFuture<>();
    StreamObserver<GetTestResponse> responseObserver = getResponseObserver();
    var requestObserver = testAdapterStub.getTest(responseObserver);
    requestObserver.onNext(request);
    requestObserver.onCompleted();
    try {
      return responseFuture.join(); // here I am not getting response, failing by timeout
    } catch (CompletionException exception) {
      ...
    }
  }

  private StreamObserver<GetTestAdapter.GetTestResponse> getTestObserver() {
    return new StreamObserver<>() {
      @Override
      public void onNext(GetTestResponse getTestResponse) {
        responseFuture.complete(getTestResponse);
      }

      @Override
      public void onError(Throwable exception) {
        responseFuture.completeExceptionally(exception);
      }

      @Override
      public void onCompleted() {
      }
    };
  }
}

所以,基本上,我不想调用其他服务,而是想使用伪装来模拟响应。 根据文档https://testinggospels.github.io/camouflage/mocking-gRPC/,我已经在正确的目录下创建了.proto文件和.mock文件,proto文件通过Postman进行了测试,我得到了响应从服务器,我知道目录是正确的,因为当我在 Docker 中启动伪装容器时,我在日志中看到那些 .mock 文件和 .proto 文件已注册。

但无论我如何尝试根据文档中的选项编写 .mock 文件,我要么在伪装日志中收到错误,表明文件有问题,要么没有得到任何响应并因超时而失败。

我尝试过:

  1. Unary Or Client Side Streaming
    模拟文件:
{
  "testResponse": {
  }
}

出现伪装错误:

Cannot read properties of undefined (reading 'delay')
我尝试在文件中添加
"delay": {{num_between lower=500 upper=600}}
选项,但显然这不是问题,而且我无法确定此日志的含义。

  1. Server Side Streaming
    模拟文件:
{
  "testResponse": {
  }
}
====
{
  "testResponse": {
  }
}

出现伪装错误:

Unexpected non-whitespace character after JSON at position 28
。在这种情况下,无论文档如何说明,伪装都不会将“====”符号视为分隔符。

  1. Bidi Streaming
    模拟文件:
{
 "data": {
  "testResponse": {
  }
 }
}

这是不会产生伪装错误的方法,我在日志中看到它应该被返回,但在客户端本身我正在等待调试并且没有得到响应,因超时而失败。

显然,我也尝试了所有这些选项以及来自服务器的真实响应,为每个 .mock 文件添加了延迟,但仍然没有得到积极的结果。

如果您对我的实施有什么问题以及如何解决它有任何建议,我将非常感激。

mocking grpc grpc-java
1个回答
0
投票

无论如何,我要关闭这个问题,因为问题不在于伪装,而在于我的客户。我修改了客户端,添加了正确的

requestObserver

  private StreamObserver<GetTestRequest> getRequestObserver(StreamObserver<GetTestResponse> responseObserver) {
return TestAdapterGrpc.newStub(grpcChannel()).getTest(
    responseObserver);

}

  private ManagedChannel grpcChannel() {
    return ManagedChannelBuilder.forTarget("host:port").intercept(grpcInterceptor)
        .build();
  }

以及注入到我的客户端中的 GRPCInterceptor grpcInterceptor 类:

public class GRPCInterceptor implements ClientInterceptor {

  public static final Metadata.Key<String> TRACE_ID_KEY = Metadata.Key.of("traceId",
      ASCII_STRING_MARSHALLER);

  @Override
  public <M, R> ClientCall<M, R> interceptCall(
      final MethodDescriptor<M, R> method, CallOptions callOptions, Channel next) {
    return new BackendForwardingClientCall<>(method,
        next.newCall(method, callOptions.withDeadlineAfter(10000, TimeUnit.MILLISECONDS))) {

      @Override
      public void sendMessage(M message) {
        log.info("Method: {}, Message: {}", methodName, message);
        super.sendMessage(message);
      }

      @Override
      public void start(Listener<R> responseListener, Metadata headers) {
        headers.put(TRACE_ID_KEY, UUID.randomUUID().toString());

        BackendListener<R> backendListener = new BackendListener<>(methodName, responseListener);
        super.start(backendListener, headers);
      }
    };
  }

  private static class BackendListener<R> extends ClientCall.Listener<R> {

    String methodName;
    ClientCall.Listener<R> responseListener;

    protected BackendListener(String methodName, ClientCall.Listener<R> responseListener) {
      super();
      this.methodName = methodName;
      this.responseListener = responseListener;
    }

    @Override
    public void onMessage(R message) {
      log.info("Method: {}, Response: {}", methodName, message);
      responseListener.onMessage(message);
    }

    @Override
    public void onHeaders(Metadata headers) {
      responseListener.onHeaders(headers);
    }

    @Override
    public void onClose(Status status, Metadata trailers) {
      responseListener.onClose(status, trailers);
    }

    @Override
    public void onReady() {
      responseListener.onReady();
    }
  }

  private static class BackendForwardingClientCall<M, R> extends
      io.grpc.ForwardingClientCall.SimpleForwardingClientCall<M, R> {

    String methodName;

    protected BackendForwardingClientCall(MethodDescriptor<M, R> method, ClientCall delegate) {
      super(delegate);
      methodName = method.getBareMethodName();
    }
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.