Search code examples
grpcwiremockprotobuf-java

Invalid wrapper type: google.protobuf.StringValue


I was using your demo project: https://github.com/wiremock/wiremock-grpc-demos

syntax = "proto3";

option csharp_namespace = "My.Package";
option java_package = "com.my.package";

import "google/protobuf/wrappers.proto";

service MySvc {
  rpc GetBond(MyRequest) returns (MyResponse) {}
}

message MyRequest {
  string myValue = 1;
}

message MyResponse {
  bool success = 1;
  string message = 2;
  google.protobuf.StringValue messageStringValue = 3;
}

& reworked GrpcTest.java to:

import com.example.grpc.HelloRequest;
import com.example.grpc.HelloResponse;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.junit5.WireMockExtension;
import com.google.protobuf.StringValue;
import com.mine.My;
import com.mine.MySvcGrpc;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.wiremock.grpc.GrpcExtensionFactory;
import org.wiremock.grpc.dsl.WireMockGrpc;
import org.wiremock.grpc.dsl.WireMockGrpcService;
import wiremock.grpc.client.GreetingsClient;

import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
import static java.lang.Thread.sleep;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.wiremock.grpc.dsl.WireMockGrpc.Status;
import static org.wiremock.grpc.dsl.WireMockGrpc.equalToMessage;
import static org.wiremock.grpc.dsl.WireMockGrpc.message;
import static org.wiremock.grpc.dsl.WireMockGrpc.method;

public class GrpcTest {

    WireMockGrpcService mockGreetingService;
    WireMockGrpcService mockRefDataService;
    ManagedChannel channel;
    GreetingsClient greetingsClient;

    @RegisterExtension
    public static WireMockExtension wm =
            WireMockExtension.newInstance()
                    .options(
                            wireMockConfig()
                                    .port(9090)
                                    .withRootDirectory("src/test/resources/wiremock")
                                    .extensions(new GrpcExtensionFactory())
                    )
                    .build();

    @BeforeEach
    void init() {
        var wiremock = new WireMock(wm.getPort());
        mockRefDataService =
                new WireMockGrpcService(wiremock, MySvcGrpc.SERVICE_NAME);
    }

    @AfterEach
    void tearDown() {
        channel.shutdown();
    }

    @Test
    void dynamic_response_via_JSON() throws InterruptedException {
        mockRefDataService.stubFor(
                method("GetResponse")
                        .willReturn(WireMockGrpc.message(
                                My.MyResponse.newBuilder()
                                        .setSuccess(true)
                                        .setMessage("abc")
                                        .setMessageStringValue(StringValue.of("ASDAS"))
                        ))
        );
        System.out.println("START");
        sleep(30000);
    }

Using Postman I send a request to grpcMockServer & it ends up with error:

Exception in thread "grpc-default-executor-0" com.google.protobuf.InvalidProtocolBufferException: Invalid wrapper type: google.protobuf.StringValue
    at com.google.protobuf.util.JsonFormat$ParserImpl.mergeWrapper(JsonFormat.java:1616)
    at com.google.protobuf.util.JsonFormat$ParserImpl.access$2100(JsonFormat.java:1276)
    at com.google.protobuf.util.JsonFormat$ParserImpl$2.merge(JsonFormat.java:1352)
    at com.google.protobuf.util.JsonFormat$ParserImpl.merge(JsonFormat.java:1432)
    at com.google.protobuf.util.JsonFormat$ParserImpl.parseFieldValue(JsonFormat.java:1995)
    at com.google.protobuf.util.JsonFormat$ParserImpl.mergeField(JsonFormat.java:1646)
    at com.google.protobuf.util.JsonFormat$ParserImpl.mergeMessage(JsonFormat.java:1477)
    at com.google.protobuf.util.JsonFormat$ParserImpl.merge(JsonFormat.java:1435)
    at com.google.protobuf.util.JsonFormat$ParserImpl.merge(JsonFormat.java:1317)
    at com.google.protobuf.util.JsonFormat$Parser.merge(JsonFormat.java:449)
    at org.wiremock.grpc.internal.JsonMessageUtils.lambda$toMessage$1(JsonMessageUtils.java:36)
    at com.github.tomakehurst.wiremock.common.Exceptions.uncheck(Exceptions.java:72)
    at org.wiremock.grpc.internal.JsonMessageUtils.toMessage(JsonMessageUtils.java:36)
    at org.wiremock.grpc.internal.UnaryServerCallHandler.lambda$invoke$0(UnaryServerCallHandler.java:92)
    at com.github.tomakehurst.wiremock.http.AbstractRequestHandler.handle(AbstractRequestHandler.java:101)
    at org.wiremock.grpc.internal.UnaryServerCallHandler.invoke(UnaryServerCallHandler.java:60)
    at org.wiremock.grpc.internal.UnaryServerCallHandler.invoke(UnaryServerCallHandler.java:31)
    at io.grpc.stub.ServerCalls$UnaryServerCallHandler$UnaryServerCallListener.onHalfClose(ServerCalls.java:182)
    at io.grpc.internal.ServerCallImpl$ServerStreamListenerImpl.halfClosed(ServerCallImpl.java:351)
    at io.grpc.internal.ServerImpl$JumpToApplicationThreadServerStreamListener$1HalfClosed.runInContext(ServerImpl.java:860)
    at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
    at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.lang.Thread.run(Thread.java:833)

My dependencies on this testClass

java.io
java.lang
java.util
Gradle: com.google.protobuf:protobuf-java:3.24.0
Gradle: io.grpc:grpc-api:1.59.0
Gradle: org.hamcrest:hamcrest:2.2
Gradle: org.junit.jupiter:junit-jupiter-api:5.10.0
Gradle: org.wiremock:wiremock-grpc-extension:0.3.0
Gradle: org.wiremock:wiremock:3.3.1
  • When I remove
.setMessageStringValue(StringValue.of("ASDAS"))

from willReturn() part there is no issue, I receive an expected response.

  • Issue also occurs with newer wiremock-grpc-extension(0.6.0): dependenties
java.io
java.lang
java.util
Gradle: com.google.protobuf:protobuf-java:3.25.1
Gradle: io.grpc:grpc-api:1.63.0
Gradle: org.hamcrest:hamcrest:2.2
Gradle: org.junit.jupiter:junit-jupiter-api:5.10.0
Gradle: org.wiremock:wiremock-grpc-extension:0.6.0
Gradle: org.wiremock:wiremock:3.3.1
  • Building only WireMockGrpc.message() ends successfully, but seems off:
WireMockGrpc.message(
                                My.MyResponse.newBuilder()
                                        .setSuccess(true)
                                        .setMessage("abc")
                                        .setMessageStringValue(StringValue.of("ASDAS"))
                        ).build();

body content of result:

Body {content={
  "success": true,
  "message": "abc",
  "messageStringValue": "ASDAS" <- here value I think should be "value": {"ASDAS"}
}, binary=false, json=false}
  • changing setting value for strinvalue field to

    .setMessageStringValue(StringValue.newBuilder().setValue("asda").build())`
    

    did not helped


Solution

  • When using imported proto definitions you need to ensure you're including them when building the descriptor (.dsc) file.

    In Gradle this is achieved via the following directive:

    task.descriptorSetOptions.includeImports = true
    

    The WireMock gRPC demos project has now been updated to reflect this: https://github.com/wiremock/wiremock-grpc-demos/blob/main/java/build.gradle#L74