diff --git a/README.md b/README.md index b6ec8072..2adcb446 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,32 @@ Description: ``` +### create-webhook + +``` +Usage: + pact-broker create-webhook URL --consumer=CONSUMER --provider=PROVIDER -X, --request=REQUEST -b, --broker-base-url=BROKER_BASE_URL + +Options: + -X, --request=REQUEST # HTTP method + -H, [--header=one two three] # Header + -d, [--data=DATA] # Data + -u, [--user=USER] # Basic auth username and password eg. username:password + --consumer=CONSUMER # Consumer name + --provider=PROVIDER # Provider name + -b, --broker-base-url=BROKER_BASE_URL # The base URL of the Pact Broker + -u, [--broker-username=BROKER_USERNAME] # Pact Broker basic auth username + -p, [--broker-password=BROKER_PASSWORD] # Pact Broker basic auth password + [--contract-content-changed], [--no-contract-content-changed] # Trigger this webhook when the pact content changes + [--provider-verification-published], [--no-provider-verification-published] # Trigger this webhook when a provider verification result is published + -v, [--verbose], [--no-verbose] # Verbose output. Default: false + +Description: + Create a curl command that executes the request that you want your webhook to execute, then replace "curl" with "pact-broker + create-webhook" and add the consumer, provider, event types and broker details. Note that the URL must be the first parameter + when executing create-webhook. +``` + ## Usage - Ruby ### Consumer diff --git a/doc/pacts/markdown/Pact Broker Client - Pact Broker.md b/doc/pacts/markdown/Pact Broker Client - Pact Broker.md index b5c47fde..6be11b73 100644 --- a/doc/pacts/markdown/Pact Broker Client - Pact Broker.md +++ b/doc/pacts/markdown/Pact Broker Client - Pact Broker.md @@ -32,6 +32,12 @@ * [A request retrieve a pact for a specific version](#a_request_retrieve_a_pact_for_a_specific_version_given_the_'Pricing_Service'_and_'Condor'_already_exist_in_the_pact-broker,_and_Condor_already_has_a_pact_published_for_version_1.3.0) given the 'Pricing Service' and 'Condor' already exist in the pact-broker, and Condor already has a pact published for version 1.3.0 +* [A request to create a webhook for a consumer and provider](#a_request_to_create_a_webhook_for_a_consumer_and_provider_given_'Condor'_does_not_exist_in_the_pact-broker) given 'Condor' does not exist in the pact-broker + +* [A request to create a webhook with a JSON body for a consumer and provider](#a_request_to_create_a_webhook_with_a_JSON_body_for_a_consumer_and_provider_given_the_'Pricing_Service'_and_'Condor'_already_exist_in_the_pact-broker) given the 'Pricing Service' and 'Condor' already exist in the pact-broker + +* [A request to create a webhook with a non-JSON body for a consumer and provider](#a_request_to_create_a_webhook_with_a_non-JSON_body_for_a_consumer_and_provider_given_the_'Pricing_Service'_and_'Condor'_already_exist_in_the_pact-broker) given the 'Pricing Service' and 'Condor' already exist in the pact-broker + * [A request to get the Pricing Service](#a_request_to_get_the_Pricing_Service_given_the_'Pricing_Service'_already_exists_in_the_pact-broker) given the 'Pricing Service' already exists in the pact-broker * [A request to get the Pricing Service](#a_request_to_get_the_Pricing_Service_given_the_'Pricing_Service'_does_not_exist_in_the_pact-broker) given the 'Pricing Service' does not exist in the pact-broker @@ -70,6 +76,8 @@ * [A request to tag the production version of Condor](#a_request_to_tag_the_production_version_of_Condor_given_'Condor'_exists_in_the_pact-broker) given 'Condor' exists in the pact-broker +* [An invalid request to create a webhook for a consumer and provider](#an_invalid_request_to_create_a_webhook_for_a_consumer_and_provider_given_the_'Pricing_Service'_and_'Condor'_already_exist_in_the_pact-broker) given the 'Pricing Service' and 'Condor' already exist in the pact-broker + #### Interactions @@ -640,6 +648,143 @@ Pact Broker will respond with: } } ``` + +Given **'Condor' does not exist in the pact-broker**, upon receiving **a request to create a webhook for a consumer and provider** from Pact Broker Client, with +```json +{ + "method": "post", + "path": "/webhooks/provider/Pricing%20Service/consumer/Condor", + "headers": { + "Content-Type": "application/json", + "Accept": "application/hal+json" + }, + "body": { + "events": [ + { + "name": "contract_content_changed" + } + ], + "request": { + "url": "https://webhook", + "method": "POST", + "headers": { + "Foo": "bar", + "Bar": "foo" + }, + "body": { + "some": "body" + }, + "username": "username", + "password": "password" + } + } +} +``` +Pact Broker will respond with: +```json +{ + "status": 404, + "headers": { + "Content-Type": "application/hal+json;charset=utf-8" + } +} +``` + +Given **the 'Pricing Service' and 'Condor' already exist in the pact-broker**, upon receiving **a request to create a webhook with a JSON body for a consumer and provider** from Pact Broker Client, with +```json +{ + "method": "post", + "path": "/webhooks/provider/Pricing%20Service/consumer/Condor", + "headers": { + "Content-Type": "application/json", + "Accept": "application/hal+json" + }, + "body": { + "events": [ + { + "name": "contract_content_changed" + } + ], + "request": { + "url": "https://webhook", + "method": "POST", + "headers": { + "Foo": "bar", + "Bar": "foo" + }, + "body": { + "some": "body" + }, + "username": "username", + "password": "password" + } + } +} +``` +Pact Broker will respond with: +```json +{ + "status": 201, + "headers": { + "Content-Type": "application/hal+json;charset=utf-8" + }, + "body": { + "_links": { + "self": { + "href": "http://localhost:1234/some-url", + "title": "A title" + } + } + } +} +``` + +Given **the 'Pricing Service' and 'Condor' already exist in the pact-broker**, upon receiving **a request to create a webhook with a non-JSON body for a consumer and provider** from Pact Broker Client, with +```json +{ + "method": "post", + "path": "/webhooks/provider/Pricing%20Service/consumer/Condor", + "headers": { + "Content-Type": "application/json", + "Accept": "application/hal+json" + }, + "body": { + "events": [ + { + "name": "contract_content_changed" + } + ], + "request": { + "url": "https://webhook", + "method": "POST", + "headers": { + "Foo": "bar", + "Bar": "foo" + }, + "body": "", + "username": "username", + "password": "password" + } + } +} +``` +Pact Broker will respond with: +```json +{ + "status": 201, + "headers": { + "Content-Type": "application/hal+json;charset=utf-8" + }, + "body": { + "_links": { + "self": { + "href": "http://localhost:1234/some-url", + "title": "A title" + } + } + } +} +``` Given **the 'Pricing Service' already exists in the pact-broker**, upon receiving **a request to get the Pricing Service** from Pact Broker Client, with ```json @@ -1247,3 +1392,51 @@ Pact Broker will respond with: } } ``` + +Given **the 'Pricing Service' and 'Condor' already exist in the pact-broker**, upon receiving **an invalid request to create a webhook for a consumer and provider** from Pact Broker Client, with +```json +{ + "method": "post", + "path": "/webhooks/provider/Pricing%20Service/consumer/Condor", + "headers": { + "Content-Type": "application/json", + "Accept": "application/hal+json" + }, + "body": { + "events": [ + { + "name": "contract_content_changed" + } + ], + "request": { + "url": null, + "method": "POST", + "headers": { + "Foo": "bar", + "Bar": "foo" + }, + "body": { + "some": "body" + }, + "username": "username", + "password": "password" + } + } +} +``` +Pact Broker will respond with: +```json +{ + "status": 400, + "headers": { + "Content-Type": "application/hal+json;charset=utf-8" + }, + "body": { + "errors": { + "request.url": [ + "Some error" + ] + } + } +} +``` diff --git a/lib/pact_broker/client/cli/broker.rb b/lib/pact_broker/client/cli/broker.rb index c5b731f0..e7dd5e0d 100644 --- a/lib/pact_broker/client/cli/broker.rb +++ b/lib/pact_broker/client/cli/broker.rb @@ -99,6 +99,63 @@ def describe_version exit(1) unless result.success end + method_option :request, aliases: "-X", desc: "HTTP method", required: true + method_option :header, aliases: "-H", type: :array, desc: "Header" + method_option :data, aliases: "-d", desc: "Data" + method_option :user, aliases: "-u", desc: "Basic auth username and password eg. username:password" + method_option :consumer, desc: "Consumer name", required: true + method_option :provider, desc: "Provider name", required: true + method_option :broker_base_url, required: true, aliases: "-b", desc: "The base URL of the Pact Broker" + method_option :broker_username, aliases: "-u", desc: "Pact Broker basic auth username" + method_option :broker_password, aliases: "-p", desc: "Pact Broker basic auth password" + method_option :contract_content_changed, type: :boolean, desc: "Trigger this webhook when the pact content changes" + method_option :provider_verification_published, type: :boolean, desc: "Trigger this webhook when a provider verification result is published" + method_option :verbose, aliases: "-v", type: :boolean, default: false, required: false, desc: "Verbose output. Default: false" + + desc 'create-webhook URL', 'Creates a webhook using the same switches as a curl request.' + long_desc File.read(File.join(File.dirname(__FILE__), 'create_webhook_long_desc.txt')) + def create_webhook webhook_url + require 'pact_broker/client/webhooks/create' + + if !(options.contract_content_changed || options.provider_verification_published) + raise PactBroker::Client::Error.new("You must select at least one of --contract-content-changed or --provider-verification-published") + end + + username = options.user ? options.user.split(":", 2).first : nil + password = options.user ? options.user.split(":", 2).last : nil + + headers = options.header.each_with_object({}) { | header, headers | headers[header.split(":", 2).first.strip] = header.split(":", 2).last.strip } + + body = options.data + if body.start_with?("@") + filepath = body[1..-1] + begin + body = File.read(filepath) + rescue StandardError => e + raise PactBroker::Client::Error.new("Couldn't read data from file \"#{filepath}\" due to #{e.class} #{e.message}") + end + end + + events = [] + events << 'contract_content_changed' if options.contract_content_changed + events << 'provider_verification_published' if options.provider_verification_published + + params = { + http_method: options.request, + url: webhook_url, + headers: headers, + username: username, + password: password, + body: body, + consumer: options.consumer, + provider: options.provider, + events: events + } + result = PactBroker::Client::Webhooks::Create.call(params, options.broker_base_url, pact_broker_client_options) + $stdout.puts result.message + exit(1) unless result.success + end + desc 'version', "Show the pact_broker-client gem version" def version $stdout.puts PactBroker::Client::VERSION diff --git a/lib/pact_broker/client/cli/create_webhook_long_desc.txt b/lib/pact_broker/client/cli/create_webhook_long_desc.txt new file mode 100644 index 00000000..9f8dac75 --- /dev/null +++ b/lib/pact_broker/client/cli/create_webhook_long_desc.txt @@ -0,0 +1 @@ +Create a curl command that executes the request that you want your webhook to execute, then replace "curl" with "pact-broker create-webhook" and add the consumer, provider, event types and broker details. Note that the URL must be the first parameter when executing create-webhook. diff --git a/lib/pact_broker/client/hal.rb b/lib/pact_broker/client/hal.rb new file mode 100644 index 00000000..0415b39f --- /dev/null +++ b/lib/pact_broker/client/hal.rb @@ -0,0 +1,3 @@ +require 'pact_broker/client/hal/link' +require 'pact_broker/client/hal/http_client' +require 'pact_broker/client/hal/entity' diff --git a/lib/pact_broker/client/webhooks/create.rb b/lib/pact_broker/client/webhooks/create.rb new file mode 100644 index 00000000..0f093453 --- /dev/null +++ b/lib/pact_broker/client/webhooks/create.rb @@ -0,0 +1,53 @@ +require 'uri' +require 'pact_broker/client/hal' +require 'ostruct' +require 'json' +require 'pact_broker/client/command_result' + +module PactBroker + module Client + module Webhooks + class Create + attr_reader :params, :pact_broker_base_url, :basic_auth_options, :verbose + + def self.call(params, pact_broker_base_url, pact_broker_client_options) + new(params, pact_broker_base_url, pact_broker_client_options).call + end + + def initialize(params, pact_broker_base_url, pact_broker_client_options) + @params = OpenStruct.new(params) + @pact_broker_base_url = pact_broker_base_url + @basic_auth_options = pact_broker_client_options[:basic_auth] || {} + @verbose = pact_broker_client_options[:verbose] + end + + def call + request_body = JSON.parse(params.body) rescue params.body + + body = { + events: params.events.collect{ | event | { "name" => event }}, + request: { + url: params.url, + method: params.http_method, + headers: params.headers, + body: request_body, + username: params.username, + password: params.password + } + } + + #TODO look for relation + create_webhook_url = "#{pact_broker_base_url.chomp("/")}/webhooks/provider/{provider}/consumer/{consumer}" + http_client = PactBroker::Client::Hal::HttpClient.new(basic_auth_options.merge(verbose: verbose)) + link = PactBroker::Client::Hal::Link.new({"href" => create_webhook_url}, http_client) + entity = link.expand(consumer: params.consumer, provider: params.provider).post(body) + if entity.success? + CommandResult.new(true, "Webhook #{entity._link('self').title_or_name.inspect} created") + else + CommandResult.new(false, "Error creating webhook. response status=#{entity.response.code} body=#{entity.response.body}") + end + end + end + end + end +end diff --git a/spec/lib/pact_broker/client/cli/broker_create_webhook_spec.rb b/spec/lib/pact_broker/client/cli/broker_create_webhook_spec.rb new file mode 100644 index 00000000..d8b7ddca --- /dev/null +++ b/spec/lib/pact_broker/client/cli/broker_create_webhook_spec.rb @@ -0,0 +1,155 @@ +require 'pact_broker/client/cli/broker' +require 'pact_broker/client/webhooks/create' + +module PactBroker + module Client + module CLI + describe Broker do + describe "create_webhook" do + before do + allow($stdout).to receive(:puts) + allow(PactBroker::Client::Webhooks::Create).to receive(:call).and_return(command_result) + broker.options = OpenStruct.new(options_hash) + end + + let(:broker) { Broker.new } + let(:data) { 'data' } + let(:user) { "username:password" } + let(:command_result) { double('command result', success: success, message: 'message') } + let(:success) { true } + + let(:options_hash) do + { + request: "POST", + header: ["Foo: bar", "Bar: foo"], + data: data, + user: user, + consumer: "consumer", + provider: "provider", + broker_base_url: "http://broker", + broker_username: "username", + broker_password: "password", + contract_content_changed: true, + verbose: true + } + end + + let(:expected_params) do + { + http_method: "POST", + url: "http://webhook", + headers: { "Foo" => "bar", "Bar" => "foo"}, + username: "username", + password: "password", + body: "data", + consumer: "consumer", + provider: "provider", + events: ["contract_content_changed"] + }.tap { |it| Pact::Fixture.add_fixture(:create_webhook_params, it) } + end + + subject { broker.create_webhook "http://webhook" } + + it "calls PactBroker::Client::Webhooks::Create with the webhook params" do + expect(PactBroker::Client::Webhooks::Create).to receive(:call) do | params, _, _ | + expect(params).to eq expected_params + command_result + end + subject + end + + it "calls PactBroker::Client::Webhooks::Create with pact broker details" do + expect(PactBroker::Client::Webhooks::Create).to receive(:call) do | _, broker_base_url, pact_broker_client_options | + expect(broker_base_url).to eq "http://broker" + expect(pact_broker_client_options).to eq(basic_auth: { username: "username", password: "password"}, verbose: true) + command_result + end + subject + end + + context "when neither event type is selected" do + before do + options_hash.delete(:contract_content_changed) + broker.options = OpenStruct.new(options_hash) + end + + it "raises an error" do + expect { subject }.to raise_error PactBroker::Client::Error, /You must select at least one/ + end + end + + context "with no basic auth" do + before do + options_hash.delete(:broker_username) + options_hash.delete(:broker_password) + broker.options = OpenStruct.new(options_hash) + end + + it "calls Webhooks::Create without basic auth" do + expect(PactBroker::Client::Webhooks::Create).to receive(:call) do | _, _, pact_broker_client_options | + expect(pact_broker_client_options).to eq(verbose: true) + command_result + end + subject + end + end + + context "when a file reference is passed for the data" do + before do + FileUtils.mkdir_p "tmp" + File.open("tmp/body.json", "w") { |file| file << "file" } + end + + let(:data) { "@tmp/body.json" } + + it "reads the file and passes it in to the Webhooks::Create call" do + expect(PactBroker::Client::Webhooks::Create).to receive(:call) do | params, _, _ | + expect(params[:body]).to eq "file" + command_result + end + subject + end + + context "when the file is not found" do + + let(:data) { "@doesnotexist.json" } + + it "raises a PactBroker::Client::Error" do + expect { subject }.to raise_error PactBroker::Client::Error, /Couldn't read data from file/ + end + end + + context "when successful" do + it "prints the message to stdout" do + expect($stdout).to receive(:puts).with('message') + subject + end + end + + context "when not successful" do + let(:success) { false } + + it "prints the message to stderr" do + expect($stdout).to receive(:puts).with('message') + begin + subject + rescue SystemExit + end + end + + it "exits with code 1" do + exited_with_error = false + begin + subject + rescue SystemExit + exited_with_error = true + end + expect(exited_with_error).to be true + end + end + end + end + end + end + end +end diff --git a/spec/pacts/pact_broker_client-pact_broker.json b/spec/pacts/pact_broker_client-pact_broker.json index 5e641699..f7846774 100644 --- a/spec/pacts/pact_broker_client-pact_broker.json +++ b/spec/pacts/pact_broker_client-pact_broker.json @@ -1243,6 +1243,205 @@ } } } + }, + { + "description": "a request to create a webhook with a JSON body for a consumer and provider", + "providerState": "the 'Pricing Service' and 'Condor' already exist in the pact-broker", + "request": { + "method": "post", + "path": "/webhooks/provider/Pricing%20Service/consumer/Condor", + "headers": { + "Content-Type": "application/json", + "Accept": "application/hal+json" + }, + "body": { + "events": [ + { + "name": "contract_content_changed" + } + ], + "request": { + "url": "https://webhook", + "method": "POST", + "headers": { + "Foo": "bar", + "Bar": "foo" + }, + "body": { + "some": "body" + }, + "username": "username", + "password": "password" + } + } + }, + "response": { + "status": 201, + "headers": { + "Content-Type": "application/hal+json;charset=utf-8" + }, + "body": { + "_links": { + "self": { + "href": "http://localhost:1234/some-url", + "title": "A title" + } + } + }, + "matchingRules": { + "$.body._links.self.href": { + "match": "regex", + "regex": "http:\\/\\/.*" + }, + "$.body._links.self.title": { + "match": "type" + } + } + } + }, + { + "description": "a request to create a webhook with a non-JSON body for a consumer and provider", + "providerState": "the 'Pricing Service' and 'Condor' already exist in the pact-broker", + "request": { + "method": "post", + "path": "/webhooks/provider/Pricing%20Service/consumer/Condor", + "headers": { + "Content-Type": "application/json", + "Accept": "application/hal+json" + }, + "body": { + "events": [ + { + "name": "contract_content_changed" + } + ], + "request": { + "url": "https://webhook", + "method": "POST", + "headers": { + "Foo": "bar", + "Bar": "foo" + }, + "body": "", + "username": "username", + "password": "password" + } + } + }, + "response": { + "status": 201, + "headers": { + "Content-Type": "application/hal+json;charset=utf-8" + }, + "body": { + "_links": { + "self": { + "href": "http://localhost:1234/some-url", + "title": "A title" + } + } + }, + "matchingRules": { + "$.body._links.self.href": { + "match": "regex", + "regex": "http:\\/\\/.*" + }, + "$.body._links.self.title": { + "match": "type" + } + } + } + }, + { + "description": "an invalid request to create a webhook for a consumer and provider", + "providerState": "the 'Pricing Service' and 'Condor' already exist in the pact-broker", + "request": { + "method": "post", + "path": "/webhooks/provider/Pricing%20Service/consumer/Condor", + "headers": { + "Content-Type": "application/json", + "Accept": "application/hal+json" + }, + "body": { + "events": [ + { + "name": "contract_content_changed" + } + ], + "request": { + "url": null, + "method": "POST", + "headers": { + "Foo": "bar", + "Bar": "foo" + }, + "body": { + "some": "body" + }, + "username": "username", + "password": "password" + } + } + }, + "response": { + "status": 400, + "headers": { + "Content-Type": "application/hal+json;charset=utf-8" + }, + "body": { + "errors": { + "request.url": [ + "Some error" + ] + } + }, + "matchingRules": { + "$.body.errors['request.url']": { + "min": 1 + }, + "$.body.errors['request.url'][*].*": { + "match": "type" + } + } + } + }, + { + "description": "a request to create a webhook for a consumer and provider", + "providerState": "'Condor' does not exist in the pact-broker", + "request": { + "method": "post", + "path": "/webhooks/provider/Pricing%20Service/consumer/Condor", + "headers": { + "Content-Type": "application/json", + "Accept": "application/hal+json" + }, + "body": { + "events": [ + { + "name": "contract_content_changed" + } + ], + "request": { + "url": "https://webhook", + "method": "POST", + "headers": { + "Foo": "bar", + "Bar": "foo" + }, + "body": { + "some": "body" + }, + "username": "username", + "password": "password" + } + } + }, + "response": { + "status": 404, + "headers": { + "Content-Type": "application/hal+json;charset=utf-8" + } + } } ], "metadata": { diff --git a/spec/service_providers/webhooks_create_spec.rb b/spec/service_providers/webhooks_create_spec.rb new file mode 100644 index 00000000..3309c669 --- /dev/null +++ b/spec/service_providers/webhooks_create_spec.rb @@ -0,0 +1,166 @@ +require_relative 'pact_helper' +require 'pact_broker/client/webhooks/create' + +RSpec.describe "creating a webhook", pact: true do + + include_context "pact broker" + + let(:params) do + { + http_method: "POST", + url: "https://webhook", + headers: { "Foo" => "bar", "Bar" => "foo"}, + username: "username", + password: "password", + body: body, + consumer: "Condor", + provider: "Pricing Service", + events: ["contract_content_changed"] + }.tap { |it| Pact::Fixture.add_fixture(:create_webhook_params, it) } + end + + let(:body) { { some: "body" }.to_json } + + let(:request_body) do + { + "events" => [ + { + "name" => "contract_content_changed" + } + ], + "request" => { + "url" => "https://webhook", + "method" => "POST", + "headers" => { + "Foo" => "bar", + "Bar" => "foo" + }, + "body" => { + "some" => "body" + }, + "username" => "username", + "password" => "password" + } + } + end + + let(:pact_broker_client_options) { {} } + + subject { PactBroker::Client::Webhooks::Create.call(params, broker_base_url, pact_broker_client_options) } + + context "when a valid webhook with a JSON body is submitted" do + before do + pact_broker + .given("the 'Pricing Service' and 'Condor' already exist in the pact-broker") + .upon_receiving("a request to create a webhook with a JSON body for a consumer and provider") + .with( + method: :post, + path: '/webhooks/provider/Pricing%20Service/consumer/Condor', + headers: post_request_headers, + body: request_body). + will_respond_with( + status: 201, + headers: pact_broker_response_headers, + body: { + _links: { + self: { + href: Pact.term('http://localhost:1234/some-url', %r{http://.*}), + title: Pact.like("A title") + } + } + } + ) + end + + it "returns a CommandResult with success = true" do + expect(subject).to be_a PactBroker::Client::CommandResult + expect(subject.success).to be true + end + end + + context "when a valid webhook with an XML body is submitted" do + before do + request_body["request"]["body"] = body + + pact_broker + .given("the 'Pricing Service' and 'Condor' already exist in the pact-broker") + .upon_receiving("a request to create a webhook with a non-JSON body for a consumer and provider") + .with( + method: :post, + path: '/webhooks/provider/Pricing%20Service/consumer/Condor', + headers: post_request_headers, + body: request_body). + will_respond_with( + status: 201, + headers: pact_broker_response_headers, + body: { + _links: { + self: { + href: Pact.term('http://localhost:1234/some-url', %r{http://.*}), + title: Pact.like("A title") + } + } + } + ) + end + + let(:body) { "" } + + it "returns a CommandResult with success = true" do + expect(subject.success).to be true + end + end + + context "when an invalid webhook is submitted" do + before do + params[:url] = nil + request_body["request"]["url"] = nil + + pact_broker + .given("the 'Pricing Service' and 'Condor' already exist in the pact-broker") + .upon_receiving("an invalid request to create a webhook for a consumer and provider") + .with( + method: :post, + path: '/webhooks/provider/Pricing%20Service/consumer/Condor', + headers: post_request_headers, + body: request_body). + will_respond_with( + status: 400, + headers: pact_broker_response_headers, + body: { + errors: { + "request.url" => Pact.each_like("Some error") + } + } + ) + end + + it "returns a CommandResult with success = false" do + expect(subject.success).to be false + expect(subject.message).to match /400/ + expect(subject.message).to match /Some error/ + end + end + + context "when one of the pacticipants does not exist" do + before do + pact_broker + .given("'Condor' does not exist in the pact-broker") + .upon_receiving("a request to create a webhook for a consumer and provider") + .with( + method: :post, + path: '/webhooks/provider/Pricing%20Service/consumer/Condor', + headers: post_request_headers, + body: request_body). + will_respond_with( + status: 404, + headers: pact_broker_response_headers + ) + end + + it "returns a CommandResult with success = false" do + expect(subject.success).to be false + expect(subject.message).to match /404/ + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4912a79d..47779572 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -12,5 +12,31 @@ ENV.delete('PACT_BROKER_BASE_URL') end + config.after(:all) do + Pact::Fixture.check_fixtures + end + config.filter_run_excluding :skip_windows => is_windows end + +module Pact + module Fixture + + def self.add_fixture key, value + fixtures[key] ||= [] + fixtures[key] << value + end + + def self.fixtures + @fixtures ||= {} + end + + def self.check_fixtures + fixtures.each do | fixture_group | + if fixture_group.size > 1 + #TODO compare fixtures to ensure they match + end + end + end + end +end diff --git a/spec/support/shared_context.rb b/spec/support/shared_context.rb index d01daea6..f1a6deae 100644 --- a/spec/support/shared_context.rb +++ b/spec/support/shared_context.rb @@ -5,7 +5,8 @@ let(:consumer_contract) { Pact::ConsumerContract.from_hash pact_hash } let(:pact_json) { pact_hash.to_json } let(:pact_broker_client) { PactBroker::Client::PactBrokerClient.new(client_config) } - let(:client_config) { { base_url: 'http://localhost:1234' } } + let(:broker_base_url) { 'http://localhost:1234' } + let(:client_config) { { base_url: broker_base_url } } let(:consumer_version) { '1.3.0' } let(:version) { '1.3.0' } let(:pact_broker_version) { Pact::Term.new(:matcher => /\d+\.\d+\.\d+/, :generate => '1.0.0') } @@ -13,6 +14,7 @@ let(:default_request_headers) { { 'Content-Type' => 'application/json'} } let(:patch_request_headers) { { 'Content-Type' => 'application/json'} } let(:put_request_headers) { { 'Content-Type' => 'application/json', 'Accept' => 'application/hal+json'} } + let(:post_request_headers) { { 'Content-Type' => 'application/json', 'Accept' => 'application/hal+json'} } let(:get_request_headers) { { 'Accept' => 'application/hal+json'} } end