YAML config file

Notation: The following conventions are used in the syntax description: Brackets "[" and "]" indicate optional parts. Brackets "<" and ">" indicate mandatory parts. Vertical lines "|" indicate that you must choose one alternative. All other symbols, including parentheses, should be taken literally.

File name and location

The gRPC service mock configuration file should be named ".grpc.mock.qa.yaml" and placed in the root of the repository. The endpoint for this mock service will be https://[[instanceName→]repo→]<owner>.grpc.qa. The HTTP service mock configuration file should be named ".http.mock.qa.yaml" and also placed in the root of the repository. The endpoint for this mock service will be https://[[instanceName→]repo→]<owner>.rest.qa. You can have both files at the same time in the same repository, both the gRPC and HTTP mock service will work as expected.

gRPC service mock

Configuration file: /.grpc.mock.qa.yaml
Endpoint:https://[[instanceName→]repo→]<owner>.grpc.qa

HTTP service mock

Configuration file: /.http.mock.qa.yaml
Endpoint:https://[[instanceName→]repo→]<owner>.rest.qa

File layout

Below are depicted names of all main sections of yaml file but without their content:


### Header section

fileVersion: v1 
instanceName: <string> 
protoFile: <string>

### Channel credentials section

channel: # optional
  credentials: <mapping> # optional

### Calls section

calls: 
- method: <string> # gRPC method in the format <package>.<Service>/<Method>,
                   # for example greet.Greeter/SayHello
  debugName: <string> # optional, default "GRPC <method> #N",
                      # in use for trace logging only
  credentials: <sequence> # optional, same as channel.credentials
  scenario: <mapping> # optional, stateful testing
  request: # optional
    header: # optional
    body|stream: # optional
  response: # optional
    header: # optional
    body|stream: # optional 
    trailer: # optional
    status: # optional
    statusDetails: # optional

Header section

A YAML file defines the version of the file, the instance name of the service, and the location of the gRPC protobuf .proto file that defines the service interfaces.

---
# constant version number
fileVersion: v1 

# a unique name of a mock service instance.
# Part of the endpoint URL https://[[instanceName→]repo→]<owner>.grpc.qa
instanceName: <string> 

# an absolute path to the .proto file in your github repository (for gRPC mocks only)
protoFile: <string> 

Channel credentials section

You can define your authentication and authorization settings for a gRPC service. A channel section defines the credentials that are applied for the whole service.

encrypted-string is a secured string that has been encrypted using asymmetric RSA algorithm. Please find Encrypt a string dialog in the mock.qa dashboard Tools menu.

channel:
  credentials:
  - type: basic-auth
    user: <string>
    password: <string>

  - type: jwt-bearer
    authority: <string>
    audience: <string> # optional
    claims: <string> # optional

  - type: ip-white-list
    allowedIps: <sequence>

  - type: client-certificate
    clientCertificateThumbprints: <sequence> # optional
    trustedRootCertificateFiles: <sequence> # optional

Calls section

A list of calls, each of which defines a specific gRPC or HTTP method that the mock service can handle.

# .grpc.mock.qa.yaml:
calls:
- method: <string> # gRPC method in the format <package>.<Service>/<Method>,
                   # for example greet.Greeter/SayHello
  debugName: <string> # optional, default "GRPC <method> #N", 
                      # in use for trace logging only
  credentials: <sequence> # optional, same as channel.credentials
  scenario: # optional, stateful testing
  request: # optional
  response: # optional
# .http.mock.qa.yaml:
calls:
- url: <string> # http url, should start with "/", supports templates,
                # for example /post/{id}
  method: <GET|HEAD|POST|PUT|DELETE|CONNECT|OPTIONS|TRACE|PATCH>
  debugName: <string> # optional, default "HTTP <method> <url> #N",
                      # in use for trace logging only
  credentials: <sequence> # optional, same as channel.credentials
  scenario: # optional, stateful testing
  request: # optional
  response: # optional

Call credentials section

Calls may include a credentials section that specifies the type of authentication that should be used for a particular call. This section is separate from the channel credentials, and its structure is similar to that of channel credentials. The credentials section does not overwrite the channel credentials but rather supplements them if any channel credentials have already been specified.

  credentials:
  - type: basic-auth
    user: user
    password: "$RSA2048:rldEHit9cK7kvhAMPBJBU+YloFipXa8Hnr30S0b8Lgbsdd54NWzyo4k0nCLeSWqsW4U7LJXSTrVjGs0VmmA1l7QFadOIHsqYU8mUToIREq9y8xfSo8M7dzSsbYuqTKUiz5oDWEufzzvy0fNGsUHgdw+pQyaePPMPkYHJE8y31JR61atLM8LorEGmKCAuy/YUEF2UHfNXIQjebncZbbSpe1P1KZ5z5l7UwJhgFVEhMO7WpWTqpHoL8kWYT0FotYtQQXAGLzTys1XEcxlrI4rWtnEZwKSx9ifC1PpIVXp7hgVpZ8BjffVyLtc6V1bkoBfaSEWUFPLX/GWhBWXLFL5zwQ=="

Call scenario section

Calls may include a scenario section for stateful scenarios in order to implement state machine behavior.

A call will be a match if the scenario.name scenario has a state scenario.requiredState (in addition to request payload matching rules specified in the call section). Once a call is matched, the scenario.name scenario state will be set to scenario.newState.

All scenarios' initial state is started.

  scenario:
    name: <string> # case-insensitive
    requiredState: <string> # a state to match.
                            # Initial state is "started"
    newState: <string> # a new state to set if a call is matched,
                       # optional 

Call request section

The request section contains matching rules for a call. It consists of a header, body, and stream sections. It can include various conditions and values that the mock service should use when matching the gRPC to HTTP method calls.

in the example below request definition will match an incoming gRPC request SayHelloRequest { Name = "Joe" }

calls:
- method: greet.Greeter/SayHello
  request:
    body:
      Name: "Joe"
- method: <string> # gRPC method in the format <package>.<Service>/<Method>,
                   # for example greet.Greeter/SayHello
  request: # optional
    header: <mapping> # optional
    body|stream: <mapping|sequence> # optional

Call response section

The response section contains a response template if a call is matched. It may contain a body, stream (for gRPC only), header, trailer, and status sections for response templating.

# .grpc.mock.qa.yaml:
  response: # optional
    randomize: <bool> # optional, response.body will be randomized
    header: # optional
    trailer: # optional
    body|stream: <mapping|sequence> # optional, for unary and streaming calls
    status: <OK|CANCELLED|NOT_FOUND|...> # optional, default OK                                         
    statusDetails: <string> # optional, default empty
# .http.mock.qa.yaml:
  response: # optional
    header: # optional
    body: <mapping|sequence> # optional
    status: <int> # optional, default 200

Multiple mock instances in a single file

If you have multiple .proto services and want to create mocks for all of them, you can include multiple mock definitions in a single configuration file, as shown below:

---
fileVersion: v1 # constant 
instanceName: instanceOne
protoFile: /one.proto
... the rest of the file ...
---
fileVersion: v1 # constant 
instanceName: instanceTwo
protoFile: /two.proto
... the rest of the file ...

Alternatively, you can use our pre-processing feature to split the mock definitions into separate files for easier maintenance:

.grpc.mock.qa.yaml file content:

#include /one.yaml
#include /two.yaml

one.yaml file content:

---
fileVersion: v1 # constant 
instanceName: instanceOne
protoFile: /one.proto
... the rest of the file ...

two.yaml file content:

---
fileVersion: v1 # constant 
instanceName: instanceTwo
protoFile: /two.proto
... the rest of the file ...

Examples and demo repository

There is a dedicated repository that contains a collection of examples, please check it out:

File description: .grpc.mock.qa.yaml

Below is a formal description of a file structure:

# Please note:
# We use YAML terms for types definitions: scalar, sequence and mapping
# - scalar: matches a string, enum, bool, int, float, date, timestamp, duration.
# - sequence: matches an ordered list (protobuf: a repeated field).
# - mapping: matches a complex type (protobuf: a message type), or a dictionary (protobuf: a map).
---
fileVersion: v1 # constant 
instanceName: <string> # a unique name of a mock service instance.
                       # Part of the endpoint URL https://[[instanceName→]repo→]<owner>.grpc.qa
protoFile: <string> # an absolute path to the .proto file in your github repository

