Home

Awesome

Stability: Maintenance Docker Cloud Build Status Docker Image Version (tag latest semver)

Overview

grpc-wiremock is a mock server for GRPC services implemented as a wrapper around the WireMock http server.

How It Works

<p align="center"> <img src="doc/overview.drawio.svg"/> </p>

grpc-wiremock starts a gRPC server generated based on provided proto files which will convert a proto grpc request to JSON and redirects it as a POST request to the WireMock then converts a http response back to grpc proto format.

  1. GRPC server works on tcp://localhost:50000
  2. WireMock server works on http://localhost:8888

Quick Usage

  1. Run
docker run -p 8888:8888 -p 50000:50000 -v $(pwd)/example/proto:/proto -v $(pwd)/example/wiremock:/wiremock adven27/grpc-wiremock
  1. Stub
curl -X POST http://localhost:8888/__admin/mappings \
  -d '{
    "request": {
        "method": "POST",
        "url": "/BalanceService/getUserBalance",
        "headers": {"withAmount": {"matches": "\\d+\\.?\\d*"} },
        "bodyPatterns" : [ {
            "equalToJson" : { "userId": "1", "currency": "EUR" }
        } ]
    },
    "response": {
        "status": 200,
        "jsonBody": { 
            "balance": { 
                "amount": { "value": { "decimal" : "{{request.headers.withAmount}}" }, "value_present": true },
                "currency": { "value": "EUR", "value_present": true }
            } 
        }
    }
}'
  1. Check
grpcurl -H 'withAmount: 100.0' -plaintext -d '{"user_id": 1, "currency": "EUR"}' localhost:50000 api.wallet.BalanceService/getUserBalance

Should get response:

{
  "balance": {
    "amount": {
      "value": {
        "decimal": "100.0"
      },
      "value_present": true
    },
    "currency": {
      "value": "EUR",
      "value_present": true
    }
  }
}

Stubbing

Stubbing should be done via WireMock JSON API

Error mapping

Default error (not 200 OK) mapping is based on https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto :

HTTP Status CodeGRPC Status
400 Bad RequestINVALID_ARGUMENT
401 UnauthorizedUNAUTHENTICATED
403 ForbiddenPERMISSION_DENIED
404 Not FoundNOT_FOUND
409 ConflictALREADY_EXISTS
429 Too Many RequestsRESOURCE_EXHAUSTED
499 Client Closed RequestCANCELLED
500 Internal Server ErrorINTERNAL
501 Not ImplementedUNIMPLEMENTED
503 Service UnavailableUNAVAILABLE
504 Gateway TimeoutDEADLINE_EXCEEDED

And could be overridden or augmented by overriding or augmenting the following properties:

grpc:
  error-code-by:
    http:
      status-code:
        400: INVALID_ARGUMENT
        401: UNAUTHENTICATED
        403: PERMISSION_DENIED
        404: NOT_FOUND
        409: ALREADY_EXISTS
        429: RESOURCE_EXHAUSTED
        499: CANCELLED
        500: INTERNAL
        501: UNIMPLEMENTED
        503: UNAVAILABLE
        504: DEADLINE_EXCEEDED

For example:

docker run \
    -e GRPC_ERRORCODEBY_HTTP_STATUSCODE_400=OUT_OF_RANGE \
    -e GRPC_ERRORCODEBY_HTTP_STATUSCODE_510=DATA_LOSS \
    adven27/grpc-wiremock

How To:

1. Configure gRPC server

Currently, following grpc server properties are supported:

GRPC_SERVER_PORT
GRPC_SERVER_MAXHEADERLISTSIZE
GRPC_SERVER_MAXMESSAGESIZE
GRPC_SERVER_MAXINBOUNDMETADATASIZE
GRPC_SERVER_MAXINBOUNDMESSAGESIZE

Could be used like this:

docker run -e GRPC_SERVER_MAXHEADERLISTSIZE=1000 adven27/grpc-wiremock

2. Configure WireMock server

WireMock server may be configured by passing command line options prefixed by wiremock_:

docker run -e WIREMOCK_DISABLE-REQUEST-LOGGING -e WIREMOCK_PORT=0 adven27/grpc-wiremock

3. Mock server-side streaming:

Given the service:

service WalletService {
  rpc searchTransaction (SearchTransactionRequest) returns (stream SearchTransactionResponse) {}
}

Then the following stub may be provided, where response.headers.streamSize specifies how many responses should be returned during the stream (1 - if absent).

The current response iteration number is available in request.headers.streamCursor:

curl -X POST http://localhost:8888/__admin/mappings \
  -d '{
  "request": {
    "method": "POST",
    "url": "/WalletService/searchTransaction"
  },
  "response": {
    "fixedDelayMilliseconds": 1000,
    "headers": {"streamSize": "5" },
    "jsonBody": {
      "transactions": [
        {
          "id": "{{request.headers.streamCursor}}",
          "userId": "1",
          "currency": "EUR",
          "amount": {
            "decimal": "{{request.headers.streamCursor}}00"
          }
        },
        {
          "id": "100{{request.headers.streamCursor}}",
          "userId": "2",
          "currency": "EUR",
          "amount": {
            "decimal": "200"
          }
        }
      ]
    }
  }
}'

4. Speed up container start

In case you don't need to change proto files, you can build your own image with precompiled protos.
See an example

5. Use with snappy compresser/decompresser

Snappy support can be enabled using EXTERNAL_CODECS env variable as follows:

docker run -e EXTERNAL_CODECS="snappy, another" adven27/grpc-wiremock

Also in docker-compose:

    image: adven27/grpc-wiremock
    ports:
      - "12085:50000" # grpc port
      - "8088:8888" # http serve port
    volumes:
      - ./example/proto:/proto
    environment:
      - EXTERNAL_CODECS=snappy

<sub>*gzip compression supported by default</sub>

6. Use in load testing

To increase performance some Wiremock related options may be tuned either directly or by enabling the "load" profile. Next two commands are identical:

docker run -e SPRING_PROFILES_ACTIVE=load adven27/grpc-wiremock
docker run \
  -e WIREMOCK_NO-REQUEST-JOURNAL \
  -e WIREMOCK_DISABLE-REQUEST-LOGGING \
  -e WIREMOCK_ASYNC-RESPONSE-ENABLED \
  -e WIREMOCK_ASYNC-RESPONSE-THREADS=10 \
  adven27/grpc-wiremock

7. Preserving proto field names in stubs

By default, stub mappings must have proto fields references in lowerCamlCase, e.g. proto field user_id must be referenced as:

{
  "request": {
    "method": "POST",
    "url": "/BalanceService/getUserBalance",
    "bodyPatterns": [{"equalToJson": { "userId": "1" }}]
  }
}

To preserve proto field names the following env variable could be used:

docker run -e JSON_PRESERVING_PROTO_FIELD_NAMES=true adven27/grpc-wiremock