README

OpenMock

OpenMock is a Go service that can mock services in integration tests, staging environment, or anywhere. The goal is to simplify the process of writing mocks in various channels. Currently it supports the following channels:

  • HTTP
  • gRPC
  • Kafka
  • AMQP (e.g. RabbitMQ)

Usage

Use it with docker.

$ docker run -it -p 9999:9999 -v $(pwd)/demo_templates:/data/templates checkr/openmock 

More complete openmock instance (e.g. redis) with docker-compose.

$ docker-compose up

Test it.

$ curl localhost:9999/ping

Dependencies.

  • HTTP (native supported, thanks to https://echo.labstack.com/)
    • One can configure HTTP port, set env OPENMOCK_HTTP_PORT=80
  • GRPC (supported through through HTTP/2 interface)
    • One can configure GRPC port, set env OPENMOCK_GRPC_PORT=50051
  • Kafka (optional)
    • To enable mocking kafka, set env OPENMOCK_KAFKA_ENABLED=true.
    • One can also config OPENMOCK_KAFKA_CLIENT_ID and OPENMOCK_KAFKA_SEED_BROKERS.
  • AMQP (optional)
    • To enable mocking amqp, set env OPENMOCK_AMQP_ENABLED=true
    • One can also config OPENMOCK_AMQP_URL.
  • NPM (development only)
    • Used in Makefile during swagger admin API server generation

OpenMock Templates

Templates are YAML files that describe the behavior of OpenMock.

Templates Directory

You can put any number of .yaml or .yml files in a directory, and then point environment variable OPENMOCK_TEMPLATES_DIR to it. OpenMock will recursively (including subdirectories) load all the YAML files. For example:

# OPENMOCK_TEMPLATES_DIR=./demo_templates

./demo_templates
├── amqp.yaml
├── files
│   └── colors.json
├── http.yaml
├── jsonrpc.yaml
├── kafka.yaml
└── payload_from_file.yaml

Schema

OpenMock is configured a list of behaviors for it to follow. Each behavior is identified by a key, and a kind:

- key: respond-to-resource
  kind: Behavior
Expect

It represents the channel to listen on and condition for the actions of the behavior to be performed. Available channels are:

  • http
  • kafka
  • amqp
  • grpc

For example, under what condition and from what channel should we proceed with the actions.

- key: no-op
  kind: Behavior
  expect:
    # Condition checks if we need to do the actions or not
    # It only proceeds if it evaluates to "true"
    condition: '{{.HTTPHeader.Get "X-Token" | eq "t1234"}}'
    # Use one (and only one) of the following channels - [http, kafka, amqp]
    http:
      method: GET
      path: /ping
    kafka:
      topic: hello_kafka_in
    amqp:
      exchange: exchange_1
      routing_key: key_in
      queue: key_in
Actions

Actions are a series of functions to run. Availabe actions are:

  • publish_amqp
  • publish_kafka
  • redis
  • reply_http
  • send_http
  • reply_grpc
  • sleep
- key: every-op
  kind: Behavior
  expect:
    http:
      method: GET
      path: /ping
  actions:
    - publish_kafka:
        topic: hello_kafka_out
        payload: >
          {
            "kafka": "OK",
            "data": {}
          }
    - sleep:
        duration: 1s
    - reply_http:
        status_code: 200
        body: OK
        headers:
          Content-Type: text/html

The actions by default run in the order defined in the mock file; you can adjust this by adding an int 'order' value from lowest to highest number. The default value for 'order' is 0.

- key: every-op
  kind: Behavior
  expect:
    http:
      method: GET
      path: /ping
  actions:
    - publish_kafka:
        topic: hello_kafka_out
        payload: >
          {
            "kafka": "OK",
            "data": {}
          }
    - sleep:
        duration: 1s
      # sleep first
      order: -1000
Templates

Templates can be useful to assemble your payloads from parts

- key: dog
  kind: Template
  template: >
    <animal>dog</animal>

- key: cat
  kind: Template
  template: >
    <animal>cat</animal>

# $ curl 0:9999/fred
# <human>   <name>fred</name>   <pets>     <animal>dog</animal>      <animal>cat</animal>    </pets> </human>
- key: get-freds-pets
  kind: Behavior
  expect:
    http:
      method: GET
      path: /fred
  actions:
    - reply_http:
        status_code: 200
        body: >
          <human>
            <name>fred</name>
            <pets>
              {{template "dog"}}
              {{template "cat"}}
            </pets>
          </human>
Abstract Behaviors

Abstract Behaviors can be used to parameterize some data.

When an abstract behavior and a behavior extending it both have actions defined, all of them are run when the behavior matches. Actions will run from lowest to highest value of the 'order' field; if this is the same for two actions the action defined earlier in the abstract behavior runs first, followed by actions in the concrete behavior. Be aware that values with all digits will be interpreted into int type (YAML syntax), and it will fail the condition check given that some helper functions are returning string types. Pipe to toString before the comparison or alternatively put quotes around the values. See example in abstract_behaviors.yml.

- key: fruit-of-the-day
  kind: AbstractBehavior
  values:
    fruit: potato
  expect:
    condition: '{{.HTTPQueryString | contains .Values.day}}'
    http:
      method: GET
      path: /fruit-of-the-day
  actions:
    - reply_http:
        status_code: 200
        body: '{"fruit": "{{.Values.fruit}}"}'

# $ curl 0:9999/fruit-of-the-day?day=monday
# {"fruit": "apple"}
- key: monday-fruit
  kind: Behavior
  extend: fruit-of-the-day
  values:
    day: monday
    fruit: apple

# $ curl 0:9999/fruit-of-the-day?day=tuesday
# {"fruit": "potato"}
- key: tuesday-fruit
  kind: Behavior
  extend: fruit-of-the-day
  values:
    day: tuesday
  actions: 
    # sleep then reply_http
    - sleep:
         duration: 1s
      order: -1000

Dynamic templating

OpenMock leverages https://golang.org/pkg/text/template/ to write dynamic templates. Specifically, it supports a lot of Context and Helper Functions.

  • Usage of {{ expr }}. One can put {{ expr }} inside three types of places:
    • expect.condition
    • action.http.body, action.grpc.payload, action.kafka.payload, action.amqp.payload
    • action.http.body_from_file, action.grpc.payload_from_file, action.kafka.payload_from_file, action.amqp.payload_from_file ({{ expr }} will be in the file)
  • Use Context inside {{ expr }}.
    .HTTPHeader      # type: http.Header; example: {{.HTTPHeader.Get "X-Token"}}
    .HTTPBody        # type: string;      example: {{.HTTPBody}}
    .HTTPPath        # type: string;      example: {{.HTTPPath}}
    .HTTPQueryString # type: string;      example: {{.HTTPQueryString}}
    
    .GRPCHeader      # type: string;      example: {{.GRPCHeader}}
    .GRPCPayload     # type: string;      example: {{.GRPCPayload}}
    .GRPCService     # type: string;      example: {{.GRPCService}}
    .GRPCMethod      # type: string;      example: {{.GRPCMethod}}
      
    .KafkaTopic      # type: string;      example: {{.KafkaTopic}}
    .KafkaPayload    # type: string;      example: {{.KafkaPayload}}
    
    .AMQPExchange    # type: string;      example: {{.AMQPExchange}}
    .AMQPRoutingKey  # type: string;      example: {{.AMQPRoutingKey}}
    .AMQPQueue       # type: string;      example: {{.AMQPQueue}}
    .AMQPPayload     # type: string;      example: {{.AMQPPayload}}
    
  • Use helper functions inside {{ expr }}. We recommend pipeline format (|) of the functions.
    # Supported functions defined in ./template_helper.go
    
      - 
      - jsonPath    # doc: https://github.com/antchfx/xpath
      - gJsonPath   # doc: https://github.com/tidwall/gjson
      - xmlPath     # doc: https://github.com/antchfx/xpath
      - uuidv5      # uuid v5 sha1 hash
      - redisDo     # run redis commands. For example {{redisDo "RPUSH" "arr" "hi"}}
      - ...
    
    # Supported functions inherited from
    # https://github.com/Masterminds/sprig/blob/master/functions.go
    
      - replace
      - uuidv4
      - regexMatch
      - ...
    
    # Examples
    {{.HTTPHeader.Get "X-Token" | eq "t1234"}}
    {{.HTTPBody | jsonPath "user/first_name" | replace "A" "a" | uuidv5 }}
    {{.HTTPBody | gJsonPath "users.0.first_name" }}
    {{.HTTPBody | xmlPath "node1/node2/node3"}}
    

Admin Interface

Openmock also by default provides an API on port 9998 to control the running instance. See api documentation. You can serve the api documentation by getting go-swagger and running:

./swagger serve --host 0.0.0.0 --port 9997 docs/api_docs/bundle.yaml"

Command Line Interface

Openmock has a command-line interface to help with certain tasks interacting with openmock instances. This is invoked with the omctl command. This uses the cobra library to provide a discoverable CLI; run omctl for a list of commands / flags.

CLI: Directory
Push

Pushes a local openmock model from the file system to a remote instance.

# Adds templates from the ./demo_templates directory to the instance running on localhost.
omctl push --directory ./demo_templates --url http://localhost:9998

Examples

Example: Mock HTTP
# demo_templates/http.yaml

# $ curl 0:9999/ping
# OK
- key: ping
  kind: Behavior
  expect:
    http:
      method: GET
      path: /ping
  actions:
    - reply_http:
        status_code: 200
        body: OK
        headers:
          Content-Type: text/html

# $ curl 0:9999/token -H X-Token:t1234 -H Y-Token:t1234
# OK
- key: header-token-200
  kind: Behavior
  expect:
    condition: '{{.HTTPHeader.Get "X-Token" | eq "t1234" | and (.HTTPHeader.Get "Y-Token" | eq "t1234")}}'
    http:
      method: GET
      path: /token
  actions:
    - reply_http:
        status_code: 200
        body: OK

# $ curl 0:9999/token
# Invalid X-Token
- key: header-token-401
  kind: Behavior
  expect:
    condition: '{{.HTTPHeader.Get "X-Token" | ne "t1234"}}'
    http:
      method: GET
      path: /token
  actions:
    - reply_http:
        status_code: 401
        body: Invalid X-Token

Example: Mock GRPC
# demo_templates/grpc.yaml

- key: example_grpc
  expect:
    grpc:
      service: demo_protobuf.ExampleService
      method: ExampleMethod
  actions:
    - reply_grpc:
        payload_from_file: './files/example_grpc_response.json'
Example: Mock Kafka
# demo_templates/kafka.yaml

- key: test_kafka_1
  kind: Behavior
  expect:
    kafka:
      topic: hello_kafka_in
  actions:
    - publish_kafka:
        topic: hello_kafka_out
        payload: >
          {
            "kafka": "OK",
            "data": {}
          }

- key: test_kafka_2
  kind: Behavior
  expect:
    kafka:
      topic: hello_kafka_in_2
  actions:
    - publish_kafka:
        topic: hello_kafka_out
        payload_from_file: './files/colors.json' # the path is relative to OPENMOCK_TEMPLATES_DIR

If you started the example from docker-compose, you can test the above kafka mocks by using a kt docker container.

# Exec into the container
docker-compose exec kt bash

# Run some kt commands inside the container
# Notice that the container is within the docker-compose network, and it connects to "kafka:9092"

$ kt topic
$ echo '{"123":"hi"}' | kt produce -topic hello_kafka_in -literal
$ kt consume -topic hello_kafka_out -offsets all=newest:newest
Example: Mock AMQP (e.g. RabbitMQ)
# demo_templates/amqp.yaml

- key: test_amqp_1
  kind: Behavior
  expect:
    amqp:
      exchange: exchange_1
      routing_key: key_in
      queue: key_in
  actions:
    - publish_amqp:
        exchange: exchange_1
        routing_key: key_out
        payload: >
          {
            "amqp": "OK",
            "data": {}
          }

- key: test_amqp_2
  kind: Behavior
  expect:
    amqp:
      exchange: exchange_1
      routing_key: key_in
      queue: key_in
  actions:
    - publish_amqp:
        exchange: exchange_1
        routing_key: key_out
        payload_from_file: './files/colors.json'
Example: Use Redis for stateful things (by default, OpenMock uses an in-memory miniredis)
# demo_templates/redis.yaml

- key: hello_redis
  kind: Behavior
  expect:
    http:
      method: GET
      path: /test_redis
  actions:
    - redis:
      - '{{.HTTPHeader.Get "X-TOKEN" | redisDo "SET" "k1"}}'
      - '{{redisDo "RPUSH" "random" uuidv4}}'
      - '{{redisDo "RPUSH" "random" uuidv4}}'
      - '{{redisDo "RPUSH" "random" uuidv4}}'
    - reply_http:
        status_code: 200
        body: >
          {
            "k1": "{{redisDo "GET" "k1"}}",
            "randomStr": "{{redisDo "LRANGE" "random" 0 -1}}",
            "random": [
              {{ $arr := redisDo "LRANGE" "random" 0 -1 | splitList ";;" }}
              {{ range $i, $v := $arr }}
                {{if isLastIndex $i $arr}}
                  "{{$v}}"
                {{else}}
                  "{{$v}}",
                {{end}}
              {{end}}
            ]
          }

# To test
# curl localhost:9999/test_redis -H "X-TOKEN:t123"  | jq .
Example: Send Webhooks
# demo_templates/webhook.yaml

- key: webhooks
  kind: Behavior
  expect:
    http:
      method: GET
      path: /send_webhook_to_httpbin
  actions:
    - send_http:
        url: "https://httpbin.org/post"
        method: POST
        body: '{"hello": "world"}'
        headers:
          X-Token: t123
    - reply_http:
        status_code: 200
        body: 'webhooks sent'

# To test
# curl localhost:9999/send_webhook_to_httpbin
Example: Use data in templates
# demo_templates/http.yaml

- key: http-request-template
  kind: Template
  template: >
    { "http_path": "{{.HTTPPath}}", "http_headers": "{{.HTTPHeader}}" }

- key: color-template
  kind: Template
  template: >
    { "color": "{{.color}}" }

- key: teapot
  kind: AbstractBehavior
  expect:
    http:
      method: GET
      path: /teapot
  actions:
    - reply_http:
        status_code: 418
        body: >
          {
            "request-info": {{ template "http-request-template" . }},
            "teapot-info": {{ template "color-template" .Values }}
          }

# $ curl 0:9999/teapot
# {   "request-info": { "http_path": "/teapot", "http_headers": "map[Accept:[*/*] User-Agent:[curl/7.54.0]]" } ,   "teapot-info": { "color": "purple" }  }
- key: purple-teapot
  kind: Behavior
  extend: teapot
  values:
    color: purple

Advanced pipeline functions

To enable advanced mocks, for example, your own encoding/decoding of the kafka messages, one can develop by directly importing the github.com/checkr/openmock package, making a copy of the swagger-generated server main, and passing in a custom OpenMock.

For example: (see example)

package main

import (
  "github.com/checkr/openmock"
  "github.com/checkr/openmock/swagger_gen/restapi"
  "github.com/checkr/openmock/swagger_gen/restapi/operations"
  /// etc
)

func consumePipelineFunc(c openmock.Context, in []byte) (out []byte, error) {
  return decode(in), nil
}

func main() {
  // server set up copy & paste...
  
  // add our custom openmock functionality
  om := &openmock.OpenMock{}
  om.ParseEnv()
  om.KafkaConsumePipelineFunc = consumePipelineFunc

  server.ConfigureAPI(om)

  // rest of server set up copy & paste...
}

GRPC Configuration Notes

OpenMock uses the APIv2 protobuf module (google.golang.org/protobuf). If your project uses the APIv1 protobuf module, you can use https://github.com/golang/protobuf/releases/tag/v1.4.0 and convert your messages to be APIv2 compatible with the proto.MessageV2 method.

Please note that OpenMock expects the payload or payload_from_file for a reply_grpc action to be in the json form of your Response protobuf message. The request should be in the Request protobuf message format as it is parsed into json to support jsonPath and gJsonPath operations.

Example configuration by directly importing the github.com/checkr/openmock package into a wrapper project.

func main() {
  // server set up copy & paste...
  
  // add our custom openmock functionality
  om := &openmock.OpenMock{}
  om.GRPCServiceMap = map[string]openmock.GRPCService{
      "demo_protobuf.ExampleService": {
          "ExampleMethod": openmock.RequestResponsePair{
              Request:  proto.MessageV2(&demo_protobuf.ExampleRequest{}),
              Response: proto.MessageV2(&demo_protobuf.ExampleResponse{}),
          },
      },
  }
  om.ParseEnv()
  server.ConfigureAPI(om)

  // rest of server set up copy & paste...

Swagger

Swagger files / directories:
Makefile                    # contains build process for swagger generation
swagger/                    # directory containing swagger definition, split 
                            # up into a few files
   index.yaml               # all the model definitions are in here
   health.yaml              # method definitions relating to e.g. /health
swagger_gen/                # directory where generated swagger files go
  restapi/
    configure_open_mock.go  # this file contains code further customized from the 
                            # generated code to hook an implementation into the API
                            # the makefiles makes sure it is preserved when 
                            # generating the other files
docs/
  api_docs/
    bundle.yaml             # combined swagger spec file, generated by Makefile
pkg/
  admin/                    # code implementing the handlers for the swagger API
Install Swagger
brew tap go-swagger/go-swagger
brew install go-swagger
Generate
  • make gen - bundles the separate swagger files and generates swagger_gen
  • make build - builds the executables om and omctl
Run

OPENMOCK_REDIS_TYPE=redis OPENMOCK_REDIS_URL=<redis Url, e.g. redis://localhost:6379> OPENMOCK_TEMPLATES_DIR=./demo_templates ./om --port 9998

Expand ▾ Collapse ▴

Documentation

Index

Constants

View Source
const (
	KindBehavior         = "Behavior"
	KindAbstractBehavior = "AbstractBehavior"
	KindTemplate         = "Template"
)

Variables

View Source
var DefaultPipelineFunc = func(c Context, in []byte) (out []byte, err error) {
	return in, nil
}

DefaultPipelineFunc directly outputs the in bytes

View Source
var GetActualAction = func(action ActionDispatcher) Action {
	if !structs.IsZero(action.ActionPublishAMQP) {
		return action.ActionPublishAMQP
	}
	if !structs.IsZero(action.ActionSendHTTP) {
		return action.ActionSendHTTP
	}
	if !structs.IsZero(action.ActionReplyHTTP) {
		return action.ActionReplyHTTP
	}
	if !structs.IsZero(action.ActionReplyGRPC) {
		return action.ActionReplyGRPC
	}
	if len(action.ActionRedis) > 0 {
		return action.ActionRedis
	}
	if !structs.IsZero(action.ActionPublishKafka) {
		return action.ActionPublishKafka
	}
	return action.ActionSleep
}

Functions

This section is empty.

Types

type AMQPMocks

type AMQPMocks map[ExpectAMQP]MocksArray

AMQPMocks is keyed by Queue name

type Action

type Action interface {
	Perform(context Context) error
}

type ActionDispatcher

type ActionDispatcher struct {
	Order              int                `yaml:"order,omitempty"`
	ActionPublishAMQP  ActionPublishAMQP  `yaml:"publish_amqp,omitempty"`
	ActionPublishKafka ActionPublishKafka `yaml:"publish_kafka,omitempty"`
	ActionRedis        ActionRedis        `yaml:"redis,omitempty"`
	ActionReplyHTTP    ActionReplyHTTP    `yaml:"reply_http,omitempty"`
	ActionSendHTTP     ActionSendHTTP     `yaml:"send_http,omitempty"`
	ActionReplyGRPC    ActionReplyGRPC    `yaml:"reply_grpc,omitempty"`
	ActionSleep        ActionSleep        `yaml:"sleep,omitempty"`
}

Action represents actions

type ActionPublishAMQP

type ActionPublishAMQP struct {
	Exchange        string `yaml:"exchange,omitempty"`
	RoutingKey      string `yaml:"routing_key,omitempty"`
	Payload         string `yaml:"payload,omitempty"`
	PayloadFromFile string `yaml:"payload_from_file,omitempty"`
}

ActionPublishAMQP represents publish AMQP action

func (ActionPublishAMQP) Perform

func (a ActionPublishAMQP) Perform(ctx Context) error

type ActionPublishKafka

type ActionPublishKafka struct {
	Topic           string `yaml:"topic,omitempty"`
	Payload         string `yaml:"payload,omitempty"`
	PayloadFromFile string `yaml:"payload_from_file,omitempty"`
}

ActionPublishKafka represents publish kafka action

func (ActionPublishKafka) Perform

func (a ActionPublishKafka) Perform(ctx Context) error

type ActionRedis

type ActionRedis []string

ActionRedis represents a list of redis commands

func (ActionRedis) Perform

func (a ActionRedis) Perform(ctx Context) error

type ActionReplyGRPC

type ActionReplyGRPC struct {
	Headers         map[string]string `yaml:"headers,omitempty"`
	Payload         string            `yaml:"payload,omitempty"`
	PayloadFromFile string            `yaml:"payload_from_file,omitempty"`
}

ActionReplyGRPC represents reply grpc action

func (ActionReplyGRPC) Perform

func (a ActionReplyGRPC) Perform(ctx Context) error

type ActionReplyHTTP

type ActionReplyHTTP struct {
	StatusCode   int               `yaml:"status_code,omitempty"`
	Headers      map[string]string `yaml:"headers,omitempty"`
	Body         string            `yaml:"body,omitempty"`
	BodyFromFile string            `yaml:"body_from_file,omitempty"`
}

ActionReplyHTTP represents reply http action

func (ActionReplyHTTP) Perform

func (a ActionReplyHTTP) Perform(ctx Context) (err error)

type ActionSendHTTP

type ActionSendHTTP struct {
	URL          string            `yaml:"url,omitempty"`
	Method       string            `yaml:"method,omitempty"`
	Headers      map[string]string `yaml:"headers,omitempty"`
	Body         string            `yaml:"body,omitempty"`
	BodyFromFile string            `yaml:"body_from_file,omitempty"`
}

ActionSendHTTP represents the send http action

func (ActionSendHTTP) Perform

func (a ActionSendHTTP) Perform(ctx Context) error

type ActionSleep

type ActionSleep struct {
	Duration time.Duration `yaml:"duration,omitempty"`
}

ActionSleep represents the sleep action

func (ActionSleep) Perform

func (a ActionSleep) Perform(ctx Context) error

type Context

type Context struct {
	HTTPContext     echo.Context
	HTTPHeader      http.Header
	HTTPBody        string
	HTTPPath        string
	HTTPQueryString string

	GRPCService string
	GRPCMethod  string
	GRPCContext echo.Context
	GRPCHeader  http.Header
	GRPCPayload string

	KafkaTopic   string
	KafkaPayload string

	AMQPExchange   string
	AMQPRoutingKey string
	AMQPQueue      string
	AMQPPayload    string

	Values map[string]interface{}
	// contains filtered or unexported fields
}

Context represents the context of the mock expectation

func (Context) MatchCondition

func (c Context) MatchCondition(condition string) (r bool)

MatchCondition checks the condition given the context

func (Context) Merge

func (c Context) Merge(other Context) (out Context)

Create a new context that combines values in this context with values in the other context if not blank

func (Context) Render

func (c Context) Render(raw string) (out string, err error)

Render renders the raw given the context

type Expect

type Expect struct {
	Condition string      `yaml:"condition,omitempty"`
	HTTP      ExpectHTTP  `yaml:"http,omitempty"`
	Kafka     ExpectKafka `yaml:"kafka,omitempty"`
	AMQP      ExpectAMQP  `yaml:"amqp,omitempty"`
	GRPC      ExpectGRPC  `yaml:"grpc,omitempty"`
}

Expect represents what to expect from a mock

type ExpectAMQP

type ExpectAMQP struct {
	Exchange   string `yaml:"exchange,omitempty"`
	RoutingKey string `yaml:"routing_key,omitempty"`
	Queue      string `yaml:"queue,omitempty"`
}

ExpectAMQP represents amqp expectation

type ExpectGRPC

type ExpectGRPC struct {
	Service string `yaml:"service,omitempty"`
	Method  string `yaml:"method,omitempty"`
}

ExpectGRPC represents grpc expectation

type ExpectHTTP

type ExpectHTTP struct {
	Method string `yaml:"method,omitempty"`
	Path   string `yaml:"path,omitempty"`
}

ExpectHTTP represents http expectation

type ExpectKafka

type ExpectKafka struct {
	Topic string `yaml:"topic,omitempty"`
}

ExpectKafka represents kafka expectation

type GRPCMocks

type GRPCMocks map[ExpectGRPC]MocksArray

GRPCMocks is keyed by service/method

type GRPCRequestResponsePair

type GRPCRequestResponsePair struct {
	Request  proto.Message
	Response proto.Message
}

GRPCRequestResponsePair is a pair of proto.Message to define the message schema of request and response of a method

type GRPCService

type GRPCService map[string]GRPCRequestResponsePair

GRPCService is a map of service_name => GRPCRequestResponsePair

type HTTPMocks

type HTTPMocks map[ExpectHTTP]MocksArray

HTTPMocks ...

type KafkaMocks

type KafkaMocks map[ExpectKafka]MocksArray

KafkaMocks is keyed by Topic

type KafkaPipelineFunc

type KafkaPipelineFunc func(c Context, in []byte) (out []byte, err error)

KafkaPipelineFunc defines pipeline functions For example, decode/encode messages

type Mock

type Mock struct {
	// Common fields
	Kind   string `yaml:"kind,omitempty"`
	Key    string `yaml:"key,omitempty"`
	Extend string `yaml:"extend,omitempty"`

	// KindBehavior fields
	Expect  Expect                 `yaml:"expect,omitempty"`
	Actions []ActionDispatcher     `yaml:"actions,omitempty"`
	Values  map[string]interface{} `yaml:"values,omitempty"`

	// KindTemplate fields
	Template string `yaml:"template,omitempty"`
}

Mock represents a mock struct swagger:model

func (*Mock) DoActions

func (m *Mock) DoActions(ctx Context) (conditionMatch bool)

func (*Mock) Validate

func (m *Mock) Validate() error

Validate validates the mock

type MockRepo

type MockRepo struct {
	HTTPMocks  HTTPMocks
	GRPCMocks  GRPCMocks
	KafkaMocks KafkaMocks
	AMQPMocks  AMQPMocks
	Templates  MocksArray

	Behaviors *orderedmap.OrderedMap
}

MockRepo stores a repository of Mocks

func (*MockRepo) AsArray

func (repo *MockRepo) AsArray() (ret []*Mock)

func (*MockRepo) ToYAML

func (repo *MockRepo) ToYAML() []byte

ToYAML outputs MockRepo to yaml bytes

type MocksArray

type MocksArray []*Mock

MocksArray represents an array of Mocks

func (MocksArray) DoActions

func (ms MocksArray) DoActions(ctx Context)

type OpenMock

type OpenMock struct {
	LogLevel              string `env:"OPENMOCK_LOG_LEVEL" envDefault:"info"`
	TemplatesDir          string `env:"OPENMOCK_TEMPLATES_DIR" envDefault:"./templates"`
	TemplatesDirHotReload bool   `env:"OPENMOCK_TEMPLATES_DIR_HOT_RELOAD" envDefault:"true"`

	// HTTP channel
	HTTPEnabled bool   `env:"OPENMOCK_HTTP_ENABLED" envDefault:"true"`
	HTTPPort    int    `env:"OPENMOCK_HTTP_PORT" envDefault:"9999"`
	HTTPHost    string `env:"OPENMOCK_HTTP_HOST" envDefault:"0.0.0.0"`
	CorsEnabled bool   `env:"OPENMOCK_CORS_ENABLED" envDefault:"false"`

	// Admin channel
	AdminHTTPEnabled bool   `env:"OPENMOCK_ADMIN_HTTP_ENABLED" envDefault:"true"`
	AdminHTTPPort    int    `env:"OPENMOCK_ADMIN_HTTP_PORT" envDefault:"9998"`
	AdminHTTPHost    string `env:"OPENMOCK_ADMIN_HTTP_HOST" envDefault:"0.0.0.0"`

	// Kafka channel
	KafkaEnabled     bool     `env:"OPENMOCK_KAFKA_ENABLED" envDefault:"false"`
	KafkaClientID    string   `env:"OPENMOCK_KAFKA_CLIENT_ID" envDefault:"openmock"`
	KafkaSeedBrokers []string `env:"OPENMOCK_KAFKA_SEED_BROKERS" envDefault:"kafka:9092" envSeparator:","`

	// AMQP channel
	AMQPEnabled bool   `env:"OPENMOCK_AMQP_ENABLED" envDefault:"false"`
	AMQPURL     string `env:"OPENMOCK_AMQP_URL" envDefault:"amqp://guest:guest@rabbitmq:5672"`

	// Redis configuration for admin's ephemeral storage or redis commands
	RedisType string `env:"OPENMOCK_REDIS_TYPE" envDefault:"memory"`
	RedisURL  string `env:"OPENMOCK_REDIS_URL" envDefault:"redis://redis:6379"`

	// GRPC channel
	GRPCEnabled bool   `env:"OPENMOCK_GRPC_ENABLED" envDefault:"false"`
	GRPCPort    int    `env:"OPENMOCK_GRPC_PORT" envDefault:"50051"`
	GRPCHost    string `env:"OPENMOCK_GRPC_HOST" envDefault:"0.0.0.0"`

	//////////////////////// Customized functions //////////////////////////////////
	// KafkaConsumePipelineFunc is a pipeline function run to when consume a message
	KafkaConsumePipelineFunc KafkaPipelineFunc
	// KafkaPublishPipelineFunc is a pipeline function run to when produce a message
	KafkaPublishPipelineFunc KafkaPipelineFunc
	// GRPCServiceMap is a map of gRPC [service_name => GRPCService]
	GRPCServiceMap map[string]GRPCService
	// contains filtered or unexported fields
}

OpenMock holds all the configuration of running openmock

func (*OpenMock) Load

func (om *OpenMock) Load() error

Load returns a map of Mocks

func (*OpenMock) ParseEnv

func (om *OpenMock) ParseEnv()

ParseEnv loads env vars into the openmock struct

func (*OpenMock) RedisDo

func (om *OpenMock) RedisDo(commandName string, args ...interface{}) (reply interface{}, err error)

func (*OpenMock) RedisTemplatesStore

func (om *OpenMock) RedisTemplatesStore() string

func (*OpenMock) SetRedis

func (om *OpenMock) SetRedis()

SetRedis sets the Redis store for OpenMock

func (*OpenMock) SetupLogrus

func (om *OpenMock) SetupLogrus()

func (*OpenMock) SetupRepo

func (om *OpenMock) SetupRepo()

func (*OpenMock) Start

func (om *OpenMock) Start()

Start starts the openmock

func (*OpenMock) Stop

func (om *OpenMock) Stop()

Stop clean up and release some resources, it's optional.

func (*OpenMock) ToArray

func (om *OpenMock) ToArray() []*Mock

func (*OpenMock) ToYAML

func (om *OpenMock) ToYAML() []byte

type RedisDoer

type RedisDoer interface {
	Do(commandName string, args ...interface{}) (reply interface{}, err error)
}

RedisDoer can run redis commands

func NewRedisDoer

func NewRedisDoer(redisURL string) RedisDoer

NewRedisDoer creates a new RedisDoer