channel: # optional
  credentials: # sequence, one or many from the list below, optional
  - type: basic-auth
    user: <string>
    password: <string>

  - type: jwt-bearer
    authority: <string>
    audience: <string> # optional
    claims: <string> # optional

  - type: ip-white-list
    allowedIps: <sequence>

  - type: client-certificate
    clientCertificateThumbprints: <sequence> # optional
    trustedRootCertificateFiles: <sequence> # optional

calls:

- method: <string> # gRPC method in the format <Package>.<Service>/<Method>,
                   # for example greet.Greeter/SayHello
  debugName: <string> # optional, default "GRPC <method> #N",
                      # in use for trace logging only
  credentials: <sequence> # optional, same as channel.credentials
  scenario: # optional, stateful testing
    name: <string> # case-insensitive
    requiredState: <string> # a state to match. Initial state is "started"
    newState: <string> # optional, a new state to set if a call is matched
  request: # optional
    header: # optional
      <arbitrary-key>: <scalar> # same as equalTo: <scalar>
      <arbitrary-key>:
        equalTo: <scalar>
        lessThan: <scalar>
        lessOrEqualTo: <scalar>
        moreThan: <scalar>
        moreOrEqualTo: <scalar>
        contains: <scalar>
        startsWith: <scalar>
        endsWith: <scalar>
        matchesWildcard: <string>
        matchesRegEx: <string>
        matchesJPath: <string>
        matchesJsonFile: <string>
        matchesYamlFile: <string>
    body|stream: <mapping> # optional
      equalTo: <scalar | mapping | sequence> # optional
      contains: <scalar | mapping | sequence> # optional
      startsWith: <scalar | mapping | sequence> # optional
      endsWith: <scalar | mapping | sequence> # optional
      matchesWildcard: <string> # optional
      matchesRegEx: <string> # optional
      matchesJPath: <string> # optional
      matchesJsonFile: <string> # optional
      matchesYamlFile: <string> # optional
      ...
      <any-property>: <any-value> # shortcut to equalTo: <any-value>
      ...
      <any-property>:
        not:
          <any-operator>
      ...
      <scalar-property>:
        equalTo: <scalar>
        equivalentTo: <sequence> # like equalTo, but ignores casing
        lessThan: <scalar>
        lessOrEqualTo: <scalar>
        moreThan: <scalar>
        moreOrEqualTo: <scalar>
        contains: <scalar>
        startsWith: <scalar>
        endsWith: <scalar>
        matchesWildcard: <string>
        matchesRegEx: <string>
        matchesJPath: <string>
        matchesJsonFile: <string>
        matchesYamlFile: <string>
      ...
      <mapping-property>:
        equalTo: <scalar | mapping>
        equivalentTo: <sequence> # like equalTo, but ignores an order
        contains: <scalar | mapping>
        startsWith: <scalar | mapping>
        endsWith: <scalar | mapping>
        matchesWildcard: <string>
        matchesRegEx: <string>
        matchesJPath: <string>
        matchesJsonFile: <string>
        matchesYamlFile: <string>
      ...
      <sequence-property>:
        count: <scalar | any-operator> # matches a count of elements
        equalTo: <scalar | sequence>
        equivalentTo: <sequence> # like equalTo, but ignores an order
        contains: <scalar | sequence>
        startsWith: <scalar | sequence>
        endsWith: <scalar | sequence>
        matchesWildcard: <string>
        matchesRegEx: <string>
        matchesJPath: <string>
        matchesJsonFile: <string>
        matchesYamlFile: <string>
    ...
  response: # optional
    randomize: <bool> # optional
    header: # optional
      <arbitrary-key>: <scalar>
    ...
    trailer: # optional
      <arbitrary-key>: <scalar>
    ...
    body|stream: <mapping | sequence> # optional, for unary calls
      fromJsonFile: <string> # optional
      fromYamlFile: <string> # optional
      ...
      <any-property>:
        fromJsonFile: <string>
        fromYamlFile: <string>
      ...
      <scalar-property>: <scalar>
      <mapping-property>: <mapping>
      <sequence-property>: <sequence>
    ...
    # https://grpc.github.io/grpc/core/md_doc_statuscodes.html
    status: <OK|CANCELLED|UNKNOWN|...> # optional, default OK
    statusDetails: <string> # optional, default empty

