Skip to content

Commit

Permalink
feat: allow custom rack middleware to be specified
Browse files Browse the repository at this point in the history
  • Loading branch information
bethesque committed Sep 6, 2018
1 parent 217136d commit ef857d4
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 15 deletions.
22 changes: 16 additions & 6 deletions lib/pact/provider_verifier/app.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
require 'pact/provider_verifier/add_header_middlware'
require 'pact/provider_verifier/provider_states/add_provider_states_header'
require 'pact/provider_verifier/provider_states/remove_provider_states_header_middleware'
require 'pact/provider_verifier/custom_middleware'
require 'pact/provider/rspec'
require 'pact/message'
Expand Down Expand Up @@ -54,16 +56,17 @@ def set_environment_variables

def configure_service_provider
# Have to declare these locally as the class scope gets lost within the block
rack_reverse_proxy = configure_reverse_proxy
rack_reverse_proxy = configure_custom_header_middleware(rack_reverse_proxy)
rack_reverse_proxy = configure_custom_middlware(rack_reverse_proxy)
application = configure_reverse_proxy
application = configure_provider_states_header_removal_middleware(application)
application = configure_custom_middleware(application)
application = configure_custom_header_middleware(application)

provider_application_version = options.provider_app_version
publish_results = options.publish_verification_results

Pact.service_provider "Running Provider Application" do
app do
rack_reverse_proxy
application
end

if provider_application_version
Expand Down Expand Up @@ -94,7 +97,7 @@ def configure_custom_header_middleware rack_reverse_proxy
end
end

def configure_custom_middlware app
def configure_custom_middleware app
if options.custom_middleware && options.custom_middleware.any?
require_custom_middlware
apply_custom_middleware(app)
Expand All @@ -103,6 +106,10 @@ def configure_custom_middlware app
end
end

def configure_provider_states_header_removal_middleware app
ProviderStates::RemoveProviderStatesHeaderMiddleware.new(app)
end

def require_custom_middlware
options.custom_middleware.each do |file|
$stdout.puts "DEBUG: Requiring custom middleware file #{file}" if options.verbose
Expand Down Expand Up @@ -132,7 +139,8 @@ def verify_pact(config)
pact_broker_password: options.broker_password,
format: options.format,
out: options.out,
ignore_failures: config.pending
ignore_failures: config.pending,
request_customizer: ProviderStates::AddProviderStatesHeader
}
verify_options[:description] = ENV['PACT_DESCRIPTION'] if ENV['PACT_DESCRIPTION']
verify_options[:provider_state] = ENV['PACT_PROVIDER_STATE'] if ENV['PACT_PROVIDER_STATE']
Expand Down Expand Up @@ -191,3 +199,5 @@ def print_deprecation_note
end
end
end


10 changes: 10 additions & 0 deletions lib/pact/provider_verifier/custom_middleware.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require 'ostruct'

module Pact
module ProviderVerifier
class CustomMiddleware
Expand All @@ -18,6 +20,14 @@ def initialize app
def call env
raise NotImplementedError
end

def provider_states_from(env)
if env["X_PACT_PROVIDER_STATES"]
env["X_PACT_PROVIDER_STATES"].collect{ | provider_state| OpenStruct.new(provider_state) }
else
[]
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
require 'delegate'

module Pact
module ProviderVerifier
module ProviderStates
class RequestDelegate < SimpleDelegator
def initialize request, extra_rack_headers
super(request)
@extra_rack_headers = extra_rack_headers
end

def headers
__getobj__().headers.merge(@extra_rack_headers)
end

def method
__getobj__().method
end
end

class AddProviderStatesHeader

def self.call(request, interaction)
if interaction.provider_state
extra_rack_headers = {
"X_PACT_PROVIDER_STATES" => [{ "name" => interaction.provider_state }]
}
RequestDelegate.new(request, extra_rack_headers)
else
request
end
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module Pact
module ProviderVerifier
module ProviderStates
class RemoveProviderStatesHeaderMiddleware
def initialize app
@app = app
end

