groxy

module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 26, 2024 License: MIT

README

build Coverage Status Go Report Card Go Reference GitHub release

gRoxy is a gRPC mocking server that allows you to mock gRPC services and responses easily by specifying the message content alongside the message definition. gRoxy is designed to be used in development and testing environments to help you test your gRPC clients and services without having to rely on the actual gRPC server.


todos

  • currently service supports only mocking unary methods, but we plan to support streaming methods as well
  • serving the gRPC reflection service
  • support for the gRPC health check service
  • passthrough mode for proxying and modifying real gRPC services

installation

You can install gRoxy using the following command:

go install github.com/Semior001/groxy/cmd/groxy@latest

Or you can pull the docker image from ghcr.io:

docker pull ghcr.io/semior001/groxy:latest

Or from the docker hub:

docker pull semior/groxy:latest

usage

Usage:
  groxy [OPTIONS]

Application Options:
  -a, --addr=                Address to listen on (default: :8080) [$ADDR]
      --signature            Enable gRoxy signature headers [$SIGNATURE]
      --reflection           Enable gRPC reflection merger [$REFLECTION]
      --json                 Enable JSON logging [$JSON]
      --debug                Enable debug mode [$DEBUG]

file:
      --file.name=           Config file name (default: groxy.yml) [$FILE_NAME]
      --file.check-interval= Check interval for the config file (default: 3s) [$FILE_CHECK_INTERVAL]
      --file.delay=          Delay before applying the changes (default: 500ms) [$FILE_DELAY]

Help Options:
  -h, --help                 Show this help message

example

The simplest configuration for a method "Stub" would look like this:

version: 1

rules:
  - match: { uri: "com.github.Semior001.groxy.example.mock.ExampleService/Stub" }
    respond:
      body: |
        message StubResponse {
            option              (groxypb.target) = true; // this option specifies that the message is a response 
            string message = 1 [(groxypb.value)  = "Hello, World!"];
            int32 code     = 2 [(groxypb.value)  = "200"];
        }

That's it. You just need to define the response message, mark it as a target response message via the option, and set values via the value option. The response message will be sent to the client when the client calls the "Stub" method. No need for providing protosets, no need for providing the whole set of definitions, just the message you want to send.

More importantly, if your response message contains lots of fields, which are not important for the test, you can just ignore them. gRoxy will leave them empty, and the client will not be able to distinguish between the real server and the mock server. That's ensured by the protobuf's backward compatibility.

Field is backward compatible if it's of the same type and the same number. Names of the fields and messages are not important.

configuration

gRoxy uses a YAML configuration file to define the rules for the gRPC mocking server. The configuration file consists of the following sections:

Section Description
version The version of the configuration file.
The current version is 1, and any other version will raise an error.
not-matched The not-matched section contains the default response if the request didn't match to any rule. Not-matched section may contain a request body, or a gRPC status.

See respond type section
upstreams The upstreams section contains the list of the upstreams that serve gRPC reflection services.
rules The rules section contains the rules for the gRPC mocking server.

Upstreams section is a key-value map of upstreams, where key is the name of the upstream to be referenced further in the rules section. Each upstream consists of the following fields:

Field Required Description
address true The address of the upstream gRPC reflection service.
tls optional The TLS configuration for the upstream. The TLS configuration consists of the following fields:
serve-reflection optional The flag that indicates whether the upstream's responses should be included in the gRPC reflection responses. No-op if --reflection flag is not provided.

Rules are defined in the rules section. Either respond or forward must be defined Each rule consists of the following fields:

Field Required Description
match true The match section contains the matchers for the request.
match.uri true The URI matcher for the request. The URI matcher is a regular expression that matches the URI of the request.
match.header optional a map of headers that should be present in the request.
match.body optional The body matcher for the request. This must be a protobuf snippet that defines the request message with values to be matched.
respond optional The respond section contains the response for the request.
forward optional The forward section contains the upstream to which request should be forwarded to.

The Respond section contains the response for the request. The respond section may contain the following fields:

Field Required Description
body optional The body of the response. This must be a protobuf snippet that defines the response message with values to be sent.
metadata optional The metadata to be sent as a response.
status optional The gRPC status to be sent as a response.
status.code true, if status is present The gRPC status code to be sent as a response.
status.msg true, if status is present The gRPC status message to be sent as a response.

The Forward section contains the upstream to which the request should be forwarded. The forward section may contain the following fields:

Field Required Description
upstream true The name of the upstream to which the request should be forwarded.
header optional The headers to be sent with the request.

