diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 48a292f..95061de 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -47,6 +47,23 @@ jobs:
PACT_BROKER_TOKEN_PACT_FOUNDATION: ${{ secrets.PACT_BROKER_TOKEN_PACT_FOUNDATION }}
PACT_BROKER_FEATURES: ${{ matrix.feature }}
TEST_FEATURE: ${{ matrix.feature }}
+ pact-v2:
+ runs-on: "ubuntu-latest"
+ continue-on-error: true
+ strategy:
+ fail-fast: false
+ matrix:
+ feature: [""]
+ steps:
+ - uses: actions/checkout@v4
+ - uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: "3.4"
+ - run: "bundle install"
+ - name: Generate and publish pacts
+ run: |
+ rm -rf spec/pacts/*
+ bundle exec rake pact:v2:spec
can-i-deploy:
runs-on: "ubuntu-latest"
needs: pact
diff --git a/Gemfile b/Gemfile
index c0d08e4..6b5cefe 100644
--- a/Gemfile
+++ b/Gemfile
@@ -15,15 +15,24 @@ group :development do
gem 'fakefs', '~> 3.0'
gem 'webmock', '~> 3.0'
gem 'conventional-changelog', '~>1.3'
- gem 'pact', '~> 1.16'
gem 'pact-support', '~> 1.16'
gem 'approvals', '0.1.7'
gem 'rspec-its', '~> 2.0'
gem 'pry-byebug'
+
+ if ENV['X_PACT_DEVELOPMENT'] == 'true'
+ gem 'pact', path: '../pact-ruby'
+ gem 'pact-ffi', path: '../pact-ffi'
+ else
+ gem 'pact'
+ gem 'pact-ffi'
+ end
+ # for pact/v2 with non rail apps
+ gem 'activesupport'
end
group :test do
gem 'faraday', '~>2.0'
gem 'faraday-retry', '~>2.0'
- gem 'rackup', '~> 2.1'
+ gem 'rack', '~> 2.1'
end
diff --git a/Rakefile b/Rakefile
index d9b0374..8460925 100644
--- a/Rakefile
+++ b/Rakefile
@@ -38,3 +38,8 @@ task 'pact:list_provider_states' do
JSON.parse(File.read(pact_file))['interactions'].collect{ | interaction| interaction['providerState'] }
}.flatten.compact.sort.uniq
end
+
+RSpec::Core::RakeTask.new('pact:v2:spec') do |task|
+ task.pattern = 'spec/pact/providers/**/*_spec.rb'
+ task.rspec_opts = ['-t pact']
+end
\ No newline at end of file
diff --git a/doc/pacts/markdown/Pact Broker Client - Pact Broker.md b/doc/pacts/markdown/Pact Broker Client - Pact Broker.md
index 8fe63a3..e285a5c 100644
--- a/doc/pacts/markdown/Pact Broker Client - Pact Broker.md
+++ b/doc/pacts/markdown/Pact Broker Client - Pact Broker.md
@@ -94,16 +94,6 @@
* [A request to mark a deployed version as not currently deploye](#a_request_to_mark_a_deployed_version_as_not_currently_deploye_given_a_currently_deployed_version_exists) given a currently deployed version exists
-* [A request to publish a pact](#a_request_to_publish_a_pact_given_'Condor'_already_exist_in_the_pact-broker,_but_the_'Pricing_Service'_does_not) given 'Condor' already exist in the pact-broker, but the 'Pricing Service' does not
-
-* [A request to publish a pact](#a_request_to_publish_a_pact_given_the_'Pricing_Service'_already_exists_in_the_pact-broker) given the 'Pricing Service' already exists in the pact-broker
-
-* [A request to publish a pact](#a_request_to_publish_a_pact_given_an_error_occurs_while_publishing_a_pact) given an error occurs while publishing a pact
-
-* [A request to publish a pact with method patch](#a_request_to_publish_a_pact_with_method_patch_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 publish a pact with method put](#a_request_to_publish_a_pact_with_method_put_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 publish contracts](#a_request_to_publish_contracts)
* [A request to record a deployment](#a_request_to_record_a_deployment_given_version_5556b8149bf8bac76bc30f50a8a2dd4c22c85f30_of_pacticipant_Foo_exists_with_a_test_environment_available_for_deployment) given version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for deployment
@@ -1077,8 +1067,7 @@ Pact Broker will respond with:
"name": "Pricing Service"
},
"interactions": [
-
- ]
+ ]
}
}
```
@@ -2118,194 +2107,6 @@ Pact Broker will respond with:
}
}
```
-
-Given **'Condor' already exist in the pact-broker, but the 'Pricing Service' does not**, upon receiving **a request to publish a pact** from Pact Broker Client, with
-```json
-{
- "method": "put",
- "path": "/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0",
- "headers": {
- "Content-Type": "application/json"
- },
- "body": {
- "consumer": {
- "name": "Condor"
- },
- "provider": {
- "name": "Pricing Service"
- },
- "interactions": [
-
- ]
- }
-}
-```
-Pact Broker will respond with:
-```json
-{
- "status": 201,
- "headers": {
- "Content-Type": "application/hal+json;charset=utf-8"
- },
- "body": {
- "_links": {
- "pb:latest-pact-version": {
- "href": "http://example.org/pacts/provider/Pricing%20Service/consumer/Condor/latest"
- }
- }
- }
-}
-```
-
-Given **the 'Pricing Service' already exists in the pact-broker**, upon receiving **a request to publish a pact** from Pact Broker Client, with
-```json
-{
- "method": "put",
- "path": "/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0",
- "headers": {
- "Content-Type": "application/json"
- },
- "body": {
- "consumer": {
- "name": "Condor"
- },
- "provider": {
- "name": "Pricing Service"
- },
- "interactions": [
-
- ]
- }
-}
-```
-Pact Broker will respond with:
-```json
-{
- "status": 201,
- "headers": {
- "Content-Type": "application/hal+json;charset=utf-8"
- },
- "body": {
- "_links": {
- "pb:latest-pact-version": {
- "href": "http://example.org/pacts/provider/Pricing%20Service/consumer/Condor/latest"
- }
- }
- }
-}
-```
-
-Given **an error occurs while publishing a pact**, upon receiving **a request to publish a pact** from Pact Broker Client, with
-```json
-{
- "method": "put",
- "path": "/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0",
- "headers": {
- "Content-Type": "application/json"
- },
- "body": {
- "consumer": {
- "name": "Condor"
- },
- "provider": {
- "name": "Pricing Service"
- },
- "interactions": [
-
- ]
- }
-}
-```
-Pact Broker will respond with:
-```json
-{
- "status": 500,
- "headers": {
- "Content-Type": "application/hal+json"
- },
- "body": {
- "error": {
- "message": "An error occurred"
- }
- }
-}
-```
-
-Given **the 'Pricing Service' and 'Condor' already exist in the pact-broker, and Condor already has a pact published for version 1.3.0**, upon receiving **a request to publish a pact with method patch** from Pact Broker Client, with
-```json
-{
- "method": "patch",
- "path": "/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0",
- "headers": {
- "Content-Type": "application/json"
- },
- "body": {
- "consumer": {
- "name": "Condor"
- },
- "provider": {
- "name": "Pricing Service"
- },
- "interactions": [
-
- ]
- }
-}
-```
-Pact Broker will respond with:
-```json
-{
- "status": 200,
- "headers": {
- "Content-Type": "application/hal+json;charset=utf-8"
- },
- "body": {
- "_links": {
- "pb:latest-pact-version": {
- "href": "http://example.org/pacts/provider/Pricing%20Service/consumer/Condor/latest"
- }
- }
- }
-}
-```
-
-Given **the 'Pricing Service' and 'Condor' already exist in the pact-broker, and Condor already has a pact published for version 1.3.0**, upon receiving **a request to publish a pact with method put** from Pact Broker Client, with
-```json
-{
- "method": "put",
- "path": "/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0",
- "headers": {
- "Content-Type": "application/json"
- },
- "body": {
- "consumer": {
- "name": "Condor"
- },
- "provider": {
- "name": "Pricing Service"
- },
- "interactions": [
-
- ]
- }
-}
-```
-Pact Broker will respond with:
-```json
-{
- "status": 200,
- "headers": {
- "Content-Type": "application/hal+json;charset=utf-8"
- },
- "body": {
- "_links": {
- "pb:latest-pact-version": {
- "href": "http://example.org/pacts/provider/Pricing%20Service/consumer/Condor/latest"
- }
- }
- }
-}
-```
Upon receiving **a request to publish contracts** from Pact Broker Client, with
```json
@@ -2411,7 +2212,9 @@ Given **version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exis
"headers": {
"Content-Type": "application/json",
"Accept": "application/hal+json"
- }
+ },
+ "body": {
+ }
}
```
Pact Broker will respond with:
@@ -2565,8 +2368,7 @@ Pact Broker will respond with:
"name": "Pricing Service"
},
"interactions": [
-
- ]
+ ]
}
}
```
@@ -2638,8 +2440,7 @@ Pact Broker will respond with:
"name": "Pricing Service"
},
"interactions": [
-
- ]
+ ]
}
}
```
@@ -2651,7 +2452,9 @@ Given **'Condor' exists in the pact-broker with version 1.3.0, tagged with 'prod
"path": "/pacticipants/Condor/versions/1.3.0/tags/prod",
"headers": {
"Content-Type": "application/json"
- }
+ },
+ "body": {
+ }
}
```
Pact Broker will respond with:
@@ -2678,7 +2481,9 @@ Given **'Condor' does not exist in the pact-broker**, upon receiving **a request
"path": "/pacticipants/Condor/versions/1.3.0/tags/prod",
"headers": {
"Content-Type": "application/json"
- }
+ },
+ "body": {
+ }
}
```
Pact Broker will respond with:
@@ -2705,7 +2510,9 @@ Given **'Condor' exists in the pact-broker**, upon receiving **a request to tag
"path": "/pacticipants/Condor/versions/1.3.0/tags/prod",
"headers": {
"Content-Type": "application/json"
- }
+ },
+ "body": {
+ }
}
```
Pact Broker will respond with:
diff --git a/doc/pacts/markdown/Pact Broker Client - PactFlow.md b/doc/pacts/markdown/Pact Broker Client - PactFlow.md
index 63990b2..089957b 100644
--- a/doc/pacts/markdown/Pact Broker Client - PactFlow.md
+++ b/doc/pacts/markdown/Pact Broker Client - PactFlow.md
@@ -260,7 +260,7 @@ PactFlow will respond with:
}
],
"pb:branch-version": {
- }
+ }
}
}
}
diff --git a/doc/pacts/markdown/Pact Broker Client V2 - Pact Broker.md b/doc/pacts/markdown/Pact Broker Client V2 - Pact Broker.md
new file mode 100644
index 0000000..7ff6345
--- /dev/null
+++ b/doc/pacts/markdown/Pact Broker Client V2 - Pact Broker.md
@@ -0,0 +1,2799 @@
+### A pact between Pact Broker Client V2 and Pact Broker
+
+#### Requests from Pact Broker Client V2 to Pact Broker
+
+* [A request for a pacticipant version](#a_request_for_a_pacticipant_version_given_version_5556b8149bf8bac76bc30f50a8a2dd4c22c85f30_of_pacticipant_Foo_exists_with_2_environments_that_aren't_test_available_for_deployment) given version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with 2 environments that aren't test available for deployment
+
+* [A request for a pacticipant version](#a_request_for_a_pacticipant_version_given_version_5556b8149bf8bac76bc30f50a8a2dd4c22c85f30_of_pacticipant_Foo_exists_with_a_test_environment_available_for_deployment) given version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for deployment
+
+* [A request for a pacticipant version](#a_request_for_a_pacticipant_version_given_version_5556b8149bf8bac76bc30f50a8a2dd4c22c85f30_of_pacticipant_Foo_exists_with_a_test_environment_available_for_release) given version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for release
+
+* [A request for an environment](#a_request_for_an_environment_given_an_environment_with_name_test_and_UUID_16926ef3-590f-4e3f-838e-719717aa88c9_exists) given an environment with name test and UUID 16926ef3-590f-4e3f-838e-719717aa88c9 exists
+
+* [A request for the compatibility matrix for a pacticipant that does not exist](#a_request_for_the_compatibility_matrix_for_a_pacticipant_that_does_not_exist)
+
+* [A request for the compatibility matrix for all versions of Foo and Bar](#a_request_for_the_compatibility_matrix_for_all_versions_of_Foo_and_Bar_given_the_pact_for_Foo_version_1.2.3_and_1.2.4_has_been_verified_by_Bar_version_4.5.6) given the pact for Foo version 1.2.3 and 1.2.4 has been verified by Bar version 4.5.6
+
+* [A request for the compatibility matrix for Foo version 1.2.3 and Bar version 4.5.6](#a_request_for_the_compatibility_matrix_for_Foo_version_1.2.3_and_Bar_version_4.5.6_given_the_pact_for_Foo_Thing_version_1.2.3_has_been_verified_by_Bar_version_4.5.6) given the pact for Foo Thing version 1.2.3 has been verified by Bar version 4.5.6
+
+* [A request for the compatibility matrix for Foo version 1.2.3 and Bar version 4.5.6](#a_request_for_the_compatibility_matrix_for_Foo_version_1.2.3_and_Bar_version_4.5.6_given_the_pact_for_Foo_version_1.2.3_has_been_verified_by_Bar_version_4.5.6) given the pact for Foo version 1.2.3 has been verified by Bar version 4.5.6
+
+* [A request for the compatibility matrix for Foo version 1.2.3 and the latest prod version of Bar](#a_request_for_the_compatibility_matrix_for_Foo_version_1.2.3_and_the_latest_prod_version_of_Bar_given_the_pact_for_Foo_version_1.2.3_has_been_successfully_verified_by_Bar_version_4.5.6_with_tag_prod,_and_1.2.4_unsuccessfully_by_9.9.9) given the pact for Foo version 1.2.3 has been successfully verified by Bar version 4.5.6 with tag prod, and 1.2.4 unsuccessfully by 9.9.9
+
+* [A request for the compatibility matrix for Foo version 1.2.3 and the latest prod versions of all other pacticipants](#a_request_for_the_compatibility_matrix_for_Foo_version_1.2.3_and_the_latest_prod_versions_of_all_other_pacticipants_given_the_pact_for_Foo_version_1.2.3_has_been_successfully_verified_by_Bar_version_4.5.6_(tagged_prod)_and_version_5.6.7) given the pact for Foo version 1.2.3 has been successfully verified by Bar version 4.5.6 (tagged prod) and version 5.6.7
+
+* [A request for the compatibility matrix for Foo version 1.2.3 and the latest version of Bar](#a_request_for_the_compatibility_matrix_for_Foo_version_1.2.3_and_the_latest_version_of_Bar_given_the_pact_for_Foo_version_1.2.3_has_been_successfully_verified_by_Bar_version_4.5.6,_and_1.2.4_unsuccessfully_by_9.9.9) given the pact for Foo version 1.2.3 has been successfully verified by Bar version 4.5.6, and 1.2.4 unsuccessfully by 9.9.9
+
+* [A request for the compatibility matrix where one or more versions does not exist](#a_request_for_the_compatibility_matrix_where_one_or_more_versions_does_not_exist_given_the_pact_for_Foo_version_1.2.3_has_been_verified_by_Bar_version_4.5.6) given the pact for Foo version 1.2.3 has been verified by Bar version 4.5.6
+
+* [A request for the compatibility matrix where only the version of Foo is specified](#a_request_for_the_compatibility_matrix_where_only_the_version_of_Foo_is_specified_given_the_pact_for_Foo_version_1.2.3_has_been_verified_by_Bar_version_4.5.6_and_version_5.6.7) given the pact for Foo version 1.2.3 has been verified by Bar version 4.5.6 and version 5.6.7
+
+* [A request for the environments](#a_request_for_the_environments_given_an_environment_with_name_test_exists) given an environment with name test exists
+
+* [A request for the index resource](#a_request_for_the_index_resource)
+
+* [A request for the index resource](#a_request_for_the_index_resource_given_the_pacticipant_relations_are_present) given the pacticipant relations are present
+
+* [A request for the index resource](#a_request_for_the_index_resource_given_the_pb:environments_relation_exists_in_the_index_resource) given the pb:environments relation exists in the index resource
+
+* [A request for the index resource](#a_request_for_the_index_resource_given_the_pb:latest-tagged-version_relation_exists_in_the_index_resource) given the pb:latest-tagged-version relation exists in the index resource
+
+* [A request for the index resource](#a_request_for_the_index_resource_given_the_pb:latest-version_relation_exists_in_the_index_resource) given the pb:latest-version relation exists in the index resource
+
+* [A request for the index resource](#a_request_for_the_index_resource_given_the_pb:pacticipant-branch_relation_exists_in_the_index_resource) given the pb:pacticipant-branch relation exists in the index resource
+
+* [A request for the index resource](#a_request_for_the_index_resource_given_the_pb:pacticipant-version_and_pb:environments_relations_exist_in_the_index_resource) given the pb:pacticipant-version and pb:environments relations exist in the index resource
+
+* [A request for the index resource](#a_request_for_the_index_resource_given_the_pb:publish-contracts_relations_exists_in_the_index_resource) given the pb:publish-contracts relations exists in the index resource
+
+* [A request for the index resource with the webhook relation](#a_request_for_the_index_resource_with_the_webhook_relation)
+
+* [A request for the list of the latest pacts from all consumers for the Pricing Service'](#a_request_for_the_list_of_the_latest_pacts_from_all_consumers_for_the_Pricing_Service'_given_a_latest_pact_between_Condor_and_the_Pricing_Service_exists) given a latest pact between Condor and the Pricing Service exists
+
+* [A request for the list of the latest prod pacts from all consumers for the Pricing Service'](#a_request_for_the_list_of_the_latest_prod_pacts_from_all_consumers_for_the_Pricing_Service'_given_tagged_as_prod_pact_between_Condor_and_the_Pricing_Service_exists) given tagged as prod pact between Condor and the Pricing Service exists
+
+* [A request for the successful rows of the compatibility matrix for all versions of Foo and Bar](#a_request_for_the_successful_rows_of_the_compatibility_matrix_for_all_versions_of_Foo_and_Bar_given_the_pact_for_Foo_version_1.2.3_has_been_successfully_verified_by_Bar_version_4.5.6,_and_1.2.4_unsuccessfully_by_9.9.9) given the pact for Foo version 1.2.3 has been successfully verified by Bar version 4.5.6, and 1.2.4 unsuccessfully by 9.9.9
+
+* [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 global webhook with a JSON body](#a_request_to_create_a_global_webhook_with_a_JSON_body)
+
+* [A request to create a pacticipant](#a_request_to_create_a_pacticipant)
+
+* [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 and a uuid](#a_request_to_create_a_webhook_with_a_JSON_body_and_a_uuid_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 JSON body for a consumer](#a_request_to_create_a_webhook_with_a_JSON_body_for_a_consumer_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 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 JSON body for a consumer specified by a label](#a_request_to_create_a_webhook_with_a_JSON_body_for_a_consumer_specified_by_a_label)
+
+* [A request to create a webhook with a JSON body for a consumer that does not exist](#a_request_to_create_a_webhook_with_a_JSON_body_for_a_consumer_that_does_not_exist)
+
+* [A request to create a webhook with a JSON body for a provider](#a_request_to_create_a_webhook_with_a_JSON_body_for_a_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 JSON body for a provider specified by a label](#a_request_to_create_a_webhook_with_a_JSON_body_for_a_provider_specified_by_a_label)
+
+* [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 create a webhook with every possible event type](#a_request_to_create_a_webhook_with_every_possible_event_type_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 an environment](#a_request_to_create_an_environment)
+
+* [A request to delete a pacticipant branch](#a_request_to_delete_a_pacticipant_branch_given_a_branch_named_main_exists_for_pacticipant_Foo) given a branch named main exists for pacticipant Foo
+
+* [A request to determine if Bar can be deployed with all Foo tagged prod, ignoring the verification for Foo version 3.4.5](#a_request_to_determine_if_Bar_can_be_deployed_with_all_Foo_tagged_prod,_ignoring_the_verification_for_Foo_version_3.4.5_given_provider_Bar_version_4.5.6_has_a_successful_verification_for_Foo_version_1.2.3_tagged_prod_and_a_failed_verification_for_version_3.4.5_tagged_prod) given provider Bar version 4.5.6 has a successful verification for Foo version 1.2.3 tagged prod and a failed verification for version 3.4.5 tagged prod
+
+* [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
+
+* [A request to list pacticipants](#a_request_to_list_pacticipants_given_'Condor'_exists_in_the_pact-broker) given 'Condor' exists in the pact-broker
+
+* [A request to list the environments](#a_request_to_list_the_environments_given_an_environment_exists) given an environment exists
+
+* [A request to list the latest pacts](#a_request_to_list_the_latest_pacts_given_a_pact_between_Condor_and_the_Pricing_Service_exists) given a pact between Condor and the Pricing Service exists
+
+* [A request to list the versions deployed to an environment for a pacticipant name and application instance](#a_request_to_list_the_versions_deployed_to_an_environment_for_a_pacticipant_name_and_application_instance_given_an_version_is_deployed_to_environment_with_UUID_16926ef3-590f-4e3f-838e-719717aa88c9_with_target_customer-1) given an version is deployed to environment with UUID 16926ef3-590f-4e3f-838e-719717aa88c9 with target customer-1
+
+* [A request to mark a deployed version as not currently deploye](#a_request_to_mark_a_deployed_version_as_not_currently_deploye_given_a_currently_deployed_version_exists) given a currently deployed version exists
+
+* [A request to publish contracts](#a_request_to_publish_contracts)
+
+* [A request to record a deployment](#a_request_to_record_a_deployment_given_version_5556b8149bf8bac76bc30f50a8a2dd4c22c85f30_of_pacticipant_Foo_exists_with_a_test_environment_available_for_deployment) given version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for deployment
+
+* [A request to record a release](#a_request_to_record_a_release_given_version_5556b8149bf8bac76bc30f50a8a2dd4c22c85f30_of_pacticipant_Foo_exists_with_a_test_environment_available_for_deployment) given version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for deployment
+
+* [A request to register the repository URL of a pacticipant](#a_request_to_register_the_repository_URL_of_a_pacticipant_given_the_'Pricing_Service'_already_exists_in_the_pact-broker) given the 'Pricing Service' already exists in the pact-broker
+
+* [A request to register the repository URL of a pacticipant](#a_request_to_register_the_repository_URL_of_a_pacticipant_given_the_'Pricing_Service'_does_not_exist_in_the_pact-broker) given the 'Pricing Service' does not exist in the pact-broker
+
+* [A request to retrieve a pacticipant](#a_request_to_retrieve_a_pacticipant_given_a_pacticipant_with_name_Foo_exists) given a pacticipant with name Foo exists
+
+* [A request to retrieve a pacticipant](#a_request_to_retrieve_a_pacticipant)
+
+* [A request to retrieve the latest 'production' version of Condor](#a_request_to_retrieve_the_latest_'production'_version_of_Condor_given_'Condor'_exists_in_the_pact-broker_with_the_latest_tagged_'production'_version_1.2.3) given 'Condor' exists in the pact-broker with the latest tagged 'production' version 1.2.3
+
+* [A request to retrieve the latest pact between Condor and the Pricing Service](#a_request_to_retrieve_the_latest_pact_between_Condor_and_the_Pricing_Service_given_a_pact_between_Condor_and_the_Pricing_Service_exists) given a pact between Condor and the Pricing Service exists
+
+* [A request to retrieve the latest pact between Condor and the Pricing Service](#a_request_to_retrieve_the_latest_pact_between_Condor_and_the_Pricing_Service_given_no_pact_between_Condor_and_the_Pricing_Service_exists) given no pact between Condor and the Pricing Service exists
+
+* [A request to retrieve the latest version of Condor](#a_request_to_retrieve_the_latest_version_of_Condor_given_'Condor'_exists_in_the_pact-broker_with_the_latest_version_1.2.3) given 'Condor' exists in the pact-broker with the latest version 1.2.3
+
+* [A request to retrieve the pact between the production verison of Condor and the Pricing Service](#a_request_to_retrieve_the_pact_between_the_production_verison_of_Condor_and_the_Pricing_Service_given_a_pact_between_Condor_and_the_Pricing_Service_exists_for_the_production_version_of_Condor) given a pact between Condor and the Pricing Service exists for the production version of Condor
+
+* [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_with_version_1.3.0,_tagged_with_'prod') given 'Condor' exists in the pact-broker with version 1.3.0, tagged with 'prod'
+
+* [A request to tag the production version of Condor](#a_request_to_tag_the_production_version_of_Condor_given_'Condor'_does_not_exist_in_the_pact-broker) given 'Condor' does not exist in the pact-broker
+
+* [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
+
+* [A request to update a pacticipant](#a_request_to_update_a_pacticipant_given_a_pacticipant_with_name_Foo_exists) given a pacticipant with name Foo exists
+
+* [A request to update a webhook](#a_request_to_update_a_webhook_given_a_webhook_with_the_uuid_696c5f93-1b7f-44bc-8d03-59440fcaa9a0_exists) given a webhook with the uuid 696c5f93-1b7f-44bc-8d03-59440fcaa9a0 exists
+
+* [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
+
+
+Given **version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with 2 environments that aren't test available for deployment**, upon receiving **a request for a pacticipant version** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/pacticipants/Foo/versions/5556b8149bf8bac76bc30f50a8a2dd4c22c85f30",
+ "headers": {
+ "Accept": "application/hal+json"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "pb:record-deployment": [
+ {
+ "href": "href",
+ "name": "prod"
+ },
+ {
+ "href": "href",
+ "name": "dev"
+ }
+ ]
+ }
+ }
+}
+```
+
+Given **version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for deployment**, upon receiving **a request for a pacticipant version** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/pacticipants/Foo/versions/5556b8149bf8bac76bc30f50a8a2dd4c22c85f30",
+ "headers": {
+ "Accept": "application/hal+json"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "pb:record-deployment": [
+ {
+ "href": "/pacticipants/Foo/versions/5556b8149bf8bac76bc30f50a8a2dd4c22c85f30/deployed-versions/environment/cb632df3-0a0d-4227-aac3-60114dd36479",
+ "name": "test"
+ }
+ ]
+ }
+ }
+}
+```
+
+Given **version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for release**, upon receiving **a request for a pacticipant version** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/pacticipants/Foo/versions/5556b8149bf8bac76bc30f50a8a2dd4c22c85f30",
+ "headers": {
+ "Accept": "application/hal+json"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "pb:record-release": [
+ {
+ "href": "/pacticipants/Foo/versions/5556b8149bf8bac76bc30f50a8a2dd4c22c85f30/released-versions/environment/cb632df3-0a0d-4227-aac3-60114dd36479",
+ "name": "test"
+ }
+ ]
+ }
+ }
+}
+```
+
+Given **an environment with name test and UUID 16926ef3-590f-4e3f-838e-719717aa88c9 exists**, upon receiving **a request for an environment** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/environments/16926ef3-590f-4e3f-838e-719717aa88c9",
+ "headers": {
+ "Accept": "application/hal+json"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "pb:currently-deployed-deployed-versions": {
+ "href": "/environments/16926ef3-590f-4e3f-838e-719717aa88c9/deployed-versions/currently-deployed"
+ }
+ }
+ }
+}
+```
+
+Upon receiving **a request for the compatibility matrix for a pacticipant that does not exist** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/matrix",
+ "query": "latestby=cvpv&q[][pacticipant]=Wiffle&q[][pacticipant]=Meep&q[][version]=1%2e2%2e3&q[][version]=9%2e9%2e9"
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 400,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "errors": [
+ "an error message"
+ ]
+ }
+}
+```
+
+Given **the pact for Foo version 1.2.3 and 1.2.4 has been verified by Bar version 4.5.6**, upon receiving **a request for the compatibility matrix for all versions of Foo and Bar** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/matrix",
+ "query": "latestby=cvpv&q[][pacticipant]=Foo&q[][pacticipant]=Bar"
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "matrix": [
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "4"
+ }
+ },
+ "pact": {
+ "createdAt": "2017-10-10T12:49:04+11:00"
+ },
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "5"
+ }
+ },
+ "verificationResult": {
+ "_links": {
+ "self": {
+ "href": "http://result"
+ }
+ },
+ "success": true,
+ "verifiedAt": "2017-10-10T12:49:04+11:00"
+ }
+ },
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "4"
+ }
+ },
+ "pact": {
+ "createdAt": "2017-10-10T12:49:04+11:00"
+ },
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "5"
+ }
+ },
+ "verificationResult": {
+ "_links": {
+ "self": {
+ "href": "http://result"
+ }
+ },
+ "success": true,
+ "verifiedAt": "2017-10-10T12:49:04+11:00"
+ }
+ }
+ ]
+ }
+}
+```
+
+Given **the pact for Foo Thing version 1.2.3 has been verified by Bar version 4.5.6**, upon receiving **a request for the compatibility matrix for Foo version 1.2.3 and Bar version 4.5.6** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/matrix",
+ "query": "latestby=cvpv&q[][pacticipant]=Foo+Thing&q[][pacticipant]=Bar&q[][version]=1%2e2%2e3&q[][version]=4%2e5%2e6"
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "matrix": [
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "4"
+ }
+ },
+ "pact": {
+ "createdAt": "2017-10-10T12:49:04+11:00"
+ },
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "5"
+ }
+ },
+ "verificationResult": {
+ "_links": {
+ "self": {
+ "href": "http://result"
+ }
+ },
+ "success": true,
+ "verifiedAt": "2017-10-10T12:49:04+11:00"
+ }
+ }
+ ],
+ "summary": {
+ "deployable": true,
+ "reason": "some text",
+ "unknown": 1
+ }
+ }
+}
+```
+
+Given **the pact for Foo version 1.2.3 has been verified by Bar version 4.5.6**, upon receiving **a request for the compatibility matrix for Foo version 1.2.3 and Bar version 4.5.6** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/matrix",
+ "query": "latestby=cvpv&q[][pacticipant]=Foo&q[][pacticipant]=Bar&q[][version]=1%2e2%2e3&q[][version]=4%2e5%2e6"
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "matrix": [
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "4"
+ }
+ },
+ "pact": {
+ "createdAt": "2017-10-10T12:49:04+11:00"
+ },
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "5"
+ }
+ },
+ "verificationResult": {
+ "_links": {
+ "self": {
+ "href": "http://result"
+ }
+ },
+ "success": true,
+ "verifiedAt": "2017-10-10T12:49:04+11:00"
+ }
+ }
+ ],
+ "summary": {
+ "deployable": true,
+ "reason": "some text",
+ "unknown": 1
+ }
+ }
+}
+```
+
+Given **the pact for Foo version 1.2.3 has been successfully verified by Bar version 4.5.6 with tag prod, and 1.2.4 unsuccessfully by 9.9.9**, upon receiving **a request for the compatibility matrix for Foo version 1.2.3 and the latest prod version of Bar** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/matrix",
+ "query": "latestby=cvpv&q[][latest]=true&q[][pacticipant]=Foo&q[][pacticipant]=Bar&q[][tag]=prod&q[][version]=1%2e2%2e3"
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "matrix": [
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "4"
+ }
+ },
+ "pact": {
+ "createdAt": "2017-10-10T12:49:04+11:00"
+ },
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "5"
+ }
+ },
+ "verificationResult": {
+ "_links": {
+ "self": {
+ "href": "http://result"
+ }
+ },
+ "success": true,
+ "verifiedAt": "2017-10-10T12:49:04+11:00"
+ }
+ }
+ ],
+ "summary": {
+ "deployable": true,
+ "reason": "some text",
+ "unknown": 1
+ }
+ }
+}
+```
+
+Given **the pact for Foo version 1.2.3 has been successfully verified by Bar version 4.5.6 (tagged prod) and version 5.6.7**, upon receiving **a request for the compatibility matrix for Foo version 1.2.3 and the latest prod versions of all other pacticipants** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/matrix",
+ "query": "latest=true&latestby=cvp&q[][pacticipant]=Foo&q[][version]=1%2e2%2e3&tag=prod"
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "matrix": [
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "1.2.3"
+ }
+ },
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "4.5.6"
+ }
+ }
+ }
+ ]
+ }
+}
+```
+
+Given **the pact for Foo version 1.2.3 has been successfully verified by Bar version 4.5.6, and 1.2.4 unsuccessfully by 9.9.9**, upon receiving **a request for the compatibility matrix for Foo version 1.2.3 and the latest version of Bar** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/matrix",
+ "query": "latestby=cvpv&q[][latest]=true&q[][pacticipant]=Foo&q[][pacticipant]=Bar&q[][version]=1%2e2%2e4"
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "matrix": [
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "4"
+ }
+ },
+ "pact": {
+ "createdAt": "2017-10-10T12:49:04+11:00"
+ },
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "5"
+ }
+ },
+ "verificationResult": {
+ "_links": {
+ "self": {
+ "href": "http://result"
+ }
+ },
+ "success": true,
+ "verifiedAt": "2017-10-10T12:49:04+11:00"
+ }
+ }
+ ],
+ "summary": {
+ "deployable": true,
+ "reason": "some text",
+ "unknown": 1
+ }
+ }
+}
+```
+
+Given **the pact for Foo version 1.2.3 has been verified by Bar version 4.5.6**, upon receiving **a request for the compatibility matrix where one or more versions does not exist** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/matrix",
+ "query": "latestby=cvpv&q[][pacticipant]=Foo&q[][pacticipant]=Bar&q[][version]=1%2e2%2e3&q[][version]=9%2e9%2e9"
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "summary": {
+ "reason": "an error message"
+ }
+ }
+}
+```
+
+Given **the pact for Foo version 1.2.3 has been verified by Bar version 4.5.6 and version 5.6.7**, upon receiving **a request for the compatibility matrix where only the version of Foo is specified** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/matrix",
+ "query": "latest=true&latestby=cvp&q[][pacticipant]=Foo&q[][version]=1%2e2%2e3"
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "matrix": [
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "4"
+ }
+ },
+ "pact": {
+ "createdAt": "2017-10-10T12:49:04+11:00"
+ },
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "5"
+ }
+ },
+ "verificationResult": {
+ "_links": {
+ "self": {
+ "href": "http://result"
+ }
+ },
+ "success": true,
+ "verifiedAt": "2017-10-10T12:49:04+11:00"
+ }
+ }
+ ],
+ "summary": {
+ "deployable": true,
+ "reason": "some text",
+ "unknown": 1
+ }
+ }
+}
+```
+
+Given **an environment with name test exists**, upon receiving **a request for the environments** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/environments",
+ "headers": {
+ "Accept": "application/hal+json"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "pb:environments": [
+ {
+ "href": "href",
+ "name": "test"
+ }
+ ]
+ }
+ }
+}
+```
+
+Upon receiving **a request for the index resource** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/",
+ "headers": {
+ "Accept": "application/hal+json"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "pb:pacticipant": {
+ "href": "/pacticipants/{pacticipant}"
+ },
+ "pb:pacticipants": {
+ "href": "/pacticipants"
+ },
+ "pb:webhooks": {
+ "href": "/webhooks"
+ }
+ }
+ }
+}
+```
+
+Given **the pacticipant relations are present**, upon receiving **a request for the index resource** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/",
+ "headers": {
+ "Accept": "application/hal+json"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "pb:pacticipant": {
+ "href": "/pacticipants/{pacticipant}"
+ },
+ "pb:pacticipants": {
+ "href": "/pacticipants"
+ }
+ }
+ }
+}
+```
+
+Given **the pb:environments relation exists in the index resource**, upon receiving **a request for the index resource** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/",
+ "headers": {
+ "Accept": "application/hal+json"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "pb:environments": {
+ "href": "/environments"
+ }
+ }
+ }
+}
+```
+
+Given **the pb:latest-tagged-version relation exists in the index resource**, upon receiving **a request for the index resource** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/",
+ "headers": {
+ "Accept": "application/hal+json, application/json"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "pb:latest-tagged-version": {
+ "href": "http://127.0.0.1:9999/pacticipants/Condor/latest-version/production"
+ }
+ }
+ }
+}
+```
+
+Given **the pb:latest-version relation exists in the index resource**, upon receiving **a request for the index resource** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/",
+ "headers": {
+ "Accept": "application/hal+json, application/json"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "pb:latest-version": {
+ "href": "http://127.0.0.1:9999/pacticipants/Condor/latest-version"
+ }
+ }
+ }
+}
+```
+
+Given **the pb:pacticipant-branch relation exists in the index resource**, upon receiving **a request for the index resource** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/",
+ "headers": {
+ "Accept": "application/hal+json"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "pb:pacticipant-branch": {
+ "href": "/pacticipants/{pacticipant}/branches/{branch}"
+ }
+ }
+ }
+}
+```
+
+Given **the pb:pacticipant-version and pb:environments relations exist in the index resource**, upon receiving **a request for the index resource** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/",
+ "headers": {
+ "Accept": "application/hal+json"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "pb:environments": {
+ "href": "/environments"
+ },
+ "pb:pacticipant-version": {
+ "href": "/pacticipants/{pacticipant}/versions/{version}"
+ }
+ }
+ }
+}
+```
+
+Given **the pb:publish-contracts relations exists in the index resource**, upon receiving **a request for the index resource** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/",
+ "headers": {
+ "Accept": "application/hal+json"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "pb:publish-contracts": {
+ "href": "/contracts/publish"
+ }
+ }
+ }
+}
+```
+
+Upon receiving **a request for the index resource with the webhook relation** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/",
+ "headers": {
+ "Accept": "application/hal+json"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "pb:webhook": {
+ "href": "/webhooks/{uuid}",
+ "templated": true
+ }
+ }
+ }
+}
+```
+
+Given **a latest pact between Condor and the Pricing Service exists**, upon receiving **a request for the list of the latest pacts from all consumers for the Pricing Service'** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/pacts/provider/Pricing%20Service/latest"
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json"
+ },
+ "body": {
+ "_links": {
+ "pb:pacts": [
+ {
+ "href": "http://example.org/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0",
+ "name": "Condor",
+ "title": "Pact between Condor (v1.3.0) and Pricing Service"
+ }
+ ],
+ "provider": {
+ "href": "http://example.org/pacticipants/Pricing%20Service",
+ "title": "Pricing Service"
+ }
+ }
+ }
+}
+```
+
+Given **tagged as prod pact between Condor and the Pricing Service exists**, upon receiving **a request for the list of the latest prod pacts from all consumers for the Pricing Service'** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/pacts/provider/Pricing%20Service/latest/prod"
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json"
+ },
+ "body": {
+ "_links": {
+ "pb:pacts": [
+ {
+ "href": "http://example.org/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0",
+ "name": "Condor",
+ "title": "Pact between Condor (v1.3.0) and Pricing Service"
+ }
+ ],
+ "provider": {
+ "href": "http://example.org/pacticipants/Pricing%20Service",
+ "title": "Pricing Service"
+ }
+ }
+ }
+}
+```
+
+Given **the pact for Foo version 1.2.3 has been successfully verified by Bar version 4.5.6, and 1.2.4 unsuccessfully by 9.9.9**, upon receiving **a request for the successful rows of the compatibility matrix for all versions of Foo and Bar** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/matrix",
+ "query": "latestby=cvpv&q[][pacticipant]=Foo&q[][pacticipant]=Bar&success[]=true"
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "matrix": [
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "4"
+ }
+ },
+ "pact": {
+ "createdAt": "2017-10-10T12:49:04+11:00"
+ },
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "5"
+ }
+ },
+ "verificationResult": {
+ "_links": {
+ "self": {
+ "href": "http://result"
+ }
+ },
+ "success": true,
+ "verifiedAt": "2017-10-10T12:49:04+11:00"
+ }
+ }
+ ],
+ "summary": {
+ "deployable": true,
+ "reason": "some text",
+ "unknown": 1
+ }
+ }
+}
+```
+
+Given **the 'Pricing Service' and 'Condor' already exist in the pact-broker, and Condor already has a pact published for version 1.3.0**, upon receiving **a request retrieve a pact for a specific version** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0"
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "consumer": {
+ "name": "Condor"
+ },
+ "interactions": [
+ ],
+ "provider": {
+ "name": "Pricing Service"
+ }
+ }
+}
+```
+
+Upon receiving **a request to create a global webhook with a JSON body** from Pact Broker Client V2, with
+```json
+{
+ "method": "POST",
+ "path": "/webhooks",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 201,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ }
+ }
+ }
+}
+```
+
+Upon receiving **a request to create a pacticipant** from Pact Broker Client V2, with
+```json
+{
+ "method": "POST",
+ "path": "/pacticipants",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "name": "Foo",
+ "repositoryUrl": "http://foo"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 201,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/pacticipants/Foo"
+ }
+ },
+ "name": "Foo",
+ "repositoryUrl": "http://foo"
+ }
+}
+```
+
+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 V2, with
+```json
+{
+ "method": "POST",
+ "path": "/webhooks/provider/Pricing%20Service/consumer/Condor",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ }
+}
+```
+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 and a uuid** from Pact Broker Client V2, with
+```json
+{
+ "method": "PUT",
+ "path": "/webhooks/696c5f93-1b7f-44bc-8d03-59440fcaa9a0",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "consumer": {
+ "name": "Condor"
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "provider": {
+ "name": "Pricing Service"
+ },
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 201,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ }
+ }
+ }
+}
+```
+
+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** from Pact Broker Client V2, with
+```json
+{
+ "method": "POST",
+ "path": "/webhooks",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "consumer": {
+ "name": "Condor"
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 201,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ }
+ }
+ }
+}
+```
+
+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 V2, with
+```json
+{
+ "method": "POST",
+ "path": "/webhooks/provider/Pricing%20Service/consumer/Condor",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 201,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ }
+ }
+ }
+}
+```
+
+Upon receiving **a request to create a webhook with a JSON body for a consumer specified by a label** from Pact Broker Client V2, with
+```json
+{
+ "method": "POST",
+ "path": "/webhooks",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "consumer": {
+ "label": "consumer_label"
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 201,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ }
+ }
+ }
+}
+```
+
+Upon receiving **a request to create a webhook with a JSON body for a consumer that does not exist** from Pact Broker Client V2, with
+```json
+{
+ "method": "POST",
+ "path": "/webhooks",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "consumer": {
+ "name": "Condor"
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 400,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "errors": {
+ "consumer.name": [
+ "Some error"
+ ]
+ }
+ }
+}
+```
+
+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 provider** from Pact Broker Client V2, with
+```json
+{
+ "method": "POST",
+ "path": "/webhooks",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "provider": {
+ "name": "Pricing Service"
+ },
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 201,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ }
+ }
+ }
+}
+```
+
+Upon receiving **a request to create a webhook with a JSON body for a provider specified by a label** from Pact Broker Client V2, with
+```json
+{
+ "method": "POST",
+ "path": "/webhooks",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "provider": {
+ "label": "provider_label"
+ },
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 201,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ }
+ }
+ }
+}
+```
+
+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 V2, with
+```json
+{
+ "method": "POST",
+ "path": "/webhooks/provider/Pricing%20Service/consumer/Condor",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": "",
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 201,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": ""
+ }
+ }
+}
+```
+
+Given **the 'Pricing Service' and 'Condor' already exist in the pact-broker**, upon receiving **a request to create a webhook with every possible event type** from Pact Broker Client V2, with
+```json
+{
+ "method": "POST",
+ "path": "/webhooks/provider/Pricing%20Service/consumer/Condor",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ },
+ {
+ "name": "contract_published"
+ },
+ {
+ "name": "provider_verification_published"
+ },
+ {
+ "name": "provider_verification_succeeded"
+ },
+ {
+ "name": "provider_verification_failed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 201,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ },
+ {
+ "name": "contract_published"
+ },
+ {
+ "name": "provider_verification_published"
+ },
+ {
+ "name": "provider_verification_succeeded"
+ },
+ {
+ "name": "provider_verification_failed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ }
+ }
+ }
+}
+```
+
+Upon receiving **a request to create an environment** from Pact Broker Client V2, with
+```json
+{
+ "method": "POST",
+ "path": "/environments",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "contacts": [
+ {
+ "details": {
+ "emailAddress": "foo@bar.com"
+ },
+ "name": "Foo team"
+ }
+ ],
+ "displayName": "Test",
+ "name": "test",
+ "production": false
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 201,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "contacts": [
+ {
+ "details": {
+ "emailAddress": "foo@bar.com"
+ },
+ "name": "Foo team"
+ }
+ ],
+ "displayName": "Test",
+ "name": "test",
+ "production": false,
+ "uuid": "ffe683ef-dcd7-4e4f-877d-f6eb3db8e86e"
+ }
+}
+```
+
+Given **a branch named main exists for pacticipant Foo**, upon receiving **a request to delete a pacticipant branch** from Pact Broker Client V2, with
+```json
+{
+ "method": "DELETE",
+ "path": "/pacticipants/Foo/branches/main"
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 204
+}
+```
+
+Given **provider Bar version 4.5.6 has a successful verification for Foo version 1.2.3 tagged prod and a failed verification for version 3.4.5 tagged prod**, upon receiving **a request to determine if Bar can be deployed with all Foo tagged prod, ignoring the verification for Foo version 3.4.5** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/matrix",
+ "query": "ignore[][pacticipant]=Foo&ignore[][version]=3%2e4%2e5&latestby=cvpv&q[][pacticipant]=Bar&q[][pacticipant]=Foo&q[][tag]=prod&q[][version]=4%2e5%2e6"
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "matrix": [
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "1.2.3"
+ }
+ },
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "4.5.6"
+ }
+ },
+ "verificationResult": {
+ "_links": {
+ "self": {
+ "href": "http://result"
+ }
+ },
+ "success": true
+ }
+ },
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "3.4.5"
+ }
+ },
+ "ignored": true,
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "4.5.6"
+ }
+ },
+ "verificationResult": {
+ "_links": {
+ "self": {
+ "href": "http://result"
+ }
+ },
+ "success": false
+ }
+ }
+ ],
+ "notices": [
+ {
+ "text": "some notice",
+ "type": "info"
+ }
+ ],
+ "summary": {
+ "deployable": true,
+ "ignored": 1
+ }
+ }
+}
+```
+
+Given **the 'Pricing Service' already exists in the pact-broker**, upon receiving **a request to get the Pricing Service** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/pacticipants/Pricing%20Service"
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json"
+ },
+ "body": {
+ "_embedded": {
+ "latest-version": {
+ "_links": {
+ "self": {
+ "href": "http://example.org/pacticipants/Pricing%20Service/versions/1.3.0"
+ }
+ },
+ "number": "1.3.0"
+ }
+ },
+ "_links": {
+ "self": {
+ "href": "http://example.org/pacticipants/Pricing%20Service"
+ },
+ "versions": {
+ "href": "http://example.org/pacticipants/Pricing%20Service/versions"
+ }
+ },
+ "name": "Pricing Service",
+ "repositoryUrl": "git@git.realestate.com.au:business-systems/pricing-service"
+ }
+}
+```
+
+Given **the 'Pricing Service' does not exist in the pact-broker**, upon receiving **a request to get the Pricing Service** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/pacticipants/Pricing%20Service"
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 404
+}
+```
+
+Given **'Condor' exists in the pact-broker**, upon receiving **a request to list pacticipants** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/pacticipants"
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json"
+ },
+ "body": {
+ "_links": {
+ "pacticipants": [
+ {
+ "href": "http://example.org/pacticipants/Condor",
+ "title": "Condor"
+ }
+ ],
+ "self": {
+ "href": "http://example.org/pacticipants"
+ }
+ },
+ "pacticipants": [
+ {
+ "_embedded": {
+ "latest-version": {
+ "_links": {
+ "self": {
+ "href": "http://example.org/pacticipants/Condor/versions/1.3.0"
+ }
+ },
+ "number": "1.3.0"
+ }
+ },
+ "_links": {
+ "self": {
+ "href": "http://example.org/pacticipants/Condor"
+ }
+ },
+ "name": "Condor"
+ }
+ ]
+ }
+}
+```
+
+Given **an environment exists**, upon receiving **a request to list the environments** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/environments",
+ "headers": {
+ "Accept": "application/hal+json"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_embedded": {
+ "environments": [
+ {
+ "contacts": [
+ {
+ "details": {
+ "emailAddress": "foo@bar.com"
+ },
+ "name": "Foo team"
+ }
+ ],
+ "displayName": "Test",
+ "name": "test",
+ "production": false,
+ "uuid": "78e85fb2-9df1-48da-817e-c9bea6294e01"
+ }
+ ]
+ }
+ }
+}
+```
+
+Given **a pact between Condor and the Pricing Service exists**, upon receiving **a request to list the latest pacts** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/pacts/latest"
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json"
+ },
+ "body": {
+ "_links": {
+ "self": {
+ "href": "http://example.org/pacts/latest"
+ }
+ },
+ "pacts": [
+ {
+ "_embedded": {
+ "consumer": {
+ "_embedded": {
+ "version": {
+ "number": "1.3.0"
+ }
+ },
+ "_links": {
+ "self": {
+ "href": "http://example.org/pacticipants/Condor"
+ }
+ },
+ "name": "Condor"
+ },
+ "provider": {
+ "_links": {
+ "self": {
+ "href": "http://example.org/pacticipants/Pricing%20Service"
+ }
+ },
+ "name": "Pricing Service"
+ }
+ },
+ "_links": {
+ "self": [
+ {
+ "href": "http://example.org/pacts/provider/Pricing%20Service/consumer/Condor/latest"
+ },
+ {
+ "href": "http://example.org/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0"
+ }
+ ]
+ }
+ }
+ ]
+ }
+}
+```
+
+Given **an version is deployed to environment with UUID 16926ef3-590f-4e3f-838e-719717aa88c9 with target customer-1**, upon receiving **a request to list the versions deployed to an environment for a pacticipant name and application instance** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/environments/16926ef3-590f-4e3f-838e-719717aa88c9/deployed-versions/currently-deployed",
+ "query": "pacticipant=Foo",
+ "headers": {
+ "Accept": "application/hal+json"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_embedded": {
+ "deployedVersions": [
+ {
+ "_links": {
+ "self": {
+ "href": "/deployed-versions/ff3adecf-cfc5-4653-a4e3-f1861092f8e0"
+ }
+ },
+ "applicationInstance": "customer-1"
+ }
+ ]
+ }
+ }
+}
+```
+
+Given **a currently deployed version exists**, upon receiving **a request to mark a deployed version as not currently deploye** from Pact Broker Client V2, with
+```json
+{
+ "method": "PATCH",
+ "path": "/deployed-versions/ff3adecf-cfc5-4653-a4e3-f1861092f8e0",
+ "headers": {
+ "Content-Type": "application/merge-patch+json"
+ },
+ "body": {
+ "currentlyDeployed": false
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_embedded": {
+ "version": {
+ "number": "2"
+ }
+ },
+ "currentlyDeployed": false
+ }
+}
+```
+
+Upon receiving **a request to publish contracts** from Pact Broker Client V2, with
+```json
+{
+ "method": "POST",
+ "path": "/contracts/publish",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "branch": "main",
+ "buildUrl": "http://build",
+ "contracts": [
+ {
+ "consumerName": "Foo",
+ "content": "eyJjb25zdW1lciI6eyJuYW1lIjoiRm9vIn0sInByb3ZpZGVyIjp7Im5hbWUiOiJCYXIifSwiaW50ZXJhY3Rpb25zIjpbeyJkZXNjcmlwdGlvbiI6ImFuIGV4YW1wbGUgcmVxdWVzdCIsInByb3ZpZGVyU3RhdGUiOiJhIHByb3ZpZGVyIHN0YXRlIiwicmVxdWVzdCI6eyJtZXRob2QiOiJHRVQiLCJwYXRoIjoiLyIsImhlYWRlcnMiOnt9fSwicmVzcG9uc2UiOnsic3RhdHVzIjoyMDAsImhlYWRlcnMiOnsiQ29udGVudC1UeXBlIjoiYXBwbGljYXRpb24vaGFsK2pzb24ifX19XSwibWV0YWRhdGEiOnsicGFjdFNwZWNpZmljYXRpb24iOnsidmVyc2lvbiI6IjIuMC4wIn19fQ==",
+ "contentType": "application/json",
+ "onConflict": "merge",
+ "providerName": "Bar",
+ "specification": "pact"
+ }
+ ],
+ "pacticipantName": "Foo",
+ "pacticipantVersionNumber": "5556b8149bf8bac76bc30f50a8a2dd4c22c85f30",
+ "tags": [
+ "dev"
+ ]
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_embedded": {
+ "pacticipant": {
+ "name": "Foo"
+ },
+ "version": {
+ "number": "5556b8149bf8bac76bc30f50a8a2dd4c22c85f30"
+ }
+ },
+ "_links": {
+ "pb:contracts": [
+ {
+ "href": "http://some-pact"
+ }
+ ],
+ "pb:pacticipant-version-tags": [
+ {
+ "name": "dev"
+ }
+ ]
+ },
+ "logs": [
+ {
+ "level": "info",
+ "message": "some message"
+ }
+ ]
+ }
+}
+```
+
+Given **version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for deployment**, upon receiving **a request to record a deployment** from Pact Broker Client V2, with
+```json
+{
+ "method": "POST",
+ "path": "/pacticipants/Foo/versions/5556b8149bf8bac76bc30f50a8a2dd4c22c85f30/deployed-versions/environment/cb632df3-0a0d-4227-aac3-60114dd36479",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "applicationInstance": "blue",
+ "target": "blue"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 201,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "target": "blue"
+ }
+}
+```
+
+Given **version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for deployment**, upon receiving **a request to record a release** from Pact Broker Client V2, with
+```json
+{
+ "method": "POST",
+ "path": "/pacticipants/Foo/versions/5556b8149bf8bac76bc30f50a8a2dd4c22c85f30/released-versions/environment/cb632df3-0a0d-4227-aac3-60114dd36479",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 201,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ }
+}
+```
+
+Given **the 'Pricing Service' already exists in the pact-broker**, upon receiving **a request to register the repository URL of a pacticipant** from Pact Broker Client V2, with
+```json
+{
+ "method": "PATCH",
+ "path": "/pacticipants/Pricing%20Service",
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "repository_url": "git@git.realestate.com.au:business-systems/pricing-service"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ }
+}
+```
+
+Given **the 'Pricing Service' does not exist in the pact-broker**, upon receiving **a request to register the repository URL of a pacticipant** from Pact Broker Client V2, with
+```json
+{
+ "method": "PATCH",
+ "path": "/pacticipants/Pricing%20Service",
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "repository_url": "git@git.realestate.com.au:business-systems/pricing-service"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 201,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ }
+}
+```
+
+Given **a pacticipant with name Foo exists**, upon receiving **a request to retrieve a pacticipant** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/pacticipants/Foo",
+ "headers": {
+ "Accept": "application/hal+json"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/pacticipants/Foo"
+ }
+ }
+ }
+}
+```
+
+Upon receiving **a request to retrieve a pacticipant** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/pacticipants/Foo",
+ "headers": {
+ "Accept": "application/hal+json"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 404
+}
+```
+
+Given **'Condor' exists in the pact-broker with the latest tagged 'production' version 1.2.3**, upon receiving **a request to retrieve the latest 'production' version of Condor** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/pacticipants/Condor/latest-version/production",
+ "headers": {
+ "Accept": "application/hal+json, application/json"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "number": "1.2.3"
+ }
+}
+```
+
+Given **a pact between Condor and the Pricing Service exists**, upon receiving **a request to retrieve the latest pact between Condor and the Pricing Service** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/pacts/provider/Pricing%20Service/consumer/Condor/latest"
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json",
+ "X-Pact-Consumer-Version": "1.3.0"
+ },
+ "body": {
+ "consumer": {
+ "name": "Condor"
+ },
+ "interactions": [
+ ],
+ "provider": {
+ "name": "Pricing Service"
+ }
+ }
+}
+```
+
+Given **no pact between Condor and the Pricing Service exists**, upon receiving **a request to retrieve the latest pact between Condor and the Pricing Service** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/pacts/provider/Pricing%20Service/consumer/Condor/latest"
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 404
+}
+```
+
+Given **'Condor' exists in the pact-broker with the latest version 1.2.3**, upon receiving **a request to retrieve the latest version of Condor** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/pacticipants/Condor/latest-version",
+ "headers": {
+ "Accept": "application/hal+json, application/json"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "number": "1.2.3"
+ }
+}
+```
+
+Given **a pact between Condor and the Pricing Service exists for the production version of Condor**, upon receiving **a request to retrieve the pact between the production verison of Condor and the Pricing Service** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/pacts/provider/Pricing%20Service/consumer/Condor/latest/prod",
+ "headers": {
+ "Accept": "application/hal+json, application/json"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "consumer": {
+ "name": "Condor"
+ },
+ "interactions": [
+ ],
+ "provider": {
+ "name": "Pricing Service"
+ }
+ }
+}
+```
+
+Given **'Condor' exists in the pact-broker with version 1.3.0, tagged with 'prod'**, upon receiving **a request to tag the production version of Condor** from Pact Broker Client V2, with
+```json
+{
+ "method": "PUT",
+ "path": "/pacticipants/Condor/versions/1.3.0/tags/prod",
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "body": {
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/pacticipants/Condor/versions/1.3.0/tags/prod"
+ }
+ }
+ }
+}
+```
+
+Given **'Condor' does not exist in the pact-broker**, upon receiving **a request to tag the production version of Condor** from Pact Broker Client V2, with
+```json
+{
+ "method": "PUT",
+ "path": "/pacticipants/Condor/versions/1.3.0/tags/prod",
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "body": {
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 201,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/pacticipants/Condor/versions/1.3.0/tags/prod"
+ }
+ }
+ }
+}
+```
+
+Given **'Condor' exists in the pact-broker**, upon receiving **a request to tag the production version of Condor** from Pact Broker Client V2, with
+```json
+{
+ "method": "PUT",
+ "path": "/pacticipants/Condor/versions/1.3.0/tags/prod",
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "body": {
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 201,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/pacticipants/Condor/versions/1.3.0/tags/prod"
+ }
+ }
+ }
+}
+```
+
+Given **a pacticipant with name Foo exists**, upon receiving **a request to update a pacticipant** from Pact Broker Client V2, with
+```json
+{
+ "method": "PATCH",
+ "path": "/pacticipants/Foo",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "name": "Foo",
+ "repositoryUrl": "http://foo"
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/pacticipants/Foo"
+ }
+ },
+ "name": "Foo",
+ "repositoryUrl": "http://foo"
+ }
+}
+```
+
+Given **a webhook with the uuid 696c5f93-1b7f-44bc-8d03-59440fcaa9a0 exists**, upon receiving **a request to update a webhook** from Pact Broker Client V2, with
+```json
+{
+ "method": "PUT",
+ "path": "/webhooks/696c5f93-1b7f-44bc-8d03-59440fcaa9a0",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "consumer": {
+ "name": "Condor"
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "provider": {
+ "name": "Pricing Service"
+ },
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ }
+}
+```
+Pact Broker will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ }
+ }
+ }
+}
+```
+
+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 V2, with
+```json
+{
+ "method": "POST",
+ "path": "/webhooks/provider/Pricing%20Service/consumer/Condor",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "username": "username"
+ }
+ }
+}
+```
+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/doc/pacts/markdown/Pact Broker Client V2 - PactFlow.md b/doc/pacts/markdown/Pact Broker Client V2 - PactFlow.md
new file mode 100644
index 0000000..59ffc3d
--- /dev/null
+++ b/doc/pacts/markdown/Pact Broker Client V2 - PactFlow.md
@@ -0,0 +1,267 @@
+### A pact between Pact Broker Client V2 and PactFlow
+
+#### Requests from Pact Broker Client V2 to PactFlow
+
+* [A request for the index resource](#a_request_for_the_index_resource)
+
+* [A request for the index resource](#a_request_for_the_index_resource_given_the_pb:publish-provider-contract_relation_exists_in_the_index_resource) given the pb:publish-provider-contract relation exists in the index resource
+
+* [A request to create a provider contract](#a_request_to_create_a_provider_contract)
+
+* [A request to create a provider contract](#a_request_to_create_a_provider_contract_given_there_is_a_pf:ui_href_in_the_response) given there is a pf:ui href in the response
+
+* [A request to create a webhook for a team](#a_request_to_create_a_webhook_for_a_team_given_a_team_with_UUID_2abbc12a-427d-432a-a521-c870af1739d9_exists) given a team with UUID 2abbc12a-427d-432a-a521-c870af1739d9 exists
+
+* [A request to publish a provider contract](#a_request_to_publish_a_provider_contract)
+
+#### Interactions
+
+
+Upon receiving **a request for the index resource** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/",
+ "headers": {
+ "Accept": "application/hal+json"
+ }
+}
+```
+PactFlow will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "pb:pacticipant": {
+ "href": "/pacticipants/{pacticipant}"
+ },
+ "pb:pacticipants": {
+ "href": "/pacticipants"
+ },
+ "pb:webhooks": {
+ "href": "/webhooks"
+ }
+ }
+ }
+}
+```
+
+Given **the pb:publish-provider-contract relation exists in the index resource**, upon receiving **a request for the index resource** from Pact Broker Client V2, with
+```json
+{
+ "method": "GET",
+ "path": "/",
+ "headers": {
+ "Accept": "application/hal+json"
+ }
+}
+```
+PactFlow will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "pf:publish-provider-contract": {
+ "href": "/provider-contracts/provider/{provider}/publish"
+ }
+ }
+ }
+}
+```
+
+Upon receiving **a request to create a provider contract** from Pact Broker Client V2, with
+```json
+{
+ "method": "PUT",
+ "path": "/contracts/provider/Bar/version/1",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "content": "LS0tCnNvbWU6IGNvbnRyYWN0Cg==",
+ "contentType": "application/yaml",
+ "contractType": "oas",
+ "verificationResults": {
+ "content": "c29tZSByZXN1bHRz",
+ "contentType": "text/plain",
+ "format": "text",
+ "success": true,
+ "verifier": "my custom tool",
+ "verifierVersion": "1.0"
+ }
+ }
+}
+```
+PactFlow will respond with:
+```json
+{
+ "status": 201,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ }
+}
+```
+
+Given **there is a pf:ui href in the response**, upon receiving **a request to create a provider contract** from Pact Broker Client V2, with
+```json
+{
+ "method": "PUT",
+ "path": "/contracts/provider/Bar/version/1",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "content": "LS0tCnNvbWU6IGNvbnRyYWN0Cg==",
+ "contentType": "application/yaml",
+ "contractType": "oas",
+ "verificationResults": {
+ "content": "c29tZSByZXN1bHRz",
+ "contentType": "text/plain",
+ "format": "text",
+ "success": true,
+ "verifier": "my custom tool",
+ "verifierVersion": "1.0"
+ }
+ }
+}
+```
+PactFlow will respond with:
+```json
+{
+ "status": 201,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "pf:ui": {
+ "href": "some-url"
+ }
+ }
+ }
+}
+```
+
+Given **a team with UUID 2abbc12a-427d-432a-a521-c870af1739d9 exists**, upon receiving **a request to create a webhook for a team** from Pact Broker Client V2, with
+```json
+{
+ "method": "POST",
+ "path": "/webhooks",
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "url": "https://webhook"
+ },
+ "teamUuid": "2abbc12a-427d-432a-a521-c870af1739d9"
+ }
+}
+```
+PactFlow will respond with:
+```json
+{
+ "status": 201,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url",
+ "title": "A title"
+ }
+ },
+ "description": "a webhook",
+ "teamUuid": "2abbc12a-427d-432a-a521-c870af1739d9"
+ }
+}
+```
+
+Upon receiving **a request to publish a provider contract** from Pact Broker Client V2, with
+```json
+{
+ "method": "POST",
+ "path": "/provider-contracts/provider/Bar/publish",
+ "headers": {
+ "Accept": "application/hal+json, application/problem+json",
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "branch": "main",
+ "buildUrl": "http://build",
+ "contract": {
+ "content": "LS0tCnNvbWU6IGNvbnRyYWN0Cg==",
+ "contentType": "application/yaml",
+ "selfVerificationResults": {
+ "content": "c29tZSByZXN1bHRz",
+ "contentType": "text/plain",
+ "format": "text",
+ "success": true,
+ "verifier": "my custom tool",
+ "verifierVersion": "1.0"
+ },
+ "specification": "oas"
+ },
+ "pacticipantVersionNumber": "1",
+ "tags": [
+ "dev"
+ ]
+ }
+}
+```
+PactFlow will respond with:
+```json
+{
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "body": {
+ "_embedded": {
+ "version": {
+ "number": "1"
+ }
+ },
+ "_links": {
+ "pb:branch-version": {
+ },
+ "pb:pacticipant-version-tags": [
+ {
+ }
+ ]
+ },
+ "notices": [
+ {
+ "text": "some notice",
+ "type": "info"
+ }
+ ]
+ }
+}
+```
diff --git a/doc/pacts/markdown/README.md b/doc/pacts/markdown/README.md
index 4c45249..8df4e3c 100644
--- a/doc/pacts/markdown/README.md
+++ b/doc/pacts/markdown/README.md
@@ -1,4 +1,4 @@
-### Pacts for Pact Broker Client
+### Pacts for Pact Broker Client V2
* [Pact Broker](Pact%20Broker%20Client%20-%20Pact%20Broker.md)
* [PactFlow](Pact%20Broker%20Client%20-%20PactFlow.md)
diff --git a/lib/pact_broker/client/versions.rb b/lib/pact_broker/client/versions.rb
index 5a14c75..7d03ce7 100644
--- a/lib/pact_broker/client/versions.rb
+++ b/lib/pact_broker/client/versions.rb
@@ -29,7 +29,7 @@ def latest options
end
def tag options
- response = put(tag_url(options), headers: default_put_headers.merge("Content-Length" => "0"))
+ response = put(tag_url(options), headers: default_put_headers, body: {}.to_json)
handle_response(response) do
true
end
diff --git a/spec/pact/providers/PactBroker/create_environment_spec.rb b/spec/pact/providers/PactBroker/create_environment_spec.rb
new file mode 100644
index 0000000..90183d5
--- /dev/null
+++ b/spec/pact/providers/PactBroker/create_environment_spec.rb
@@ -0,0 +1,94 @@
+require_relative '../../../pact_ruby_v2_spec_helper'
+require 'pact_broker/client/environments/create_environment'
+
+RSpec.describe "create an environment", pact: true do
+ pact_broker
+ include_context "pact broker"
+ include_context "pact broker - pact-ruby-v2"
+ include PactBrokerPactHelperMethods
+
+ let(:params) do
+ {
+ name: "test",
+ display_name: "Test",
+ production: false,
+ contact_name: "Foo team",
+ contact_email_address: "foo@bar.com"
+
+ }
+ end
+ let(:pact_broker_client_options) { {} }
+ let(:request_body) do
+ {
+ name: "test",
+ displayName: "Test",
+ production: false,
+ contacts: [{
+ name: "Foo team",
+ details: {
+ emailAddress: "foo@bar.com"
+ }
+ }]
+ }
+ end
+
+ let(:options) do
+ {
+ verbose: verbose
+ }
+ end
+ let(:verbose) { false }
+ let(:pact_broker_base_url) { "http://127.0.0.1:9999" }
+ let(:pact_broker_client_options) { { pact_broker_base_url: pact_broker_base_url } }
+
+ subject { PactBroker::Client::Environments::CreateEnvironment.call(params, options, pact_broker_client_options) }
+
+ def mock_index
+ new_interaction
+ .given("the pb:environments relation exists in the index resource")
+ .upon_receiving("a request for the index resource")
+ .with_request(
+ method: "GET",
+ path: '/',
+ headers: get_request_headers).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ _links: {
+ :'pb:environments' => {
+ href: generate_mock_server_url(
+ regex: ".*(\\/environments)$",
+ example: "/environments"
+ )
+ }
+ }
+ }
+ )
+ end
+
+ def mock_environment_creation_request
+ new_interaction
+ .upon_receiving("a request to create an environment")
+ .with_request(
+ method: "POST",
+ path: "/environments",
+ headers: post_request_headers,
+ body: request_body
+ )
+ .will_respond_with(
+ status: 201,
+ headers: pact_broker_response_headers,
+ body: request_body.merge("uuid" => match_type_of("ffe683ef-dcd7-4e4f-877d-f6eb3db8e86e"))
+ )
+ end
+
+ it "returns a success result" do
+ mock_index
+ mock_environment_creation_request
+ execute_http_pact do |mock_server|
+ expect(subject.success).to be true
+ expect(subject.message).to include "Created test environment in the Pact Broker with UUID ffe683ef-dcd7-4e4f-877d-f6eb3db8e86e"
+ end
+ end
+end
diff --git a/spec/pact/providers/PactBroker/delete_branch_spec.rb b/spec/pact/providers/PactBroker/delete_branch_spec.rb
new file mode 100644
index 0000000..ff89d52
--- /dev/null
+++ b/spec/pact/providers/PactBroker/delete_branch_spec.rb
@@ -0,0 +1,74 @@
+require_relative '../../../pact_ruby_v2_spec_helper'
+require "pact_broker/client/branches/delete_branch"
+
+RSpec.describe "delete a branch", pact: true do
+ pact_broker # our "Pact Broker" service Pact provider helper
+ include_context "pact broker"
+ include_context "pact broker - pact-ruby-v2"
+ include PactBrokerPactHelperMethods
+
+ let(:params) do
+ {
+ pacticipant: "Foo",
+ branch: "main",
+ error_when_not_found: true
+ }
+ end
+
+ let(:options) do
+ {
+ verbose: verbose
+ }
+ end
+
+ let(:pact_broker_base_url) { "http://127.0.0.1:9999" }
+ let(:pact_broker_client_options) { { pact_broker_base_url: pact_broker_base_url } }
+ let(:response_headers) { { "Content-Type" => "application/hal+json"} }
+ let(:verbose) { false }
+
+ subject { PactBroker::Client::Branches::DeleteBranch.call(params, options, pact_broker_client_options) }
+
+ def mock_index
+ new_interaction
+ .given("the pb:pacticipant-branch relation exists in the index resource")
+ .upon_receiving("a request for the index resource")
+ .with_request(
+ method: "GET",
+ path: '/',
+ headers: get_request_headers).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ _links: {
+ :'pb:pacticipant-branch' => {
+ href: generate_mock_server_url(
+ regex: ".*(\\/pacticipants\\/.*\\/branches\\/.*)$",
+ example: "/pacticipants/{pacticipant}/branches/{branch}"
+ ),
+ }
+ }
+ }
+ )
+ end
+
+ def mock_branch_delete_request
+ new_interaction
+ .given("a branch named main exists for pacticipant Foo")
+ .upon_receiving("a request to delete a pacticipant branch")
+ .with_request(
+ method: "DELETE",
+ path: "/pacticipants/Foo/branches/main",
+ )
+ .will_respond_with(
+ status: 204
+ )
+ end
+ it "returns a success result" do
+ mock_index
+ mock_branch_delete_request
+ execute_http_pact do |mock_server|
+ expect(subject.success).to be true
+ end
+ end
+end
diff --git a/spec/pact/providers/PactBroker/extra_goodies_spec.rb b/spec/pact/providers/PactBroker/extra_goodies_spec.rb
new file mode 100644
index 0000000..1a28c67
--- /dev/null
+++ b/spec/pact/providers/PactBroker/extra_goodies_spec.rb
@@ -0,0 +1,117 @@
+require_relative '../../../pact_ruby_v2_spec_helper'
+require 'pact_broker/client/pact_broker_client'
+
+
+module PactBroker::Client
+ describe PactBrokerClient, :pact => true do
+
+ pact_broker
+ let(:pact_broker_client) { PactBrokerClient.new(base_url: 'http://localhost:9999') }
+
+ describe "listing pacts" do
+ context "when pacts exist" do
+ let(:response_body) { JSON.parse(File.read("./spec/support/pacts_latest_list.json"))}
+ let(:expected_pacts) do
+ [{
+ :consumer => {
+ :name => 'Condor',
+ :version => {
+ :number => '1.3.0'
+ }
+ },
+ :provider => {
+ :name => 'Pricing Service'
+ }
+ }
+ ]
+ end
+ let(:interaction) do
+ new_interaction.
+ given("a pact between Condor and the Pricing Service exists").
+ upon_receiving("a request to list the latest pacts").
+ with_request(
+ method: :get,
+ path: '/pacts/latest',
+ headers: {} ).
+ will_respond_with( headers: {'Content-Type' => match_regex(%r{application/hal\+json.*},'application/hal+json')},
+ status: 200,
+ body: response_body
+ )
+ end
+ it "returns the response body" do
+ interaction.execute do |mock_server|
+ expect(pact_broker_client.pacts.list_latest).to eq(expected_pacts)
+ end
+ end
+ end
+ end
+
+ describe "listing pacticipants" do
+ context "when a pacticipant exists" do
+ let(:response_body) { JSON.parse(File.read("./spec/support/pacticipants_list.json"))}
+ let(:interaction) do
+ new_interaction.
+ given("'Condor' exists in the pact-broker").
+ upon_receiving("a request to list pacticipants").
+ with_request(
+ method: :get,
+ path: '/pacticipants',
+ headers: {} ).
+ will_respond_with( headers: {'Content-Type' => match_regex(%r{application/hal\+json.*},'application/hal+json')},
+ status: 200,
+ body: response_body
+ )
+ end
+ it "returns the response body" do
+ interaction.execute do |mock_server|
+ puts "mock_server: #{mock_server.url}"
+ expect(pact_broker_client.pacticipants.list).to eq response_body
+ end
+ end
+ end
+ end
+
+ describe "get pacticipant" do
+ context "when the pacticipant exists" do
+ let(:response_body) { JSON.parse(File.read("./spec/support/pacticipant_get.json"))}
+ let(:options) { {pacticipant: 'Pricing Service'}}
+ let(:interaction) do
+ new_interaction.
+ given("the 'Pricing Service' already exists in the pact-broker").
+ upon_receiving("a request to get the Pricing Service").
+ with_request(
+ method: :get,
+ path: '/pacticipants/Pricing%20Service',
+ headers: {} ).
+ will_respond_with( headers: {'Content-Type' => match_regex(%r{application/hal\+json.*},'application/hal+json')},
+ status: 200,
+ body: response_body
+ )
+ end
+ it "returns the response body" do
+ interaction.execute do |mock_server|
+ expect(pact_broker_client.pacticipants.get1(options)).to eq response_body
+ end
+ end
+ end
+ context "when the pacticipant does not exist" do
+ let(:options) { {pacticipant: 'Pricing Service'}}
+ let(:interaction) do
+ new_interaction.
+ given("the 'Pricing Service' does not exist in the pact-broker").
+ upon_receiving("a request to get the Pricing Service").
+ with_request(
+ method: :get,
+ path: '/pacticipants/Pricing%20Service',
+ headers: {} ).
+ will_respond_with( status: 404 )
+ end
+ it "returns nil" do
+ interaction.execute do |mock_server|
+ expect(pact_broker_client.pacticipants.get1(options)).to be_nil
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/pact/providers/PactBroker/list_environments_spec.rb b/spec/pact/providers/PactBroker/list_environments_spec.rb
new file mode 100644
index 0000000..465219d
--- /dev/null
+++ b/spec/pact/providers/PactBroker/list_environments_spec.rb
@@ -0,0 +1,90 @@
+require_relative '../../../pact_ruby_v2_spec_helper'
+require 'pact_broker/client/environments/list_environments'
+
+RSpec.describe "list environments", pact: true do
+ pact_broker
+ include_context "pact broker"
+ include_context "pact broker - pact-ruby-v2"
+ include PactBrokerPactHelperMethods
+
+ let(:params) { { output: output } }
+ let(:output) { "text" }
+ let(:response_body) do
+ {
+ _embedded: {
+ environments: match_each(
+ {
+ uuid: "78e85fb2-9df1-48da-817e-c9bea6294e01",
+ name: "test",
+ displayName: "Test",
+ production: false,
+ contacts: [{
+ name: "Foo team",
+ details: {
+ emailAddress: "foo@bar.com"
+ }
+ }]
+ }
+ )
+ }
+ }
+ end
+ let(:options) do
+ {
+ verbose: verbose
+ }
+ end
+ let(:verbose) { false }
+ let(:pact_broker_base_url) { "http://127.0.0.1:9999" }
+ let(:pact_broker_client_options) { { pact_broker_base_url: pact_broker_base_url } }
+ subject { PactBroker::Client::Environments::ListEnvironments.call(params, options, pact_broker_client_options) }
+
+ def mock_index
+ new_interaction
+ .given("the pb:environments relation exists in the index resource")
+ .upon_receiving("a request for the index resource")
+ .with_request(
+ method: "GET",
+ path: '/',
+ headers: get_request_headers).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ _links: {
+ :'pb:environments' => {
+ href: generate_mock_server_url(
+ regex: ".*(\\/environments)$",
+ example: "/environments"
+ )
+ }
+ }
+ }
+ )
+ end
+
+ def mock_get_environments
+ new_interaction
+ .given("an environment exists")
+ .upon_receiving("a request to list the environments")
+ .with_request(
+ method: "GET",
+ path: "/environments",
+ headers: get_request_headers
+ )
+ .will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: response_body
+ )
+ end
+
+ it "returns a success result" do
+ mock_index
+ mock_get_environments
+ execute_http_pact do |mock_server|
+ expect(subject.success).to be true
+ Approvals.verify(subject.message, :name => "list_environments", format: :txt)
+ end
+ end
+end
diff --git a/spec/pact/providers/PactBroker/pact_broker_client_matrix_ignore_spec.rb b/spec/pact/providers/PactBroker/pact_broker_client_matrix_ignore_spec.rb
new file mode 100644
index 0000000..dc4611a
--- /dev/null
+++ b/spec/pact/providers/PactBroker/pact_broker_client_matrix_ignore_spec.rb
@@ -0,0 +1,125 @@
+require_relative '../../../pact_ruby_v2_spec_helper'
+require 'pact_broker/client/can_i_deploy'
+
+module PactBroker::Client
+ describe Matrix, :pact => true do
+
+ pact_broker
+ include_context "pact broker"
+ include_context "pact broker - pact-ruby-v2"
+
+ describe "can-i-deploy ignoring a pacticipant version" do
+ let(:matrix_response_body) { matrix }
+ let(:matrix) do
+ {
+ "summary" => {
+ "deployable" => true,
+ "ignored" => 1
+ },
+ "notices" => match_each("text" => "some notice", "type" => "info"),
+ "matrix" => [
+ {
+ "consumer" => {
+ "name" => "Foo",
+ "version" => {
+ "number" => "1.2.3"
+ }
+ },
+ "provider" => {
+ "name" => "Bar",
+ "version" => {
+ "number" => "4.5.6"
+ }
+ },
+ "verificationResult" => {
+ "success" => true,
+ "_links" => {
+ "self" => {
+ "href" => match_type_of("http://result")
+ }
+ }
+ }
+ },{
+ "consumer" => {
+ "name" => "Foo",
+ "version" => {
+ "number" => "3.4.5"
+ }
+ },
+ "provider" => {
+ "name" => "Bar",
+ "version" => {
+ "number" => "4.5.6"
+ }
+ },
+ "verificationResult" => {
+ "success" => false,
+ "_links" => {
+ "self" => {
+ "href" => match_type_of("http://result")
+ }
+ }
+ },
+ "ignored" => true
+ }
+ ]
+ }
+
+ end
+ let(:selectors) { [{ pacticipant: "Bar", version: "4.5.6" }, { pacticipant: "Foo", tag: "prod" } ] }
+ let(:matrix_options) do
+ {
+ ignore_selectors: [{ pacticipant: "Foo", version: "3.4.5" }]
+ }
+ end
+ let(:options) { { retry_while_unknown: 0, output: 'table' } }
+
+ before do
+ new_interaction
+ .given("provider Bar version 4.5.6 has a successful verification for Foo version 1.2.3 tagged prod and a failed verification for version 3.4.5 tagged prod")
+ .upon_receiving("a request to determine if Bar can be deployed with all Foo tagged prod, ignoring the verification for Foo version 3.4.5")
+ .with_request(
+ method: :get,
+ path: "/matrix",
+ # TIP:
+ # To setup a query parameter with
+ # - multiple values for the same key
+ # use an array of hashes otherwise you can pass a hash
+ query:
+ [
+ {"q[][pacticipant]" => "Bar"}, # q[][pacticipant] => ["Bar"]
+ {"q[][version]" => "4.5.6"},
+ {"q[][pacticipant]" => "Foo"}, # now q[][pacticipant] => ["Bar", "Foo"]
+ {"q[][tag]" => "prod"},
+ {"latestby" => "cvpv"},
+ {"ignore[][pacticipant]" => "Foo"},
+ {"ignore[][version]" => "3.4.5"}
+ ]
+ # { # example of a query hash - duplicate keys will be overwritten
+ # "q[][pacticipant]" => "Bar", # q[][pacticipant] => ["Bar"]
+ # "q[][version]" => "4.5.6",
+ # "q[][pacticipant]" => "Foo", # q[][pacticipant] => ["Foo"]
+ # "q[][tag]" => "prod",
+ # "latestby" => "cvpv",
+ # "ignore[][pacticipant]" => "Foo",
+ # "ignore[][version]" => "3.4.5",
+ # }
+ )
+ .will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: matrix_response_body
+ )
+ end
+
+ let(:pact_broker_base_url) { "http://127.0.0.1:9999" }
+ subject { PactBroker::Client::CanIDeploy.call(selectors, matrix_options, options, { pact_broker_base_url: pact_broker_base_url })}
+
+ it 'returns the CLI output' do
+ execute_http_pact do |mock_server|
+ Approvals.verify(subject.message, :name => "can_i_deploy_ignore", format: :txt)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/pact/providers/PactBroker/pact_broker_client_matrix_spec.rb b/spec/pact/providers/PactBroker/pact_broker_client_matrix_spec.rb
new file mode 100644
index 0000000..27f1aa1
--- /dev/null
+++ b/spec/pact/providers/PactBroker/pact_broker_client_matrix_spec.rb
@@ -0,0 +1,371 @@
+require_relative '../../../pact_ruby_v2_spec_helper'
+require 'pact_broker/client'
+require "pact_broker/client/matrix/query"
+
+module PactBroker::Client
+ describe Matrix, :pact => true do
+
+ pact_broker
+ include_context "pact broker"
+ include_context "pact broker - pact-ruby-v2"
+
+ describe "retriving the compatibility matrix" do
+ let(:matrix_response_body) { match_type_of(matrix) }
+ let(:matrix) { JSON.parse(File.read('spec/support/matrix.json')) }
+ let(:selectors) { [{ pacticipant: "Foo", version: "1.2.3" }, { pacticipant: "Bar", version: "4.5.6" }] }
+ let(:options) { {} }
+ let(:pact_broker_base_url) { "http://127.0.0.1:9999" }
+ subject { PactBroker::Client::Matrix::Query.call({ selectors: selectors, options: options }, {}, { pact_broker_base_url: pact_broker_base_url }) }
+
+ context "when results are found" do
+ let(:interaction) do
+ new_interaction.
+ given("the pact for Foo version 1.2.3 has been verified by Bar version 4.5.6").
+ upon_receiving("a request for the compatibility matrix for Foo version 1.2.3 and Bar version 4.5.6").
+ with_request(
+ method: :get,
+ path: "/matrix",
+ query: [
+ {"q[][pacticipant]" => "Foo"},
+ {"q[][version]" => "1.2.3"},
+ {"q[][pacticipant]" => "Bar"},
+ {"q[][version]" => "4.5.6"},
+ {"latestby" => "cvpv"}
+ ]
+ ).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: matrix_response_body
+ )
+ end
+
+ it 'returns the pact matrix' do
+ interaction.execute do |mock_server|
+ matrix = subject
+ expect(matrix[:matrix].size).to eq 1
+ end
+ end
+ end
+
+ context "when the pacticipant name has a space in it" do
+ let(:interaction1) do
+ new_interaction.
+ given("the pact for Foo Thing version 1.2.3 has been verified by Bar version 4.5.6").
+ upon_receiving("a request for the compatibility matrix for Foo version 1.2.3 and Bar version 4.5.6").
+ with_request(
+ method: :get,
+ path: "/matrix",
+ query: [
+ {"q[][pacticipant]" => "Foo Thing"},
+ {"q[][version]" => "1.2.3"},
+ {"q[][pacticipant]" => "Bar"},
+ {"q[][version]" => "4.5.6"},
+ {"latestby" => "cvpv"}
+ ]
+ ).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: matrix_response_body
+ )
+ end
+
+ let(:selectors) { [{ pacticipant: "Foo Thing", version: "1.2.3" }, { pacticipant: "Bar", version: "4.5.6" }] }
+
+ it 'incorrectly escapes the spaces but it still seems to work' do
+ interaction1.execute do |mock_server|
+ matrix = subject
+ expect(matrix[:matrix].size).to eq 1
+ end
+ end
+ end
+
+ context "with only one version selector" do
+ let(:interaction) do
+ new_interaction.
+ given("the pact for Foo version 1.2.3 has been verified by Bar version 4.5.6 and version 5.6.7").
+ upon_receiving("a request for the compatibility matrix where only the version of Foo is specified").
+ with_request(
+ method: :get,
+ path: "/matrix",
+ query: [
+ {"q[][pacticipant]" => "Foo"},
+ {"q[][version]" => "1.2.3"},
+ {"latestby" => "cvp"},
+ {"latest" => "true"}
+ ]
+ ).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: matrix_response_body
+ )
+ end
+
+ let(:selectors) { [{ pacticipant: "Foo", version: "1.2.3" }] }
+
+ it 'returns the row with the lastest verification for version 1.2.3' do
+ interaction.execute do |mock_server|
+ matrix = subject
+ expect(matrix[:matrix].size).to eq 1
+ end
+ end
+ end
+
+ context "when one or more of the versions does not exist" do
+ let(:interaction) do
+ new_interaction.
+ given("the pact for Foo version 1.2.3 has been verified by Bar version 4.5.6").
+ upon_receiving("a request for the compatibility matrix where one or more versions does not exist").
+ with_request(
+ method: :get,
+ path: "/matrix",
+ query: [
+ {"q[][pacticipant]" => "Foo"},
+ {"q[][version]" => "1.2.3"},
+ {"q[][pacticipant]" => "Bar"},
+ {"q[][version]" => "9.9.9"},
+ {"latestby" => "cvpv"}
+ ]
+ ).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ summary: {
+ reason: match_type_of("an error message")
+ }
+ }
+ )
+ end
+
+ let(:selectors) { [{ pacticipant: "Foo", version: "1.2.3" }, { pacticipant: "Bar", version: "9.9.9" }] }
+
+ it 'does not raise an error' do
+ interaction.execute do |mock_server|
+ subject
+ end
+ end
+ end
+
+ context "when results are not found" do
+ let(:interaction) do
+ new_interaction.
+ upon_receiving("a request for the compatibility matrix for a pacticipant that does not exist").
+ with_request(
+ method: :get,
+ path: "/matrix",
+ query: [
+ {"q[][pacticipant]" => "Wiffle"},
+ {"q[][version]" => "1.2.3"},
+ {"q[][pacticipant]" => "Meep"},
+ {"q[][version]" => "9.9.9"},
+ {"latestby" => "cvpv"}
+ ]
+ ).
+ will_respond_with(
+ status: 400,
+ headers: pact_broker_response_headers,
+ body: {
+ errors: match_each("an error message")
+ }
+ )
+ end
+
+ let(:selectors) { [{ pacticipant: "Wiffle", version: "1.2.3" }, { pacticipant: "Meep", version: "9.9.9" }] }
+
+ it 'raises an error' do
+ interaction.execute do |mock_server|
+ expect {
+ subject
+ }.to raise_error PactBroker::Client::Hal::ErrorResponseReturned, /an error message/
+ end
+ end
+ end
+
+ context "when no versions are specified" do
+ let(:interaction) do
+ new_interaction.
+ given("the pact for Foo version 1.2.3 and 1.2.4 has been verified by Bar version 4.5.6").
+ upon_receiving("a request for the compatibility matrix for all versions of Foo and Bar").
+ with_request(
+ method: :get,
+ path: "/matrix",
+ query: [
+ {"q[][pacticipant]" => "Foo"},
+ {"q[][pacticipant]" => "Bar"},
+ {"latestby" => "cvpv"}
+ ]
+ ).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ matrix: match_each(matrix_row, 2)
+ }
+ )
+ end
+ let(:matrix_row) { JSON.parse(File.read('spec/support/matrix.json'))['matrix'].first }
+ let(:selectors) { [{ pacticipant: "Foo" }, { pacticipant: "Bar" }] }
+
+ it "returns multiple rows" do
+ interaction.execute do |mock_server|
+ matrix = subject
+ expect(matrix[:matrix].size).to eq 2
+ end
+ end
+ end
+
+ context "when the success option is true" do
+ let(:interaction) do
+ new_interaction.
+ given("the pact for Foo version 1.2.3 has been successfully verified by Bar version 4.5.6, and 1.2.4 unsuccessfully by 9.9.9").
+ upon_receiving("a request for the successful rows of the compatibility matrix for all versions of Foo and Bar").
+ with_request(
+ method: :get,
+ path: "/matrix",
+ query: [
+ {"q[][pacticipant]" => "Foo"},
+ {"q[][pacticipant]" => "Bar"},
+ {"latestby" => "cvpv"},
+ {"success[]" => "true"}
+ ]
+ ).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: matrix_response_body
+ )
+ end
+ let(:matrix_row) { JSON.parse(File.read('spec/support/matrix.json'))['matrix'].first }
+ let(:selectors) { [{ pacticipant: "Foo" }, { pacticipant: "Bar" }] }
+ let(:options) { {success: true} }
+
+ it "returns only the successful row" do
+ interaction.execute do |mock_server|
+ matrix = pact_broker_client.matrix.get(selectors, options)
+ expect(matrix[:matrix].size).to eq 1
+ end
+ end
+ end
+
+ context "when the latest version for a given tag is specified" do
+ let(:interaction) do
+ new_interaction.
+ given("the pact for Foo version 1.2.3 has been successfully verified by Bar version 4.5.6 with tag prod, and 1.2.4 unsuccessfully by 9.9.9").
+ upon_receiving("a request for the compatibility matrix for Foo version 1.2.3 and the latest prod version of Bar").
+ with_request(
+ method: :get,
+ path: "/matrix",
+ query: [
+ {"q[][pacticipant]" => "Foo"},
+ {"q[][version]" => "1.2.3"},
+ {"q[][pacticipant]" => "Bar"},
+ {"q[][latest]" => "true"},
+ {"q[][tag]" => "prod"},
+ {"latestby" => "cvpv"}
+ ]
+ ).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: matrix_response_body
+ )
+ end
+ let(:matrix_row) { JSON.parse(File.read('spec/support/matrix.json'))['matrix'].first }
+ let(:selectors) { [{ pacticipant: "Foo", version: "1.2.3"}, { pacticipant: "Bar", latest: true, tag: 'prod' }] }
+ let(:options) { {} }
+
+ it "returns the matrix with the latest prod version of Bar" do
+ interaction.execute do |mock_server|
+ matrix = pact_broker_client.matrix.get(selectors, options)
+ expect(matrix[:matrix].size).to eq 1
+ end
+ end
+ end
+
+ context "when the latest version is specified" do
+ let(:interaction) do
+ new_interaction.
+ given("the pact for Foo version 1.2.3 has been successfully verified by Bar version 4.5.6, and 1.2.4 unsuccessfully by 9.9.9").
+ upon_receiving("a request for the compatibility matrix for Foo version 1.2.3 and the latest version of Bar").
+ with_request(
+ method: :get,
+ path: "/matrix",
+ query: [
+ {"q[][pacticipant]" => "Foo"},
+ {"q[][version]" => "1.2.4"},
+ {"q[][pacticipant]" => "Bar"},
+ {"q[][latest]" => "true"},
+ {"latestby" => "cvpv"}
+ ]
+ ).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: matrix_response_body
+ )
+ end
+ let(:matrix_row) { JSON.parse(File.read('spec/support/matrix.json'))['matrix'].first }
+ let(:selectors) { [{ pacticipant: "Foo", version: "1.2.4"}, { pacticipant: "Bar", latest: true }] }
+ let(:options) { {} }
+
+ it "returns the matrix with the latest prod version of Bar" do
+ interaction.execute do |mock_server|
+ matrix = pact_broker_client.matrix.get(selectors, options)
+ expect(matrix[:matrix].size).to eq 1
+ end
+ end
+ end
+
+ context "when checking if we can deploy with the latest tagged versions of the other services" do
+ let(:interaction) do
+ new_interaction.
+ given("the pact for Foo version 1.2.3 has been successfully verified by Bar version 4.5.6 (tagged prod) and version 5.6.7").
+ upon_receiving("a request for the compatibility matrix for Foo version 1.2.3 and the latest prod versions of all other pacticipants").
+ with_request(
+ method: :get,
+ path: "/matrix",
+ query: [
+ {"q[][pacticipant]" => "Foo"},
+ {"q[][version]" => "1.2.3"},
+ {"latestby" => "cvp"},
+ {"latest" => "true"},
+ {"tag" => "prod"}
+ ]
+ ).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: matrix_response_body
+ )
+ end
+
+ let(:selectors) { [{ pacticipant: "Foo", version: "1.2.3" }] }
+
+ let(:matrix_response_body) {
+ {
+ matrix: [{
+ consumer: { name: 'Foo', version: { number: '1.2.3' } },
+ provider: { name: 'Bar', version: { number: '4.5.6'} },
+ }]
+ }
+ }
+
+ let(:options) { { to_tag: 'prod' } }
+
+ it "returns the matrix with the latest prod version of Bar" do
+ interaction.execute do |mock_server|
+ matrix = pact_broker_client.matrix.get(selectors, options)
+ expect(matrix[:matrix].size).to eq 1
+ end
+ end
+ end
+
+ context "with an environment name" do
+ it "passes the environment name in the options"
+ end
+ end
+ end
+end
diff --git a/spec/pact/providers/PactBroker/pact_broker_client_publish_spec.rb b/spec/pact/providers/PactBroker/pact_broker_client_publish_spec.rb
new file mode 100644
index 0000000..9bdb627
--- /dev/null
+++ b/spec/pact/providers/PactBroker/pact_broker_client_publish_spec.rb
@@ -0,0 +1,149 @@
+require 'pact_broker/client/pact_broker_client'
+require_relative '../../../pact_ruby_v2_spec_helper'
+
+
+module PactBroker::Client
+ describe PactBrokerClient, :pact => true do
+
+ pact_broker
+ include_context "pact broker"
+ include_context "pact broker - pact-ruby-v2"
+
+ # This endpoint fails on the pact_broker
+ # it is the old end point only used with
+ # PACT_BROKER_FEATURES=publish_pacts_using_old_api=true
+ describe "publishing a pact", :skip do
+
+ let(:options) { { pact_hash: pact_hash, consumer_version: consumer_version }}
+ let(:location) { 'http://example.org/pacts/provider/Pricing%20Service/consumer/Condor/latest' }
+ context "when the provider already exists in the pact-broker" do
+
+ let(:interaction) do
+ new_interaction.
+ given("the 'Pricing Service' already exists in the pact-broker").
+ upon_receiving("a request to publish a pact").
+ with_request(
+ method: :put,
+ path: '/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0',
+ headers: default_request_headers,
+ body: pact_hash ).
+ will_respond_with(
+ headers: pact_broker_response_headers,
+ status: 201,
+ body: {
+ _links: {
+ :'pb:latest-pact-version' => {
+ href: location
+ }
+ }
+ }
+ )
+ end
+ it "returns the URL to find the newly published pact" do
+ interaction.execute do | mockserver |
+ expect(pact_broker_client.pacticipants.versions.pacts.publish(options)).to eq location
+ end
+ end
+ end
+
+ context "when the provider, consumer, pact and version already exist in the pact-broker" do
+ shared_examples "an already-existing pact" do |method|
+ let(:interaction) do
+ new_interaction.
+ given("the 'Pricing Service' and 'Condor' already exist in the pact-broker, and Condor already has a pact published for version 1.3.0").
+ upon_receiving("a request to publish a pact with method #{method}").
+ with_request(
+ method: method,
+ path: '/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0',
+ headers: default_request_headers,
+ body: pact_hash ).
+ will_respond_with(
+ headers: pact_broker_response_headers,
+ status: 200,
+ body: {
+ _links: {
+ :'pb:latest-pact-version' => {
+ href: location
+ }
+ }
+ }
+ )
+ end
+
+ it "returns true" do
+ interaction.execute do | mockserver |
+ expect(pact_broker_client.pacticipants.versions.pacts.publish(options)).to be_truthy
+ end
+ end
+ end
+
+ context "when the write method is set to merge" do
+ let(:client_config) { super().merge(client_options: {write: :merge}) }
+
+ it_behaves_like "an already-existing pact", :patch
+ end
+
+ context "when the write method is not set" do
+ it_behaves_like "an already-existing pact", :put
+ end
+ end
+
+ context "when the provider does not exist, but the consumer, pact and version already exist in the pact-broker" do
+ let(:interaction) do
+ new_interaction.
+ given("'Condor' already exist in the pact-broker, but the 'Pricing Service' does not").
+ upon_receiving("a request to publish a pact").
+ with_request(
+ method: :put,
+ path: '/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0',
+ headers: default_request_headers,
+ body: pact_hash ).
+ will_respond_with(
+ headers: pact_broker_response_headers,
+ status: 201,
+ body: {
+ _links: {
+ :'pb:latest-pact-version' => {
+ href: location
+ }
+ }
+ }
+ )
+ end
+ it "returns true" do
+ interaction.execute do | mockserver |
+ expect(pact_broker_client.pacticipants.versions.pacts.publish(options)).to be_truthy
+ end
+ end
+ end
+
+ context "when publishing is not successful" do
+ let(:interaction) do
+ new_interaction.
+ given("an error occurs while publishing a pact").
+ upon_receiving("a request to publish a pact").
+ with_request(
+ method: :put,
+ path: '/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0',
+ headers: default_request_headers,
+ body: pact_hash ).
+ will_respond_with(
+ status: 500,
+ headers: {'Content-Type' => match_regex(%r{application/.*json.*},'application/hal+json')},
+ body: {
+ error: {
+ message: match_regex(/.*/,'An error occurred')
+ }
+ }
+ )
+ end
+ it "raises an error" do
+ interaction.execute do | mockserver |
+ expect { pact_broker_client.pacticipants.versions.pacts.publish options }.to raise_error /An error occurred/
+ end
+ end
+ end
+
+ end
+ end
+end
diff --git a/spec/pact/providers/PactBroker/pact_broker_client_register_repository_spec.rb b/spec/pact/providers/PactBroker/pact_broker_client_register_repository_spec.rb
new file mode 100644
index 0000000..66b31f8
--- /dev/null
+++ b/spec/pact/providers/PactBroker/pact_broker_client_register_repository_spec.rb
@@ -0,0 +1,58 @@
+require 'pact_broker/client/pact_broker_client'
+require_relative '../../../pact_ruby_v2_spec_helper'
+
+module PactBroker::Client
+ describe Pacticipants, :pact => true do
+
+ pact_broker
+ include_context "pact broker"
+ include_context "pact broker - pact-ruby-v2"
+
+ let(:repository_url ) { "git@git.realestate.com.au:business-systems/pricing-service" }
+
+ describe "registering a repository url" do
+ context "where the pacticipant does not already exist in the pact-broker" do
+ let(:interaction) do
+ new_interaction.
+ given("the 'Pricing Service' does not exist in the pact-broker").
+ upon_receiving("a request to register the repository URL of a pacticipant").
+ with_request(
+ method: :patch,
+ path: '/pacticipants/Pricing%20Service',
+ headers: old_patch_request_headers,
+ body: {repository_url: repository_url} ).
+ will_respond_with(
+ status: 201,
+ headers: pact_broker_response_headers
+ )
+ end
+ it "returns true" do
+ interaction.execute do | mockserver |
+ expect(pact_broker_client.pacticipants.update({:pacticipant => 'Pricing Service', :repository_url => repository_url})).to be true
+ end
+ end
+ end
+ context "where the 'Pricing Service' exists in the pact-broker" do
+ let(:interaction) do
+ new_interaction.
+ given("the 'Pricing Service' already exists in the pact-broker").
+ upon_receiving("a request to register the repository URL of a pacticipant").
+ with_request(
+ method: :patch,
+ path: '/pacticipants/Pricing%20Service',
+ headers: old_patch_request_headers,
+ body: { repository_url: repository_url }).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers
+ )
+ end
+ it "returns true" do
+ interaction.execute do | mockserver |
+ expect(pact_broker_client.pacticipants.update({:pacticipant => 'Pricing Service', :repository_url => repository_url})).to be true
+ end
+ end
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/spec/pact/providers/PactBroker/pact_broker_client_retrieve_all_pacts_for_provider_spec.rb b/spec/pact/providers/PactBroker/pact_broker_client_retrieve_all_pacts_for_provider_spec.rb
new file mode 100644
index 0000000..2b6c884
--- /dev/null
+++ b/spec/pact/providers/PactBroker/pact_broker_client_retrieve_all_pacts_for_provider_spec.rb
@@ -0,0 +1,62 @@
+require_relative '../../../pact_ruby_v2_spec_helper'
+
+require 'pact_broker/client'
+
+module PactBroker::Client
+ describe Pacts, :pact => true do
+
+ pact_broker
+ include_context "pact broker"
+ include_context "pact broker - pact-ruby-v2"
+
+ describe "retriving all pacts for provider" do
+ let(:response_body) { match_type_of(JSON.parse(File.read("./spec/support/latest_pacts_for_provider.json"))) }
+ let(:expectedPactsArray) { [{:name => "Condor", :href => "http://example.org/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0"}] }
+
+ context "when retrieving all the latest pacts for provider with prod tag specified" do
+ let(:interaction) do
+ new_interaction.
+ given("tagged as prod pact between Condor and the Pricing Service exists").
+ upon_receiving("a request for the list of the latest prod pacts from all consumers for the Pricing Service'").
+ with_request(
+ method: :get,
+ path: "/pacts/provider/Pricing%20Service/latest/prod",
+ headers: {}).
+ will_respond_with(
+ headers: {'Content-Type' => match_regex(%r{application/.*json.*},'application/hal+json')},
+ status: 200,
+ body: response_body)
+ end
+ it 'returns the map of all provider latest prod pacts' do
+ interaction.execute do | mockserver |
+ pactsArray = pact_broker_client.pacticipants.versions.pacts.list_latest_for_provider provider: 'Pricing Service', tag: 'prod'
+ expect(pactsArray.length).to eq(1)
+ expect(pactsArray).to eq(expectedPactsArray)
+ end
+ end
+ end
+ context "when retrieving all the latest pacts for provider with no tag specified" do
+ let(:interaction) do
+ new_interaction.
+ given("a latest pact between Condor and the Pricing Service exists").
+ upon_receiving("a request for the list of the latest pacts from all consumers for the Pricing Service'").
+ with_request(
+ method: :get,
+ path: "/pacts/provider/Pricing%20Service/latest",
+ headers: {}).
+ will_respond_with(
+ headers: {'Content-Type' => match_regex(%r{application/.*json.*},'application/hal+json')},
+ status: 200,
+ body: response_body)
+ end
+ it 'returns the map of all provider latest pacts' do
+ interaction.execute do | mockserver |
+ pactsArray = pact_broker_client.pacticipants.versions.pacts.list_latest_for_provider provider: 'Pricing Service'
+ expect(pactsArray.length).to eq(1)
+ expect(pactsArray).to eq(expectedPactsArray)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/pact/providers/PactBroker/pact_broker_client_retrieve_pact_spec.rb b/spec/pact/providers/PactBroker/pact_broker_client_retrieve_pact_spec.rb
new file mode 100644
index 0000000..551b990
--- /dev/null
+++ b/spec/pact/providers/PactBroker/pact_broker_client_retrieve_pact_spec.rb
@@ -0,0 +1,119 @@
+require_relative '../../../pact_ruby_v2_spec_helper'
+require 'pact_broker/client'
+
+module PactBroker::Client
+ describe Pacts, :pact => true do
+
+ pact_broker
+ include_context "pact broker"
+ include_context "pact broker - pact-ruby-v2"
+
+ describe "retrieving a pact" do
+ describe "retriving a specific version" do
+ let(:interaction) do
+ new_interaction.
+ given("the 'Pricing Service' and 'Condor' already exist in the pact-broker, and Condor already has a pact published for version 1.3.0").
+ upon_receiving("a request retrieve a pact for a specific version").
+ with_request(
+ method: :get,
+ path: '/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0',
+ headers: {} ).
+ will_respond_with(
+ headers: pact_broker_response_headers,
+ status: 200,
+ body: pact_hash
+ )
+ end
+ it "returns the pact json" do
+ interaction.execute do | mockserver |
+ response = pact_broker_client.pacticipants.versions.pacts.get consumer: 'Condor', provider: 'Pricing Service', consumer_version: '1.3.0'
+ expect(response).to eq(pact_json)
+ end
+ end
+ end
+
+ describe "finding the latest version" do
+ context "when a pact is found" do
+
+ let(:response_headers) do
+ pact_broker_response_headers.merge(
+ {'Content-Type' => match_regex(%r{application/.*json.*},'application/hal+json')},
+ 'X-Pact-Consumer-Version' => consumer_version
+ )
+ end
+ let(:interaction) do
+ new_interaction.
+ given("a pact between Condor and the Pricing Service exists").
+ upon_receiving("a request to retrieve the latest pact between Condor and the Pricing Service").
+ with_request(
+ method: :get,
+ path: '/pacts/provider/Pricing%20Service/consumer/Condor/latest',
+ headers: {}
+ ).
+ will_respond_with(
+ status: 200,
+ headers: response_headers,
+ body: pact_hash
+ )
+ end
+
+ it "returns the pact json" do
+ interaction.execute do | mockserver |
+ response = pact_broker_client.pacticipants.versions.pacts.latest consumer: 'Condor', provider: 'Pricing Service'
+ expect(response).to eq(pact_json)
+ end
+ end
+
+ end
+ context "when no pact is found" do
+ let(:interaction) do
+ new_interaction.
+ given("no pact between Condor and the Pricing Service exists").
+ upon_receiving("a request to retrieve the latest pact between Condor and the Pricing Service").
+ with_request(
+ method: :get,
+ path: '/pacts/provider/Pricing%20Service/consumer/Condor/latest',
+ headers: {}
+ ).
+ will_respond_with(
+ status: 404
+ )
+ end
+ it "returns nil" do
+ interaction.execute do | mockserver |
+ response = pact_broker_client.pacticipants.versions.pacts.latest consumer: 'Condor', provider: 'Pricing Service'
+ expect(response).to eq(nil)
+ end
+ end
+ end
+ end
+ describe "finding the latest production version" do
+ context "when a pact is found" do
+ let(:interaction) do
+ new_interaction.
+ given("a pact between Condor and the Pricing Service exists for the production version of Condor").
+ upon_receiving("a request to retrieve the pact between the production verison of Condor and the Pricing Service").
+ with_request(
+ method: :get,
+ path: '/pacts/provider/Pricing%20Service/consumer/Condor/latest/prod',
+ headers: { 'Accept' => 'application/hal+json, application/json'}
+ ).
+ will_respond_with(
+ status: 200,
+ body: pact_hash,
+ headers: pact_broker_response_headers
+ )
+ end
+
+ it "returns the pact json" do
+ interaction.execute do | mockserver |
+ response = pact_broker_client.pacticipants.versions.pacts.latest consumer: 'Condor', provider: 'Pricing Service', tag: 'prod'
+ expect(response).to eq(pact_json)
+ end
+ end
+ end
+ end
+ end
+
+ end
+end
diff --git a/spec/pact/providers/PactBroker/pact_broker_client_tags_spec.rb b/spec/pact/providers/PactBroker/pact_broker_client_tags_spec.rb
new file mode 100644
index 0000000..d86dc53
--- /dev/null
+++ b/spec/pact/providers/PactBroker/pact_broker_client_tags_spec.rb
@@ -0,0 +1,110 @@
+require 'spec_helper'
+require 'pact_broker/client'
+require_relative '../../../pact_ruby_v2_spec_helper'
+
+
+describe PactBroker::Client::Versions, pact: true do
+
+ pact_broker
+ include_context "pact broker"
+ include_context "pact broker - pact-ruby-v2"
+
+ describe "tagging a version with prod details" do
+ let(:repository_ref) { "packages/condor-#{version}" }
+
+ let(:tag_options) { {pacticipant: 'Condor', version: version, repository_ref: repository_ref, :tag => 'prod'} }
+ context "when the component exists" do
+ let(:interaction) do
+ new_interaction.
+ given("'Condor' exists in the pact-broker").
+ upon_receiving("a request to tag the production version of Condor").
+ with_request(
+ method: :put,
+ path: '/pacticipants/Condor/versions/1.3.0/tags/prod',
+ headers: default_request_headers, body: {}).
+ will_respond_with(
+ status: 201,
+ headers: pact_broker_response_headers,
+ body: {
+ _links: {
+ self: {
+ href: generate_mock_server_url(
+ regex: ".*(\\/pacticipants\\/Condor\\/versions\\/1\\.3\\.0\\/tags\\/prod)$",
+ example: "/pacticipants/Condor/versions/1.3.0/tags/prod"
+ )
+ }
+ }
+ }
+ )
+ end
+ it "returns true" do
+ interaction.execute do | mockserver |
+ expect(pact_broker_client.pacticipants.versions.tag tag_options).to be true
+ end
+ end
+ end
+ context "when the component does not exist" do
+ let(:interaction) do
+ new_interaction.
+ given("'Condor' does not exist in the pact-broker").
+ upon_receiving("a request to tag the production version of Condor").
+ with_request(
+ method: :put,
+ path: '/pacticipants/Condor/versions/1.3.0/tags/prod',
+ headers: default_request_headers, body: {}).
+ will_respond_with(
+ status: 201,
+ headers: pact_broker_response_headers,
+ body: {
+ _links: {
+ self: {
+ href: generate_mock_server_url(
+ regex: ".*(\\/pacticipants\\/Condor\\/versions\\/1\\.3\\.0\\/tags\\/prod)$",
+ example: "/pacticipants/Condor/versions/1.3.0/tags/prod"
+ )
+ }
+ }
+ }
+ )
+ end
+ it "returns true" do
+ interaction.execute do | mockserver |
+ expect(pact_broker_client.pacticipants.versions.tag tag_options).to be true
+ end
+ end
+ end
+
+ context "when the tag already exists" do
+ let(:interaction) do
+ new_interaction.
+ given("'Condor' exists in the pact-broker with version 1.3.0, tagged with 'prod'").
+ upon_receiving("a request to tag the production version of Condor").
+ with_request(
+ method: :put,
+ path: '/pacticipants/Condor/versions/1.3.0/tags/prod',
+ headers: default_request_headers, body: {}).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ _links: {
+ self: {
+ href: generate_mock_server_url(
+ regex: ".*(\\/pacticipants\\/Condor\\/versions\\/1\\.3\\.0\\/tags\\/prod)$",
+ example: "/pacticipants/Condor/versions/1.3.0/tags/prod"
+ )
+ }
+ }
+ }
+ )
+ end
+
+ it "returns true" do
+ interaction.execute do | mockserver |
+ expect(pact_broker_client.pacticipants.versions.tag tag_options).to be true
+ end
+ end
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/spec/pact/providers/PactBroker/pact_broker_client_versions_spec.rb b/spec/pact/providers/PactBroker/pact_broker_client_versions_spec.rb
new file mode 100644
index 0000000..adeb25e
--- /dev/null
+++ b/spec/pact/providers/PactBroker/pact_broker_client_versions_spec.rb
@@ -0,0 +1,133 @@
+require_relative '../../../pact_ruby_v2_spec_helper'
+
+require 'pact_broker/client'
+
+describe PactBroker::Client::Versions, pact: true do
+
+ pact_broker
+ include_context "pact broker"
+ include_context "pact broker - pact-ruby-v2"
+
+ let(:get_headers) { { "Accept" => "application/hal+json, application/json" } }
+ let(:pact_broker_base_url) { "http://127.0.0.1:9999" }
+
+ describe "retrieving the latest pacticipant version" do
+ let(:latest_version_path) { "/pacticipants/Condor/latest-version" }
+ let(:latest_version_url) { pact_broker_base_url + latest_version_path }
+
+ let(:interaction) do
+ new_interaction
+ .given("the pb:latest-version relation exists in the index resource")
+ .upon_receiving("a request for the index resource")
+ .with_request(
+ method: :get,
+ path: '/',
+ headers: get_headers).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ _links: {
+ :'pb:latest-version' => {
+ href: generate_mock_server_url(
+ regex: ".*(\\/pacticipants\\/.*\\/latest-version)$",
+ example: latest_version_url
+ )
+ }
+ }
+ }
+ )
+
+ new_interaction
+ .given("'Condor' exists in the pact-broker with the latest version 1.2.3")
+ .upon_receiving("a request to retrieve the latest version of Condor")
+ .with_request(
+ method: :get,
+ path: '/pacticipants/Condor/latest-version',
+ headers: get_headers).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ number: '1.2.3',
+ _links: {
+ self: {
+ href: generate_mock_server_url(
+ regex: "(.*)$",
+ example: "/some-url"
+ ),
+ }
+ }
+ }
+ )
+ end
+
+ it "returns the version hash" do
+ interaction.execute do | mockserver |
+ version_hash = pact_broker_client.pacticipants.versions.latest(pacticipant: 'Condor')
+ expect(version_hash[:number]).to eq '1.2.3'
+ expect(version_hash[:_links][:self][:href]).to eq 'http://127.0.0.1:9999/some-url'
+ end
+ end
+ end
+
+ describe "retrieving the latest pacticipant version for a tag" do
+ let(:latest_tagged_version_path) { "/pacticipants/Condor/latest-version/production" }
+ let(:latest_tagged_version_url) { pact_broker_base_url + latest_tagged_version_path }
+
+ let(:interaction) do
+ new_interaction
+ .given("the pb:latest-tagged-version relation exists in the index resource")
+ .upon_receiving("a request for the index resource")
+ .with_request(
+ method: :get,
+ path: '/',
+ headers: get_headers).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ _links: {
+ :'pb:latest-tagged-version' => {
+ href: generate_mock_server_url(
+ regex: ".*(\\/pacticipants\\/.*\\/latest-version\\/.*)$",
+ example: latest_tagged_version_url
+ )
+ }
+ }
+ }
+ )
+
+ new_interaction
+ .given("'Condor' exists in the pact-broker with the latest tagged 'production' version 1.2.3")
+ .upon_receiving("a request to retrieve the latest 'production' version of Condor")
+ .with_request(
+ method: :get,
+ path: '/pacticipants/Condor/latest-version/production',
+ headers: get_headers).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ number: '1.2.3',
+ _links: {
+ self: {
+ href: generate_mock_server_url(
+ regex: "(.*)$",
+ example: "/some-url"
+ ),
+ }
+ }
+ }
+ )
+ end
+
+ it "returns the version hash" do
+ interaction.execute do | mockserver |
+ version_hash = pact_broker_client.pacticipants.versions.latest(pacticipant: 'Condor', tag: 'production')
+ expect(version_hash[:number]).to eq '1.2.3'
+ expect(version_hash[:_links][:self][:href]).to eq 'http://127.0.0.1:9999/some-url'
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/spec/pact/providers/PactBroker/pacticipants_create_spec.rb b/spec/pact/providers/PactBroker/pacticipants_create_spec.rb
new file mode 100644
index 0000000..efdfbac
--- /dev/null
+++ b/spec/pact/providers/PactBroker/pacticipants_create_spec.rb
@@ -0,0 +1,157 @@
+require_relative '../../../pact_ruby_v2_spec_helper'
+
+require 'pact_broker/client/pacticipants/create'
+
+RSpec.describe "creating or updating a pacticipant", pact: true do
+ pact_broker
+ include_context "pact broker"
+ include_context "pact broker - pact-ruby-v2"
+ include PactBrokerPactHelperMethods
+
+ let(:pact_broker_base_url) { "http://127.0.0.1:9999" }
+
+ before do
+ index_links = {
+ 'pb:pacticipants' => {
+ href: generate_mock_server_url(
+ regex: ".*(\\/pacticipants)$",
+ example: "/pacticipants"
+ )
+ },
+ 'pb:pacticipant' => {
+ href: generate_mock_server_url(
+ regex: ".*(\\/pacticipants\\/\\{pacticipant\\})$",
+ example: "/pacticipants/{pacticipant}"
+ )
+ }
+ }
+ new_interaction
+ .given("the pacticipant relations are present")
+ .upon_receiving("a request for the index resource")
+ .with_request(
+ method: :get,
+ path: '/',
+ headers: get_request_headers).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ _links: index_links
+ }
+ )
+ end
+
+ let(:params) do
+ {
+ name: "Foo",
+ repository_url: "http://foo"
+ }
+ end
+
+ let(:request_body) { { name: "Foo", repositoryUrl: "http://foo" } }
+
+
+ let(:response_status) { 201 }
+ let(:create_success_response) do
+ {
+ status: response_status,
+ headers: pact_broker_response_headers,
+ body: {
+ name: "Foo",
+ repositoryUrl: "http://foo",
+ _links: {
+ self: {
+ href: generate_mock_server_url(
+ regex: ".*(\\/pacticipants\\/Foo)$",
+ example: "/pacticipants/Foo"
+ ),
+ }
+ }
+ }
+ }
+ end
+
+ let(:get_success_response) do
+ {
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ _links: {
+ self: {
+ href: generate_mock_server_url(
+ regex: ".*(\\/pacticipants\\/Foo)$",
+ example: "/pacticipants/Foo"
+ ),
+ }
+ }
+ }
+ }
+ end
+
+ let(:pact_broker_client_options) { { pact_broker_base_url: pact_broker_base_url} }
+ let(:options) { {} }
+
+ subject { PactBroker::Client::Pacticipants2::Create.call(params, options, pact_broker_client_options) }
+
+ context "when the pacticipant does not already exist" do
+ let(:interaction) do
+ new_interaction
+ .upon_receiving("a request to retrieve a pacticipant")
+ .with_request(
+ method: :get,
+ path: '/pacticipants/Foo',
+ headers: get_request_headers)
+ .will_respond_with(status: 404)
+
+ new_interaction
+ .upon_receiving("a request to create a pacticipant")
+ .with_request(
+ method: :post,
+ path: '/pacticipants',
+ headers: post_request_headers,
+ body: request_body)
+ .will_respond_with(**create_success_response)
+ end
+
+ it "returns a CommandResult with success = true" do
+ interaction.execute do | mockserver |
+ expect(subject).to be_a PactBroker::Client::CommandResult
+ expect(subject.success).to be true
+ expect(subject.message).to include "Pacticipant \"Foo\" created"
+ end
+ end
+ end
+
+ context "when the pacticipant does already exist" do
+ let(:interaction) do
+ new_interaction
+ .given("a pacticipant with name Foo exists")
+ .upon_receiving("a request to retrieve a pacticipant")
+ .with_request(
+ method: :get,
+ path: '/pacticipants/Foo',
+ headers: get_request_headers)
+ .will_respond_with(**get_success_response)
+
+ new_interaction
+ .given("a pacticipant with name Foo exists")
+ .upon_receiving("a request to update a pacticipant")
+ .with_request(
+ method: :patch,
+ path: '/pacticipants/Foo',
+ headers: post_request_headers,
+ body: request_body)
+ .will_respond_with(**create_success_response)
+ end
+
+ let(:response_status) { 200 }
+
+ it "returns a CommandResult with success = true" do
+ interaction.execute do | mockserver |
+ expect(subject).to be_a PactBroker::Client::CommandResult
+ expect(subject.success).to be true
+ expect(subject.message).to include "Pacticipant \"Foo\" updated"
+ end
+ end
+ end
+end
diff --git a/spec/pact/providers/PactBroker/publish_pacts_spec.rb b/spec/pact/providers/PactBroker/publish_pacts_spec.rb
new file mode 100644
index 0000000..6b76717
--- /dev/null
+++ b/spec/pact/providers/PactBroker/publish_pacts_spec.rb
@@ -0,0 +1,122 @@
+require 'pact_broker/client/publish_pacts'
+require_relative '../../../pact_ruby_v2_spec_helper'
+
+RSpec.describe "publishing contracts", pact: true do
+ before do
+ allow_any_instance_of(PactBroker::Client::Hal::HttpClient).to receive(:sleep)
+ allow_any_instance_of(PactBroker::Client::Hal::HttpClient).to receive(:default_max_tries).and_return(1)
+ end
+ pact_broker
+ include_context "pact broker"
+ include_context "pact broker - pact-ruby-v2"
+ include PactBrokerPactHelperMethods
+
+ let(:pact_broker_base_url) { "http://127.0.0.1:9999" }
+ let(:pacticipant_name) { "Foo" }
+ let(:version_number) { "5556b8149bf8bac76bc30f50a8a2dd4c22c85f30" }
+ let(:output) { "text" }
+ let(:build_url) { "http://build" }
+ let(:consumer_version_params) do
+ {
+ pacticipant_name: pacticipant_name,
+ number: version_number,
+ tags: ["dev"],
+ branch: "main",
+ build_url: build_url,
+ output: output
+ }
+ end
+ let(:pact_file_path_1) { "spec/fixtures/foo-bar.json" }
+ let(:pact_file_paths) { [pact_file_path_1] }
+ let(:options) { { merge: true } }
+ let(:pact_broker_client_options) { {} }
+ let(:expected_content) { Base64.strict_encode64(JSON.parse(File.read(pact_file_path_1)).to_json) }
+ let(:request_body) do
+ {
+ pacticipantName: pacticipant_name,
+ pacticipantVersionNumber: version_number,
+ branch: "main",
+ tags: ["dev"],
+ buildUrl: "http://build",
+ contracts: [
+ {
+ consumerName: pacticipant_name,
+ providerName: "Bar",
+ specification: "pact",
+ contentType: "application/json",
+ content: expected_content,
+ onConflict: "merge"
+ }
+ ]
+ }
+ end
+
+ subject { PactBroker::Client::PublishPacts.call(pact_broker_base_url, pact_file_paths, consumer_version_params, options, pact_broker_client_options) }
+
+ def mock_index
+ new_interaction
+ .given("the pb:publish-contracts relations exists in the index resource")
+ .upon_receiving("a request for the index resource")
+ .with_request(
+ method: "GET",
+ path: '/',
+ headers: get_request_headers).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ _links: {
+ :'pb:publish-contracts' => {
+ href: generate_mock_server_url(
+ regex: ".*(\\/contracts\\/publish)$",
+ example: "/contracts/publish"
+ )
+ }
+ }
+ }
+ )
+ end
+
+ def mock_contract_publication
+ new_interaction
+ .upon_receiving("a request to publish contracts")
+ .with_request(
+ method: "POST",
+ path: '/contracts/publish',
+ headers: post_request_headers,
+ body: request_body).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ _embedded: {
+ pacticipant: {
+ name: pacticipant_name
+ },
+ version: {
+ number: version_number
+ }
+ },
+ logs: match_each(level: "info", message: "some message"),
+ _links: {
+ :'pb:pacticipant-version-tags' => [{ name: "dev"} ],
+ :'pb:contracts' => [{ href: match_type_of("http://some-pact") }]
+ }
+ }
+ )
+ end
+
+ context "with valid params" do
+ before do
+ mock_index
+ mock_contract_publication
+ end
+
+ it "returns a success result" do
+ execute_http_pact do | mockserver |
+ expect(subject.success).to be true
+ expect(subject.message).to include "some message"
+ end
+ end
+ end
+end
diff --git a/spec/pact/providers/PactBroker/record_deployment_spec.rb b/spec/pact/providers/PactBroker/record_deployment_spec.rb
new file mode 100644
index 0000000..652639c
--- /dev/null
+++ b/spec/pact/providers/PactBroker/record_deployment_spec.rb
@@ -0,0 +1,220 @@
+require_relative '../../../pact_ruby_v2_spec_helper'
+require 'pact_broker/client/deployments/record_deployment'
+
+RSpec.describe "recording a deployment", pact: true do
+ pact_broker
+ include_context "pact broker"
+ include_context "pact broker - pact-ruby-v2"
+ include PactBrokerPactHelperMethods
+
+ let(:pacticipant_name) { "Foo" }
+ let(:version_number) { "5556b8149bf8bac76bc30f50a8a2dd4c22c85f30" }
+ let(:environment_name) { "test" }
+ let(:output) { "text" }
+ let(:application_instance) { "blue" }
+ let(:params) do
+ {
+ pacticipant_name: pacticipant_name,
+ version_number: version_number,
+ environment_name: environment_name,
+ application_instance: application_instance
+ }
+ end
+ let(:options) do
+ {
+ output: output
+ }
+ end
+
+ let(:pact_broker_base_url) { "http://127.0.0.1:9999" }
+ let(:pact_broker_client_options) { { pact_broker_base_url: pact_broker_base_url } }
+
+ subject { PactBroker::Client::Deployments::RecordDeployment.call(params, options, pact_broker_client_options) }
+
+ def mock_index
+ new_interaction
+ .given("the pb:pacticipant-version and pb:environments relations exist in the index resource")
+ .upon_receiving("a request for the index resource")
+ .with_request(
+ method: "GET",
+ path: '/',
+ headers: get_request_headers).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ _links: {
+ :'pb:pacticipant-version' => {
+ href: generate_mock_server_url(
+ regex: ".*(\\/pacticipants\\/.*\\/versions\\/.*)$",
+ example: "/pacticipants/{pacticipant}/versions/{version}"
+ ),
+ },
+ :'pb:environments' => {
+ href: generate_mock_server_url(
+ regex: ".*(\\/environments)$",
+ example: "/environments"
+ )
+ }
+ }
+ }
+ )
+ end
+
+ def mock_pacticipant_version_with_test_environment_available_for_deployment
+ new_interaction
+ .given("version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for deployment")
+ .upon_receiving("a request for a pacticipant version")
+ .with_request(
+ method: "GET",
+ path: "/pacticipants/Foo/versions/5556b8149bf8bac76bc30f50a8a2dd4c22c85f30",
+ headers: get_request_headers
+ )
+ .will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ _links: {
+ "pb:record-deployment" => [
+ {
+ name: "test",
+ href: generate_mock_server_url(
+ regex: ".*(\\/pacticipants\\/.*\\/versions\\/.*\\/deployed-versions\\/environment\\/.*)$",
+ example: "/pacticipants/#{pacticipant_name}/versions/#{version_number}/deployed-versions/environment/cb632df3-0a0d-4227-aac3-60114dd36479"
+ ),
+ }
+ ]
+ }
+ }
+ )
+ end
+
+ def mock_pacticipant_version_without_test_environment_available_for_deployment
+ new_interaction
+ .given("version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with 2 environments that aren't test available for deployment")
+ .upon_receiving("a request for a pacticipant version")
+ .with_request(
+ method: "GET",
+ path: "/pacticipants/Foo/versions/5556b8149bf8bac76bc30f50a8a2dd4c22c85f30",
+ headers: get_request_headers
+ )
+ .will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ _links: {
+ "pb:record-deployment" => [
+ match_type_of(
+ name: "prod",
+ href: "href"
+ ),
+ match_type_of(
+ name: "dev",
+ href: "href"
+ ),
+ ]
+ }
+ }
+ )
+ end
+
+ def mock_environments
+ new_interaction
+ .given("an environment with name test exists")
+ .upon_receiving("a request for the environments")
+ .with_request(
+ method: "GET",
+ path: "/environments",
+ headers: get_request_headers
+ )
+ .will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ _links: {
+ "pb:environments" => [
+ {
+ name: "test",
+ href: match_type_of("href")
+ }
+ ]
+ }
+ }
+ )
+ end
+
+ def mock_record_deployment
+ new_interaction
+ .given("version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for deployment")
+ .upon_receiving("a request to record a deployment")
+ .with_request(
+ method: "POST",
+ path: "/pacticipants/Foo/versions/5556b8149bf8bac76bc30f50a8a2dd4c22c85f30/deployed-versions/environment/cb632df3-0a0d-4227-aac3-60114dd36479",
+ headers: post_request_headers,
+ body: {
+ applicationInstance: application_instance,
+ target: application_instance
+ }
+ )
+ .will_respond_with(
+ status: 201,
+ headers: pact_broker_response_headers,
+ body: {
+ target: application_instance
+ }
+ )
+ end
+
+ context "when the deployment is recorded successfully" do
+ before do
+ mock_index
+ mock_pacticipant_version_with_test_environment_available_for_deployment
+ mock_record_deployment
+ end
+
+ it "returns a success message" do
+ execute_http_pact do | mockserver |
+ expect(subject.success).to be true
+ expect(subject.message).to include "Recorded deployment of Foo version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 to test environment (application instance blue) in the Pact Broker."
+ end
+ end
+
+ context "when the output is json" do
+ let(:output) { "json" }
+
+ it "returns the JSON payload" do
+ execute_http_pact do | mockserver |
+ expect(JSON.parse(subject.message)).to eq "target" => application_instance
+ end
+ end
+ end
+ end
+
+ context "when the specified environment is not available for recording a deployment" do
+ before do
+ mock_index
+ mock_pacticipant_version_without_test_environment_available_for_deployment
+ mock_environments
+ end
+
+ context "when the specified environment does not exist" do
+ let(:environment_name) { "foo" }
+
+ it "returns an error response" do
+ execute_http_pact do | mockserver |
+ expect(subject.success).to be false
+ expect(subject.message).to include "No environment found"
+ end
+ end
+ end
+
+ context "when the specified environment does exist" do
+ it "returns an error response" do
+ execute_http_pact do | mockserver |
+ expect(subject.success).to be false
+ expect(subject.message).to include "not an available option"
+ end
+ end
+ end
+ end
+end
diff --git a/spec/pact/providers/PactBroker/record_release_spec.rb b/spec/pact/providers/PactBroker/record_release_spec.rb
new file mode 100644
index 0000000..718e402
--- /dev/null
+++ b/spec/pact/providers/PactBroker/record_release_spec.rb
@@ -0,0 +1,149 @@
+require_relative '../../../pact_ruby_v2_spec_helper'
+require 'pact_broker/client/deployments/record_deployment'
+
+RSpec.describe "recording a release", pact: true do
+ pact_broker
+ include_context "pact broker"
+ include_context "pact broker - pact-ruby-v2"
+ include PactBrokerPactHelperMethods
+
+ let(:pacticipant_name) { "Foo" }
+ let(:version_number) { "5556b8149bf8bac76bc30f50a8a2dd4c22c85f30" }
+ let(:environment_name) { "test" }
+ let(:output) { "text" }
+ let(:target) { "blue" }
+ let(:params) do
+ {
+ pacticipant_name: pacticipant_name,
+ version_number: version_number,
+ environment_name: environment_name
+ }
+ end
+ let(:options) do
+ {
+ output: output
+ }
+ end
+
+ let(:pact_broker_base_url) { "http://127.0.0.1:9999" }
+ let(:pact_broker_client_options) { { pact_broker_base_url: pact_broker_base_url } }
+
+ subject { PactBroker::Client::Deployments::RecordRelease.call(params, options, pact_broker_client_options) }
+
+ def mock_index
+ new_interaction
+ .given("the pb:pacticipant-version and pb:environments relations exist in the index resource")
+ .upon_receiving("a request for the index resource")
+ .with_request(
+ method: "GET",
+ path: '/',
+ headers: get_request_headers).
+ will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ _links: {
+ :'pb:pacticipant-version' => {
+ href: generate_mock_server_url(
+ regex: ".*(\\/pacticipants\\/.*\\/versions\\/.*)$",
+ example: "/pacticipants/{pacticipant}/versions/{version}"
+ ),
+ },
+ :'pb:environments' => {
+ href: generate_mock_server_url(
+ regex: ".*(\\/environments)$",
+ example: "/environments"
+ )
+ }
+ }
+ }
+ )
+ end
+
+ def mock_pacticipant_version_with_test_environment_available_for_release
+ new_interaction
+ .given("version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for release")
+ .upon_receiving("a request for a pacticipant version")
+ .with_request(
+ method: "GET",
+ path: "/pacticipants/Foo/versions/5556b8149bf8bac76bc30f50a8a2dd4c22c85f30",
+ headers: get_request_headers
+ )
+ .will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ _links: {
+ "pb:record-release" => [
+ {
+ name: "test",
+ href: generate_mock_server_url(
+ regex: ".*(\\/pacticipants\\/.*\\/versions\\/.*\\/released-versions\\/environment\\/.*)$",
+ example: "/pacticipants/#{pacticipant_name}/versions/#{version_number}/released-versions/environment/cb632df3-0a0d-4227-aac3-60114dd36479"
+ ),
+ }
+ ]
+ }
+ }
+ )
+ end
+
+ def mock_environments
+ new_interaction
+ .given("an environment with name test exists")
+ .upon_receiving("a request for the environments")
+ .with_request(
+ method: "GET",
+ path: "/environments",
+ headers: get_request_headers
+ )
+ .will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ _links: {
+ "pb:environments" => [
+ {
+ name: "test",
+ href: generate_mock_server_url(
+ regex: ".*(\\/environments\\/.*)$",
+ example: "/environments/cb632df3-0a0d-4227-aac3-60114dd36479"
+ )
+ }
+ ]
+ }
+ }
+ )
+ end
+
+ def mock_record_release
+ new_interaction
+ .given("version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for deployment")
+ .upon_receiving("a request to record a release")
+ .with_request(
+ method: "POST",
+ path: "/pacticipants/Foo/versions/5556b8149bf8bac76bc30f50a8a2dd4c22c85f30/released-versions/environment/cb632df3-0a0d-4227-aac3-60114dd36479",
+ headers: post_request_headers,
+ body: {}
+ )
+ .will_respond_with(
+ status: 201,
+ headers: pact_broker_response_headers
+ )
+ end
+
+ context "when the deployment is recorded successfully" do
+ before do
+ mock_index
+ mock_pacticipant_version_with_test_environment_available_for_release
+ mock_record_release
+ end
+
+ it "returns a success message" do
+ execute_http_pact do | mockserver |
+ expect(subject.success).to be true
+ expect(subject.message).to include "Recorded release of Foo version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 to test environment in the Pact Broker."
+ end
+ end
+ end
+end
diff --git a/spec/pact/providers/PactBroker/record_undeployment_spec.rb b/spec/pact/providers/PactBroker/record_undeployment_spec.rb
new file mode 100644
index 0000000..554d666
--- /dev/null
+++ b/spec/pact/providers/PactBroker/record_undeployment_spec.rb
@@ -0,0 +1,176 @@
+require_relative '../../../pact_ruby_v2_spec_helper'
+require 'pact_broker/client/deployments/record_undeployment'
+
+RSpec.describe "recording an undeployment", pact: true do
+ pact_broker
+ include_context "pact broker"
+ include_context "pact broker - pact-ruby-v2"
+ include PactBrokerPactHelperMethods
+
+ let(:pacticipant_name) { "Foo" }
+ let(:environment_name) { "test" }
+ let(:output) { "text" }
+ let(:application_instance) { "customer-1" }
+ let(:params) do
+ {
+ pacticipant_name: pacticipant_name,
+ environment_name: environment_name,
+ application_instance: application_instance
+ }
+ end
+ let(:options) do
+ {
+ output: output,
+ verbose: true
+ }
+ end
+ let(:pact_broker_base_url) { "http://127.0.0.1:9999" }
+ let(:webmock_base_url) { "http://broker" }
+ let(:pact_broker_client_options) { { pact_broker_base_url: webmock_base_url } }
+
+ let(:test_environment_placeholder_path) { "/environments/16926ef3-590f-4e3f-838e-719717aa88c9" }
+ let(:currently_deployed_versions_placeholder_path) { "/environments/16926ef3-590f-4e3f-838e-719717aa88c9/deployed-versions/currently-deployed" }
+ let(:deployed_version_placeholder_path) { "/deployed-versions/ff3adecf-cfc5-4653-a4e3-f1861092f8e0"}
+
+ subject { PactBroker::Client::Deployments::RecordUndeployment.call(params, options, pact_broker_client_options) }
+
+ let(:index_body_hash) do
+ {
+ _links: {
+ :'pb:environments' => {
+ href: "#{webmock_base_url}/environments"
+ }
+ }
+ }
+ end
+
+ let(:environments_hash) do
+ {
+ _links: {
+ :'pb:environments' => [
+ {
+ name: "test",
+ href: pact_broker_base_url + test_environment_placeholder_path
+ }
+ ]
+ }
+ }
+ end
+
+ let!(:index_request) do
+ stub_request(:get, "http://broker").to_return(status: 200, body: index_body_hash.to_json, headers: { "Content-Type" => "application/hal+json" } )
+ end
+
+ let!(:environments_request) do
+ stub_request(:get, "http://broker/environments").to_return(status: 200, body: environments_hash.to_json, headers: { "Content-Type" => "application/hal+json" } )
+ end
+
+ def mock_test_environment
+ new_interaction
+ .given("an environment with name test and UUID 16926ef3-590f-4e3f-838e-719717aa88c9 exists")
+ .upon_receiving("a request for an environment")
+ .with_request(
+ method: "GET",
+ path: test_environment_placeholder_path,
+ headers: get_request_headers
+ )
+ .will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ _links: {
+ :'pb:currently-deployed-deployed-versions' => {
+ href: generate_mock_server_url(
+ regex: ".*(\\/environments\\/.*\\/deployed-versions\\/currently-deployed)$",
+ example: currently_deployed_versions_placeholder_path
+ ),
+ }
+ }
+ }
+ )
+ end
+
+ def mock_deployed_versions_search_results
+ new_interaction
+ .given("an version is deployed to environment with UUID 16926ef3-590f-4e3f-838e-719717aa88c9 with target customer-1")
+ .upon_receiving("a request to list the versions deployed to an environment for a pacticipant name and application instance")
+ .with_request(
+ method: "GET",
+ path: currently_deployed_versions_placeholder_path,
+ query: { pacticipant: pacticipant_name },
+ headers: get_request_headers
+ )
+ .will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ _embedded: {
+ deployedVersions: [
+ {
+ applicationInstance: application_instance,
+ _links: {
+ self: {
+ href: generate_mock_server_url(
+ regex: ".*(\\/deployed-versions\\/.*)$",
+ example: deployed_version_placeholder_path
+ ),
+ }
+ }
+ }
+ ]
+ }
+ }
+ )
+ end
+
+ def mock_mark_deployed_version_as_undeployed
+ new_interaction
+ .given("a currently deployed version exists")
+ .upon_receiving("a request to mark a deployed version as not currently deploye")
+ .with_request(
+ method: "PATCH",
+ path: deployed_version_placeholder_path,
+ body: { currentlyDeployed: false },
+ headers: patch_request_headers
+ )
+ .will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: deployed_version_hash
+ )
+ end
+
+ let(:deployed_version_hash) do
+ {
+ "currentlyDeployed" => false,
+ "_embedded" => {
+ "version" => {
+ "number" => match_type_of("2")
+ }
+ }
+ }
+ end
+
+ context "when the deployment is recorded successfully" do
+ before do
+ mock_test_environment
+ mock_deployed_versions_search_results
+ mock_mark_deployed_version_as_undeployed
+ end
+
+ it "returns a success message" do
+ execute_http_pact do | mockserver |
+ expect(subject.success).to be true
+ expect(subject.message).to include "Recorded undeployment of Foo version 2 from test environment (application instance customer-1) in the Pact Broker"
+ end
+ end
+
+ # context "when the output is json" do
+ # let(:output) { "json" }
+
+ # it "returns the JSON payload" do
+ # expect(JSON.parse(subject.message)).to eq [Pact::Reification.from_term(deployed_version_hash)]
+ # end
+ # end
+ end
+end
diff --git a/spec/pact/providers/PactBroker/webhooks_create_spec.rb b/spec/pact/providers/PactBroker/webhooks_create_spec.rb
new file mode 100644
index 0000000..45b01ab
--- /dev/null
+++ b/spec/pact/providers/PactBroker/webhooks_create_spec.rb
@@ -0,0 +1,444 @@
+require_relative '../../../pact_ruby_v2_spec_helper'
+
+require 'pact_broker/client/webhooks/create'
+
+RSpec.describe "creating a webhook", pact: true do
+
+ pact_broker
+ include_context "pact broker"
+ include_context "pact broker - pact-ruby-v2"
+ include PactBrokerPactHelperMethods
+
+ let(:event_names) { %w{contract_content_changed contract_published provider_verification_published provider_verification_succeeded provider_verification_failed} }
+
+ let(:params) do
+ {
+ description: "a webhook",
+ events: %w{contract_content_changed},
+ http_method: "POST",
+ url: "https://webhook",
+ headers: { "Foo" => "bar", "Bar" => "foo"},
+ username: "username",
+ password: "password",
+ body: body,
+ consumer: "Condor",
+ provider: "Pricing Service"
+ }.tap { |it| Pact::Fixture.add_fixture(:create_webhook_params, it) }
+ end
+
+ let(:body) { { some: "body" }.to_json }
+
+ let(:request_body) do
+ {
+ "description" => "a webhook",
+ "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(:response_status) { 201 }
+ let(:success_response) do
+ {
+ status: response_status,
+ headers: pact_broker_response_headers,
+ body: {
+ description: match_type_of("a webhook"),
+ request: {
+ body: {
+ some: "body"
+ }
+ },
+ events: [
+ name: "contract_content_changed"
+ ],
+ _links: {
+ self: {
+ href: generate_mock_server_url(
+ regex: "(.*)$",
+ example: "/some-url"
+ ),
+ }
+ }
+ }
+ }
+ end
+
+ let(:pact_broker_base_url) { "http://127.0.0.1:9999" }
+ let(:pact_broker_client_options) { { pact_broker_base_url: pact_broker_base_url } }
+
+ subject { PactBroker::Client::Webhooks::Create.call(params, pact_broker_base_url, pact_broker_client_options) }
+
+ context "when a valid webhook with a JSON body is submitted" do
+ before do
+ new_interaction
+ .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_request(
+ method: :post,
+ path: '/webhooks/provider/Pricing%20Service/consumer/Condor',
+ headers: post_request_headers,
+ body: request_body)
+ .will_respond_with(**success_response)
+ end
+
+ it "returns a CommandResult with success = true" do
+ execute_http_pact do | mockserver |
+ expect(subject).to be_a PactBroker::Client::CommandResult
+ expect(subject.success).to be true
+ expect(subject.message).to eq "Webhook \"a webhook\" created"
+ end
+ end
+ end
+
+ context "when a valid webhook with every possible event type is sumbitted" do
+ before do
+ params.merge!(events: event_names)
+ request_body.merge!("events" => event_names.map{ |event_name| { "name" => event_name } })
+ success_response[:body].merge!(events: event_names.map{ |event_name| { "name" => event_name } })
+
+ new_interaction
+ .given("the 'Pricing Service' and 'Condor' already exist in the pact-broker")
+ .upon_receiving("a request to create a webhook with every possible event type")
+ .with_request(
+ method: :post,
+ path: '/webhooks/provider/Pricing%20Service/consumer/Condor',
+ headers: post_request_headers,
+ body: request_body)
+ .will_respond_with(**success_response)
+ end
+
+ it "returns a CommandResult with success = true" do
+ execute_http_pact do | mockserver |
+ expect(subject.success).to be true
+ end
+ end
+ end
+
+ context "when a valid webhook with an XML body is submitted" do
+ before do
+ request_body["request"]["body"] = body
+ success_response[:body][:request][:body] = body
+
+ new_interaction
+ .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_request(
+ method: :post,
+ path: '/webhooks/provider/Pricing%20Service/consumer/Condor',
+ headers: post_request_headers,
+ body: request_body)
+ .will_respond_with(**success_response)
+ end
+
+ let(:body) { "" }
+
+ it "returns a CommandResult with success = true" do
+ execute_http_pact do | mockserver |
+ expect(subject.success).to be true
+ end
+ end
+ end
+
+ context "when an invalid webhook is submitted" do
+ before do
+ params[:url] = nil
+ request_body["request"].delete("url")
+
+ new_interaction
+ .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_request(
+ 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" => match_each("Some error")
+ }
+ }
+ )
+ end
+
+ it "returns a CommandResult with success = false" do
+ execute_http_pact do | mockserver |
+ expect(subject.success).to be false
+ expect(subject.message).to match /400/
+ expect(subject.message).to match /Some error/
+ end
+ end
+ end
+
+ context "when one of the pacticipants does not exist" do
+ before do
+ new_interaction
+ .given("'Condor' does not exist in the pact-broker")
+ .upon_receiving("a request to create a webhook for a consumer and provider")
+ .with_request(
+ 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
+ execute_http_pact do | mockserver |
+ expect(subject.success).to be false
+ expect(subject.message).to match /404/
+ end
+ end
+ end
+
+ context "when only a consumer is specified" do
+ before do
+ params.delete(:provider)
+ request_body["consumer"] = { "name" => "Condor" }
+ mock_pact_broker_index(self, pact_broker_base_url)
+
+ new_interaction
+ .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")
+ .with_request(
+ method: :post,
+ path: '/webhooks',
+ headers: post_request_headers,
+ body: request_body)
+ .will_respond_with(**success_response)
+ end
+
+ it "returns a CommandResult with success = true" do
+ execute_http_pact do | mockserver |
+ expect(subject.success).to be true
+ expect(subject.message).to eq "Webhook \"a webhook\" created"
+ end
+ end
+ end
+
+ context "when consumer is specified using a label" do
+ before do
+ params.delete(:consumer)
+ params.delete(:provider)
+ params.merge!(consumer_label: "consumer_label")
+ request_body["consumer"] = { "label" => "consumer_label" }
+ mock_pact_broker_index(self, pact_broker_base_url)
+
+ new_interaction
+ .upon_receiving("a request to create a webhook with a JSON body for a consumer specified by a label")
+ .with_request(
+ method: :post,
+ path: '/webhooks',
+ headers: post_request_headers,
+ body: request_body)
+ .will_respond_with(**success_response)
+ end
+
+ it "returns a CommandResult with success = true" do
+ execute_http_pact do | mockserver |
+ expect(subject.success).to be true
+ expect(subject.message).to eq "Webhook \"a webhook\" created"
+ end
+ end
+ end
+
+ context "when only a consumer is specified and it does not exist" do
+ before do
+ params.delete(:provider)
+ request_body["consumer"] = { "name" => "Condor" }
+ mock_pact_broker_index(self, pact_broker_base_url)
+
+ new_interaction
+ .upon_receiving("a request to create a webhook with a JSON body for a consumer that does not exist")
+ .with_request(
+ method: :post,
+ path: '/webhooks',
+ headers: post_request_headers,
+ body: request_body)
+ .will_respond_with(
+ status: 400,
+ headers: pact_broker_response_headers,
+ body: {
+ errors: {
+ "consumer.name" => match_each("Some error")
+ }
+ })
+ end
+
+ it "returns a CommandResult with success = true" do
+ execute_http_pact do | mockserver |
+ expect(subject.success).to be false
+ end
+ end
+ end
+
+ context "when only a provider is specified" do
+ before do
+ params.delete(:consumer)
+ request_body["provider"] = { "name" => "Pricing Service" }
+ mock_pact_broker_index(self, pact_broker_base_url)
+
+ new_interaction
+ .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 provider")
+ .with_request(
+ method: :post,
+ path: '/webhooks',
+ headers: post_request_headers,
+ body: request_body)
+ .will_respond_with(**success_response)
+ end
+
+ it "returns a CommandResult with success = true" do
+ execute_http_pact do | mockserver |
+ expect(subject.success).to be true
+ end
+ end
+ end
+
+ context "when provider is specified using a label" do
+ before do
+ params.delete(:consumer)
+ params.delete(:provider)
+ params.merge!(provider_label: "provider_label")
+ request_body["provider"] = { "label" => "provider_label" }
+ mock_pact_broker_index(self, pact_broker_base_url)
+
+ new_interaction
+ .upon_receiving("a request to create a webhook with a JSON body for a provider specified by a label")
+ .with_request(
+ method: :post,
+ path: '/webhooks',
+ headers: post_request_headers,
+ body: request_body)
+ .will_respond_with(**success_response)
+ end
+
+ it "returns a CommandResult with success = true" do
+ execute_http_pact do | mockserver |
+ expect(subject.success).to be true
+ expect(subject.message).to eq "Webhook \"a webhook\" created"
+ end
+ end
+ end
+
+ context "when neither consumer nor provider are specified" do
+ before do
+ params.delete(:consumer)
+ params.delete(:provider)
+ mock_pact_broker_index(self, pact_broker_base_url)
+
+ new_interaction
+ .upon_receiving("a request to create a global webhook with a JSON body")
+ .with_request(
+ method: :post,
+ path: '/webhooks',
+ headers: post_request_headers,
+ body: request_body)
+ .will_respond_with(**success_response)
+ end
+
+ it "returns a CommandResult with success = true" do
+ execute_http_pact do | mockserver |
+ expect(subject.success).to be true
+ end
+ end
+ end
+
+ context "when a uuid is specified" do
+ before do
+ params.merge!(uuid: uuid)
+ request_body["provider"] = { "name" => "Pricing Service" }
+ request_body["consumer"] = { "name" => "Condor" }
+ new_interaction
+ .upon_receiving("a request for the index resource with the webhook relation")
+ .with_request(
+ method: :get,
+ path: '/',
+ headers: get_request_headers
+ )
+ .will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ _links: {
+ :'pb:webhook' => {
+ href: generate_mock_server_url(
+ regex: ".*(\\/webhooks\\/\\{uuid\\})$",
+ example: "/webhooks/{uuid}"
+ ),
+ templated: true
+ }
+ }
+ }
+ )
+ end
+
+ let(:uuid) { '696c5f93-1b7f-44bc-8d03-59440fcaa9a0' }
+
+ context "when the webhook does not already exist" do
+ before do
+ new_interaction
+ .upon_receiving("a request to create a webhook with a JSON body and a uuid")
+ .given("the 'Pricing Service' and 'Condor' already exist in the pact-broker")
+ .with_request(
+ method: :put,
+ path: "/webhooks/#{uuid}",
+ headers: put_request_headers,
+ body: request_body)
+ .will_respond_with(**success_response)
+ end
+
+ it "returns a CommandResult with success = true" do
+ execute_http_pact do | mockserver |
+ expect(subject).to be_a PactBroker::Client::CommandResult
+ expect(subject.success).to be true
+ expect(subject.message).to eq "Webhook \"a webhook\" created"
+ end
+ end
+ end
+
+ context "when the webhook does exist" do
+ before do
+ new_interaction
+ .upon_receiving("a request to update a webhook")
+ .given("a webhook with the uuid #{uuid} exists")
+ .with_request(
+ method: :put,
+ path: "/webhooks/#{uuid}",
+ headers: put_request_headers,
+ body: request_body)
+ .will_respond_with(**success_response)
+ end
+
+ let(:response_status) { 200 }
+
+ it "returns a CommandResult with success = true" do
+ execute_http_pact do | mockserver |
+ expect(subject).to be_a PactBroker::Client::CommandResult
+ expect(subject.success).to be true
+ expect(subject.message).to eq "Webhook \"a webhook\" updated"
+ end
+ end
+ end
+ end
+end
diff --git a/spec/pact/providers/PactFlow/pactflow_publish_provider_contract_spec.rb b/spec/pact/providers/PactFlow/pactflow_publish_provider_contract_spec.rb
new file mode 100644
index 0000000..f486e18
--- /dev/null
+++ b/spec/pact/providers/PactFlow/pactflow_publish_provider_contract_spec.rb
@@ -0,0 +1,145 @@
+require "yaml"
+require_relative '../../../pact_ruby_v2_spec_helper'
+require "pactflow/client/provider_contracts/publish"
+
+RSpec.describe "publishing a provider contract to PactFlow", pact: true do
+ before do
+ allow_any_instance_of(PactBroker::Client::Hal::HttpClient).to receive(:sleep)
+ allow_any_instance_of(PactBroker::Client::Hal::HttpClient).to receive(:default_max_tries).and_return(1)
+ end
+
+ pactflow
+ include_context "pact broker"
+ include_context "pact broker - pact-ruby-v2"
+ include PactBrokerPactHelperMethods
+
+ let(:command_params) do
+ {
+ provider_name: "Bar",
+ provider_version_number: "1",
+ branch_name: "main",
+ tags: ["dev"],
+ build_url: "http://build",
+ contract: {
+ content: { "some" => "contract" }.to_yaml,
+ content_type: "application/yaml",
+ specification: "oas"
+ },
+ verification_results: {
+ success: true,
+ content: "some results",
+ content_type: "text/plain",
+ format: "text",
+ verifier: "my custom tool",
+ verifier_version: "1.0"
+ }
+ }
+ end
+
+ let(:request_body) do
+ {
+ "pacticipantVersionNumber" => "1",
+ "tags" => ["dev"],
+ "branch" => "main",
+ "buildUrl" => "http://build",
+ "contract" => {
+ "content" => "LS0tCnNvbWU6IGNvbnRyYWN0Cg==",
+ "contentType" => "application/yaml",
+ "specification" => "oas",
+ "selfVerificationResults" => {
+ "success" => true,
+ "content" => "c29tZSByZXN1bHRz",
+ "contentType" => "text/plain",
+ "format" => "text",
+ "verifier" => "my custom tool",
+ "verifierVersion" => "1.0"
+ }
+ }
+ }
+ end
+
+ let(:response_status) { 200 }
+
+ # Can't tell from the response if the buildUrl was correct, but it's not that important
+ # Add some assertions to the body to ensure we have called the endpoint correctly,
+ # not because we use the properties in the CLI output.
+ # There is unfortunately no good way to determine from the response whether or not
+ # we have correctly published the self verification results.
+ let(:success_response) do
+ {
+ status: response_status,
+ headers: pact_broker_response_headers,
+ body: {
+ "notices" => match_each("text" => "some notice", "type" => "info"),
+ "_embedded" => {
+ "version" => {
+ # This tells us we have set the version number correctly
+ "number" => "1"
+ }
+ },
+ "_links" => {
+ # The links tell us we have successfully created the tags, but we don't care about the contents
+ "pb:pacticipant-version-tags" => [{}],
+ # The link tells us we have successfully created the branch version, but we don't care about the contents
+ "pb:branch-version" => {},
+ }
+ }
+ }
+ end
+
+ let(:options) do
+ {
+ verbose: false
+ }
+ end
+ let(:pactflow_mock_service_base_url) { "http://127.0.0.1:9998" }
+
+ let(:pact_broker_client_options) do
+ { pact_broker_base_url: pactflow_mock_service_base_url }
+ end
+
+ subject { Pactflow::Client::ProviderContracts::Publish.call(command_params, options, pact_broker_client_options) }
+
+ context "creating a provider contract with valid parameters" do
+ before do
+ new_interaction
+ .given("the pb:publish-provider-contract relation exists in the index resource")
+ .upon_receiving("a request for the index resource")
+ .with_request(
+ method: "GET",
+ path: "/",
+ headers: get_request_headers
+ ).will_respond_with(
+ status: 200,
+ headers: pact_broker_response_headers,
+ body: {
+ _links: {
+ :'pf:publish-provider-contract' => {
+ href: generate_mock_server_url(
+ regex: ".*(\\/provider-contracts\\/provider\\/.*\\/publish)$",
+ example: "/provider-contracts/provider/{provider}/publish"
+ ),
+ }
+ }
+ }
+ )
+
+ new_interaction
+ .upon_receiving("a request to publish a provider contract")
+ .with_request(
+ method: :post,
+ path: '/provider-contracts/provider/Bar/publish',
+ headers: post_request_headers.merge("Accept" => "application/hal+json,application/problem+json"),
+ body: request_body
+ ).will_respond_with(**success_response)
+ end
+
+ it "returns a CommandResult with success = true" do
+ execute_http_pact do |mock_server|
+ expect(subject).to be_a PactBroker::Client::CommandResult
+ expect(subject.success).to be true
+ expect(subject.message).to include "some notice"
+ end
+ end
+ end
+end
diff --git a/spec/pact/providers/PactFlow/pactflow_publish_provider_contract_the_old_way_spec.rb b/spec/pact/providers/PactFlow/pactflow_publish_provider_contract_the_old_way_spec.rb
new file mode 100644
index 0000000..8abe9ed
--- /dev/null
+++ b/spec/pact/providers/PactFlow/pactflow_publish_provider_contract_the_old_way_spec.rb
@@ -0,0 +1,138 @@
+require_relative '../../../pact_ruby_v2_spec_helper'
+require "yaml"
+require "pactflow/client/provider_contracts/publish_the_old_way"
+require "pact_broker/client/versions/create"
+
+
+RSpec.describe "publishing a provider contract to PactFlow the old way", pact: true do
+ before do
+ # no point re-testing this
+ allow(PactBroker::Client::Versions::Create).to receive(:call).and_return(double("result", success: true))
+ end
+
+ pactflow
+ include_context "pact broker"
+ include_context "pact broker - pact-ruby-v2"
+ include PactBrokerPactHelperMethods
+
+ let(:command_params) do
+ {
+ provider_name: "Bar",
+ provider_version_number: "1",
+ branch_name: "main",
+ tags: ["dev"],
+ contract: {
+ content: { "some" => "contract" }.to_yaml,
+ content_type: "application/yaml",
+ specification: "oas"
+ },
+ verification_results: {
+ success: true,
+ content: "some results",
+ content_type: "text/plain",
+ format: "text",
+ verifier: "my custom tool",
+ verifier_version: "1.0"
+ }
+ }
+ end
+
+ let(:body) { { some: "body" }.to_json }
+
+ let(:request_body) do
+ {
+ "content" => "LS0tCnNvbWU6IGNvbnRyYWN0Cg==",
+ "contractType" => "oas",
+ "contentType" => "application/yaml",
+ "verificationResults" => {
+ "success" => true,
+ "content" => "c29tZSByZXN1bHRz",
+ "contentType" => "text/plain",
+ "format" => "text",
+ "verifier" => "my custom tool",
+ "verifierVersion" => "1.0"
+ }
+ }
+ end
+
+ let(:response_status) { 201 }
+ let(:success_response) do
+ {
+ status: response_status,
+ headers: pact_broker_response_headers
+ }
+ end
+
+ let(:options) do
+ {
+ verbose: false
+ }
+ end
+
+ let(:pactflow_mock_service_base_url) { "http://127.0.0.1:9998" }
+
+ let(:pact_broker_client_options) do
+ { pact_broker_base_url: pactflow_mock_service_base_url }
+ end
+
+
+ subject { Pactflow::Client::ProviderContracts::PublishTheOldWay.call(command_params, options, pact_broker_client_options) }
+
+ context "creating a provider contract with valid parameters" do
+ let(:interaction) do
+ new_interaction
+ .upon_receiving("a request to create a provider contract")
+ .with_request(
+ method: :put,
+ path: "/contracts/provider/Bar/version/1",
+ headers: put_request_headers,
+ body: request_body)
+ .will_respond_with(**success_response)
+ end
+
+ it "returns a CommandResult with success = true" do
+ interaction.execute do |mock_server|
+ expect(subject).to be_a PactBroker::Client::CommandResult
+ expect(subject.success).to be true
+ expect(subject.message).to include "Successfully published provider contract for Bar version 1"
+ expect(subject.message).not_to include pactflow_mock_service_base_url
+ end
+ end
+ end
+
+ context "creating a provider contract with valid parameters with pf:ui return results" do
+ let(:success_response_with_pf_ui_url) do
+ {
+ status: response_status,
+ headers: pact_broker_response_headers,
+ body: { "_links": {
+ "pf:ui": {
+ "href": match_type_of("some-url")
+ }
+ } }
+ }
+ end
+ let(:interaction) do
+ new_interaction
+ .given("there is a pf:ui href in the response")
+ .upon_receiving("a request to create a provider contract")
+ .with_request(
+ method: :put,
+ path: "/contracts/provider/Bar/version/1",
+ headers: put_request_headers,
+ body: request_body
+ )
+ .will_respond_with(**success_response_with_pf_ui_url)
+ end
+
+ it "returns a CommandResult with success = true and a provider contract ui url" do
+ interaction.execute do |mock_server|
+ expect(subject).to be_a PactBroker::Client::CommandResult
+ expect(subject.success).to be true
+ expect(subject.message).to include "Successfully published provider contract for Bar version 1"
+ expect(subject.message).to include "Next steps:"
+ expect(subject.message).to include "some-url"
+ end
+ end
+ end
+end
diff --git a/spec/pact/providers/PactFlow/pactflow_webhooks_create_spec.rb b/spec/pact/providers/PactFlow/pactflow_webhooks_create_spec.rb
new file mode 100644
index 0000000..192d256
--- /dev/null
+++ b/spec/pact/providers/PactFlow/pactflow_webhooks_create_spec.rb
@@ -0,0 +1,94 @@
+require_relative '../../../pact_ruby_v2_spec_helper'
+require 'pact_broker/client/webhooks/create'
+
+RSpec.describe "creating a webhook in PactFlow", pact: true do
+
+ pactflow
+ include_context "pact broker"
+ include_context "pact broker - pact-ruby-v2"
+ include PactBrokerPactHelperMethods
+
+ let(:params) do
+ {
+ description: "a webhook",
+ events: %w{contract_content_changed},
+ http_method: "POST",
+ url: "https://webhook",
+ headers: { "Foo" => "bar", "Bar" => "foo"},
+ body: body,
+ team_uuid: "2abbc12a-427d-432a-a521-c870af1739d9"
+ }
+ end
+
+ let(:body) { { some: "body" }.to_json }
+
+ let(:request_body) do
+ {
+ "description" => "a webhook",
+ "events" => [
+ "name" => "contract_content_changed"
+ ],
+ "request" => {
+ "url" => "https://webhook",
+ "method" => "POST",
+ "headers" => {
+ "Foo" => "bar",
+ "Bar" => "foo"
+ },
+ "body" => {
+ "some" => "body"
+ },
+ },
+ "teamUuid" => "2abbc12a-427d-432a-a521-c870af1739d9"
+ }
+ end
+
+ let(:response_status) { 201 }
+ let(:success_response) do
+ {
+ status: response_status,
+ headers: pact_broker_response_headers,
+ body: {
+ description: match_type_of("a webhook"),
+ teamUuid: "2abbc12a-427d-432a-a521-c870af1739d9",
+ _links: {
+ self: {
+ href: generate_mock_server_url(
+ regex: "(.*)$",
+ example: "/some-url"
+ ),
+ title: match_type_of("A title")
+ }
+ }
+ }
+ }
+ end
+
+ let(:pactflow_mock_service_base_url) { "http://127.0.0.1:9998" }
+ let(:pact_broker_client_options) { {} }
+
+ subject { PactBroker::Client::Webhooks::Create.call(params, pactflow_mock_service_base_url, pact_broker_client_options) }
+
+ context "when a valid webhook with a team specified is submitted" do
+ before do
+ mock_pact_broker_index(self, pactflow_mock_service_base_url)
+ new_interaction
+ .given("a team with UUID 2abbc12a-427d-432a-a521-c870af1739d9 exists")
+ .upon_receiving("a request to create a webhook for a team")
+ .with_request(
+ method: :post,
+ path: '/webhooks',
+ headers: post_request_headers,
+ body: request_body)
+ .will_respond_with(**success_response)
+ end
+
+ it "returns a CommandResult with success = true" do
+ execute_http_pact do |mock_server|
+ expect(subject).to be_a PactBroker::Client::CommandResult
+ expect(subject.success).to be true
+ expect(subject.message).to eq "Webhook \"a webhook\" created"
+ end
+ end
+ end
+end
diff --git a/spec/pact_ruby_v2_spec_helper.rb b/spec/pact_ruby_v2_spec_helper.rb
new file mode 100644
index 0000000..0e95235
--- /dev/null
+++ b/spec/pact_ruby_v2_spec_helper.rb
@@ -0,0 +1,78 @@
+
+require 'pact/v2'
+require 'pact/v2/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
+
+
+def bar_provider
+ has_http_pact_between 'Foo', 'Bar', opts: {
+ pact_dir: "spec/pacts",
+ log_level: :info,
+ pact_specification: "2",
+ # Valid versions are 1, 1.1, 2, 3, 4. Default is V4
+ # V prefix is optional, and case insensitive
+ }
+
+end
+
+def pact_broker
+ has_http_pact_between 'Pact Broker Client V2', 'Pact Broker', opts: {
+ pact_dir: "spec/pacts",
+ log_level: :info,
+ mock_port: 9999,
+ pact_specification: "2",
+ }
+end
+
+def pactflow
+ has_http_pact_between 'Pact Broker Client V2', 'PactFlow', opts: {
+ pact_dir: "spec/pacts",
+ log_level: :debug,
+ mock_port: 9998,
+ pact_specification: "2",
+ }
+end
+
+
+module PactBrokerPactHelperMethods
+
+
+ def mock_pact_broker_index(context, mock_service_url = nil)
+ new_interaction
+ .upon_receiving("a request for the index resource")
+ .with_request(
+ method: :get,
+ path: '/',
+ headers: context.get_request_headers).
+ will_respond_with(
+ status: 200,
+ headers: context.pact_broker_response_headers,
+ body: {
+ _links: {
+ :'pb:webhooks' => {
+ href: generate_mock_server_url(
+ regex: ".*(\\/webhooks)$",
+ example: "/webhooks"
+ )
+ },
+ :'pb:pacticipants' => {
+ href: generate_mock_server_url(
+ regex: ".*(\\/pacticipants)$",
+ example: "/pacticipants"
+ )
+ },
+ :'pb:pacticipant' => {
+ href: generate_mock_server_url(
+ regex: ".*(\\/pacticipants\\/{pacticipant})$",
+ example: "/pacticipants/{pacticipant}"
+ )
+ }
+ }
+ }
+ )
+ end
+
+end
\ No newline at end of file
diff --git a/spec/pacts/Pact Broker Client V2-Pact Broker.json b/spec/pacts/Pact Broker Client V2-Pact Broker.json
new file mode 100644
index 0000000..996cd96
--- /dev/null
+++ b/spec/pacts/Pact Broker Client V2-Pact Broker.json
@@ -0,0 +1,2848 @@
+{
+ "consumer": {
+ "name": "Pact Broker Client V2"
+ },
+ "interactions": [
+ {
+ "description": "a request for an environment",
+ "providerState": "an environment with name test and UUID 16926ef3-590f-4e3f-838e-719717aa88c9 exists",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json"
+ },
+ "method": "GET",
+ "path": "/environments/16926ef3-590f-4e3f-838e-719717aa88c9"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "pb:currently-deployed-deployed-versions": {
+ "href": "/environments/16926ef3-590f-4e3f-838e-719717aa88c9/deployed-versions/currently-deployed"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links['pb:currently-deployed-deployed-versions'].href": {
+ "match": "regex",
+ "regex": ".*(\\/environments\\/.*\\/deployed-versions\\/currently-deployed)$"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the compatibility matrix for Foo version 1.2.3 and Bar version 4.5.6",
+ "providerState": "the pact for Foo Thing version 1.2.3 has been verified by Bar version 4.5.6",
+ "request": {
+ "method": "GET",
+ "path": "/matrix",
+ "query": "latestby=cvpv&q[][pacticipant]=Foo+Thing&q[][pacticipant]=Bar&q[][version]=1%2e2%2e3&q[][version]=4%2e5%2e6"
+ },
+ "response": {
+ "body": {
+ "matrix": [
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "4"
+ }
+ },
+ "pact": {
+ "createdAt": "2017-10-10T12:49:04+11:00"
+ },
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "5"
+ }
+ },
+ "verificationResult": {
+ "_links": {
+ "self": {
+ "href": "http://result"
+ }
+ },
+ "success": true,
+ "verifiedAt": "2017-10-10T12:49:04+11:00"
+ }
+ }
+ ],
+ "summary": {
+ "deployable": true,
+ "reason": "some text",
+ "unknown": 1
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body": {
+ "match": "type"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the compatibility matrix for Foo version 1.2.3 and Bar version 4.5.6",
+ "providerState": "the pact for Foo version 1.2.3 has been verified by Bar version 4.5.6",
+ "request": {
+ "method": "GET",
+ "path": "/matrix",
+ "query": "latestby=cvpv&q[][pacticipant]=Foo&q[][pacticipant]=Bar&q[][version]=1%2e2%2e3&q[][version]=4%2e5%2e6"
+ },
+ "response": {
+ "body": {
+ "matrix": [
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "4"
+ }
+ },
+ "pact": {
+ "createdAt": "2017-10-10T12:49:04+11:00"
+ },
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "5"
+ }
+ },
+ "verificationResult": {
+ "_links": {
+ "self": {
+ "href": "http://result"
+ }
+ },
+ "success": true,
+ "verifiedAt": "2017-10-10T12:49:04+11:00"
+ }
+ }
+ ],
+ "summary": {
+ "deployable": true,
+ "reason": "some text",
+ "unknown": 1
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body": {
+ "match": "type"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the compatibility matrix for Foo version 1.2.3 and the latest prod version of Bar",
+ "providerState": "the pact for Foo version 1.2.3 has been successfully verified by Bar version 4.5.6 with tag prod, and 1.2.4 unsuccessfully by 9.9.9",
+ "request": {
+ "method": "GET",
+ "path": "/matrix",
+ "query": "latestby=cvpv&q[][latest]=true&q[][pacticipant]=Foo&q[][pacticipant]=Bar&q[][tag]=prod&q[][version]=1%2e2%2e3"
+ },
+ "response": {
+ "body": {
+ "matrix": [
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "4"
+ }
+ },
+ "pact": {
+ "createdAt": "2017-10-10T12:49:04+11:00"
+ },
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "5"
+ }
+ },
+ "verificationResult": {
+ "_links": {
+ "self": {
+ "href": "http://result"
+ }
+ },
+ "success": true,
+ "verifiedAt": "2017-10-10T12:49:04+11:00"
+ }
+ }
+ ],
+ "summary": {
+ "deployable": true,
+ "reason": "some text",
+ "unknown": 1
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body": {
+ "match": "type"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the compatibility matrix for Foo version 1.2.3 and the latest prod versions of all other pacticipants",
+ "providerState": "the pact for Foo version 1.2.3 has been successfully verified by Bar version 4.5.6 (tagged prod) and version 5.6.7",
+ "request": {
+ "method": "GET",
+ "path": "/matrix",
+ "query": "latest=true&latestby=cvp&q[][pacticipant]=Foo&q[][version]=1%2e2%2e3&tag=prod"
+ },
+ "response": {
+ "body": {
+ "matrix": [
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "1.2.3"
+ }
+ },
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "4.5.6"
+ }
+ }
+ }
+ ]
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the compatibility matrix for Foo version 1.2.3 and the latest version of Bar",
+ "providerState": "the pact for Foo version 1.2.3 has been successfully verified by Bar version 4.5.6, and 1.2.4 unsuccessfully by 9.9.9",
+ "request": {
+ "method": "GET",
+ "path": "/matrix",
+ "query": "latestby=cvpv&q[][latest]=true&q[][pacticipant]=Foo&q[][pacticipant]=Bar&q[][version]=1%2e2%2e4"
+ },
+ "response": {
+ "body": {
+ "matrix": [
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "4"
+ }
+ },
+ "pact": {
+ "createdAt": "2017-10-10T12:49:04+11:00"
+ },
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "5"
+ }
+ },
+ "verificationResult": {
+ "_links": {
+ "self": {
+ "href": "http://result"
+ }
+ },
+ "success": true,
+ "verifiedAt": "2017-10-10T12:49:04+11:00"
+ }
+ }
+ ],
+ "summary": {
+ "deployable": true,
+ "reason": "some text",
+ "unknown": 1
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body": {
+ "match": "type"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the compatibility matrix for a pacticipant that does not exist",
+ "request": {
+ "method": "GET",
+ "path": "/matrix",
+ "query": "latestby=cvpv&q[][pacticipant]=Wiffle&q[][pacticipant]=Meep&q[][version]=1%2e2%2e3&q[][version]=9%2e9%2e9"
+ },
+ "response": {
+ "body": {
+ "errors": [
+ "an error message"
+ ]
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body.errors": {
+ "match": "type",
+ "min": 1
+ }
+ },
+ "status": 400
+ }
+ },
+ {
+ "description": "a request for the compatibility matrix for all versions of Foo and Bar",
+ "providerState": "the pact for Foo version 1.2.3 and 1.2.4 has been verified by Bar version 4.5.6",
+ "request": {
+ "method": "GET",
+ "path": "/matrix",
+ "query": "latestby=cvpv&q[][pacticipant]=Foo&q[][pacticipant]=Bar"
+ },
+ "response": {
+ "body": {
+ "matrix": [
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "4"
+ }
+ },
+ "pact": {
+ "createdAt": "2017-10-10T12:49:04+11:00"
+ },
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "5"
+ }
+ },
+ "verificationResult": {
+ "_links": {
+ "self": {
+ "href": "http://result"
+ }
+ },
+ "success": true,
+ "verifiedAt": "2017-10-10T12:49:04+11:00"
+ }
+ },
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "4"
+ }
+ },
+ "pact": {
+ "createdAt": "2017-10-10T12:49:04+11:00"
+ },
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "5"
+ }
+ },
+ "verificationResult": {
+ "_links": {
+ "self": {
+ "href": "http://result"
+ }
+ },
+ "success": true,
+ "verifiedAt": "2017-10-10T12:49:04+11:00"
+ }
+ }
+ ]
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body.matrix": {
+ "match": "type",
+ "min": 2
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the compatibility matrix where one or more versions does not exist",
+ "providerState": "the pact for Foo version 1.2.3 has been verified by Bar version 4.5.6",
+ "request": {
+ "method": "GET",
+ "path": "/matrix",
+ "query": "latestby=cvpv&q[][pacticipant]=Foo&q[][pacticipant]=Bar&q[][version]=1%2e2%2e3&q[][version]=9%2e9%2e9"
+ },
+ "response": {
+ "body": {
+ "summary": {
+ "reason": "an error message"
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body.summary.reason": {
+ "match": "type"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the compatibility matrix where only the version of Foo is specified",
+ "providerState": "the pact for Foo version 1.2.3 has been verified by Bar version 4.5.6 and version 5.6.7",
+ "request": {
+ "method": "GET",
+ "path": "/matrix",
+ "query": "latest=true&latestby=cvp&q[][pacticipant]=Foo&q[][version]=1%2e2%2e3"
+ },
+ "response": {
+ "body": {
+ "matrix": [
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "4"
+ }
+ },
+ "pact": {
+ "createdAt": "2017-10-10T12:49:04+11:00"
+ },
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "5"
+ }
+ },
+ "verificationResult": {
+ "_links": {
+ "self": {
+ "href": "http://result"
+ }
+ },
+ "success": true,
+ "verifiedAt": "2017-10-10T12:49:04+11:00"
+ }
+ }
+ ],
+ "summary": {
+ "deployable": true,
+ "reason": "some text",
+ "unknown": 1
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body": {
+ "match": "type"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the index resource",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json"
+ },
+ "method": "GET",
+ "path": "/"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "pb:pacticipant": {
+ "href": "/pacticipants/{pacticipant}"
+ },
+ "pb:pacticipants": {
+ "href": "/pacticipants"
+ },
+ "pb:webhooks": {
+ "href": "/webhooks"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links['pb:pacticipant'].href": {
+ "match": "regex",
+ "regex": ".*(\\/pacticipants\\/{pacticipant})$"
+ },
+ "$.body._links['pb:pacticipants'].href": {
+ "match": "regex",
+ "regex": ".*(\\/pacticipants)$"
+ },
+ "$.body._links['pb:webhooks'].href": {
+ "match": "regex",
+ "regex": ".*(\\/webhooks)$"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the index resource",
+ "providerState": "the pacticipant relations are present",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json"
+ },
+ "method": "GET",
+ "path": "/"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "pb:pacticipant": {
+ "href": "/pacticipants/{pacticipant}"
+ },
+ "pb:pacticipants": {
+ "href": "/pacticipants"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links['pb:pacticipant'].href": {
+ "match": "regex",
+ "regex": ".*(\\/pacticipants\\/\\{pacticipant\\})$"
+ },
+ "$.body._links['pb:pacticipants'].href": {
+ "match": "regex",
+ "regex": ".*(\\/pacticipants)$"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the index resource",
+ "providerState": "the pb:environments relation exists in the index resource",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json"
+ },
+ "method": "GET",
+ "path": "/"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "pb:environments": {
+ "href": "/environments"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links['pb:environments'].href": {
+ "match": "regex",
+ "regex": ".*(\\/environments)$"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the index resource",
+ "providerState": "the pb:latest-tagged-version relation exists in the index resource",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json, application/json"
+ },
+ "method": "GET",
+ "path": "/"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "pb:latest-tagged-version": {
+ "href": "http://127.0.0.1:9999/pacticipants/Condor/latest-version/production"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links['pb:latest-tagged-version'].href": {
+ "match": "regex",
+ "regex": ".*(\\/pacticipants\\/.*\\/latest-version\\/.*)$"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the index resource",
+ "providerState": "the pb:latest-version relation exists in the index resource",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json, application/json"
+ },
+ "method": "GET",
+ "path": "/"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "pb:latest-version": {
+ "href": "http://127.0.0.1:9999/pacticipants/Condor/latest-version"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links['pb:latest-version'].href": {
+ "match": "regex",
+ "regex": ".*(\\/pacticipants\\/.*\\/latest-version)$"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the index resource",
+ "providerState": "the pb:pacticipant-branch relation exists in the index resource",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json"
+ },
+ "method": "GET",
+ "path": "/"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "pb:pacticipant-branch": {
+ "href": "/pacticipants/{pacticipant}/branches/{branch}"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links['pb:pacticipant-branch'].href": {
+ "match": "regex",
+ "regex": ".*(\\/pacticipants\\/.*\\/branches\\/.*)$"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the index resource",
+ "providerState": "the pb:pacticipant-version and pb:environments relations exist in the index resource",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json"
+ },
+ "method": "GET",
+ "path": "/"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "pb:environments": {
+ "href": "/environments"
+ },
+ "pb:pacticipant-version": {
+ "href": "/pacticipants/{pacticipant}/versions/{version}"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links['pb:environments'].href": {
+ "match": "regex",
+ "regex": ".*(\\/environments)$"
+ },
+ "$.body._links['pb:pacticipant-version'].href": {
+ "match": "regex",
+ "regex": ".*(\\/pacticipants\\/.*\\/versions\\/.*)$"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for a pacticipant version",
+ "providerState": "version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with 2 environments that aren't test available for deployment",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json"
+ },
+ "method": "GET",
+ "path": "/pacticipants/Foo/versions/5556b8149bf8bac76bc30f50a8a2dd4c22c85f30"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "pb:record-deployment": [
+ {
+ "href": "href",
+ "name": "prod"
+ },
+ {
+ "href": "href",
+ "name": "dev"
+ }
+ ]
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links['pb:record-deployment'][0]": {
+ "match": "type"
+ },
+ "$.body._links['pb:record-deployment'][1]": {
+ "match": "type"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for a pacticipant version",
+ "providerState": "version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for deployment",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json"
+ },
+ "method": "GET",
+ "path": "/pacticipants/Foo/versions/5556b8149bf8bac76bc30f50a8a2dd4c22c85f30"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "pb:record-deployment": [
+ {
+ "href": "/pacticipants/Foo/versions/5556b8149bf8bac76bc30f50a8a2dd4c22c85f30/deployed-versions/environment/cb632df3-0a0d-4227-aac3-60114dd36479",
+ "name": "test"
+ }
+ ]
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links['pb:record-deployment'][0].href": {
+ "match": "regex",
+ "regex": ".*(\\/pacticipants\\/.*\\/versions\\/.*\\/deployed-versions\\/environment\\/.*)$"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for a pacticipant version",
+ "providerState": "version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for release",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json"
+ },
+ "method": "GET",
+ "path": "/pacticipants/Foo/versions/5556b8149bf8bac76bc30f50a8a2dd4c22c85f30"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "pb:record-release": [
+ {
+ "href": "/pacticipants/Foo/versions/5556b8149bf8bac76bc30f50a8a2dd4c22c85f30/released-versions/environment/cb632df3-0a0d-4227-aac3-60114dd36479",
+ "name": "test"
+ }
+ ]
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links['pb:record-release'][0].href": {
+ "match": "regex",
+ "regex": ".*(\\/pacticipants\\/.*\\/versions\\/.*\\/released-versions\\/environment\\/.*)$"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the environments",
+ "providerState": "an environment with name test exists",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json"
+ },
+ "method": "GET",
+ "path": "/environments"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "pb:environments": [
+ {
+ "href": "href",
+ "name": "test"
+ }
+ ]
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links['pb:environments'][0].href": {
+ "match": "type"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the index resource",
+ "providerState": "the pb:publish-contracts relations exists in the index resource",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json"
+ },
+ "method": "GET",
+ "path": "/"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "pb:publish-contracts": {
+ "href": "/contracts/publish"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links['pb:publish-contracts'].href": {
+ "match": "regex",
+ "regex": ".*(\\/contracts\\/publish)$"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the index resource with the webhook relation",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json"
+ },
+ "method": "GET",
+ "path": "/"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "pb:webhook": {
+ "href": "/webhooks/{uuid}",
+ "templated": true
+ }
+ }
+ },
+ "generators": null,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links['pb:webhook'].href": {
+ "match": "regex",
+ "regex": ".*(\\/webhooks\\/\\{uuid\\})$"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the list of the latest pacts from all consumers for the Pricing Service'",
+ "providerState": "a latest pact between Condor and the Pricing Service exists",
+ "request": {
+ "method": "GET",
+ "path": "/pacts/provider/Pricing%20Service/latest"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "pb:pacts": [
+ {
+ "href": "http://example.org/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0",
+ "name": "Condor",
+ "title": "Pact between Condor (v1.3.0) and Pricing Service"
+ }
+ ],
+ "provider": {
+ "href": "http://example.org/pacticipants/Pricing%20Service",
+ "title": "Pricing Service"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json"
+ },
+ "matchingRules": {
+ "$.body": {
+ "match": "type"
+ },
+ "$.headers['Content-Type']": {
+ "match": "regex",
+ "regex": "(?-mix:application\\/.*json.*)"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the list of the latest prod pacts from all consumers for the Pricing Service'",
+ "providerState": "tagged as prod pact between Condor and the Pricing Service exists",
+ "request": {
+ "method": "GET",
+ "path": "/pacts/provider/Pricing%20Service/latest/prod"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "pb:pacts": [
+ {
+ "href": "http://example.org/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0",
+ "name": "Condor",
+ "title": "Pact between Condor (v1.3.0) and Pricing Service"
+ }
+ ],
+ "provider": {
+ "href": "http://example.org/pacticipants/Pricing%20Service",
+ "title": "Pricing Service"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json"
+ },
+ "matchingRules": {
+ "$.body": {
+ "match": "type"
+ },
+ "$.headers['Content-Type']": {
+ "match": "regex",
+ "regex": "(?-mix:application\\/.*json.*)"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the successful rows of the compatibility matrix for all versions of Foo and Bar",
+ "providerState": "the pact for Foo version 1.2.3 has been successfully verified by Bar version 4.5.6, and 1.2.4 unsuccessfully by 9.9.9",
+ "request": {
+ "method": "GET",
+ "path": "/matrix",
+ "query": "latestby=cvpv&q[][pacticipant]=Foo&q[][pacticipant]=Bar&success[]=true"
+ },
+ "response": {
+ "body": {
+ "matrix": [
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "4"
+ }
+ },
+ "pact": {
+ "createdAt": "2017-10-10T12:49:04+11:00"
+ },
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "5"
+ }
+ },
+ "verificationResult": {
+ "_links": {
+ "self": {
+ "href": "http://result"
+ }
+ },
+ "success": true,
+ "verifiedAt": "2017-10-10T12:49:04+11:00"
+ }
+ }
+ ],
+ "summary": {
+ "deployable": true,
+ "reason": "some text",
+ "unknown": 1
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body": {
+ "match": "type"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request retrieve a pact for a specific version",
+ "providerState": "the 'Pricing Service' and 'Condor' already exist in the pact-broker, and Condor already has a pact published for version 1.3.0",
+ "request": {
+ "method": "GET",
+ "path": "/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0"
+ },
+ "response": {
+ "body": {
+ "consumer": {
+ "name": "Condor"
+ },
+ "interactions": [],
+ "provider": {
+ "name": "Pricing Service"
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request to create a global webhook with a JSON body",
+ "request": {
+ "body": {
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ },
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "POST",
+ "path": "/webhooks"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links.self.href": {
+ "match": "regex",
+ "regex": "(.*)$"
+ },
+ "$.body.description": {
+ "match": "type"
+ }
+ },
+ "status": 201
+ }
+ },
+ {
+ "description": "a request to create a webhook for a consumer and provider",
+ "providerState": "'Condor' does not exist in the pact-broker",
+ "request": {
+ "body": {
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ },
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "POST",
+ "path": "/webhooks/provider/Pricing%20Service/consumer/Condor"
+ },
+ "response": {
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "status": 404
+ }
+ },
+ {
+ "description": "a request to create a webhook with a JSON body and a uuid",
+ "providerState": "the 'Pricing Service' and 'Condor' already exist in the pact-broker",
+ "request": {
+ "body": {
+ "consumer": {
+ "name": "Condor"
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "provider": {
+ "name": "Pricing Service"
+ },
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ },
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "PUT",
+ "path": "/webhooks/696c5f93-1b7f-44bc-8d03-59440fcaa9a0"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links.self.href": {
+ "match": "regex",
+ "regex": "(.*)$"
+ },
+ "$.body.description": {
+ "match": "type"
+ }
+ },
+ "status": 201
+ }
+ },
+ {
+ "description": "a request to create a webhook with a JSON body for a consumer",
+ "providerState": "the 'Pricing Service' and 'Condor' already exist in the pact-broker",
+ "request": {
+ "body": {
+ "consumer": {
+ "name": "Condor"
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ },
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "POST",
+ "path": "/webhooks"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links.self.href": {
+ "match": "regex",
+ "regex": "(.*)$"
+ },
+ "$.body.description": {
+ "match": "type"
+ }
+ },
+ "status": 201
+ }
+ },
+ {
+ "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": {
+ "body": {
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ },
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "POST",
+ "path": "/webhooks/provider/Pricing%20Service/consumer/Condor"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links.self.href": {
+ "match": "regex",
+ "regex": "(.*)$"
+ },
+ "$.body.description": {
+ "match": "type"
+ }
+ },
+ "status": 201
+ }
+ },
+ {
+ "description": "a request to create a webhook with a JSON body for a consumer specified by a label",
+ "request": {
+ "body": {
+ "consumer": {
+ "label": "consumer_label"
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ },
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "POST",
+ "path": "/webhooks"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links.self.href": {
+ "match": "regex",
+ "regex": "(.*)$"
+ },
+ "$.body.description": {
+ "match": "type"
+ }
+ },
+ "status": 201
+ }
+ },
+ {
+ "description": "a request to create a webhook with a JSON body for a consumer that does not exist",
+ "request": {
+ "body": {
+ "consumer": {
+ "name": "Condor"
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ },
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "POST",
+ "path": "/webhooks"
+ },
+ "response": {
+ "body": {
+ "errors": {
+ "consumer.name": [
+ "Some error"
+ ]
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body.errors['consumer.name']": {
+ "match": "type",
+ "min": 1
+ }
+ },
+ "status": 400
+ }
+ },
+ {
+ "description": "a request to create a webhook with a JSON body for a provider",
+ "providerState": "the 'Pricing Service' and 'Condor' already exist in the pact-broker",
+ "request": {
+ "body": {
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "provider": {
+ "name": "Pricing Service"
+ },
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ },
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "POST",
+ "path": "/webhooks"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links.self.href": {
+ "match": "regex",
+ "regex": "(.*)$"
+ },
+ "$.body.description": {
+ "match": "type"
+ }
+ },
+ "status": 201
+ }
+ },
+ {
+ "description": "a request to create a webhook with a JSON body for a provider specified by a label",
+ "request": {
+ "body": {
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "provider": {
+ "label": "provider_label"
+ },
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ },
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "POST",
+ "path": "/webhooks"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links.self.href": {
+ "match": "regex",
+ "regex": "(.*)$"
+ },
+ "$.body.description": {
+ "match": "type"
+ }
+ },
+ "status": 201
+ }
+ },
+ {
+ "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": {
+ "body": {
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": "",
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ },
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "POST",
+ "path": "/webhooks/provider/Pricing%20Service/consumer/Condor"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": ""
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links.self.href": {
+ "match": "regex",
+ "regex": "(.*)$"
+ },
+ "$.body.description": {
+ "match": "type"
+ }
+ },
+ "status": 201
+ }
+ },
+ {
+ "description": "a request to create a webhook with every possible event type",
+ "providerState": "the 'Pricing Service' and 'Condor' already exist in the pact-broker",
+ "request": {
+ "body": {
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ },
+ {
+ "name": "contract_published"
+ },
+ {
+ "name": "provider_verification_published"
+ },
+ {
+ "name": "provider_verification_succeeded"
+ },
+ {
+ "name": "provider_verification_failed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ },
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "POST",
+ "path": "/webhooks/provider/Pricing%20Service/consumer/Condor"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ },
+ {
+ "name": "contract_published"
+ },
+ {
+ "name": "provider_verification_published"
+ },
+ {
+ "name": "provider_verification_succeeded"
+ },
+ {
+ "name": "provider_verification_failed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links.self.href": {
+ "match": "regex",
+ "regex": "(.*)$"
+ },
+ "$.body.description": {
+ "match": "type"
+ }
+ },
+ "status": 201
+ }
+ },
+ {
+ "description": "a request to create an environment",
+ "request": {
+ "body": {
+ "contacts": [
+ {
+ "details": {
+ "emailAddress": "foo@bar.com"
+ },
+ "name": "Foo team"
+ }
+ ],
+ "displayName": "Test",
+ "name": "test",
+ "production": false
+ },
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "POST",
+ "path": "/environments"
+ },
+ "response": {
+ "body": {
+ "contacts": [
+ {
+ "details": {
+ "emailAddress": "foo@bar.com"
+ },
+ "name": "Foo team"
+ }
+ ],
+ "displayName": "Test",
+ "name": "test",
+ "production": false,
+ "uuid": "ffe683ef-dcd7-4e4f-877d-f6eb3db8e86e"
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body.uuid": {
+ "match": "type"
+ }
+ },
+ "status": 201
+ }
+ },
+ {
+ "description": "a request to delete a pacticipant branch",
+ "providerState": "a branch named main exists for pacticipant Foo",
+ "request": {
+ "method": "DELETE",
+ "path": "/pacticipants/Foo/branches/main"
+ },
+ "response": {
+ "status": 204
+ }
+ },
+ {
+ "description": "a request to determine if Bar can be deployed with all Foo tagged prod, ignoring the verification for Foo version 3.4.5",
+ "providerState": "provider Bar version 4.5.6 has a successful verification for Foo version 1.2.3 tagged prod and a failed verification for version 3.4.5 tagged prod",
+ "request": {
+ "method": "GET",
+ "path": "/matrix",
+ "query": "ignore[][pacticipant]=Foo&ignore[][version]=3%2e4%2e5&latestby=cvpv&q[][pacticipant]=Bar&q[][pacticipant]=Foo&q[][tag]=prod&q[][version]=4%2e5%2e6"
+ },
+ "response": {
+ "body": {
+ "matrix": [
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "1.2.3"
+ }
+ },
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "4.5.6"
+ }
+ },
+ "verificationResult": {
+ "_links": {
+ "self": {
+ "href": "http://result"
+ }
+ },
+ "success": true
+ }
+ },
+ {
+ "consumer": {
+ "name": "Foo",
+ "version": {
+ "number": "3.4.5"
+ }
+ },
+ "ignored": true,
+ "provider": {
+ "name": "Bar",
+ "version": {
+ "number": "4.5.6"
+ }
+ },
+ "verificationResult": {
+ "_links": {
+ "self": {
+ "href": "http://result"
+ }
+ },
+ "success": false
+ }
+ }
+ ],
+ "notices": [
+ {
+ "text": "some notice",
+ "type": "info"
+ }
+ ],
+ "summary": {
+ "deployable": true,
+ "ignored": 1
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body.matrix[0].verificationResult._links.self.href": {
+ "match": "type"
+ },
+ "$.body.matrix[1].verificationResult._links.self.href": {
+ "match": "type"
+ },
+ "$.body.notices": {
+ "match": "type",
+ "min": 1
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request to get the Pricing Service",
+ "providerState": "the 'Pricing Service' already exists in the pact-broker",
+ "request": {
+ "method": "GET",
+ "path": "/pacticipants/Pricing%20Service"
+ },
+ "response": {
+ "body": {
+ "_embedded": {
+ "latest-version": {
+ "_links": {
+ "self": {
+ "href": "http://example.org/pacticipants/Pricing%20Service/versions/1.3.0"
+ }
+ },
+ "number": "1.3.0"
+ }
+ },
+ "_links": {
+ "self": {
+ "href": "http://example.org/pacticipants/Pricing%20Service"
+ },
+ "versions": {
+ "href": "http://example.org/pacticipants/Pricing%20Service/versions"
+ }
+ },
+ "name": "Pricing Service",
+ "repositoryUrl": "git@git.realestate.com.au:business-systems/pricing-service"
+ },
+ "headers": {
+ "Content-Type": "application/hal+json"
+ },
+ "matchingRules": {
+ "$.headers['Content-Type']": {
+ "match": "regex",
+ "regex": "(?-mix:application\\/hal\\+json.*)"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request to get the Pricing Service",
+ "providerState": "the 'Pricing Service' does not exist in the pact-broker",
+ "request": {
+ "method": "GET",
+ "path": "/pacticipants/Pricing%20Service"
+ },
+ "response": {
+ "status": 404
+ }
+ },
+ {
+ "description": "a request to list pacticipants",
+ "providerState": "'Condor' exists in the pact-broker",
+ "request": {
+ "method": "GET",
+ "path": "/pacticipants"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "pacticipants": [
+ {
+ "href": "http://example.org/pacticipants/Condor",
+ "title": "Condor"
+ }
+ ],
+ "self": {
+ "href": "http://example.org/pacticipants"
+ }
+ },
+ "pacticipants": [
+ {
+ "_embedded": {
+ "latest-version": {
+ "_links": {
+ "self": {
+ "href": "http://example.org/pacticipants/Condor/versions/1.3.0"
+ }
+ },
+ "number": "1.3.0"
+ }
+ },
+ "_links": {
+ "self": {
+ "href": "http://example.org/pacticipants/Condor"
+ }
+ },
+ "name": "Condor"
+ }
+ ]
+ },
+ "headers": {
+ "Content-Type": "application/hal+json"
+ },
+ "matchingRules": {
+ "$.headers['Content-Type']": {
+ "match": "regex",
+ "regex": "(?-mix:application\\/hal\\+json.*)"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request to list the environments",
+ "providerState": "an environment exists",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json"
+ },
+ "method": "GET",
+ "path": "/environments"
+ },
+ "response": {
+ "body": {
+ "_embedded": {
+ "environments": [
+ {
+ "contacts": [
+ {
+ "details": {
+ "emailAddress": "foo@bar.com"
+ },
+ "name": "Foo team"
+ }
+ ],
+ "displayName": "Test",
+ "name": "test",
+ "production": false,
+ "uuid": "78e85fb2-9df1-48da-817e-c9bea6294e01"
+ }
+ ]
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._embedded.environments": {
+ "match": "type",
+ "min": 1
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request to list the latest pacts",
+ "providerState": "a pact between Condor and the Pricing Service exists",
+ "request": {
+ "method": "GET",
+ "path": "/pacts/latest"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "self": {
+ "href": "http://example.org/pacts/latest"
+ }
+ },
+ "pacts": [
+ {
+ "_embedded": {
+ "consumer": {
+ "_embedded": {
+ "version": {
+ "number": "1.3.0"
+ }
+ },
+ "_links": {
+ "self": {
+ "href": "http://example.org/pacticipants/Condor"
+ }
+ },
+ "name": "Condor"
+ },
+ "provider": {
+ "_links": {
+ "self": {
+ "href": "http://example.org/pacticipants/Pricing%20Service"
+ }
+ },
+ "name": "Pricing Service"
+ }
+ },
+ "_links": {
+ "self": [
+ {
+ "href": "http://example.org/pacts/provider/Pricing%20Service/consumer/Condor/latest"
+ },
+ {
+ "href": "http://example.org/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "headers": {
+ "Content-Type": "application/hal+json"
+ },
+ "matchingRules": {
+ "$.headers['Content-Type']": {
+ "match": "regex",
+ "regex": "(?-mix:application\\/hal\\+json.*)"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request to list the versions deployed to an environment for a pacticipant name and application instance",
+ "providerState": "an version is deployed to environment with UUID 16926ef3-590f-4e3f-838e-719717aa88c9 with target customer-1",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json"
+ },
+ "method": "GET",
+ "path": "/environments/16926ef3-590f-4e3f-838e-719717aa88c9/deployed-versions/currently-deployed",
+ "query": "pacticipant=Foo"
+ },
+ "response": {
+ "body": {
+ "_embedded": {
+ "deployedVersions": [
+ {
+ "_links": {
+ "self": {
+ "href": "/deployed-versions/ff3adecf-cfc5-4653-a4e3-f1861092f8e0"
+ }
+ },
+ "applicationInstance": "customer-1"
+ }
+ ]
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._embedded.deployedVersions[0]._links.self.href": {
+ "match": "regex",
+ "regex": ".*(\\/deployed-versions\\/.*)$"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request to mark a deployed version as not currently deploye",
+ "providerState": "a currently deployed version exists",
+ "request": {
+ "body": {
+ "currentlyDeployed": false
+ },
+ "headers": {
+ "Content-Type": "application/merge-patch+json"
+ },
+ "method": "PATCH",
+ "path": "/deployed-versions/ff3adecf-cfc5-4653-a4e3-f1861092f8e0"
+ },
+ "response": {
+ "body": {
+ "_embedded": {
+ "version": {
+ "number": "2"
+ }
+ },
+ "currentlyDeployed": false
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._embedded.version.number": {
+ "match": "type"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request to publish contracts",
+ "request": {
+ "body": {
+ "branch": "main",
+ "buildUrl": "http://build",
+ "contracts": [
+ {
+ "consumerName": "Foo",
+ "content": "eyJjb25zdW1lciI6eyJuYW1lIjoiRm9vIn0sInByb3ZpZGVyIjp7Im5hbWUiOiJCYXIifSwiaW50ZXJhY3Rpb25zIjpbeyJkZXNjcmlwdGlvbiI6ImFuIGV4YW1wbGUgcmVxdWVzdCIsInByb3ZpZGVyU3RhdGUiOiJhIHByb3ZpZGVyIHN0YXRlIiwicmVxdWVzdCI6eyJtZXRob2QiOiJHRVQiLCJwYXRoIjoiLyIsImhlYWRlcnMiOnt9fSwicmVzcG9uc2UiOnsic3RhdHVzIjoyMDAsImhlYWRlcnMiOnsiQ29udGVudC1UeXBlIjoiYXBwbGljYXRpb24vaGFsK2pzb24ifX19XSwibWV0YWRhdGEiOnsicGFjdFNwZWNpZmljYXRpb24iOnsidmVyc2lvbiI6IjIuMC4wIn19fQ==",
+ "contentType": "application/json",
+ "onConflict": "merge",
+ "providerName": "Bar",
+ "specification": "pact"
+ }
+ ],
+ "pacticipantName": "Foo",
+ "pacticipantVersionNumber": "5556b8149bf8bac76bc30f50a8a2dd4c22c85f30",
+ "tags": [
+ "dev"
+ ]
+ },
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "POST",
+ "path": "/contracts/publish"
+ },
+ "response": {
+ "body": {
+ "_embedded": {
+ "pacticipant": {
+ "name": "Foo"
+ },
+ "version": {
+ "number": "5556b8149bf8bac76bc30f50a8a2dd4c22c85f30"
+ }
+ },
+ "_links": {
+ "pb:contracts": [
+ {
+ "href": "http://some-pact"
+ }
+ ],
+ "pb:pacticipant-version-tags": [
+ {
+ "name": "dev"
+ }
+ ]
+ },
+ "logs": [
+ {
+ "level": "info",
+ "message": "some message"
+ }
+ ]
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links['pb:contracts'][0].href": {
+ "match": "type"
+ },
+ "$.body.logs": {
+ "match": "type",
+ "min": 1
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request to record a deployment",
+ "providerState": "version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for deployment",
+ "request": {
+ "body": {
+ "applicationInstance": "blue",
+ "target": "blue"
+ },
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "POST",
+ "path": "/pacticipants/Foo/versions/5556b8149bf8bac76bc30f50a8a2dd4c22c85f30/deployed-versions/environment/cb632df3-0a0d-4227-aac3-60114dd36479"
+ },
+ "response": {
+ "body": {
+ "target": "blue"
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "status": 201
+ }
+ },
+ {
+ "description": "a request to record a release",
+ "providerState": "version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for deployment",
+ "request": {
+ "body": {},
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "POST",
+ "path": "/pacticipants/Foo/versions/5556b8149bf8bac76bc30f50a8a2dd4c22c85f30/released-versions/environment/cb632df3-0a0d-4227-aac3-60114dd36479"
+ },
+ "response": {
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "status": 201
+ }
+ },
+ {
+ "description": "a request to register the repository URL of a pacticipant",
+ "providerState": "the 'Pricing Service' already exists in the pact-broker",
+ "request": {
+ "body": {
+ "repository_url": "git@git.realestate.com.au:business-systems/pricing-service"
+ },
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "method": "PATCH",
+ "path": "/pacticipants/Pricing%20Service"
+ },
+ "response": {
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request to register the repository URL of a pacticipant",
+ "providerState": "the 'Pricing Service' does not exist in the pact-broker",
+ "request": {
+ "body": {
+ "repository_url": "git@git.realestate.com.au:business-systems/pricing-service"
+ },
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "method": "PATCH",
+ "path": "/pacticipants/Pricing%20Service"
+ },
+ "response": {
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "status": 201
+ }
+ },
+ {
+ "description": "a request to retrieve a pacticipant",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json"
+ },
+ "method": "GET",
+ "path": "/pacticipants/Foo"
+ },
+ "response": {
+ "status": 404
+ }
+ },
+ {
+ "description": "a request to create a pacticipant",
+ "request": {
+ "body": {
+ "name": "Foo",
+ "repositoryUrl": "http://foo"
+ },
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "POST",
+ "path": "/pacticipants"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/pacticipants/Foo"
+ }
+ },
+ "name": "Foo",
+ "repositoryUrl": "http://foo"
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links.self.href": {
+ "match": "regex",
+ "regex": ".*(\\/pacticipants\\/Foo)$"
+ }
+ },
+ "status": 201
+ }
+ },
+ {
+ "description": "a request to retrieve a pacticipant",
+ "providerState": "a pacticipant with name Foo exists",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json"
+ },
+ "method": "GET",
+ "path": "/pacticipants/Foo"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/pacticipants/Foo"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links.self.href": {
+ "match": "regex",
+ "regex": ".*(\\/pacticipants\\/Foo)$"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request to retrieve the latest 'production' version of Condor",
+ "providerState": "'Condor' exists in the pact-broker with the latest tagged 'production' version 1.2.3",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json, application/json"
+ },
+ "method": "GET",
+ "path": "/pacticipants/Condor/latest-version/production"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "number": "1.2.3"
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links.self.href": {
+ "match": "regex",
+ "regex": "(.*)$"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request to retrieve the latest pact between Condor and the Pricing Service",
+ "providerState": "a pact between Condor and the Pricing Service exists",
+ "request": {
+ "method": "GET",
+ "path": "/pacts/provider/Pricing%20Service/consumer/Condor/latest"
+ },
+ "response": {
+ "body": {
+ "consumer": {
+ "name": "Condor"
+ },
+ "interactions": [],
+ "provider": {
+ "name": "Pricing Service"
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json",
+ "X-Pact-Consumer-Version": "1.3.0"
+ },
+ "matchingRules": {
+ "$.headers['Content-Type']": {
+ "match": "regex",
+ "regex": "(?-mix:application\\/.*json.*)"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request to retrieve the latest pact between Condor and the Pricing Service",
+ "providerState": "no pact between Condor and the Pricing Service exists",
+ "request": {
+ "method": "GET",
+ "path": "/pacts/provider/Pricing%20Service/consumer/Condor/latest"
+ },
+ "response": {
+ "status": 404
+ }
+ },
+ {
+ "description": "a request to retrieve the latest version of Condor",
+ "providerState": "'Condor' exists in the pact-broker with the latest version 1.2.3",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json, application/json"
+ },
+ "method": "GET",
+ "path": "/pacticipants/Condor/latest-version"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "number": "1.2.3"
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links.self.href": {
+ "match": "regex",
+ "regex": "(.*)$"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request to retrieve the pact between the production verison of Condor and the Pricing Service",
+ "providerState": "a pact between Condor and the Pricing Service exists for the production version of Condor",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json, application/json"
+ },
+ "method": "GET",
+ "path": "/pacts/provider/Pricing%20Service/consumer/Condor/latest/prod"
+ },
+ "response": {
+ "body": {
+ "consumer": {
+ "name": "Condor"
+ },
+ "interactions": [],
+ "provider": {
+ "name": "Pricing Service"
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request to tag the production version of Condor",
+ "providerState": "'Condor' does not exist in the pact-broker",
+ "request": {
+ "body": {},
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "method": "PUT",
+ "path": "/pacticipants/Condor/versions/1.3.0/tags/prod"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/pacticipants/Condor/versions/1.3.0/tags/prod"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links.self.href": {
+ "match": "regex",
+ "regex": ".*(\\/pacticipants\\/Condor\\/versions\\/1\\.3\\.0\\/tags\\/prod)$"
+ }
+ },
+ "status": 201
+ }
+ },
+ {
+ "description": "a request to tag the production version of Condor",
+ "providerState": "'Condor' exists in the pact-broker",
+ "request": {
+ "body": {},
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "method": "PUT",
+ "path": "/pacticipants/Condor/versions/1.3.0/tags/prod"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/pacticipants/Condor/versions/1.3.0/tags/prod"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links.self.href": {
+ "match": "regex",
+ "regex": ".*(\\/pacticipants\\/Condor\\/versions\\/1\\.3\\.0\\/tags\\/prod)$"
+ }
+ },
+ "status": 201
+ }
+ },
+ {
+ "description": "a request to tag the production version of Condor",
+ "providerState": "'Condor' exists in the pact-broker with version 1.3.0, tagged with 'prod'",
+ "request": {
+ "body": {},
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "method": "PUT",
+ "path": "/pacticipants/Condor/versions/1.3.0/tags/prod"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/pacticipants/Condor/versions/1.3.0/tags/prod"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links.self.href": {
+ "match": "regex",
+ "regex": ".*(\\/pacticipants\\/Condor\\/versions\\/1\\.3\\.0\\/tags\\/prod)$"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request to update a pacticipant",
+ "providerState": "a pacticipant with name Foo exists",
+ "request": {
+ "body": {
+ "name": "Foo",
+ "repositoryUrl": "http://foo"
+ },
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "PATCH",
+ "path": "/pacticipants/Foo"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/pacticipants/Foo"
+ }
+ },
+ "name": "Foo",
+ "repositoryUrl": "http://foo"
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links.self.href": {
+ "match": "regex",
+ "regex": ".*(\\/pacticipants\\/Foo)$"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request to update a webhook",
+ "providerState": "a webhook with the uuid 696c5f93-1b7f-44bc-8d03-59440fcaa9a0 exists",
+ "request": {
+ "body": {
+ "consumer": {
+ "name": "Condor"
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "provider": {
+ "name": "Pricing Service"
+ },
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "url": "https://webhook",
+ "username": "username"
+ }
+ },
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "PUT",
+ "path": "/webhooks/696c5f93-1b7f-44bc-8d03-59440fcaa9a0"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url"
+ }
+ },
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ }
+ }
+ },
+ "generators": null,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links.self.href": {
+ "match": "regex",
+ "regex": "(.*)$"
+ },
+ "$.body.description": {
+ "match": "type"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "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": {
+ "body": {
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "password": "password",
+ "username": "username"
+ }
+ },
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "POST",
+ "path": "/webhooks/provider/Pricing%20Service/consumer/Condor"
+ },
+ "response": {
+ "body": {
+ "errors": {
+ "request.url": [
+ "Some error"
+ ]
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body.errors['request.url']": {
+ "match": "type",
+ "min": 1
+ }
+ },
+ "status": 400
+ }
+ }
+ ],
+ "metadata": {
+ "pact-ruby-v2": {
+ "pact-ffi": "0.4.28"
+ },
+ "pactRust": {
+ "ffi": "0.4.28",
+ "mockserver": "1.2.16",
+ "models": "1.3.5"
+ },
+ "pactSpecification": {
+ "version": "2.0.0"
+ }
+ },
+ "provider": {
+ "name": "Pact Broker"
+ }
+}
\ No newline at end of file
diff --git a/spec/pacts/Pact Broker Client V2-PactFlow.json b/spec/pacts/Pact Broker Client V2-PactFlow.json
new file mode 100644
index 0000000..71e970b
--- /dev/null
+++ b/spec/pacts/Pact Broker Client V2-PactFlow.json
@@ -0,0 +1,294 @@
+{
+ "consumer": {
+ "name": "Pact Broker Client V2"
+ },
+ "interactions": [
+ {
+ "description": "a request for the index resource",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json"
+ },
+ "method": "GET",
+ "path": "/"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "pb:pacticipant": {
+ "href": "/pacticipants/{pacticipant}"
+ },
+ "pb:pacticipants": {
+ "href": "/pacticipants"
+ },
+ "pb:webhooks": {
+ "href": "/webhooks"
+ }
+ }
+ },
+ "generators": null,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links['pb:pacticipant'].href": {
+ "match": "regex",
+ "regex": ".*(\\/pacticipants\\/{pacticipant})$"
+ },
+ "$.body._links['pb:pacticipants'].href": {
+ "match": "regex",
+ "regex": ".*(\\/pacticipants)$"
+ },
+ "$.body._links['pb:webhooks'].href": {
+ "match": "regex",
+ "regex": ".*(\\/webhooks)$"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request for the index resource",
+ "providerState": "the pb:publish-provider-contract relation exists in the index resource",
+ "request": {
+ "headers": {
+ "Accept": "application/hal+json"
+ },
+ "method": "GET",
+ "path": "/"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "pf:publish-provider-contract": {
+ "href": "/provider-contracts/provider/{provider}/publish"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links['pf:publish-provider-contract'].href": {
+ "match": "regex",
+ "regex": ".*(\\/provider-contracts\\/provider\\/.*\\/publish)$"
+ }
+ },
+ "status": 200
+ }
+ },
+ {
+ "description": "a request to create a provider contract",
+ "request": {
+ "body": {
+ "content": "LS0tCnNvbWU6IGNvbnRyYWN0Cg==",
+ "contentType": "application/yaml",
+ "contractType": "oas",
+ "verificationResults": {
+ "content": "c29tZSByZXN1bHRz",
+ "contentType": "text/plain",
+ "format": "text",
+ "success": true,
+ "verifier": "my custom tool",
+ "verifierVersion": "1.0"
+ }
+ },
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "PUT",
+ "path": "/contracts/provider/Bar/version/1"
+ },
+ "response": {
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "status": 201
+ }
+ },
+ {
+ "description": "a request to create a provider contract",
+ "providerState": "there is a pf:ui href in the response",
+ "request": {
+ "body": {
+ "content": "LS0tCnNvbWU6IGNvbnRyYWN0Cg==",
+ "contentType": "application/yaml",
+ "contractType": "oas",
+ "verificationResults": {
+ "content": "c29tZSByZXN1bHRz",
+ "contentType": "text/plain",
+ "format": "text",
+ "success": true,
+ "verifier": "my custom tool",
+ "verifierVersion": "1.0"
+ }
+ },
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "PUT",
+ "path": "/contracts/provider/Bar/version/1"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "pf:ui": {
+ "href": "some-url"
+ }
+ }
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links['pf:ui'].href": {
+ "match": "type"
+ }
+ },
+ "status": 201
+ }
+ },
+ {
+ "description": "a request to create a webhook for a team",
+ "providerState": "a team with UUID 2abbc12a-427d-432a-a521-c870af1739d9 exists",
+ "request": {
+ "body": {
+ "description": "a webhook",
+ "events": [
+ {
+ "name": "contract_content_changed"
+ }
+ ],
+ "request": {
+ "body": {
+ "some": "body"
+ },
+ "headers": {
+ "Bar": "foo",
+ "Foo": "bar"
+ },
+ "method": "POST",
+ "url": "https://webhook"
+ },
+ "teamUuid": "2abbc12a-427d-432a-a521-c870af1739d9"
+ },
+ "headers": {
+ "Accept": "application/hal+json",
+ "Content-Type": "application/json"
+ },
+ "method": "POST",
+ "path": "/webhooks"
+ },
+ "response": {
+ "body": {
+ "_links": {
+ "self": {
+ "href": "/some-url",
+ "title": "A title"
+ }
+ },
+ "description": "a webhook",
+ "teamUuid": "2abbc12a-427d-432a-a521-c870af1739d9"
+ },
+ "generators": null,
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body._links.self.href": {
+ "match": "regex",
+ "regex": "(.*)$"
+ },
+ "$.body._links.self.title": {
+ "match": "type"
+ },
+ "$.body.description": {
+ "match": "type"
+ }
+ },
+ "status": 201
+ }
+ },
+ {
+ "description": "a request to publish a provider contract",
+ "request": {
+ "body": {
+ "branch": "main",
+ "buildUrl": "http://build",
+ "contract": {
+ "content": "LS0tCnNvbWU6IGNvbnRyYWN0Cg==",
+ "contentType": "application/yaml",
+ "selfVerificationResults": {
+ "content": "c29tZSByZXN1bHRz",
+ "contentType": "text/plain",
+ "format": "text",
+ "success": true,
+ "verifier": "my custom tool",
+ "verifierVersion": "1.0"
+ },
+ "specification": "oas"
+ },
+ "pacticipantVersionNumber": "1",
+ "tags": [
+ "dev"
+ ]
+ },
+ "headers": {
+ "Accept": "application/hal+json, application/problem+json",
+ "Content-Type": "application/json"
+ },
+ "method": "POST",
+ "path": "/provider-contracts/provider/Bar/publish"
+ },
+ "response": {
+ "body": {
+ "_embedded": {
+ "version": {
+ "number": "1"
+ }
+ },
+ "_links": {
+ "pb:branch-version": {},
+ "pb:pacticipant-version-tags": [
+ {}
+ ]
+ },
+ "notices": [
+ {
+ "text": "some notice",
+ "type": "info"
+ }
+ ]
+ },
+ "headers": {
+ "Content-Type": "application/hal+json;charset=utf-8"
+ },
+ "matchingRules": {
+ "$.body.notices": {
+ "match": "type",
+ "min": 1
+ }
+ },
+ "status": 200
+ }
+ }
+ ],
+ "metadata": {
+ "pact-ruby-v2": {
+ "pact-ffi": "0.4.28"
+ },
+ "pactRust": {
+ "ffi": "0.4.28",
+ "mockserver": "1.2.16",
+ "models": "1.3.5"
+ },
+ "pactSpecification": {
+ "version": "2.0.0"
+ }
+ },
+ "provider": {
+ "name": "PactFlow"
+ }
+}
\ No newline at end of file
diff --git a/spec/pacts/pact_broker_client-pact_broker.json b/spec/pacts/pact_broker_client-pact_broker.json
index 53b4f95..5f219f8 100644
--- a/spec/pacts/pact_broker_client-pact_broker.json
+++ b/spec/pacts/pact_broker_client-pact_broker.json
@@ -110,7 +110,7 @@
"matchingRules": {
"$.headers.Content-Type": {
"match": "regex",
- "regex": "application\\/hal\\+json"
+ "regex": "application\\/hal\\+json.*"
}
}
}
@@ -165,7 +165,7 @@
"matchingRules": {
"$.headers.Content-Type": {
"match": "regex",
- "regex": "application\\/hal\\+json"
+ "regex": "application\\/hal\\+json.*"
}
}
}
@@ -209,7 +209,7 @@
"matchingRules": {
"$.headers.Content-Type": {
"match": "regex",
- "regex": "application\\/hal\\+json"
+ "regex": "application\\/hal\\+json.*"
}
}
}
@@ -811,189 +811,6 @@
}
}
},
- {
- "description": "a request to publish a pact",
- "providerState": "the 'Pricing Service' already exists in the pact-broker",
- "request": {
- "method": "put",
- "path": "/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0",
- "headers": {
- "Content-Type": "application/json"
- },
- "body": {
- "consumer": {
- "name": "Condor"
- },
- "provider": {
- "name": "Pricing Service"
- },
- "interactions": [
-
- ]
- }
- },
- "response": {
- "status": 201,
- "headers": {
- "Content-Type": "application/hal+json;charset=utf-8"
- },
- "body": {
- "_links": {
- "pb:latest-pact-version": {
- "href": "http://example.org/pacts/provider/Pricing%20Service/consumer/Condor/latest"
- }
- }
- }
- }
- },
- {
- "description": "a request to publish a pact with method patch",
- "providerState": "the 'Pricing Service' and 'Condor' already exist in the pact-broker, and Condor already has a pact published for version 1.3.0",
- "request": {
- "method": "patch",
- "path": "/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0",
- "headers": {
- "Content-Type": "application/json"
- },
- "body": {
- "consumer": {
- "name": "Condor"
- },
- "provider": {
- "name": "Pricing Service"
- },
- "interactions": [
-
- ]
- }
- },
- "response": {
- "status": 200,
- "headers": {
- "Content-Type": "application/hal+json;charset=utf-8"
- },
- "body": {
- "_links": {
- "pb:latest-pact-version": {
- "href": "http://example.org/pacts/provider/Pricing%20Service/consumer/Condor/latest"
- }
- }
- }
- }
- },
- {
- "description": "a request to publish a pact with method put",
- "providerState": "the 'Pricing Service' and 'Condor' already exist in the pact-broker, and Condor already has a pact published for version 1.3.0",
- "request": {
- "method": "put",
- "path": "/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0",
- "headers": {
- "Content-Type": "application/json"
- },
- "body": {
- "consumer": {
- "name": "Condor"
- },
- "provider": {
- "name": "Pricing Service"
- },
- "interactions": [
-
- ]
- }
- },
- "response": {
- "status": 200,
- "headers": {
- "Content-Type": "application/hal+json;charset=utf-8"
- },
- "body": {
- "_links": {
- "pb:latest-pact-version": {
- "href": "http://example.org/pacts/provider/Pricing%20Service/consumer/Condor/latest"
- }
- }
- }
- }
- },
- {
- "description": "a request to publish a pact",
- "providerState": "'Condor' already exist in the pact-broker, but the 'Pricing Service' does not",
- "request": {
- "method": "put",
- "path": "/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0",
- "headers": {
- "Content-Type": "application/json"
- },
- "body": {
- "consumer": {
- "name": "Condor"
- },
- "provider": {
- "name": "Pricing Service"
- },
- "interactions": [
-
- ]
- }
- },
- "response": {
- "status": 201,
- "headers": {
- "Content-Type": "application/hal+json;charset=utf-8"
- },
- "body": {
- "_links": {
- "pb:latest-pact-version": {
- "href": "http://example.org/pacts/provider/Pricing%20Service/consumer/Condor/latest"
- }
- }
- }
- }
- },
- {
- "description": "a request to publish a pact",
- "providerState": "an error occurs while publishing a pact",
- "request": {
- "method": "put",
- "path": "/pacts/provider/Pricing%20Service/consumer/Condor/version/1.3.0",
- "headers": {
- "Content-Type": "application/json"
- },
- "body": {
- "consumer": {
- "name": "Condor"
- },
- "provider": {
- "name": "Pricing Service"
- },
- "interactions": [
-
- ]
- }
- },
- "response": {
- "status": 500,
- "headers": {
- "Content-Type": "application/hal+json"
- },
- "body": {
- "error": {
- "message": "An error occurred"
- }
- },
- "matchingRules": {
- "$.headers.Content-Type": {
- "match": "regex",
- "regex": "application\\/.*json"
- },
- "$.body.error.message": {
- "match": "regex",
- "regex": ".*"
- }
- }
- }
- },
{
"description": "a request to register the repository URL of a pacticipant",
"providerState": "the 'Pricing Service' does not exist in the pact-broker",
@@ -1126,8 +943,7 @@
"name": "Pricing Service"
},
"interactions": [
-
- ]
+ ]
}
}
},
@@ -1154,13 +970,12 @@
"name": "Pricing Service"
},
"interactions": [
-
- ]
+ ]
},
"matchingRules": {
"$.headers.Content-Type": {
"match": "regex",
- "regex": "application\\/.*json"
+ "regex": "application\\/.*json.*"
}
}
}
@@ -1203,8 +1018,7 @@
"name": "Pricing Service"
},
"interactions": [
-
- ]
+ ]
}
}
},
@@ -1216,6 +1030,8 @@
"path": "/pacticipants/Condor/versions/1.3.0/tags/prod",
"headers": {
"Content-Type": "application/json"
+ },
+ "body": {
}
},
"response": {
@@ -1246,6 +1062,8 @@
"path": "/pacticipants/Condor/versions/1.3.0/tags/prod",
"headers": {
"Content-Type": "application/json"
+ },
+ "body": {
}
},
"response": {
@@ -1276,6 +1094,8 @@
"path": "/pacticipants/Condor/versions/1.3.0/tags/prod",
"headers": {
"Content-Type": "application/json"
+ },
+ "body": {
}
},
"response": {
@@ -1323,7 +1143,7 @@
"matchingRules": {
"$.body._links.pb:latest-version.href": {
"match": "regex",
- "regex": "http:\\/\\/.*{pacticipant}"
+ "regex": "http:\\/\\/.*{pacticipant}.*"
}
}
}
@@ -1888,6 +1708,8 @@
"headers": {
"Content-Type": "application/json",
"Accept": "application/hal+json"
+ },
+ "body": {
}
},
"response": {
@@ -1960,7 +1782,7 @@
"matchingRules": {
"$.body._embedded.deployedVersions[0]._links.self.href": {
"match": "regex",
- "regex": "^http"
+ "regex": "^http.*"
}
}
}
diff --git a/spec/pacts/pact_broker_client-pactflow.json b/spec/pacts/pact_broker_client-pactflow.json
index 8c0d86f..c2774ba 100644
--- a/spec/pacts/pact_broker_client-pactflow.json
+++ b/spec/pacts/pact_broker_client-pactflow.json
@@ -87,10 +87,10 @@
"_links": {
"pb:pacticipant-version-tags": [
{
- }
+ }
],
"pb:branch-version": {
- }
+ }
}
},
"matchingRules": {
diff --git a/spec/service_providers/extra_goodies_spec.rb b/spec/service_providers/extra_goodies_spec.rb
index 3da2016..f31db12 100644
--- a/spec/service_providers/extra_goodies_spec.rb
+++ b/spec/service_providers/extra_goodies_spec.rb
@@ -33,7 +33,7 @@ module PactBroker::Client
method: :get,
path: '/pacts/latest',
headers: {} ).
- will_respond_with( headers: {'Content-Type' => Pact.term(generate: 'application/hal+json', matcher: %r{application/hal\+json})},
+ will_respond_with( headers: {'Content-Type' => Pact.term(generate: 'application/hal+json', matcher: %r{application/hal\+json.*})},
status: 200,
body: response_body
)
@@ -55,7 +55,7 @@ module PactBroker::Client
method: :get,
path: '/pacticipants',
headers: {} ).
- will_respond_with( headers: {'Content-Type' => Pact.term(generate: 'application/hal+json', matcher: %r{application/hal\+json})},
+ will_respond_with( headers: {'Content-Type' => Pact.term(generate: 'application/hal+json', matcher: %r{application/hal\+json.*})},
status: 200,
body: response_body
)
@@ -78,7 +78,7 @@ module PactBroker::Client
method: :get,
path: '/pacticipants/Pricing%20Service',
headers: {} ).
- will_respond_with( headers: {'Content-Type' => Pact.term(generate: 'application/hal+json', matcher: %r{application/hal\+json})},
+ will_respond_with( headers: {'Content-Type' => Pact.term(generate: 'application/hal+json', matcher: %r{application/hal\+json.*})},
status: 200,
body: response_body
)
diff --git a/spec/service_providers/pact_broker_client_publish_spec.rb b/spec/service_providers/pact_broker_client_publish_spec.rb
index cda1c3b..712ab48 100644
--- a/spec/service_providers/pact_broker_client_publish_spec.rb
+++ b/spec/service_providers/pact_broker_client_publish_spec.rb
@@ -6,7 +6,7 @@ module PactBroker::Client
include_context "pact broker"
- describe "publishing a pact" do
+ describe "publishing a pact", :skip do
let(:options) { { pact_hash: pact_hash, consumer_version: consumer_version }}
let(:location) { 'http://example.org/pacts/provider/Pricing%20Service/consumer/Condor/latest' }
@@ -117,7 +117,7 @@ module PactBroker::Client
body: pact_hash ).
will_respond_with(
status: 500,
- headers: {'Content-Type' => Pact.term(generate: 'application/hal+json', matcher: %r{application/.*json})},
+ headers: {'Content-Type' => Pact.term(generate: 'application/hal+json', matcher: %r{application/.*json.*})},
body: {
error: {
message: Pact::Term.new(matcher: /.*/, generate: 'An error occurred')
diff --git a/spec/service_providers/pact_broker_client_retrieve_pact_spec.rb b/spec/service_providers/pact_broker_client_retrieve_pact_spec.rb
index cf11194..49df51e 100644
--- a/spec/service_providers/pact_broker_client_retrieve_pact_spec.rb
+++ b/spec/service_providers/pact_broker_client_retrieve_pact_spec.rb
@@ -33,7 +33,7 @@ module PactBroker::Client
let(:response_headers) do
pact_broker_response_headers.merge(
- 'Content-Type' => Pact.term(generate: 'application/hal+json', matcher: %r{application/.*json}),
+ 'Content-Type' => Pact.term(generate: 'application/hal+json', matcher: %r{application/.*json.*}),
'X-Pact-Consumer-Version' => consumer_version
)
end
diff --git a/spec/service_providers/pact_broker_client_tags_spec.rb b/spec/service_providers/pact_broker_client_tags_spec.rb
index d34ce80..eb04a48 100644
--- a/spec/service_providers/pact_broker_client_tags_spec.rb
+++ b/spec/service_providers/pact_broker_client_tags_spec.rb
@@ -18,7 +18,7 @@
with(
method: :put,
path: '/pacticipants/Condor/versions/1.3.0/tags/prod',
- headers: default_request_headers).
+ headers: default_request_headers, body: {}).
will_respond_with(
status: 201,
headers: pact_broker_response_headers,
@@ -46,7 +46,7 @@
with(
method: :put,
path: '/pacticipants/Condor/versions/1.3.0/tags/prod',
- headers: default_request_headers).
+ headers: default_request_headers, body: {}).
will_respond_with(
status: 201,
headers: pact_broker_response_headers,
@@ -75,7 +75,7 @@
with(
method: :put,
path: '/pacticipants/Condor/versions/1.3.0/tags/prod',
- headers: default_request_headers).
+ headers: default_request_headers, body: {}).
will_respond_with(
status: 200,
headers: pact_broker_response_headers,
diff --git a/spec/service_providers/pact_broker_client_versions_spec.rb b/spec/service_providers/pact_broker_client_versions_spec.rb
index e806ef1..667baea 100644
--- a/spec/service_providers/pact_broker_client_versions_spec.rb
+++ b/spec/service_providers/pact_broker_client_versions_spec.rb
@@ -25,7 +25,7 @@
body: {
_links: {
:'pb:latest-version' => {
- href: Pact.term(latest_version_url, /http:\/\/.*{pacticipant}/)
+ href: Pact.term(latest_version_url, /http:\/\/.*{pacticipant}.*/)
}
}
}
diff --git a/spec/service_providers/record_release_spec.rb b/spec/service_providers/record_release_spec.rb
index 351a705..3a854cd 100644
--- a/spec/service_providers/record_release_spec.rb
+++ b/spec/service_providers/record_release_spec.rb
@@ -107,7 +107,8 @@ def mock_record_release
.with(
method: "POST",
path: "/HAL-REL-PLACEHOLDER-PB-RECORD-RELEASE-FOO-5556B8149BF8BAC76BC30F50A8A2DD4C22C85F30-TEST",
- headers: post_request_headers
+ headers: post_request_headers,
+ body: {}
)
.will_respond_with(
status: 201,
diff --git a/spec/service_providers/record_undeployment_spec.rb b/spec/service_providers/record_undeployment_spec.rb
index 1a78b8d..ccb197e 100644
--- a/spec/service_providers/record_undeployment_spec.rb
+++ b/spec/service_providers/record_undeployment_spec.rb
@@ -103,7 +103,7 @@ def mock_deployed_versions_search_results
applicationInstance: application_instance,
_links: {
self: {
- href: Pact.term(pact_broker.mock_service_base_url + deployed_version_placeholder_path, /^http/)
+ href: Pact.term(pact_broker.mock_service_base_url + deployed_version_placeholder_path, /^http.*/)
}
}
}
diff --git a/spec/support/shared_context.rb b/spec/support/shared_context.rb
index 1423e3b..e7b7e76 100644
--- a/spec/support/shared_context.rb
+++ b/spec/support/shared_context.rb
@@ -23,3 +23,8 @@
let(:post_request_headers) { { 'Content-Type' => 'application/json', 'Accept' => 'application/hal+json'} }
let(:get_request_headers) { { 'Accept' => 'application/hal+json'} }
end
+
+shared_context "pact broker - pact-ruby-v2" do
+ let(:pact_hash) { PactBroker::Client::PactHash[consumer: {name: 'Condor'}, interactions: [], provider: {name: 'Pricing Service'}] }
+ let(:broker_base_url) { 'http://localhost:9999' }
+end
diff --git a/spec/support/ssl_server.rb b/spec/support/ssl_server.rb
index 209d684..e532298 100644
--- a/spec/support/ssl_server.rb
+++ b/spec/support/ssl_server.rb
@@ -32,11 +32,11 @@ def webrick_opts port
require "webrick"
require "webrick/https"
require "rack"
- require "rackup/handler/webrick"
+ require "rack/handler/webrick"
opts = webrick_opts(4444)
- Rackup::Handler::WEBrick.run(app, **opts) do |server|
+ Rack::Handler::WEBrick.run(app, **opts) do |server|
@server = server
end
end