Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
name: Test

on: [push, pull_request]
on:
pull_request:
push:
branches:
- master

jobs:
test:
Expand All @@ -16,13 +20,10 @@ jobs:
with:
ruby-version: ${{ matrix.ruby_version }}
- run: "bundle install"
env:
PACT_RUBY_V2_ENABLE: 'true'
- run: "bundle exec rake pact:spec"
- run: "bundle exec rake pact:v2:spec"
- run: cat spec/pacts/test_message_consumer-test_message_producer.json
- run: bundle exec rake pact:verify
shell: bash
if: matrix.os != 'windows-latest'
- run: bundle exec rake pact:v2:verify
if: matrix.os != 'windows-latest' # no kafka on windows
23 changes: 9 additions & 14 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,20 @@ group :development, :test do

gem 'rspec'

# gem 'pact'

gem 'pact-message'

gem 'rake'
if ENV['X_PACT_DEVELOPMENT']
if ENV['X_PACT_DEVELOPMENT'] == 'true'
gem 'pact', path: '../pact-ruby'
gem 'pact-ffi', path: '../pact-ffi'
else
gem 'pact', git: 'https://github.com/safdotdev/pact-ruby.git', branch: 'feat/pact-ruby-v2-conditional-install'
gem 'pact'
gem 'pact-ffi'
end
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw]
gem 'combustion'
# for pact/v2 with non rail apps
gem 'activesupport'
# gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw]
# gem 'combustion'
gem 'webmock'

end

# required to process messages in pact-ruby-v2
unless RUBY_PLATFORM =~ /win32|x64-mingw32|x64-mingw-ucrt/
gem "sbmt-kafka_consumer", ">= 2.0.1"
gem "sbmt-kafka_producer", ">= 1.0"
end
# gem "karafka-rdkafka", ">= 0.20.0"
end
6 changes: 3 additions & 3 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ ENV['PACT_RUBY_V1_ENABLE'] = 'true'

RSpec::Core::RakeTask.new('pact:v2:spec') do |task|
task.pattern = 'spec/pact/providers/**/*_spec.rb'
task.rspec_opts = ['-t pact_v2']
task.rspec_opts = ['-t pact_v2', '--require pact_v2_helper']
end
RSpec::Core::RakeTask.new('pact:spec') do |task|
task.pattern = 'spec/service_consumers/*_spec.rb'
task.pattern = 'spec/consumer_spec.rb'
task.rspec_opts = ['-t pact']
end

RSpec::Core::RakeTask.new('pact:v2:verify') do |task|
task.pattern = 'spec/pact/consumers/**/*_spec.rb'
task.rspec_opts = ['-t pact_v2']
task.rspec_opts = ['-t pact_v2', '--require pact_v2_helper']
end
17 changes: 17 additions & 0 deletions spec/pact/consumers/message_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

require 'pact/v2'
require 'pact/v2/rspec'
require_relative '../../../app/producers/test_message_producer'

RSpec.describe 'Test Message Provider', :pact_v2 do
message_pact_provider 'Test Message Producer', opts: {
pact_dir: File.expand_path('../../pacts', __dir__),
}

handle_message 'a customer created message' do |provider_state|
body = TestMessageProducer.new.publish_message
metadata = {}
[body, metadata]
end
end
67 changes: 67 additions & 0 deletions spec/pact/providers/TestMessageProvider/message_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
require 'pact/v2'
require 'pact/v2/rspec'
require_relative '../../../../app/consumers/test_message_consumer'

describe TestMessageConsumer, :pact_v2 do
has_message_pact_between 'Test Message Consumer', 'Test Message Provider', opts: {
pact_dir: File.expand_path('../../../pacts', __dir__),
}

subject(:consumer) { TestMessageConsumer.new }

describe 'Test Message Consumer' do
# Notice that the expected message payload has fields which are different to that of the actual producer.
# The TestMessageProducer actually sends a message with an additional 'title' field and a renamed 'surname' field.
# See app/producers/test_message_producer.rb.

# before do
# # Here we are calling test_message_producer, which is mocking the actual TestMessageProducer defined in app/producers/test_message_producer.rb.
# # In pact-message we use mocked providers in consumer side tests. These are defined in a similar way to mocked APIs/service providers in standard HTTP CDCT.
# # See spec/support/pact_spec_helper.rb.
# let(:expected_payload)
# {
# "email": match_type_of('jane@example.com'),
# "first_name": match_type_of('Jane')
# # "last_name": Pact.like("Doe") # uncomment to see failure in provider code
# }

# let(:interaction) do
# new_interaction.given('A customer is created')
# .upon_receiving('a customer created message')
# # .with_metadata()
# # .with_json_contents(match_type_of(expected_payload))
# .with_json_contents(expected_payload)
# end
# end

# This test is a bit redundant, it's essentially marking our own homework and will always pass.
# However IRL the consumer would probably be doing something more complex which we could assert on.
# See spec/pacts/test_message_consumer-test_message_producer.json for the generated contract file.
# Note that this contract does not match what the producer outputs in app/producers/test_message_producer.rb..
# If we were to run producer side verification on this contract, it should fail.
# This failure would indicate a mismatch between the consumers expectations of the message format and what the producer actually sends.

let(:expected_payload) do
{
"email": match_type_of('jane@example.com'),
"first_name": match_type_of('Jane')
# "last_name": Pact.like("Doe") # uncomment to see failure in provider code
}
end

let(:interaction) do
new_interaction.given('A customer is created')
.upon_receiving('a customer created message')
# .with_metadata()
# .with_json_contents(match_type_of(expected_payload))
.with_json_contents(expected_payload)
end

it 'Successfully consumes the message and creates a pact contract file' do
interaction.execute do |json_payload, _meta|
@message = consumer.consume_message(json_payload)
expect(@message).to eq(json_payload)
end
end
end
end
9 changes: 9 additions & 0 deletions spec/pact_v2_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

require 'pact/v2'
require 'pact/v2/rspec'
require 'webmock/rspec'
# for pact/v2 with non rail apps
require 'active_support/core_ext/object/deep_dup'
require 'active_support/core_ext/object/blank'
# https://guides.rubyonrails.org/active_support_core_extensions.html#stand-alone-active-support
66 changes: 66 additions & 0 deletions spec/pacts/Test Message Consumer-Test Message Provider.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"consumer": {
"name": "Test Message Consumer"
},
"interactions": [
{
"contents": {
"content": {
"email": "jane@example.com",
"first_name": "Jane"
},
"contentType": "application/json",
"encoded": false
},
"description": "a customer created message",
"matchingRules": {
"body": {
"$.email": {
"combine": "AND",
"matchers": [
{
"match": "type"
}
]
},
"$.first_name": {
"combine": "AND",
"matchers": [
{
"match": "type"
}
]
}
}
},
"metadata": {
"contentType": "application/json"
},
"pending": false,
"providerStates": [
{
"name": "A customer is created",
"params": {
"contentType": "application/json"
}
}
],
"type": "Asynchronous/Messages"
}
],
"metadata": {
"pact-ruby-v2": {
"pact-ffi": "0.4.28"
},
"pactRust": {
"ffi": "0.4.28",
"models": "1.3.5"
},
"pactSpecification": {
"version": "4.0"
}
},
"provider": {
"name": "Test Message Provider"
}
}
3 changes: 2 additions & 1 deletion spec/pacts/test_message_consumer-test_message_producer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"providerStates": [
{
"name": "A customer is created",
"params": {}
"params": {
}
}
],
"contents": {
Expand Down