File description: .http.mock.qa.yaml

Below is a formal description of a file structure:

---
fileVersion: v1 # constant
instanceName: <string> # unique per repository

channel: # optional
  credentials: # sequence, one or many from the list below, optional
  - type: basic-auth
    user: <string>
    password: <string>

  - type: jwt-bearer
    authority: <string>
    audience: <string> # optional
    claims: <string> # optional

  - type: ip-white-list
    allowedIps: <sequence>

  - type: client-certificate
    clientCertificateThumbprints: <sequence> # optional
    trustedRootCertificateFiles: <sequence> # optional

calls:

- url: <string> # http url, should start with "/", supports templates,
                # for example /post/{id}
  method: <GET|HEAD|POST|PUT|DELETE|CONNECT|OPTIONS|TRACE|PATCH>
  debugName: <string> # optional, default "HTTP <method> <url> #N",
                      # in use for trace logging only
  credentials: <sequence> # optional, same as channel.credentials
  scenario: # optional, stateful testing
    name: <string> # case-insensitive
    requiredState: <string> # a state to match. Initial state is "started"
    newState: <string> # optional, a new state to set if a call is matched
  request: # optional
    header: # optional
      <arbitrary-key>: <scalar> # same as equalTo: <scalar>
      <arbitrary-key>:
        equalTo: <scalar>
        contains: <scalar>
        startsWith: <scalar>
        endsWith: <scalar>
        matchesWildcard: <string>
        matchesRegEx: <string>
        matchesJPath: <string>
        matchesJsonFile: <string>
        matchesYamlFile: <string>
    body: <mapping> # optional, for unary calls
      equalTo: <scalar | mapping | sequence> # optional
      contains: <scalar | mapping | sequence> # optional
      startsWith: <scalar | mapping | sequence> # optional
      endsWith: <scalar | mapping | sequence> # optional
      matchesWildcard: <string> # optional
      matchesRegEx: <string> # optional
      matchesJPath: <string> # optional
      matchesJsonFile: <string> # optional
      matchesYamlFile: <string> # optional
      ...
      <any-property>: <any-value> # shortcut to equalTo: <any-value>
      ...
      <any-property>:
        not:
          <any-operator>
      ...
      <scalar-property>:
        equalTo: <scalar>
        equivalentTo: <sequence> # like equalTo, but ignores casing
        lessThan: <scalar>
        lessOrEqualTo: <scalar>
        moreThan: <scalar>
        moreOrEqualTo: <scalar>
        contains: <scalar>
        startsWith: <scalar>
        endsWith: <scalar>
        matchesWildcard: <string>
        matchesRegEx: <string>
        matchesJPath: <string>
        matchesJsonFile: <string>
        matchesYamlFile: <string>
      ...
      <mapping-property>:
        equalTo: <scalar | mapping>
        equivalentTo: <sequence> # like equalTo, but ignores an order
        contains: <scalar | mapping>
        startsWith: <scalar | mapping>
        endsWith: <scalar | mapping>
        matchesWildcard: <string>
        matchesRegEx: <string>
        matchesJPath: <string>
        matchesJsonFile: <string>
        matchesYamlFile: <string>
      ...
      <sequence-property>:
        count: <scalar | any-operator> # matches a count of elements
        equalTo: <scalar | sequence>
        equivalentTo: <sequence> # like equalTo, but ignores an order
        contains: <scalar | sequence>
        startsWith: <scalar | sequence>
        endsWith: <scalar | sequence>
        matchesWildcard: <string>
        matchesRegEx: <string>
        matchesJPath: <string>
        matchesJsonFile: <string>
        matchesYamlFile: <string>
  response: # optional
    header: # optional
      <arbitrary-key>: <scalar>
    ...
    body: <mapping> # optional, for unary calls
      fromJsonFile: <string> # optional
      fromYamlFile: <string> # optional
      ...
      <any-property>:
        fromJsonFile: <string>
        fromYamlFile: <string>
      ...
      <scalar-property>: <scalar>
      <mapping-property>: <mapping>
      <sequence-property>: <sequence>
    ...
    status: <int> # optional, default 200