Kuper-Tech / sbmt-pact

Ruby gem for simplified Pact testing between microservices, supporting the latest Pact specifications and multiple transport protocols
MIT License
46 stars 1 forks source link
grpc http kafka pact pact-tests

Sbmt Pact

sbmt-pact is a powerful Ruby gem designed to simplify and streamline Pact testing between microservices. This gem provides a robust set of RSpec utilities to help developers implement consumer-driven contract testing in microservice architectures.

In the world of microservices, ensuring seamless communication between services is crucial. This gem leverages the Pact to enable effective contract testing, allowing you to catch integration issues early in the development cycle. Contract testing is a way to check if different parts of a system work well together. It's like making sure two puzzle pieces fit perfectly before assembling the whole puzzle. Each part is tested on its own to see if it follows a set of rules (the "contract") that everyone agreed on. This helps catch problems early and makes sure all parts of the system speak the same language.

Motivation

Currently, the existing version of the pact-ruby gem only supports Pact Specification versions v1 and v2, which doesn't allow for:

The pact-ruby gem is in maintenance mode, as there has been a transition to rust-core, which is intended to be used through FFI in non-Rust stacks.

This gem eliminates the above-mentioned limitations and implements support for the latest versions of Pact specifications:

Architecture

Pact tests architecture

Usage

For each type of interaction (due to their specific features), a separate version of DSL has been implemented. However, the general principles remain the same for each type of interaction.


# Declaration of a consumer test, always include the :pact tag
# This is used in CI/CD pipelines to separate Pact tests from other RSpec tests
# Pact tests are not run as part of the general RSpec pipeline
RSpec.describe "SomePactConsumerTestForAnyTransport", :pact do
  # declaration of the type of interaction - here we determine which consumer and provider interact on which transport
  has_http_pact_between "CONSUMER-NAME", "PROVIDER-NAME"
  # or
  has_grpc_pact_between "CONSUMER-NAME", "PROVIDER-NAME"
  # or
  has_message_pact_between "CONSUMER-NAME", "PROVIDER-NAME"

  # the context for one of the interactions, for example GET /api/v2/stores
  context "with GET /api/v2/stores" do
      let(:interaction) do
        # creating a new interaction - within which we describe the contract
        new_interaction
          # if you need to save any metadata for subsequent use by the test provider,
          # for example, specify the entity ID that will need to be moved to the database in the test provider
          # we use the provider states, see more at https://docs.pact.io/getting_started/provider_states
          .given("UNIQUE PROVIDER STATE", key1: value1, key2: value2)
          # the description of the interaction, used for identification inside the package binding,
          # is optional in some cases, but it is recommended to always specify
          .upon_receiving("UNIQUE INTERACTION DESCRIPTION")
          # the description of the request using the matchers
          # the name and parameters of the method differ for different transports
          .with_request(...)
          # the description of the response using the matchers
          # the name and parameters of the method differ for different transports
          .with_response(...)
          # further, there are differences for different types of transports,
          # for more information, see the relevant sections of the documentation
      end

      it "executes the pact test without errors" do
        interaction.execute do
          # here our client is called for the API being tested
          # in this context, the client can be: http client, grpc client, kafka consumer
          expect(make_request).to be_success
        end
      end
    end
  end

Common DSL Methods:

HTTP consumers

Specific DSL methods:

More at http_client_spec.rb

gRPC consumers

Specific DSL methods:

More at grpc_client_spec.rb

Kafka consumers

Specific DSL methods:

Next, the specifics are one of two options for describing the format:

JSON (to describe a message in a JSON representation):

PROTO (to describe the message in the protobuf view):

More at kafka_spec.rb

Matchers

Matchers are special helper methods that allow you to define rules for matching request/response parameters at the level of the pact manifest. The matchers are described in the Pact specifications. In this gem, the matchers are implemented as RSpec helpers.

For details of the implementation, see matchers.rb

See the different uses of the matchers in matchers_spec.rb

Development & Test

Install Dip

Setup

dip provision

Run unit tests

dip rspec

Run pact tests

The Pact tests are not run within the general rspec pipeline, they need to be run separately, see below

Consumer tests

dip pact consumer
# or
bundle exec rspec -t pact spec/pact/providers/**/*_spec.rb

NOTE If you have never run it, you need to run it at least once to generate json-pact manifests that will be used in provider tests (below)

Provider tests

dip pact provider
# or
bundle exec rspec -t pact spec/pact/consumers/*_spec.rb

Using Pact Broker locally

If you need to check the ability to work with a package broker locally, you need to do the following:

$ dip up pact-broker
$ dip pact consumer
$ dip pact-cli publish
$ dip pact provider-with-local-broker