The configuration file is being watched for changes, and the server will reload the configuration file if it changes.

You can also take a look at examples for more information.

gRPC reflection

gRoxy supports gRPC reflection services. If you want to merge the responses from the upstream gRPC reflection services, you need to provide the --reflection flag and set the serve-reflection flag to true on the upstreams that should be included in the reflection responses.

The reflection responses are merged in the following way:

  1. Services are merged and unified by the package + service name.
  2. File descriptors are merged into a single array among the upstreams.
  3. AllExtensionNumbersOfType responds with the first non-error response from the upstreams.

groxypb

gRoxy uses the groxypb annotations to define values in protobuf message snippets. It compiles protobuf in a runtime, checking the target via the groxypb.target option and interpreting values via the groxypb.value option.

Example of the snippet:

message SomeMessage {
    option              (groxypb.target) = true; 
    string message = 1 [(groxypb.value) = "Hello, World!"];
    int32 code = 2     [(groxypb.value) = "200"];
}
multiline strings

protobuf itself doesn't support multiline strings, so gRoxy introduces it's own syntax for them in order to allow to specify complex values in groxypb.value option. Multiline strings should be enclosed in triple backticks:

message Dependency {
  string field1 = 1;
  int32  field2 = 2;
  bool   field3 = 3;
}

message SomeMessage {
    option              (groxypb.target) = true; 
    string message = 1 [(groxypb.value) = `Hello, 
    World!`];
    Dependency dependency = 2 [(groxypb.value) = `{
        "field1": "value1",
        "field2": 2,
        "field3": true
    }`];
}
nested messages

In case of nested messages, there are two options how to set values:

  1. Set the value in the nested message:
message SomeMessage {
    option                    (groxypb.target) = true; 
    string parent_value = 1   [(groxypb.value) = "parent"];
    NestedMessage nested = 2;
}

message NestedMessage {
    string nested_value = 1 [(groxypb.value) = "nested"];
}
  1. Set the JSON value in the annotation to the parent's field:
message SomeMessage {
    option                    (groxypb.target) = true; 
    string parent_value = 1  [(groxypb.value) = "parent"];
    NestedMessage nested = 2 [(groxypb.value) = '{"nested_value": "nested"}'];
}
enums

For enums, the value should be set as a string name of the enum value:

enum SomeEnum { 
    EMPTY = 0; 
    NEEDED_VALUE = 2; 
}

message StubResponse {
    option (groxypb.target) = true;
    SomeEnum some_enum = 9 [(groxypb.value) = 'NEEDED_VALUE'];
}
repeated fields

For repeated fields, the value should be set as a JSON array of the values:

message StubResponse {
    option (groxypb.target) = true;
    repeated string repeated_field = 1 [(groxypb.value) = '["value1", "value2"]'];
}
maps

For maps, the value should be set as a JSON object of the key-value pairs:

message StubResponse {
    option (groxypb.target) = true;
    map<string, string> map_field = 1 [(groxypb.value) = '{"key1": "value1", "key2": "value2"}'];
}

status

The project is currently in active development, and breaking changes may occur until the release of version 1.0. However, we strive to minimize disruptions and will only introduce breaking changes when there is a compelling reason to do so.

Directories

Path Synopsis
cmd
groxy
Package main is an application entrypoint.
Package main is an application entrypoint.
Package groxypb provides the definitions of the options to instantly fill the protobuf message.
Package groxypb provides the definitions of the options to instantly fill the protobuf message.
pkg
discovery
Package discovery provides the interface for matching gRPC requests to upstreams.
Package discovery provides the interface for matching gRPC requests to upstreams.
discovery/fileprovider
Package fileprovider provides a file-based discovery provider.
Package fileprovider provides a file-based discovery provider.
grpcx
Package grpcx contains helper types and functions to work with gRPC streams and messages.
Package grpcx contains helper types and functions to work with gRPC streams and messages.
grpcx/grpctest
Package grpctest contains the gRPC server to test streaming helpers.
Package grpctest contains the gRPC server to test streaming helpers.
protodef
Package protodef provides functions to make dynamic protobuf messages with the use of the groxypb options in protobuf snippets.
Package protodef provides functions to make dynamic protobuf messages with the use of the groxypb options in protobuf snippets.
proxy
Package proxy provides server and codec for proxying gRPC requests.
Package proxy provides server and codec for proxying gRPC requests.
proxy/middleware
Package middleware contains middlewares for gRPC unknown handlers.
Package middleware contains middlewares for gRPC unknown handlers.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL