Skip to content

Commit

Permalink
Merge pull request #320 from pact-foundation/feat/v3_generators
Browse files Browse the repository at this point in the history
Feat/v3 generators
  • Loading branch information
YOU54F authored Nov 29, 2024
2 parents de1f3c7 + 02f39f7 commit 83fee58
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 12 deletions.
15 changes: 10 additions & 5 deletions lib/pact/provider/request.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require 'json'
require 'pact/reification'
require 'pact/shared/null_expectation'
require 'pact/generators'

module Pact
module Provider
Expand All @@ -10,34 +11,38 @@ class Replayable
# See https://github.com/rack/rack/blob/e7d741c6282ca4cf4e01506f5681e6e6b14c0b32/SPEC#L87-89
NO_HTTP_PREFIX = ["CONTENT-TYPE", "CONTENT-LENGTH"]

def initialize expected_request
def initialize expected_request, state_params = nil
@expected_request = expected_request
@state_params = state_params
end

def method
expected_request.method
end

def path
expected_request.full_path
Pact::Generators.apply_generators(expected_request, "path", expected_request.full_path, @state_params)
end

def body
case expected_request.body
when String then expected_request.body
when NullExpectation then ''
else
reified_body
Pact::Generators.apply_generators(expected_request, "body", reified_body, @state_params)
end
end

def headers
request_headers = {}
return request_headers if expected_request.headers.is_a?(Pact::NullExpectation)

expected_request.headers.each do |key, value|
request_headers[rack_request_header_for(key)] = Pact::Reification.from_term(value)
request_headers[key] = Pact::Reification.from_term(value)
end
request_headers

request_headers = Pact::Generators.apply_generators(expected_request, "header", request_headers, @state_params)
request_headers.map{ |key,value| [rack_request_header_for(key), value]}.to_h
end

private
Expand Down
8 changes: 5 additions & 3 deletions lib/pact/provider/rspec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def honour_pactfile pact_source, pact_json, options
pact_uri = pact_source.uri
Pact.configuration.output_stream.puts "INFO: Reading pact at #{pact_uri}"
consumer_contract = Pact::ConsumerContract.from_json(pact_json)

suffix = pact_uri.metadata[:pending] ? " [PENDING]": ""
example_group_description = "Verifying a pact between #{consumer_contract.consumer.name} and #{consumer_contract.provider.name}#{suffix}"
example_group_metadata = { pactfile_uri: pact_uri, pact_criteria: options[:criteria] }
Expand Down Expand Up @@ -77,7 +78,6 @@ def describe_interaction_with_provider_state interaction, options
end

def describe_interaction interaction, options

# pact_uri and pact_interaction are used by
# Pact::Provider::RSpec::PactBrokerFormatter

Expand All @@ -103,8 +103,9 @@ def describe_interaction interaction, options
before do | example |
interaction_context.run_once :before do
Pact.configuration.logger.info "Running example '#{Pact::RSpec.full_description(example)}'"
set_up_provider_states interaction.provider_states, options[:consumer]
replay_interaction interaction, options[:request_customizer]
provider_states_result = set_up_provider_states interaction.provider_states, options[:consumer]
state_params = provider_states_result[interaction.provider_state];
replay_interaction interaction, options[:request_customizer], state_params
interaction_context.last_response = last_response
end
end
Expand All @@ -129,6 +130,7 @@ def describe_message expected_response, interaction_context
include Pact::RSpec::Matchers
extend Pact::Matchers::Messages


let(:expected_contents) { expected_response.body[:contents].as_json }
let(:response) { interaction_context.last_response }
let(:differ) { Pact.configuration.body_differ_for_content_type diff_content_type }
Expand Down
12 changes: 9 additions & 3 deletions lib/pact/provider/test_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ module TestMethods
include Pact::Logging
include Rack::Test::Methods

def replay_interaction interaction, request_customizer = nil
request = Request::Replayable.new(interaction.request)
def replay_interaction interaction, request_customizer = nil, state_params = nil
request = Request::Replayable.new(interaction.request, state_params)
request = request_customizer.call(request, interaction) if request_customizer
args = [request.path, request.body, request.headers]

Expand All @@ -42,11 +42,17 @@ def parse_body_from_response rack_response
end

def set_up_provider_states provider_states, consumer, options = {}
provider_states_result = {};
# If there are no provider state, execute with an nil state to ensure global and base states are executed
Pact.configuration.provider_state_set_up.call(nil, consumer, options) if provider_states.nil? || provider_states.empty?
provider_states.each do | provider_state |
Pact.configuration.provider_state_set_up.call(provider_state.name, consumer, options.merge(params: provider_state.params))
result = Pact.configuration.provider_state_set_up.call(provider_state.name, consumer, options.merge(params: provider_state.params))
if result.is_a?(Hash)
provider_states_result[provider_state.name] = result
end
end

provider_states_result
end

def tear_down_provider_states provider_states, consumer, options = {}
Expand Down
4 changes: 3 additions & 1 deletion pact.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ Gem::Specification.new do |gem|
gem.add_runtime_dependency 'rack-test', '>= 0.6.3', '< 3.0.0'
gem.add_runtime_dependency 'thor', '>= 0.20', '< 2.0'
gem.add_runtime_dependency "rainbow", '~> 3.1'
gem.add_runtime_dependency 'string_pattern', '~> 2.0'
gem.add_runtime_dependency 'jsonpath', '~> 1.0'

gem.add_runtime_dependency 'pact-support', '~> 1.16', '>= 1.16.9'
gem.add_runtime_dependency 'pact-support', '~> 1.19', '>= 1.19.0'
gem.add_runtime_dependency 'pact-mock_service', '~> 3.0', '>= 3.3.1'

gem.add_development_dependency 'rake', '~> 13.0'
Expand Down
68 changes: 68 additions & 0 deletions spec/lib/pact/provider/generators_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
require 'pact/generators'
require 'pact/provider/request'

describe Pact::Generators do
it 'apply_generators for path' do
expected_request = Pact::Request::Expected.from_hash({
method: 'GET',
path: '/path/1',
generators: {
'path' => {
'type' => 'ProviderState',
'expression' => '/path/${itemID}'
}
}
})
state_params = {
'itemID' => 2
}
request = Pact::Provider::Request::Replayable.new(expected_request, state_params)
expect(request.path).to eq('/path/2')
end

it 'apply_generators for headers' do
expected_request = Pact::Request::Expected.from_hash({
method: 'GET',
path: '/path/1',
headers: {
'Authorization' => 'Bearer 123'
},
generators: {
'header' => {
'$.Authorization' => {
'expression' => 'Bearer ${accessToken}',
'type' => 'ProviderState'
}
}
}
})
state_params = {
'accessToken' => 'ABC'
}
request = Pact::Provider::Request::Replayable.new(expected_request, state_params)
expect(request.headers).to eq({
'HTTP_AUTHORIZATION' => 'Bearer ABC'
})
end

it 'apply_generators for body' do
expected_request = Pact::Request::Expected.from_hash({
method: 'GET',
path: '/path/1',
body: {
'result' => [
'12345F'
]
},
generators: {
'body' => {
'$.result[0]' => {
'type' => 'RandomHexadecimal'
}
}
}
})
request = Pact::Provider::Request::Replayable.new(expected_request)
expect(request.body['result'][0].length).to eq(8)
end
end

0 comments on commit 83fee58

Please sign in to comment.