def call env
@app.call(remove_header(env))
end

def remove_header env
env.reject { | key, value | key == "X_PACT_PROVIDER_STATES" }
end
end
end
end
end
2 changes: 1 addition & 1 deletion pact-provider-verifier.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Gem::Specification.new do |gem|
gem.license = 'MIT'

gem.add_runtime_dependency 'rspec', '~> 3.5'
gem.add_runtime_dependency 'pact', '~>1.33', '>= 1.33.2'
gem.add_runtime_dependency 'pact', '~>1.34'
gem.add_runtime_dependency 'pact-message', '~>0.4', '>=0.4.1'
gem.add_runtime_dependency 'faraday', '~> 0.9', '>= 0.9.0'
gem.add_runtime_dependency 'faraday_middleware', '~> 0.10'
Expand Down
12 changes: 8 additions & 4 deletions spec/integration_with_custom_middleware_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@
sleep 2
end

context "with --custom-provider-header specified" do
context "with --custom-middleware specified" do

subject { `bundle exec bin/pact-provider-verifier spec/support/pacts/needs-custom-auth.json --custom-middleware #{Dir.pwd}/spec/support/custom_middleware.rb -a 1.0.100 --provider-base-url http://localhost:4570 2>&1` }
subject { `bundle exec bin/pact-provider-verifier spec/support/pacts/needs-custom-auth.json --custom-middleware #{Dir.pwd}/spec/support/custom_middleware.rb -a 1.0.100 --provider-base-url http://localhost:4570 -v 2>&1` }

it "exits with a 0 exit code" do

it "can modify the request" do
subject
puts subject
expect($?).to eq 0
end

it "can access the provider state information" do
expect(subject).to include "The provider state name is 'custom authorization is required'"
end

it "the output contains a success message" do
expect(subject).to include "0 failures"
end
Expand Down
33 changes: 30 additions & 3 deletions spec/lib/pact/provider_verifier/custom_middleware_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,39 @@ module ProviderVerifier
describe CustomMiddleware do
describe ".descendants" do

class TestMiddlware < Pact::ProviderVerifier::CustomMiddleware
class TestMiddleware < Pact::ProviderVerifier::CustomMiddleware

end

it "returns the TestMiddlware" do
expect(CustomMiddleware.descendants).to eq [TestMiddlware]
it "returns the TestMiddleware" do
expect(CustomMiddleware.descendants).to eq [TestMiddleware]
end
end

describe "#provider_states_from" do

subject { CustomMiddleware.new(nil).provider_states_from(env) }

context "when the X_PACT_PROVIDER_STATES header exists" do
let(:env) do
{
"X_PACT_PROVIDER_STATES" => [{
"name" => "foo"
}]
}
end

it "returns an array of provider states" do
expect(subject.first.name).to eq "foo"
end
end

context "when the X_PACT_PROVIDER_STATES header does not exist" do
let(:env) { {} }

it "returns an empty array" do
expect(subject).to eq []
end
end
end
end
Expand Down
4 changes: 3 additions & 1 deletion spec/support/custom_middleware.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
class AddCustomAuth < Pact::ProviderVerifier::CustomMiddleware

def initialize app
@app = app
end

def call env
env['HTTP_AUTHORIZATION'] = 'Basic cGFjdDpwYWN0'
provider_states = provider_states_from(env)
provider_state_name = provider_states.any? && provider_states.first.name
puts "The provider state name is '#{provider_state_name}'"
@app.call(env)
end
end
1 change: 1 addition & 0 deletions spec/support/pacts/needs-custom-auth.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
},
"interactions": [
{
"providerState": "custom authorization is required",
"description": "a request without any auth header",
"request": {
"method": "GET",
Expand Down

0 comments on commit ef857d4

Please sign in to comment.