Fadelis / grpcmock

A gRPC Java testing tool to easily mock endpoints of gRPC services for IT or Unit testing
http://grpcmock.org
Apache License 2.0
145 stars 13 forks source link

How to mock StatusRuntimeException with metadata? #37

Open yunweiguo opened 4 weeks ago

yunweiguo commented 4 weeks ago

I want to use grpcmock for unit testing, but I've encountered an issue

Here is my code

public static void adaptException(Runnable runnable, StreamObserver streamObserver) {
    try {
      runnable.run();
    } catch (ApiException e) {
      Metadata trailers = new Metadata();
      Map errorMap = JacksonUtil.readValue(JacksonUtil.writeValueAsString(e), Map.class);
      errorMap.remove("stackTrace");
      trailers.put(Metadata.Key.of("error", Metadata.ASCII_STRING_MARSHALLER),
          JacksonUtil.writeValueAsString(errorMap));
      int errorCode = e.getErrorCode();
      String errorMessage = e.getErrorMessage();
      if (errorCode == INTERNAL_UNAUTHORIZED) {
        streamObserver.onError(
            new StatusRuntimeException(Status.PERMISSION_DENIED.withDescription(errorMessage), trailers));
      } else if (TOKEN_ERROR_CODES.contains(errorCode)) {
        streamObserver.onError(
            new StatusRuntimeException(Status.UNAUTHENTICATED.withDescription(errorMessage), trailers));
      } else {
        streamObserver.onError(new StatusRuntimeException(Status.UNKNOWN.withDescription(errorMessage), trailers));
      }
    } catch (Throwable e) {
      log.error("adaptException error", e);
      streamObserver.onError(new StatusRuntimeException(Status.UNKNOWN));
    }
  }

I put error information in the metadata. And consumer can get the error info.

I want to know how can I mock it?I didn't find a similar usage in the source code of grpcmock. I tried the following code,but it didn't work

 Metadata trailers = new Metadata();
 trailers.put(Metadata.Key.of("error", Metadata.ASCII_STRING_MARSHALLER), "{\"errorCode\":10501}");

stubFor(unaryMethod(TesseractServiceGrpc.getGetQuotePermissionParamMethod())
                .willReturn(Status.UNAUTHENTICATED.withCause(new StatusRuntimeException(Status.UNAUTHENTICATED.withDescription("errorMessage"), trailers)))
                .nextWillReturn(Status.UNAUTHENTICATED.withDescription("errorMessage").augmentDescription(trailers.toString()))
                .nextWillReturn(response(mockResponse)));
Fadelis commented 3 weeks ago

Hi, it's not very clear from your description what you're trying to achieve, since your code snippet supposedly contains client side exception handling, where your client sends the augmented exceptions and not reading the trailers from the api call exception, which is what grpc mock is meant for - mocking external api responses. Unless you want to verify that your sending correct error responses to the external server, but then you need to use the verification methods of grpc mock.

akexorcist commented 2 days ago

@yunweiguo Here is what I done to mock an error with metadata

val trailers: Metadata = Metadata().apply {
    put(Metadata.Key.of("message", Metadata.ASCII_STRING_MARSHALLER), "Additional message")
}

val response: ExceptionResponseActionBuilder = GrpcMock.exception(
    Status.UNAUTHENTICATED.asRuntimeException(trailers)
)

GrpcMock.stubFor(
    unaryMethod(unaryMethod(TesseractServiceGrpc.getGetQuotePermissionParamMethod())
        .willReturn(response)
)