summaryrefslogtreecommitdiff
path: root/python-pactman.spec
diff options
context:
space:
mode:
Diffstat (limited to 'python-pactman.spec')
-rw-r--r--python-pactman.spec2487
1 files changed, 2487 insertions, 0 deletions
diff --git a/python-pactman.spec b/python-pactman.spec
new file mode 100644
index 0000000..5bdcd07
--- /dev/null
+++ b/python-pactman.spec
@@ -0,0 +1,2487 @@
+%global _empty_manifest_terminate_build 0
+Name: python-pactman
+Version: 2.30.0
+Release: 1
+Summary: Tools for creating and verifying consumer driven contracts using the Pact framework.
+License: MIT, Copyright (c) 2018 ReeceTech
+URL: https://github.com/reecetech/pactman
+Source0: https://mirrors.nju.edu.cn/pypi/web/packages/2d/0a/dcb9ae4c5034383071d49675c39df5ed8f6edd3cca083780e777a786c36a/pactman-2.30.0.tar.gz
+BuildArch: noarch
+
+
+%description
+# pactman
+
+[![](https://img.shields.io/pypi/v/pactman.svg)](https://pypi.org/project/pactman/) [![](https://travis-ci.org/reecetech/pactman.svg?branch=master)](https://travis-ci.org/reecetech/pactman.svg?branch=master)
+
+Python version of Pact mocking, generation and verification.
+
+Enables [consumer driven contract testing], providing unit test mocking of provider services
+and DSL for the consumer project, and interaction playback and verification for the service
+provider project. Currently supports versions 1.1, 2 and 3 of the [Pact specification].
+
+For more information about what Pact is, and how it can help you
+test your code more efficiently, check out the [Pact documentation].
+
+Contains code originally from the [pact-python](https://github.com/pact-foundation/pact-python) project.
+
+pactman is maintained by the [ReeceTech](https://www.reecetech.com.au/) team as part of their toolkit to
+keep their large (and growing) microservices architecture under control.
+
+* [How to use pactman](#how-to-use-pactman)
+ * [Installation](#installation)
+ * [Writing a Pact](#writing-a-pact)
+ * [Writing the Consumer Test](#writing-the-consumer-test)
+ * [Expecting Variable Content](#expecting-variable-content)
+ * [Verifying Pacts Against a Service](#verifying-pacts-against-a-service)
+* [Development](#development)
+ * [Release History](#release-history)
+
+## pactman vs pact-python
+
+The key difference is all functionality is implemented in Python, rather than shelling out or forking
+to the ruby implementation. This allows for a much nicer mocking user experience (it mocks urllib3
+directly), is faster, less messy configuration (multiple providers means multiple ruby processes spawned
+on different ports).
+
+Where `pact-python` required management of a background Ruby server, and manually starting and stopping
+it, `pactman` allows a much nicer usage like:
+
+```python
+import requests
+from pactman import Consumer, Provider
+
+pact = Consumer('Consumer').has_pact_with(Provider('Provider'))
+
+def test_interaction():
+ pact.given("some data exists").upon_receiving("a request") \
+ .with_request("get", "/", query={"foo": ["bar"]}).will_respond_with(200)
+ with pact:
+ requests.get(pact.uri, params={"foo": ["bar"]})
+```
+
+It also supports a broader set of the pact specification (versions 1.1 through to 3).
+
+The pact verifier has been engineered from the start to talk to a pact broker (both to discover pacts
+and to return verification results).
+
+There’s a few other quality of life improvements, but those are the big ones.
+
+# How to use pactman
+
+## Installation
+
+`pactman` requires Python 3.6 to run.
+
+```
+pip install pactman
+```
+
+## Writing a Pact
+Creating a complete contract is a two step process:
+
+1. Create a unit test on the consumer side that declares the expectations it has of the provider
+2. Create a provider state that allows the contract to pass when replayed against the provider
+
+## Writing the Consumer Test
+
+If we have a method that communicates with one of our external services, which we'll call
+`Provider`, and our product, `Consumer` is hitting an endpoint on `Provider` at
+`/users/<user>` to get information about a particular user.
+
+If the `Consumer`'s code to fetch a user looked like this:
+
+```python
+import requests
+
+def get_user(user_name):
+ response = requests.get(f'http://service.example/users/{user_name}')
+ return response.json()
+```
+
+Then `Consumer`'s contract test is a regular unit test, but *using pactman for mocking*,
+and might look something like this:
+
+```python
+import unittest
+from pactman import Consumer, Provider
+
+pact = Consumer('Consumer').has_pact_with(Provider('Provider'))
+
+class GetUserInfoContract(unittest.TestCase):
+ def test_get_user(self):
+ expected = {
+ 'username': 'UserA',
+ 'id': 123,
+ 'groups': ['Editors']
+ }
+
+ pact.given(
+ 'UserA exists and is not an administrator'
+ ).upon_receiving(
+ 'a request for UserA'
+ ).with_request(
+ 'GET', '/users/UserA'
+ ) .will_respond_with(200, body=expected)
+
+ with pact:
+ result = get_user('UserA')
+
+ self.assertEqual(result, expected)
+```
+
+This does a few important things:
+
+ - Defines the Consumer and Provider objects that describe our product and our service under test
+ - Uses `given` to define the setup criteria for the Provider `UserA exists and is not an administrator`
+ - Defines what the request that is expected to be made by the consumer will contain
+ - Defines how the server is expected to respond
+
+Using the Pact object as a [context manager], we call our method under test
+which will then communicate with the Pact mock. The mock will respond with
+the items we defined, allowing us to assert that the method processed the response and
+returned the expected value.
+
+If you want more control over when the mock is configured and the interactions verified,
+use the `setup` and `verify` methods, respectively:
+
+```python
+Consumer('Consumer').has_pact_with(Provider('Provider')).given(
+ 'UserA exists and is not an administrator'
+).upon_receiving(
+ 'a request for UserA'
+).with_request(
+ 'GET', '/users/UserA'
+) .will_respond_with(200, body=expected)
+
+pact.setup()
+try:
+ # Some additional steps before running the code under test
+ result = get_user('UserA')
+ # Some additional steps before verifying all interactions have occurred
+finally:
+ pact.verify()
+```
+
+### An important note about pact relationship definition
+
+You may have noticed that the pact relationship is defined at the module level in our
+examples:
+
+```python
+pact = Consumer('Consumer').has_pact_with(Provider('Provider'))
+```
+
+This is because it *must only be done once* per test suite. By default the pact file is
+cleared out when that relationship is defined, so if you define it more than once per test
+suite you'll end up only storing the *last* pact declared per relationship. For more on this
+subject, see [writing multiple pacts](#writing-multiple-pacts).
+
+### Requests
+
+When defining the expected HTTP request that your code is expected to make you
+can specify the method, path, body, headers, and query:
+
+```python
+pact.with_request(
+ method='GET',
+ path='/api/v1/my-resources/',
+ query={'search': 'example'}
+)
+```
+
+`query` is used to specify URL query parameters, so the above example expects
+a request made to `/api/v1/my-resources/?search=example`.
+
+```python
+pact.with_request(
+ method='POST',
+ path='/api/v1/my-resources/123',
+ body={'user_ids': [1, 2, 3]},
+ headers={'Content-Type': 'application/json'},
+)
+```
+
+You can define exact values for your expected request like the examples above,
+or you can use the matchers defined later to assist in handling values that are
+variable.
+
+### Some important has_pact_with() options()
+
+The `has_pact_with(provider...)` call has quite a few options documented in its API, but a couple are
+worth mentioning in particular:
+
+`version` declares the pact specification version that the provider supports. This defaults to "2.0.0", but "3.0.0"
+is also acceptable if your provider supports [Pact specification version 3]:
+
+```python
+from pactman import Consumer, Provider
+pact = Consumer('Consumer').has_pact_with(Provider('Provider'), version='3.0.0')
+```
+
+`file_write_mode` defaults to `"overwrite"` and should be that or `"merge"`. Overwrite ensures
+that any existing pact file will be removed when `has_pact_with()` is invoked. Merge will retain
+the pact file and add new pacts to that file. See [writing multiple pacts](#writing-multiple-pacts).
+If you absolutely do not want pact files to be written, use `"never"`.
+
+`use_mocking_server` defaults to `False` and controls the mocking method used by `pactman`. The default is to
+patch `urllib3`, which is the library underpinning `requests` and is also used by some other projects. If you
+are using a different library to make your HTTP requests which does not use `urllib3` underneath then you will need
+to set the `use_mocking_server` argument to `True`. This causes `pactman` to run an actual HTTP server to mock the
+requests (the server is listening on `pact.uri` - use that to redirect your HTTP requests to the mock server.) You
+may also set the `PACT_USE_MOCKING_SERVER` environment variable to "yes" to force your entire suite to use the server
+approach. You should declare the pact particpants (consumer and provider) outside of your tests and will need
+to start and stop the mocking service outside of your tests too. The code below shows what using the server might
+look like:
+
+```python
+import atexit
+from pactman import Consumer, Provider
+pact = Consumer('Consumer').has_pact_with(Provider('Provider'), use_mocking_server=True)
+pact.start_mocking()
+atexit.register(pact.stop_mocking)
+``````
+
+You'd then use `pact` to declare pacts between those participants.
+
+### Writing multiple pacts
+
+During a test run you're likely to need to write multiple pact interactions for a consumer/provider
+relationship. `pactman` will manage the pact file as follows:
+
+- When `has_pact_with()` is invoked it will by default remove any existing pact JSON file for the
+ stated consumer & provider.
+- You may invoke `Consumer('Consumer').has_pact_with(Provider('Provider'))` once at the start of
+ your tests. This could be done as a pytest module or session fixture, or through some other
+ mechanism and store it in a variable. By convention this is called `pact` in all of our examples.
+- If that is not suitable, you may manually indicate to `has_pact_with()` that it should either
+ retain (`file_write_mode="merge"`) or remove (`file_write_mode="overwrite"`) the existing
+ pact file.
+
+### Some words about given()
+
+You use `given()` to indicate to the provider that they should have some state in order to
+be able to satisfy the interaction. You should agree upon the state and its specification
+in discussion with the provider.
+
+If you are defining a version 3 pact you may define provider states more richly, for example:
+
+```python
+(pact
+ .given("this is a simple state as in v2")
+ .and_given("also the user must exist", username="alex")
+)
+```
+
+Now you may specify additional parameters to accompany your provider state text. These are
+passed as keyword arguments, and they're optional. You may also provider additional provider
+states using the `and_given()` call, which may be invoked many times if necessary. It and
+`given()` have the same calling convention: a provider state name and any optional parameters.
+
+## Expecting Variable Content
+The default validity testing of equal values works great if that user information is always
+static, but what happens if the user has a last updated field that is set to the current time
+every time the object is modified? To handle variable data and make your tests more robust,
+there are several helpful matchers:
+
+### Includes(matcher, sample_data)
+
+*Available in version 3.0.0+ pacts*
+
+Asserts that the value should contain the given substring, for example::
+
+```python
+from pactman import Includes, Like
+Like({
+ 'id': 123, # match integer, value varies
+ 'content': Includes('spam', 'Sample spamming content') # content must contain the string "spam"
+})
+```
+
+The `matcher` and `sample_data` are used differently by consumer and provider depending
+upon whether they're used in the `with_request()` or `will_respond_with()` sections
+of the pact. Using the above example:
+
+#### Includes in request
+When you run the tests for the consumer, the mock will verify that the data
+the consumer uses in its request contains the `matcher` string, raising an AssertionError
+if invalid. When the contract is verified by the provider, the `sample_data` will be
+used in the request to the real provider service, in this case `'Sample spamming content'`.
+
+#### Includes in response
+When you run the tests for the consumer, the mock will return the data you provided
+as `sample_data`, in this case `'Sample spamming content'`. When the contract is verified on the
+provider, the data returned from the real provider service will be verified to ensure it
+contains the `matcher` string.
+
+### Term(matcher, sample_data)
+Asserts the value should match the given regular expression. You could use this
+to expect a timestamp with a particular format in the request or response where
+you know you need a particular format, but are unconcerned about the exact date:
+
+```python
+from pactman import Term
+
+(pact
+ .given('UserA exists and is not an administrator')
+ .upon_receiving('a request for UserA')
+ .with_request(
+ 'post',
+ '/users/UserA/info',
+ body={'commencement_date': Term('\d+-\d+-\d', '1972-01-01')})
+ .will_respond_with(200, body={
+ 'username': 'UserA',
+ 'last_modified': Term('\d+-\d+-\d+T\d+:\d+:\d+', '2016-12-15T20:16:01')
+ }))
+```
+
+The `matcher` and `sample_data` are used differently by consumer and provider depending
+upon whether they're used in the `with_request()` or `will_respond_with()` sections
+of the pact. Using the above example:
+
+#### Term in request
+When you run the tests for the consumer, the mock will verify that the `commencement_date`
+the consumer uses in its request matches the `matcher`, raising an AssertionError
+if invalid. When the contract is verified by the provider, the `sample_data` will be
+used in the request to the real provider service, in this case `1972-01-01`.
+
+#### Term in response
+When you run the tests for the consumer, the mock will return the `last_modified` you provided
+as `sample_data`, in this case `2016-12-15T20:16:01`. When the contract is verified on the
+provider, the regex will be used to search the response from the real provider service
+and the test will be considered successful if the regex finds a match in the response.
+
+### Like(sample_data)
+Asserts the element's type matches the `sample_data`. For example:
+
+```python
+from pactman import Like
+Like(123) # Matches if the value is an integer
+Like('hello world') # Matches if the value is a string
+Like(3.14) # Matches if the value is a float
+```
+
+#### Like in request
+When you run the tests for the consumer, the mock will verify that values are
+of the correct type, raising an AssertionError if invalid. When the contract is
+verified by the provider, the `sample_data` will be used in the request to the
+real provider service.
+
+#### Like in response
+When you run the tests for the consumer, the mock will return the `sample_data`.
+When the contract is verified on the provider, the values generated by the provider
+service will be checked to match the type of `sample_data`.
+
+#### Applying Like to complex data structures
+When a dictionary is used as an argument for Like, all the child objects (and their child objects etc.)
+will be matched according to their types, unless you use a more specific matcher like a Term.
+
+```python
+from pactman import Like, Term
+Like({
+ 'username': Term('[a-zA-Z]+', 'username'),
+ 'id': 123, # integer
+ 'confirmed': False, # boolean
+ 'address': { # dictionary
+ 'street': '200 Bourke St' # string
+ }
+})
+```
+
+### EachLike(sample_data, minimum=1)
+Asserts the value is an array type that consists of elements
+like `sample_data`. It can be used to assert simple arrays:
+
+```python
+from pactman import EachLike
+EachLike(1) # All items are integers
+EachLike('hello') # All items are strings
+```
+
+Or other matchers can be nested inside to assert more complex objects:
+
+```python
+from pactman import EachLike, Term
+EachLike({
+ 'username': Term('[a-zA-Z]+', 'username'),
+ 'id': 123,
+ 'groups': EachLike('administrators')
+})
+```
+
+> Note, you do not need to specify everything that will be returned from the Provider in a
+> JSON response, any extra data that is received will be ignored and the tests will still pass.
+
+For more information see [Matching](https://docs.pact.io/documentation/matching.html)
+
+### Enforcing equality matching with Equals
+
+*Available in version 3.0.0+ pacts*
+
+If you have a sub-term of a `Like` which needs to match an exact value like the default
+validity test then you can use `Equals`, for example::
+
+```python
+from pactman import Equals, Like
+Like({
+ 'id': 123, # match integer, value varies
+ 'username': Equals('alex') # username must always be "alex"
+})
+```
+
+### Body payload rules
+The `body` payload is assumed to be JSON data. In the absence of a `Content-Type` header
+we assume `Content-Type: application/json; charset=UTF-8` (JSON text is Unicode and the
+default encoding is UTF-8).
+
+During verification non-JSON payloads are compared for equality.
+
+During mocking, the HTTP response will be handled as:
+
+1. If there's no `Content-Type` header, assume JSON: serialise with `json.dumps()`, encode to
+ UTF-8 and add the header `Content-Type: application/json; charset=UTF-8`.
+2. If there's a `Content-Type` header and it says `application/json` then serialise with
+ json.dumps() and use the charset in the header, defaulting to UTF-8.
+3. Otherwise pass through the `Content-Type` header and body as-is.
+ Binary data is not supported.
+
+
+## Verifying Pacts Against a Service
+You have two options for verifying pacts against a service you created:
+
+1. Use the `pactman-verifier` command-line program which replays the pact assertions against
+ a running instance of your service, or
+2. Use the `pytest` support built into pactman to replay the pacts as test cases, allowing
+ use of other testing mechanisms such as mocking and transaction control.
+
+### Using `pactman-verifier`
+
+Run `pactman-verifier -h` to see the options available. To run all pacts registered to a provider in a [Pact Broker]:
+
+ pactman-verifier -b http://pact-broker.example/ <provider name> <provider url> <provider setup url>
+
+You can pass in a local pact file with `-l`, this will verify the service against the local file instead of the broker:
+
+ pactman-verifier -l /tmp/localpact.json <provider name> <provider url> <provider setup url>
+
+You can use `--custom-provider-header` to pass in headers to be passed to provider state setup and verify calls. it can
+be used multiple times
+
+ pactman-verifier -b <broker url> --custom-provider-header "someheader:value" --custom-provider-header
+ "this:that" <provider name> <provider url> <provider state url>
+
+An additional header may also be supplied in the `PROVIDER_EXTRA_HEADER` environment variable, though the command
+line argument(s) would override this.
+
+#### Provider States
+
+In many cases, your contracts will need very specific data to exist on the provider
+to pass successfully. If you are fetching a user profile, that user needs to exist,
+if querying a list of records, one or more records needs to exist. To support
+decoupling the testing of the consumer and provider, Pact offers the idea of provider
+states to communicate from the consumer what data should exist on the provider.
+
+When setting up the testing of a provider you will also need to setup the management of
+these provider states. The Pact verifier does this by making additional HTTP requests to
+the `<provider setup url>` you provide. This URL could be
+on the provider application or a separate one. Some strategies for managing state include:
+
+- Having endpoints in your application that are not active in production that create and delete your datastore state
+- A separate application that has access to the same datastore to create and delete,
+ like a separate App Engine module or Docker container pointing to the same datastore
+- A standalone application that can start and stop the other server with different datastore states
+
+For more information about provider states, refer to the [Pact documentation] on [Provider States].
+
+### Verifying Pacts Using `pytest`
+
+To verify pacts for a provider you would write a new pytest test module in the provider's test suite.
+If you don't want it to be exercised in your usual unit test run you can call it `verify_pacts.py`.
+
+Your test code needs to use the `pact_verifier` fixture provided by pactman, invoking
+its `verify()` method with the URL to the running instance of your service (`pytest-django` provides
+a handy `live_server` fixture which works well here) and a callback to set up provider states (described
+below).
+
+You'll need to include some extra command-line arguments to pytest (also described below) to indicate
+where the pacts should come from, and whether verification results should be posted to a pact broker.
+
+An example for a Django project might contain:
+
+```python
+from django.contrib.auth.models import User
+from pactman.verifier.verify import ProviderStateMissing
+
+def provider_state(name, **params):
+ if name == 'the user "pat" exists':
+ User.objects.create(username='pat', fullname=params['fullname'])
+ else:
+ raise ProviderStateMissing(name)
+
+def test_pacts(live_server, pact_verifier):
+ pact_verifier.verify(live_server.url, provider_state)
+```
+
+The `pact_verifier.verify` call may also take a third argument to supply additional HTTP headers
+to send to the server during verification - specify them as a dictionary.
+
+The test function may do any level of mocking and data setup using standard pytest fixtures - so mocking
+downstream APIs or other interactions within the provider may be done with standard monkeypatching.
+
+#### Provider states using `pytest`
+
+The `provider_state` function passed to `pact_verifier.verify` will be passed the `providerState` and
+`providerStates` for all pacts being verified.
+
+- For pacts with **providerState** the `name` argument will be the `providerState` value,
+ and `params` will be empty.
+- For pacts with **providerStates** the function will be invoked once per entry in `providerStates`
+ array with the `name` argument taken from the array entry `name` parameter, and `params` from
+ the `params` parameter.
+
+#### Command line options to control `pytest` verifying pacts
+
+Once you have written the pytest code, you need to invoke pytest with additional arguments:
+
+`--pact-broker-url=<URL>` provides the base URL of the Pact broker to retrieve pacts from for the
+provider. You must also provide `--pact-provider-name=<ProviderName>` to identify which provider to
+retrieve pacts for from the broker.
+
+The broker URL and provider name may alternatively be provided through the environment variables
+`PACT_BROKER_URL` and `PACT_PROVIDER_NAME`.
+
+You may provide `--pact-verify-consumer=<ConsumerName>` to limit
+the pacts verified to just that consumer. As with the command-line verifier, you may provide basic
+auth details in the broker URL, or through the `PACT_BROKER_AUTH` environment variable. If your broker
+requires a bearer token you may provide it with `--pact-broker-token=<TOKEN>` or the `PACT_BROKER_TOKEN`
+environment variable.
+
+`--pact-files=<file pattern>` verifies some on-disk pact JSON files identified by the wildcard pattern
+(unix glob pattern matching, use `**` to match multiple directories).
+
+If you pulled the pacts from a broker and wish to publish verification results, use `--pact-publish-results`
+to turn on publishing the results. This option also requires you to specify `--pact-provider-version=<version>`.
+
+So, for example:
+
+```bash
+# verify some local pacts in /tmp/pacts
+$ pytest --pact-files=/tmp/pacts/*.json tests/verify_pacts.py
+
+# verify some pacts in a broker for the provider MyService
+$ pytest --pact-broker-url=http://pact-broker.example/ --pact-provider-name=MyService tests/verify_pacts.py
+```
+
+If you need to see the traceback that caused a pact failure you can use the verbosity flag
+to pytest (`pytest -v`).
+
+See the "pact" section in the pytest command-line help (`pytest -h`) for all command-line options.
+
+### Pact Broker Configuration
+
+You may also specify the broker URL in the environment variable `PACT_BROKER_URL`.
+
+If HTTP Basic Auth is required for the broker, that may be provided in the URL:
+
+ pactman-verifier -b http://user:password@pact-broker.example/ ...
+ pytest --pact-broker-url=http://user:password@pact-broker.example/ ...
+
+or set in the `PACT_BROKER_AUTH` environment variable as `user:password`.
+
+If your broker needs a bearer token then you may provide that on the command line or set it in the
+environment variable `PACT_BROKER_TOKEN`.
+
+#### Filtering Broker Pacts by Tag
+
+If your consumer pacts have tags (called "consumer version tags" because they attach to specific
+versions) then you may specify the tag(s) to fetch pacts for on the command line. Multiple tags
+may be specified, and all pacts matching any tags specified will be verified. For example, to ensure
+you're verifying your Provider against the *production* pact versions from your Consumers, use:
+
+ pactman-verifier --consumer-version-tag=production -b http://pact-broker.example/ ...
+ pytest --pact-verify-consumer-tag=production --pact-broker-url=http://pact-broker.example/ ...
+
+
+# Development
+Please read [CONTRIBUTING.md](CONTRIBUTING.md)
+
+## Release History
+
+3.0.0 (FUTURE, DEPRECATION WARNINGS)
+
+- remove DEPRECATED `--pact-consumer-name` command-line option
+
+2.30.0
+
+- DELETE requests may now have query strings, thanks @MazeDeveloper
+- Nicer feedback if no pact source is specified on command line, thanks @artamonovkirill
+- Add PACT_PROVIDER_NAME to environment vars, thanks @artamonovkirill
+
+2.29.0
+
+- Added support for `**` recursive globbing with `--pact-files`, thanks @maksimt
+
+2.28.0
+
+- Fixed edge case where `fail()` was not being invoked in an exact match
+ causing the pytest reporter to not know there'd been a failure
+- Address deprecation of `semver.parse` in semver
+- Dropped Python 3.6 testing, added Python 3.8 testing
+
+2.27.0
+
+- Fix typo in pytest plugin preventing `--pact-verify-consumer-tag` from working
+- Added PATCH support
+
+2.26.0
+
+- Allow pytest verification to specify `extra_provider_headers`
+
+2.25.0
+
+- Add option to allow pytest to succeed even if a pact verification fails
+
+2.24.0
+
+- Better integration of pact failure information in pytest
+
+2.23.0
+
+- Enable setting of authentication credentials when connecting to the pact broker
+- Allow filtering of pacts fetched from broker to be filtered by consumer version tag
+- Improve the naming and organisation of the pytest command line options
+
+2.22.0
+
+- Better implementation of change in 2.21.0
+
+2.21.0
+
+- Handle warning level messages in command line output handler
+
+2.20.0
+
+- Fix pytest mode to correctly detect array element rule failure as a pytest failure
+- Allow restricting pytest verification runs to a single consumer using --pact-consumer-name
+
+2.19.0
+
+- Correct teardown of pact context manager where the pact is used in multiple
+ interactions (`with interaction1, interaction2` instead of `with pact`).
+
+2.18.0
+
+- Correct bug in cleanup that resulted in urllib mocking breaking.
+
+2.17.0
+
+- Handle absence of any provider state (!) in pytest setup.
+
+2.16.0
+
+- Delay shenanigans around checking pacts directory until pacts are actually written
+ to allow module-level pact definition without side effects.
+
+2.15.0
+
+- Fix structure of serialisation for header matching rules.
+- Add `"never"` to the `file_write_mode` options.
+- Handle x-www-form-urlencoded POST request bodies.
+
+2.14.0
+
+- Improve verbose messages to clarify what they're saying.
+
+2.13.0
+
+- Add ability to supply additional headers to provider during verification (thanks @ryallsa)
+
+2.12.1
+
+- Fix pact-python Term compatibility
+
+2.12.0
+
+- Add `Equals` and `Includes` matchers for pact v3+
+- Make verification fail if missing header specified in interaction
+- Significantly improved support for pytest provider verification of pacts
+- Turned pact state call failures into warnings rather than errors
+
+2.11.0
+
+- Ensure query param values are lists
+
+2.10.0
+
+- Allow `has_pact_with()` to accept `file_write_mode`
+- Fix bug introduced in 2.9.0 where generating multiple pacts would result in a single pact
+ being recorded
+
+2.9.0
+
+- Fix `with_request` when called with a dict query (thanks Cong)
+- Make `start_mocking()` and `stop_mocking()` optional with non-server mocking
+- Add shortcut so `python -m pactman.verifier.command_line` is just `python -m pactman`
+ (mostly used in testing before release)
+- Handle the `None` provider state
+- Ensure pact spec versions are consistent across all mocks used to generate a pact file
+
+2.8.0
+
+- Close up some edge cases in body content during mocking, and document in README
+
+2.7.0
+
+- Added `and_given()` as a method of defining additonal provider states for v3+ pacts
+- Added more tests for pact generation (serialisation) which fixed a few edge case bugs
+- Fix handling of lower-case HTTP methods in verifier (thanks Cong!)
+
+2.6.1
+
+- Fix issue where mocked `urlopen` didn't handle the correct number of positional arguments
+
+2.6.0
+
+- Fix several issues cause by a failure to detect failure in several test cases
+ (header, path and array element rules may not have been applied)
+- Fix rules applying to a single non-first element in an array
+- Fix generation of consumer / provider name in <v3 pacts
+
+2.5.0
+
+- Fix some bugs around empty array verification
+
+2.4.0
+
+- Create the pact destination dir if it's missing and its parent exists
+
+2.3.0
+
+- Fix some issues around mocking request queries and the mock's verification of same
+- Fix header regex matching in mock verification
+- Actually use the version passed in to `has_pact_with()`
+- Fix some pact v3 generation issues (thanks pan Jacek)
+
+2.2.0
+
+- Reinstate lost result output.
+
+2.1.0
+
+- Corrected the definition of request payload when there is no `body` in the request
+
+2.0.0
+
+- Correctly determine pact verification result when publishing to broker.
+
+1.2.0
+
+- Corrected use of format_path in command line error handling.
+- Tweaked README for clarity.
+
+1.1.0
+
+- Renamed the `pact-verifier` command to `pactman-verifier` to avoid
+ confusion with other pre-existing packages that provide a command-line
+ incompatible `pact-verifier` command.
+- Support verification of HEAD requests (oops).
+
+1.0.8
+
+- Corrected project URL in project metadata (thanks Jonathan Moss)
+- Fix verbose output
+
+1.0.7
+
+- Added some Trove classifiers to aid potential users.
+
+1.0.6
+
+- Corrected mis-named command-line option.
+
+1.0.5
+
+- Corrected some packaging issues
+
+1.0.4
+
+- Initial release of pactman, including ReeceTech's pact-verifier version 3.17 and pact-python version 0.17.0
+
+[consumer driven contract testing]: https://2018.pycon-au.org/talks/44811-pact-in-python/
+[context manager]: https://en.wikibooks.org/wiki/Python_Programming/Context_Managers
+[Pact]: https://www.gitbook.com/book/pact-foundation/pact/details
+[Pact Broker]: https://docs.pact.io/getting_started/sharing_pacts
+[Pact documentation]: https://docs.pact.io/
+[Pact specification]: https://github.com/pact-foundation/pact-specification
+[Pact specification version 3]: https://github.com/pact-foundation/pact-specification/tree/version-3
+[Provider States]: https://docs.pact.io/provider/using_provider_states_effectively
+[pact-provider-verifier]: https://github.com/pact-foundation/pact-provider-verifier
+
+%package -n python3-pactman
+Summary: Tools for creating and verifying consumer driven contracts using the Pact framework.
+Provides: python-pactman
+BuildRequires: python3-devel
+BuildRequires: python3-setuptools
+BuildRequires: python3-pip
+%description -n python3-pactman
+# pactman
+
+[![](https://img.shields.io/pypi/v/pactman.svg)](https://pypi.org/project/pactman/) [![](https://travis-ci.org/reecetech/pactman.svg?branch=master)](https://travis-ci.org/reecetech/pactman.svg?branch=master)
+
+Python version of Pact mocking, generation and verification.
+
+Enables [consumer driven contract testing], providing unit test mocking of provider services
+and DSL for the consumer project, and interaction playback and verification for the service
+provider project. Currently supports versions 1.1, 2 and 3 of the [Pact specification].
+
+For more information about what Pact is, and how it can help you
+test your code more efficiently, check out the [Pact documentation].
+
+Contains code originally from the [pact-python](https://github.com/pact-foundation/pact-python) project.
+
+pactman is maintained by the [ReeceTech](https://www.reecetech.com.au/) team as part of their toolkit to
+keep their large (and growing) microservices architecture under control.
+
+* [How to use pactman](#how-to-use-pactman)
+ * [Installation](#installation)
+ * [Writing a Pact](#writing-a-pact)
+ * [Writing the Consumer Test](#writing-the-consumer-test)
+ * [Expecting Variable Content](#expecting-variable-content)
+ * [Verifying Pacts Against a Service](#verifying-pacts-against-a-service)
+* [Development](#development)
+ * [Release History](#release-history)
+
+## pactman vs pact-python
+
+The key difference is all functionality is implemented in Python, rather than shelling out or forking
+to the ruby implementation. This allows for a much nicer mocking user experience (it mocks urllib3
+directly), is faster, less messy configuration (multiple providers means multiple ruby processes spawned
+on different ports).
+
+Where `pact-python` required management of a background Ruby server, and manually starting and stopping
+it, `pactman` allows a much nicer usage like:
+
+```python
+import requests
+from pactman import Consumer, Provider
+
+pact = Consumer('Consumer').has_pact_with(Provider('Provider'))
+
+def test_interaction():
+ pact.given("some data exists").upon_receiving("a request") \
+ .with_request("get", "/", query={"foo": ["bar"]}).will_respond_with(200)
+ with pact:
+ requests.get(pact.uri, params={"foo": ["bar"]})
+```
+
+It also supports a broader set of the pact specification (versions 1.1 through to 3).
+
+The pact verifier has been engineered from the start to talk to a pact broker (both to discover pacts
+and to return verification results).
+
+There’s a few other quality of life improvements, but those are the big ones.
+
+# How to use pactman
+
+## Installation
+
+`pactman` requires Python 3.6 to run.
+
+```
+pip install pactman
+```
+
+## Writing a Pact
+Creating a complete contract is a two step process:
+
+1. Create a unit test on the consumer side that declares the expectations it has of the provider
+2. Create a provider state that allows the contract to pass when replayed against the provider
+
+## Writing the Consumer Test
+
+If we have a method that communicates with one of our external services, which we'll call
+`Provider`, and our product, `Consumer` is hitting an endpoint on `Provider` at
+`/users/<user>` to get information about a particular user.
+
+If the `Consumer`'s code to fetch a user looked like this:
+
+```python
+import requests
+
+def get_user(user_name):
+ response = requests.get(f'http://service.example/users/{user_name}')
+ return response.json()
+```
+
+Then `Consumer`'s contract test is a regular unit test, but *using pactman for mocking*,
+and might look something like this:
+
+```python
+import unittest
+from pactman import Consumer, Provider
+
+pact = Consumer('Consumer').has_pact_with(Provider('Provider'))
+
+class GetUserInfoContract(unittest.TestCase):
+ def test_get_user(self):
+ expected = {
+ 'username': 'UserA',
+ 'id': 123,
+ 'groups': ['Editors']
+ }
+
+ pact.given(
+ 'UserA exists and is not an administrator'
+ ).upon_receiving(
+ 'a request for UserA'
+ ).with_request(
+ 'GET', '/users/UserA'
+ ) .will_respond_with(200, body=expected)
+
+ with pact:
+ result = get_user('UserA')
+
+ self.assertEqual(result, expected)
+```
+
+This does a few important things:
+
+ - Defines the Consumer and Provider objects that describe our product and our service under test
+ - Uses `given` to define the setup criteria for the Provider `UserA exists and is not an administrator`
+ - Defines what the request that is expected to be made by the consumer will contain
+ - Defines how the server is expected to respond
+
+Using the Pact object as a [context manager], we call our method under test
+which will then communicate with the Pact mock. The mock will respond with
+the items we defined, allowing us to assert that the method processed the response and
+returned the expected value.
+
+If you want more control over when the mock is configured and the interactions verified,
+use the `setup` and `verify` methods, respectively:
+
+```python
+Consumer('Consumer').has_pact_with(Provider('Provider')).given(
+ 'UserA exists and is not an administrator'
+).upon_receiving(
+ 'a request for UserA'
+).with_request(
+ 'GET', '/users/UserA'
+) .will_respond_with(200, body=expected)
+
+pact.setup()
+try:
+ # Some additional steps before running the code under test
+ result = get_user('UserA')
+ # Some additional steps before verifying all interactions have occurred
+finally:
+ pact.verify()
+```
+
+### An important note about pact relationship definition
+
+You may have noticed that the pact relationship is defined at the module level in our
+examples:
+
+```python
+pact = Consumer('Consumer').has_pact_with(Provider('Provider'))
+```
+
+This is because it *must only be done once* per test suite. By default the pact file is
+cleared out when that relationship is defined, so if you define it more than once per test
+suite you'll end up only storing the *last* pact declared per relationship. For more on this
+subject, see [writing multiple pacts](#writing-multiple-pacts).
+
+### Requests
+
+When defining the expected HTTP request that your code is expected to make you
+can specify the method, path, body, headers, and query:
+
+```python
+pact.with_request(
+ method='GET',
+ path='/api/v1/my-resources/',
+ query={'search': 'example'}
+)
+```
+
+`query` is used to specify URL query parameters, so the above example expects
+a request made to `/api/v1/my-resources/?search=example`.
+
+```python
+pact.with_request(
+ method='POST',
+ path='/api/v1/my-resources/123',
+ body={'user_ids': [1, 2, 3]},
+ headers={'Content-Type': 'application/json'},
+)
+```
+
+You can define exact values for your expected request like the examples above,
+or you can use the matchers defined later to assist in handling values that are
+variable.
+
+### Some important has_pact_with() options()
+
+The `has_pact_with(provider...)` call has quite a few options documented in its API, but a couple are
+worth mentioning in particular:
+
+`version` declares the pact specification version that the provider supports. This defaults to "2.0.0", but "3.0.0"
+is also acceptable if your provider supports [Pact specification version 3]:
+
+```python
+from pactman import Consumer, Provider
+pact = Consumer('Consumer').has_pact_with(Provider('Provider'), version='3.0.0')
+```
+
+`file_write_mode` defaults to `"overwrite"` and should be that or `"merge"`. Overwrite ensures
+that any existing pact file will be removed when `has_pact_with()` is invoked. Merge will retain
+the pact file and add new pacts to that file. See [writing multiple pacts](#writing-multiple-pacts).
+If you absolutely do not want pact files to be written, use `"never"`.
+
+`use_mocking_server` defaults to `False` and controls the mocking method used by `pactman`. The default is to
+patch `urllib3`, which is the library underpinning `requests` and is also used by some other projects. If you
+are using a different library to make your HTTP requests which does not use `urllib3` underneath then you will need
+to set the `use_mocking_server` argument to `True`. This causes `pactman` to run an actual HTTP server to mock the
+requests (the server is listening on `pact.uri` - use that to redirect your HTTP requests to the mock server.) You
+may also set the `PACT_USE_MOCKING_SERVER` environment variable to "yes" to force your entire suite to use the server
+approach. You should declare the pact particpants (consumer and provider) outside of your tests and will need
+to start and stop the mocking service outside of your tests too. The code below shows what using the server might
+look like:
+
+```python
+import atexit
+from pactman import Consumer, Provider
+pact = Consumer('Consumer').has_pact_with(Provider('Provider'), use_mocking_server=True)
+pact.start_mocking()
+atexit.register(pact.stop_mocking)
+``````
+
+You'd then use `pact` to declare pacts between those participants.
+
+### Writing multiple pacts
+
+During a test run you're likely to need to write multiple pact interactions for a consumer/provider
+relationship. `pactman` will manage the pact file as follows:
+
+- When `has_pact_with()` is invoked it will by default remove any existing pact JSON file for the
+ stated consumer & provider.
+- You may invoke `Consumer('Consumer').has_pact_with(Provider('Provider'))` once at the start of
+ your tests. This could be done as a pytest module or session fixture, or through some other
+ mechanism and store it in a variable. By convention this is called `pact` in all of our examples.
+- If that is not suitable, you may manually indicate to `has_pact_with()` that it should either
+ retain (`file_write_mode="merge"`) or remove (`file_write_mode="overwrite"`) the existing
+ pact file.
+
+### Some words about given()
+
+You use `given()` to indicate to the provider that they should have some state in order to
+be able to satisfy the interaction. You should agree upon the state and its specification
+in discussion with the provider.
+
+If you are defining a version 3 pact you may define provider states more richly, for example:
+
+```python
+(pact
+ .given("this is a simple state as in v2")
+ .and_given("also the user must exist", username="alex")
+)
+```
+
+Now you may specify additional parameters to accompany your provider state text. These are
+passed as keyword arguments, and they're optional. You may also provider additional provider
+states using the `and_given()` call, which may be invoked many times if necessary. It and
+`given()` have the same calling convention: a provider state name and any optional parameters.
+
+## Expecting Variable Content
+The default validity testing of equal values works great if that user information is always
+static, but what happens if the user has a last updated field that is set to the current time
+every time the object is modified? To handle variable data and make your tests more robust,
+there are several helpful matchers:
+
+### Includes(matcher, sample_data)
+
+*Available in version 3.0.0+ pacts*
+
+Asserts that the value should contain the given substring, for example::
+
+```python
+from pactman import Includes, Like
+Like({
+ 'id': 123, # match integer, value varies
+ 'content': Includes('spam', 'Sample spamming content') # content must contain the string "spam"
+})
+```
+
+The `matcher` and `sample_data` are used differently by consumer and provider depending
+upon whether they're used in the `with_request()` or `will_respond_with()` sections
+of the pact. Using the above example:
+
+#### Includes in request
+When you run the tests for the consumer, the mock will verify that the data
+the consumer uses in its request contains the `matcher` string, raising an AssertionError
+if invalid. When the contract is verified by the provider, the `sample_data` will be
+used in the request to the real provider service, in this case `'Sample spamming content'`.
+
+#### Includes in response
+When you run the tests for the consumer, the mock will return the data you provided
+as `sample_data`, in this case `'Sample spamming content'`. When the contract is verified on the
+provider, the data returned from the real provider service will be verified to ensure it
+contains the `matcher` string.
+
+### Term(matcher, sample_data)
+Asserts the value should match the given regular expression. You could use this
+to expect a timestamp with a particular format in the request or response where
+you know you need a particular format, but are unconcerned about the exact date:
+
+```python
+from pactman import Term
+
+(pact
+ .given('UserA exists and is not an administrator')
+ .upon_receiving('a request for UserA')
+ .with_request(
+ 'post',
+ '/users/UserA/info',
+ body={'commencement_date': Term('\d+-\d+-\d', '1972-01-01')})
+ .will_respond_with(200, body={
+ 'username': 'UserA',
+ 'last_modified': Term('\d+-\d+-\d+T\d+:\d+:\d+', '2016-12-15T20:16:01')
+ }))
+```
+
+The `matcher` and `sample_data` are used differently by consumer and provider depending
+upon whether they're used in the `with_request()` or `will_respond_with()` sections
+of the pact. Using the above example:
+
+#### Term in request
+When you run the tests for the consumer, the mock will verify that the `commencement_date`
+the consumer uses in its request matches the `matcher`, raising an AssertionError
+if invalid. When the contract is verified by the provider, the `sample_data` will be
+used in the request to the real provider service, in this case `1972-01-01`.
+
+#### Term in response
+When you run the tests for the consumer, the mock will return the `last_modified` you provided
+as `sample_data`, in this case `2016-12-15T20:16:01`. When the contract is verified on the
+provider, the regex will be used to search the response from the real provider service
+and the test will be considered successful if the regex finds a match in the response.
+
+### Like(sample_data)
+Asserts the element's type matches the `sample_data`. For example:
+
+```python
+from pactman import Like
+Like(123) # Matches if the value is an integer
+Like('hello world') # Matches if the value is a string
+Like(3.14) # Matches if the value is a float
+```
+
+#### Like in request
+When you run the tests for the consumer, the mock will verify that values are
+of the correct type, raising an AssertionError if invalid. When the contract is
+verified by the provider, the `sample_data` will be used in the request to the
+real provider service.
+
+#### Like in response
+When you run the tests for the consumer, the mock will return the `sample_data`.
+When the contract is verified on the provider, the values generated by the provider
+service will be checked to match the type of `sample_data`.
+
+#### Applying Like to complex data structures
+When a dictionary is used as an argument for Like, all the child objects (and their child objects etc.)
+will be matched according to their types, unless you use a more specific matcher like a Term.
+
+```python
+from pactman import Like, Term
+Like({
+ 'username': Term('[a-zA-Z]+', 'username'),
+ 'id': 123, # integer
+ 'confirmed': False, # boolean
+ 'address': { # dictionary
+ 'street': '200 Bourke St' # string
+ }
+})
+```
+
+### EachLike(sample_data, minimum=1)
+Asserts the value is an array type that consists of elements
+like `sample_data`. It can be used to assert simple arrays:
+
+```python
+from pactman import EachLike
+EachLike(1) # All items are integers
+EachLike('hello') # All items are strings
+```
+
+Or other matchers can be nested inside to assert more complex objects:
+
+```python
+from pactman import EachLike, Term
+EachLike({
+ 'username': Term('[a-zA-Z]+', 'username'),
+ 'id': 123,
+ 'groups': EachLike('administrators')
+})
+```
+
+> Note, you do not need to specify everything that will be returned from the Provider in a
+> JSON response, any extra data that is received will be ignored and the tests will still pass.
+
+For more information see [Matching](https://docs.pact.io/documentation/matching.html)
+
+### Enforcing equality matching with Equals
+
+*Available in version 3.0.0+ pacts*
+
+If you have a sub-term of a `Like` which needs to match an exact value like the default
+validity test then you can use `Equals`, for example::
+
+```python
+from pactman import Equals, Like
+Like({
+ 'id': 123, # match integer, value varies
+ 'username': Equals('alex') # username must always be "alex"
+})
+```
+
+### Body payload rules
+The `body` payload is assumed to be JSON data. In the absence of a `Content-Type` header
+we assume `Content-Type: application/json; charset=UTF-8` (JSON text is Unicode and the
+default encoding is UTF-8).
+
+During verification non-JSON payloads are compared for equality.
+
+During mocking, the HTTP response will be handled as:
+
+1. If there's no `Content-Type` header, assume JSON: serialise with `json.dumps()`, encode to
+ UTF-8 and add the header `Content-Type: application/json; charset=UTF-8`.
+2. If there's a `Content-Type` header and it says `application/json` then serialise with
+ json.dumps() and use the charset in the header, defaulting to UTF-8.
+3. Otherwise pass through the `Content-Type` header and body as-is.
+ Binary data is not supported.
+
+
+## Verifying Pacts Against a Service
+You have two options for verifying pacts against a service you created:
+
+1. Use the `pactman-verifier` command-line program which replays the pact assertions against
+ a running instance of your service, or
+2. Use the `pytest` support built into pactman to replay the pacts as test cases, allowing
+ use of other testing mechanisms such as mocking and transaction control.
+
+### Using `pactman-verifier`
+
+Run `pactman-verifier -h` to see the options available. To run all pacts registered to a provider in a [Pact Broker]:
+
+ pactman-verifier -b http://pact-broker.example/ <provider name> <provider url> <provider setup url>
+
+You can pass in a local pact file with `-l`, this will verify the service against the local file instead of the broker:
+
+ pactman-verifier -l /tmp/localpact.json <provider name> <provider url> <provider setup url>
+
+You can use `--custom-provider-header` to pass in headers to be passed to provider state setup and verify calls. it can
+be used multiple times
+
+ pactman-verifier -b <broker url> --custom-provider-header "someheader:value" --custom-provider-header
+ "this:that" <provider name> <provider url> <provider state url>
+
+An additional header may also be supplied in the `PROVIDER_EXTRA_HEADER` environment variable, though the command
+line argument(s) would override this.
+
+#### Provider States
+
+In many cases, your contracts will need very specific data to exist on the provider
+to pass successfully. If you are fetching a user profile, that user needs to exist,
+if querying a list of records, one or more records needs to exist. To support
+decoupling the testing of the consumer and provider, Pact offers the idea of provider
+states to communicate from the consumer what data should exist on the provider.
+
+When setting up the testing of a provider you will also need to setup the management of
+these provider states. The Pact verifier does this by making additional HTTP requests to
+the `<provider setup url>` you provide. This URL could be
+on the provider application or a separate one. Some strategies for managing state include:
+
+- Having endpoints in your application that are not active in production that create and delete your datastore state
+- A separate application that has access to the same datastore to create and delete,
+ like a separate App Engine module or Docker container pointing to the same datastore
+- A standalone application that can start and stop the other server with different datastore states
+
+For more information about provider states, refer to the [Pact documentation] on [Provider States].
+
+### Verifying Pacts Using `pytest`
+
+To verify pacts for a provider you would write a new pytest test module in the provider's test suite.
+If you don't want it to be exercised in your usual unit test run you can call it `verify_pacts.py`.
+
+Your test code needs to use the `pact_verifier` fixture provided by pactman, invoking
+its `verify()` method with the URL to the running instance of your service (`pytest-django` provides
+a handy `live_server` fixture which works well here) and a callback to set up provider states (described
+below).
+
+You'll need to include some extra command-line arguments to pytest (also described below) to indicate
+where the pacts should come from, and whether verification results should be posted to a pact broker.
+
+An example for a Django project might contain:
+
+```python
+from django.contrib.auth.models import User
+from pactman.verifier.verify import ProviderStateMissing
+
+def provider_state(name, **params):
+ if name == 'the user "pat" exists':
+ User.objects.create(username='pat', fullname=params['fullname'])
+ else:
+ raise ProviderStateMissing(name)
+
+def test_pacts(live_server, pact_verifier):
+ pact_verifier.verify(live_server.url, provider_state)
+```
+
+The `pact_verifier.verify` call may also take a third argument to supply additional HTTP headers
+to send to the server during verification - specify them as a dictionary.
+
+The test function may do any level of mocking and data setup using standard pytest fixtures - so mocking
+downstream APIs or other interactions within the provider may be done with standard monkeypatching.
+
+#### Provider states using `pytest`
+
+The `provider_state` function passed to `pact_verifier.verify` will be passed the `providerState` and
+`providerStates` for all pacts being verified.
+
+- For pacts with **providerState** the `name` argument will be the `providerState` value,
+ and `params` will be empty.
+- For pacts with **providerStates** the function will be invoked once per entry in `providerStates`
+ array with the `name` argument taken from the array entry `name` parameter, and `params` from
+ the `params` parameter.
+
+#### Command line options to control `pytest` verifying pacts
+
+Once you have written the pytest code, you need to invoke pytest with additional arguments:
+
+`--pact-broker-url=<URL>` provides the base URL of the Pact broker to retrieve pacts from for the
+provider. You must also provide `--pact-provider-name=<ProviderName>` to identify which provider to
+retrieve pacts for from the broker.
+
+The broker URL and provider name may alternatively be provided through the environment variables
+`PACT_BROKER_URL` and `PACT_PROVIDER_NAME`.
+
+You may provide `--pact-verify-consumer=<ConsumerName>` to limit
+the pacts verified to just that consumer. As with the command-line verifier, you may provide basic
+auth details in the broker URL, or through the `PACT_BROKER_AUTH` environment variable. If your broker
+requires a bearer token you may provide it with `--pact-broker-token=<TOKEN>` or the `PACT_BROKER_TOKEN`
+environment variable.
+
+`--pact-files=<file pattern>` verifies some on-disk pact JSON files identified by the wildcard pattern
+(unix glob pattern matching, use `**` to match multiple directories).
+
+If you pulled the pacts from a broker and wish to publish verification results, use `--pact-publish-results`
+to turn on publishing the results. This option also requires you to specify `--pact-provider-version=<version>`.
+
+So, for example:
+
+```bash
+# verify some local pacts in /tmp/pacts
+$ pytest --pact-files=/tmp/pacts/*.json tests/verify_pacts.py
+
+# verify some pacts in a broker for the provider MyService
+$ pytest --pact-broker-url=http://pact-broker.example/ --pact-provider-name=MyService tests/verify_pacts.py
+```
+
+If you need to see the traceback that caused a pact failure you can use the verbosity flag
+to pytest (`pytest -v`).
+
+See the "pact" section in the pytest command-line help (`pytest -h`) for all command-line options.
+
+### Pact Broker Configuration
+
+You may also specify the broker URL in the environment variable `PACT_BROKER_URL`.
+
+If HTTP Basic Auth is required for the broker, that may be provided in the URL:
+
+ pactman-verifier -b http://user:password@pact-broker.example/ ...
+ pytest --pact-broker-url=http://user:password@pact-broker.example/ ...
+
+or set in the `PACT_BROKER_AUTH` environment variable as `user:password`.
+
+If your broker needs a bearer token then you may provide that on the command line or set it in the
+environment variable `PACT_BROKER_TOKEN`.
+
+#### Filtering Broker Pacts by Tag
+
+If your consumer pacts have tags (called "consumer version tags" because they attach to specific
+versions) then you may specify the tag(s) to fetch pacts for on the command line. Multiple tags
+may be specified, and all pacts matching any tags specified will be verified. For example, to ensure
+you're verifying your Provider against the *production* pact versions from your Consumers, use:
+
+ pactman-verifier --consumer-version-tag=production -b http://pact-broker.example/ ...
+ pytest --pact-verify-consumer-tag=production --pact-broker-url=http://pact-broker.example/ ...
+
+
+# Development
+Please read [CONTRIBUTING.md](CONTRIBUTING.md)
+
+## Release History
+
+3.0.0 (FUTURE, DEPRECATION WARNINGS)
+
+- remove DEPRECATED `--pact-consumer-name` command-line option
+
+2.30.0
+
+- DELETE requests may now have query strings, thanks @MazeDeveloper
+- Nicer feedback if no pact source is specified on command line, thanks @artamonovkirill
+- Add PACT_PROVIDER_NAME to environment vars, thanks @artamonovkirill
+
+2.29.0
+
+- Added support for `**` recursive globbing with `--pact-files`, thanks @maksimt
+
+2.28.0
+
+- Fixed edge case where `fail()` was not being invoked in an exact match
+ causing the pytest reporter to not know there'd been a failure
+- Address deprecation of `semver.parse` in semver
+- Dropped Python 3.6 testing, added Python 3.8 testing
+
+2.27.0
+
+- Fix typo in pytest plugin preventing `--pact-verify-consumer-tag` from working
+- Added PATCH support
+
+2.26.0
+
+- Allow pytest verification to specify `extra_provider_headers`
+
+2.25.0
+
+- Add option to allow pytest to succeed even if a pact verification fails
+
+2.24.0
+
+- Better integration of pact failure information in pytest
+
+2.23.0
+
+- Enable setting of authentication credentials when connecting to the pact broker
+- Allow filtering of pacts fetched from broker to be filtered by consumer version tag
+- Improve the naming and organisation of the pytest command line options
+
+2.22.0
+
+- Better implementation of change in 2.21.0
+
+2.21.0
+
+- Handle warning level messages in command line output handler
+
+2.20.0
+
+- Fix pytest mode to correctly detect array element rule failure as a pytest failure
+- Allow restricting pytest verification runs to a single consumer using --pact-consumer-name
+
+2.19.0
+
+- Correct teardown of pact context manager where the pact is used in multiple
+ interactions (`with interaction1, interaction2` instead of `with pact`).
+
+2.18.0
+
+- Correct bug in cleanup that resulted in urllib mocking breaking.
+
+2.17.0
+
+- Handle absence of any provider state (!) in pytest setup.
+
+2.16.0
+
+- Delay shenanigans around checking pacts directory until pacts are actually written
+ to allow module-level pact definition without side effects.
+
+2.15.0
+
+- Fix structure of serialisation for header matching rules.
+- Add `"never"` to the `file_write_mode` options.
+- Handle x-www-form-urlencoded POST request bodies.
+
+2.14.0
+
+- Improve verbose messages to clarify what they're saying.
+
+2.13.0
+
+- Add ability to supply additional headers to provider during verification (thanks @ryallsa)
+
+2.12.1
+
+- Fix pact-python Term compatibility
+
+2.12.0
+
+- Add `Equals` and `Includes` matchers for pact v3+
+- Make verification fail if missing header specified in interaction
+- Significantly improved support for pytest provider verification of pacts
+- Turned pact state call failures into warnings rather than errors
+
+2.11.0
+
+- Ensure query param values are lists
+
+2.10.0
+
+- Allow `has_pact_with()` to accept `file_write_mode`
+- Fix bug introduced in 2.9.0 where generating multiple pacts would result in a single pact
+ being recorded
+
+2.9.0
+
+- Fix `with_request` when called with a dict query (thanks Cong)
+- Make `start_mocking()` and `stop_mocking()` optional with non-server mocking
+- Add shortcut so `python -m pactman.verifier.command_line` is just `python -m pactman`
+ (mostly used in testing before release)
+- Handle the `None` provider state
+- Ensure pact spec versions are consistent across all mocks used to generate a pact file
+
+2.8.0
+
+- Close up some edge cases in body content during mocking, and document in README
+
+2.7.0
+
+- Added `and_given()` as a method of defining additonal provider states for v3+ pacts
+- Added more tests for pact generation (serialisation) which fixed a few edge case bugs
+- Fix handling of lower-case HTTP methods in verifier (thanks Cong!)
+
+2.6.1
+
+- Fix issue where mocked `urlopen` didn't handle the correct number of positional arguments
+
+2.6.0
+
+- Fix several issues cause by a failure to detect failure in several test cases
+ (header, path and array element rules may not have been applied)
+- Fix rules applying to a single non-first element in an array
+- Fix generation of consumer / provider name in <v3 pacts
+
+2.5.0
+
+- Fix some bugs around empty array verification
+
+2.4.0
+
+- Create the pact destination dir if it's missing and its parent exists
+
+2.3.0
+
+- Fix some issues around mocking request queries and the mock's verification of same
+- Fix header regex matching in mock verification
+- Actually use the version passed in to `has_pact_with()`
+- Fix some pact v3 generation issues (thanks pan Jacek)
+
+2.2.0
+
+- Reinstate lost result output.
+
+2.1.0
+
+- Corrected the definition of request payload when there is no `body` in the request
+
+2.0.0
+
+- Correctly determine pact verification result when publishing to broker.
+
+1.2.0
+
+- Corrected use of format_path in command line error handling.
+- Tweaked README for clarity.
+
+1.1.0
+
+- Renamed the `pact-verifier` command to `pactman-verifier` to avoid
+ confusion with other pre-existing packages that provide a command-line
+ incompatible `pact-verifier` command.
+- Support verification of HEAD requests (oops).
+
+1.0.8
+
+- Corrected project URL in project metadata (thanks Jonathan Moss)
+- Fix verbose output
+
+1.0.7
+
+- Added some Trove classifiers to aid potential users.
+
+1.0.6
+
+- Corrected mis-named command-line option.
+
+1.0.5
+
+- Corrected some packaging issues
+
+1.0.4
+
+- Initial release of pactman, including ReeceTech's pact-verifier version 3.17 and pact-python version 0.17.0
+
+[consumer driven contract testing]: https://2018.pycon-au.org/talks/44811-pact-in-python/
+[context manager]: https://en.wikibooks.org/wiki/Python_Programming/Context_Managers
+[Pact]: https://www.gitbook.com/book/pact-foundation/pact/details
+[Pact Broker]: https://docs.pact.io/getting_started/sharing_pacts
+[Pact documentation]: https://docs.pact.io/
+[Pact specification]: https://github.com/pact-foundation/pact-specification
+[Pact specification version 3]: https://github.com/pact-foundation/pact-specification/tree/version-3
+[Provider States]: https://docs.pact.io/provider/using_provider_states_effectively
+[pact-provider-verifier]: https://github.com/pact-foundation/pact-provider-verifier
+
+%package help
+Summary: Development documents and examples for pactman
+Provides: python3-pactman-doc
+%description help
+# pactman
+
+[![](https://img.shields.io/pypi/v/pactman.svg)](https://pypi.org/project/pactman/) [![](https://travis-ci.org/reecetech/pactman.svg?branch=master)](https://travis-ci.org/reecetech/pactman.svg?branch=master)
+
+Python version of Pact mocking, generation and verification.
+
+Enables [consumer driven contract testing], providing unit test mocking of provider services
+and DSL for the consumer project, and interaction playback and verification for the service
+provider project. Currently supports versions 1.1, 2 and 3 of the [Pact specification].
+
+For more information about what Pact is, and how it can help you
+test your code more efficiently, check out the [Pact documentation].
+
+Contains code originally from the [pact-python](https://github.com/pact-foundation/pact-python) project.
+
+pactman is maintained by the [ReeceTech](https://www.reecetech.com.au/) team as part of their toolkit to
+keep their large (and growing) microservices architecture under control.
+
+* [How to use pactman](#how-to-use-pactman)
+ * [Installation](#installation)
+ * [Writing a Pact](#writing-a-pact)
+ * [Writing the Consumer Test](#writing-the-consumer-test)
+ * [Expecting Variable Content](#expecting-variable-content)
+ * [Verifying Pacts Against a Service](#verifying-pacts-against-a-service)
+* [Development](#development)
+ * [Release History](#release-history)
+
+## pactman vs pact-python
+
+The key difference is all functionality is implemented in Python, rather than shelling out or forking
+to the ruby implementation. This allows for a much nicer mocking user experience (it mocks urllib3
+directly), is faster, less messy configuration (multiple providers means multiple ruby processes spawned
+on different ports).
+
+Where `pact-python` required management of a background Ruby server, and manually starting and stopping
+it, `pactman` allows a much nicer usage like:
+
+```python
+import requests
+from pactman import Consumer, Provider
+
+pact = Consumer('Consumer').has_pact_with(Provider('Provider'))
+
+def test_interaction():
+ pact.given("some data exists").upon_receiving("a request") \
+ .with_request("get", "/", query={"foo": ["bar"]}).will_respond_with(200)
+ with pact:
+ requests.get(pact.uri, params={"foo": ["bar"]})
+```
+
+It also supports a broader set of the pact specification (versions 1.1 through to 3).
+
+The pact verifier has been engineered from the start to talk to a pact broker (both to discover pacts
+and to return verification results).
+
+There’s a few other quality of life improvements, but those are the big ones.
+
+# How to use pactman
+
+## Installation
+
+`pactman` requires Python 3.6 to run.
+
+```
+pip install pactman
+```
+
+## Writing a Pact
+Creating a complete contract is a two step process:
+
+1. Create a unit test on the consumer side that declares the expectations it has of the provider
+2. Create a provider state that allows the contract to pass when replayed against the provider
+
+## Writing the Consumer Test
+
+If we have a method that communicates with one of our external services, which we'll call
+`Provider`, and our product, `Consumer` is hitting an endpoint on `Provider` at
+`/users/<user>` to get information about a particular user.
+
+If the `Consumer`'s code to fetch a user looked like this:
+
+```python
+import requests
+
+def get_user(user_name):
+ response = requests.get(f'http://service.example/users/{user_name}')
+ return response.json()
+```
+
+Then `Consumer`'s contract test is a regular unit test, but *using pactman for mocking*,
+and might look something like this:
+
+```python
+import unittest
+from pactman import Consumer, Provider
+
+pact = Consumer('Consumer').has_pact_with(Provider('Provider'))
+
+class GetUserInfoContract(unittest.TestCase):
+ def test_get_user(self):
+ expected = {
+ 'username': 'UserA',
+ 'id': 123,
+ 'groups': ['Editors']
+ }
+
+ pact.given(
+ 'UserA exists and is not an administrator'
+ ).upon_receiving(
+ 'a request for UserA'
+ ).with_request(
+ 'GET', '/users/UserA'
+ ) .will_respond_with(200, body=expected)
+
+ with pact:
+ result = get_user('UserA')
+
+ self.assertEqual(result, expected)
+```
+
+This does a few important things:
+
+ - Defines the Consumer and Provider objects that describe our product and our service under test
+ - Uses `given` to define the setup criteria for the Provider `UserA exists and is not an administrator`
+ - Defines what the request that is expected to be made by the consumer will contain
+ - Defines how the server is expected to respond
+
+Using the Pact object as a [context manager], we call our method under test
+which will then communicate with the Pact mock. The mock will respond with
+the items we defined, allowing us to assert that the method processed the response and
+returned the expected value.
+
+If you want more control over when the mock is configured and the interactions verified,
+use the `setup` and `verify` methods, respectively:
+
+```python
+Consumer('Consumer').has_pact_with(Provider('Provider')).given(
+ 'UserA exists and is not an administrator'
+).upon_receiving(
+ 'a request for UserA'
+).with_request(
+ 'GET', '/users/UserA'
+) .will_respond_with(200, body=expected)
+
+pact.setup()
+try:
+ # Some additional steps before running the code under test
+ result = get_user('UserA')
+ # Some additional steps before verifying all interactions have occurred
+finally:
+ pact.verify()
+```
+
+### An important note about pact relationship definition
+
+You may have noticed that the pact relationship is defined at the module level in our
+examples:
+
+```python
+pact = Consumer('Consumer').has_pact_with(Provider('Provider'))
+```
+
+This is because it *must only be done once* per test suite. By default the pact file is
+cleared out when that relationship is defined, so if you define it more than once per test
+suite you'll end up only storing the *last* pact declared per relationship. For more on this
+subject, see [writing multiple pacts](#writing-multiple-pacts).
+
+### Requests
+
+When defining the expected HTTP request that your code is expected to make you
+can specify the method, path, body, headers, and query:
+
+```python
+pact.with_request(
+ method='GET',
+ path='/api/v1/my-resources/',
+ query={'search': 'example'}
+)
+```
+
+`query` is used to specify URL query parameters, so the above example expects
+a request made to `/api/v1/my-resources/?search=example`.
+
+```python
+pact.with_request(
+ method='POST',
+ path='/api/v1/my-resources/123',
+ body={'user_ids': [1, 2, 3]},
+ headers={'Content-Type': 'application/json'},
+)
+```
+
+You can define exact values for your expected request like the examples above,
+or you can use the matchers defined later to assist in handling values that are
+variable.
+
+### Some important has_pact_with() options()
+
+The `has_pact_with(provider...)` call has quite a few options documented in its API, but a couple are
+worth mentioning in particular:
+
+`version` declares the pact specification version that the provider supports. This defaults to "2.0.0", but "3.0.0"
+is also acceptable if your provider supports [Pact specification version 3]:
+
+```python
+from pactman import Consumer, Provider
+pact = Consumer('Consumer').has_pact_with(Provider('Provider'), version='3.0.0')
+```
+
+`file_write_mode` defaults to `"overwrite"` and should be that or `"merge"`. Overwrite ensures
+that any existing pact file will be removed when `has_pact_with()` is invoked. Merge will retain
+the pact file and add new pacts to that file. See [writing multiple pacts](#writing-multiple-pacts).
+If you absolutely do not want pact files to be written, use `"never"`.
+
+`use_mocking_server` defaults to `False` and controls the mocking method used by `pactman`. The default is to
+patch `urllib3`, which is the library underpinning `requests` and is also used by some other projects. If you
+are using a different library to make your HTTP requests which does not use `urllib3` underneath then you will need
+to set the `use_mocking_server` argument to `True`. This causes `pactman` to run an actual HTTP server to mock the
+requests (the server is listening on `pact.uri` - use that to redirect your HTTP requests to the mock server.) You
+may also set the `PACT_USE_MOCKING_SERVER` environment variable to "yes" to force your entire suite to use the server
+approach. You should declare the pact particpants (consumer and provider) outside of your tests and will need
+to start and stop the mocking service outside of your tests too. The code below shows what using the server might
+look like:
+
+```python
+import atexit
+from pactman import Consumer, Provider
+pact = Consumer('Consumer').has_pact_with(Provider('Provider'), use_mocking_server=True)
+pact.start_mocking()
+atexit.register(pact.stop_mocking)
+``````
+
+You'd then use `pact` to declare pacts between those participants.
+
+### Writing multiple pacts
+
+During a test run you're likely to need to write multiple pact interactions for a consumer/provider
+relationship. `pactman` will manage the pact file as follows:
+
+- When `has_pact_with()` is invoked it will by default remove any existing pact JSON file for the
+ stated consumer & provider.
+- You may invoke `Consumer('Consumer').has_pact_with(Provider('Provider'))` once at the start of
+ your tests. This could be done as a pytest module or session fixture, or through some other
+ mechanism and store it in a variable. By convention this is called `pact` in all of our examples.
+- If that is not suitable, you may manually indicate to `has_pact_with()` that it should either
+ retain (`file_write_mode="merge"`) or remove (`file_write_mode="overwrite"`) the existing
+ pact file.
+
+### Some words about given()
+
+You use `given()` to indicate to the provider that they should have some state in order to
+be able to satisfy the interaction. You should agree upon the state and its specification
+in discussion with the provider.
+
+If you are defining a version 3 pact you may define provider states more richly, for example:
+
+```python
+(pact
+ .given("this is a simple state as in v2")
+ .and_given("also the user must exist", username="alex")
+)
+```
+
+Now you may specify additional parameters to accompany your provider state text. These are
+passed as keyword arguments, and they're optional. You may also provider additional provider
+states using the `and_given()` call, which may be invoked many times if necessary. It and
+`given()` have the same calling convention: a provider state name and any optional parameters.
+
+## Expecting Variable Content
+The default validity testing of equal values works great if that user information is always
+static, but what happens if the user has a last updated field that is set to the current time
+every time the object is modified? To handle variable data and make your tests more robust,
+there are several helpful matchers:
+
+### Includes(matcher, sample_data)
+
+*Available in version 3.0.0+ pacts*
+
+Asserts that the value should contain the given substring, for example::
+
+```python
+from pactman import Includes, Like
+Like({
+ 'id': 123, # match integer, value varies
+ 'content': Includes('spam', 'Sample spamming content') # content must contain the string "spam"
+})
+```
+
+The `matcher` and `sample_data` are used differently by consumer and provider depending
+upon whether they're used in the `with_request()` or `will_respond_with()` sections
+of the pact. Using the above example:
+
+#### Includes in request
+When you run the tests for the consumer, the mock will verify that the data
+the consumer uses in its request contains the `matcher` string, raising an AssertionError
+if invalid. When the contract is verified by the provider, the `sample_data` will be
+used in the request to the real provider service, in this case `'Sample spamming content'`.
+
+#### Includes in response
+When you run the tests for the consumer, the mock will return the data you provided
+as `sample_data`, in this case `'Sample spamming content'`. When the contract is verified on the
+provider, the data returned from the real provider service will be verified to ensure it
+contains the `matcher` string.
+
+### Term(matcher, sample_data)
+Asserts the value should match the given regular expression. You could use this
+to expect a timestamp with a particular format in the request or response where
+you know you need a particular format, but are unconcerned about the exact date:
+
+```python
+from pactman import Term
+
+(pact
+ .given('UserA exists and is not an administrator')
+ .upon_receiving('a request for UserA')
+ .with_request(
+ 'post',
+ '/users/UserA/info',
+ body={'commencement_date': Term('\d+-\d+-\d', '1972-01-01')})
+ .will_respond_with(200, body={
+ 'username': 'UserA',
+ 'last_modified': Term('\d+-\d+-\d+T\d+:\d+:\d+', '2016-12-15T20:16:01')
+ }))
+```
+
+The `matcher` and `sample_data` are used differently by consumer and provider depending
+upon whether they're used in the `with_request()` or `will_respond_with()` sections
+of the pact. Using the above example:
+
+#### Term in request
+When you run the tests for the consumer, the mock will verify that the `commencement_date`
+the consumer uses in its request matches the `matcher`, raising an AssertionError
+if invalid. When the contract is verified by the provider, the `sample_data` will be
+used in the request to the real provider service, in this case `1972-01-01`.
+
+#### Term in response
+When you run the tests for the consumer, the mock will return the `last_modified` you provided
+as `sample_data`, in this case `2016-12-15T20:16:01`. When the contract is verified on the
+provider, the regex will be used to search the response from the real provider service
+and the test will be considered successful if the regex finds a match in the response.
+
+### Like(sample_data)
+Asserts the element's type matches the `sample_data`. For example:
+
+```python
+from pactman import Like
+Like(123) # Matches if the value is an integer
+Like('hello world') # Matches if the value is a string
+Like(3.14) # Matches if the value is a float
+```
+
+#### Like in request
+When you run the tests for the consumer, the mock will verify that values are
+of the correct type, raising an AssertionError if invalid. When the contract is
+verified by the provider, the `sample_data` will be used in the request to the
+real provider service.
+
+#### Like in response
+When you run the tests for the consumer, the mock will return the `sample_data`.
+When the contract is verified on the provider, the values generated by the provider
+service will be checked to match the type of `sample_data`.
+
+#### Applying Like to complex data structures
+When a dictionary is used as an argument for Like, all the child objects (and their child objects etc.)
+will be matched according to their types, unless you use a more specific matcher like a Term.
+
+```python
+from pactman import Like, Term
+Like({
+ 'username': Term('[a-zA-Z]+', 'username'),
+ 'id': 123, # integer
+ 'confirmed': False, # boolean
+ 'address': { # dictionary
+ 'street': '200 Bourke St' # string
+ }
+})
+```
+
+### EachLike(sample_data, minimum=1)
+Asserts the value is an array type that consists of elements
+like `sample_data`. It can be used to assert simple arrays:
+
+```python
+from pactman import EachLike
+EachLike(1) # All items are integers
+EachLike('hello') # All items are strings
+```
+
+Or other matchers can be nested inside to assert more complex objects:
+
+```python
+from pactman import EachLike, Term
+EachLike({
+ 'username': Term('[a-zA-Z]+', 'username'),
+ 'id': 123,
+ 'groups': EachLike('administrators')
+})
+```
+
+> Note, you do not need to specify everything that will be returned from the Provider in a
+> JSON response, any extra data that is received will be ignored and the tests will still pass.
+
+For more information see [Matching](https://docs.pact.io/documentation/matching.html)
+
+### Enforcing equality matching with Equals
+
+*Available in version 3.0.0+ pacts*
+
+If you have a sub-term of a `Like` which needs to match an exact value like the default
+validity test then you can use `Equals`, for example::
+
+```python
+from pactman import Equals, Like
+Like({
+ 'id': 123, # match integer, value varies
+ 'username': Equals('alex') # username must always be "alex"
+})
+```
+
+### Body payload rules
+The `body` payload is assumed to be JSON data. In the absence of a `Content-Type` header
+we assume `Content-Type: application/json; charset=UTF-8` (JSON text is Unicode and the
+default encoding is UTF-8).
+
+During verification non-JSON payloads are compared for equality.
+
+During mocking, the HTTP response will be handled as:
+
+1. If there's no `Content-Type` header, assume JSON: serialise with `json.dumps()`, encode to
+ UTF-8 and add the header `Content-Type: application/json; charset=UTF-8`.
+2. If there's a `Content-Type` header and it says `application/json` then serialise with
+ json.dumps() and use the charset in the header, defaulting to UTF-8.
+3. Otherwise pass through the `Content-Type` header and body as-is.
+ Binary data is not supported.
+
+
+## Verifying Pacts Against a Service
+You have two options for verifying pacts against a service you created:
+
+1. Use the `pactman-verifier` command-line program which replays the pact assertions against
+ a running instance of your service, or
+2. Use the `pytest` support built into pactman to replay the pacts as test cases, allowing
+ use of other testing mechanisms such as mocking and transaction control.
+
+### Using `pactman-verifier`
+
+Run `pactman-verifier -h` to see the options available. To run all pacts registered to a provider in a [Pact Broker]:
+
+ pactman-verifier -b http://pact-broker.example/ <provider name> <provider url> <provider setup url>
+
+You can pass in a local pact file with `-l`, this will verify the service against the local file instead of the broker:
+
+ pactman-verifier -l /tmp/localpact.json <provider name> <provider url> <provider setup url>
+
+You can use `--custom-provider-header` to pass in headers to be passed to provider state setup and verify calls. it can
+be used multiple times
+
+ pactman-verifier -b <broker url> --custom-provider-header "someheader:value" --custom-provider-header
+ "this:that" <provider name> <provider url> <provider state url>
+
+An additional header may also be supplied in the `PROVIDER_EXTRA_HEADER` environment variable, though the command
+line argument(s) would override this.
+
+#### Provider States
+
+In many cases, your contracts will need very specific data to exist on the provider
+to pass successfully. If you are fetching a user profile, that user needs to exist,
+if querying a list of records, one or more records needs to exist. To support
+decoupling the testing of the consumer and provider, Pact offers the idea of provider
+states to communicate from the consumer what data should exist on the provider.
+
+When setting up the testing of a provider you will also need to setup the management of
+these provider states. The Pact verifier does this by making additional HTTP requests to
+the `<provider setup url>` you provide. This URL could be
+on the provider application or a separate one. Some strategies for managing state include:
+
+- Having endpoints in your application that are not active in production that create and delete your datastore state
+- A separate application that has access to the same datastore to create and delete,
+ like a separate App Engine module or Docker container pointing to the same datastore
+- A standalone application that can start and stop the other server with different datastore states
+
+For more information about provider states, refer to the [Pact documentation] on [Provider States].
+
+### Verifying Pacts Using `pytest`
+
+To verify pacts for a provider you would write a new pytest test module in the provider's test suite.
+If you don't want it to be exercised in your usual unit test run you can call it `verify_pacts.py`.
+
+Your test code needs to use the `pact_verifier` fixture provided by pactman, invoking
+its `verify()` method with the URL to the running instance of your service (`pytest-django` provides
+a handy `live_server` fixture which works well here) and a callback to set up provider states (described
+below).
+
+You'll need to include some extra command-line arguments to pytest (also described below) to indicate
+where the pacts should come from, and whether verification results should be posted to a pact broker.
+
+An example for a Django project might contain:
+
+```python
+from django.contrib.auth.models import User
+from pactman.verifier.verify import ProviderStateMissing
+
+def provider_state(name, **params):
+ if name == 'the user "pat" exists':
+ User.objects.create(username='pat', fullname=params['fullname'])
+ else:
+ raise ProviderStateMissing(name)
+
+def test_pacts(live_server, pact_verifier):
+ pact_verifier.verify(live_server.url, provider_state)
+```
+
+The `pact_verifier.verify` call may also take a third argument to supply additional HTTP headers
+to send to the server during verification - specify them as a dictionary.
+
+The test function may do any level of mocking and data setup using standard pytest fixtures - so mocking
+downstream APIs or other interactions within the provider may be done with standard monkeypatching.
+
+#### Provider states using `pytest`
+
+The `provider_state` function passed to `pact_verifier.verify` will be passed the `providerState` and
+`providerStates` for all pacts being verified.
+
+- For pacts with **providerState** the `name` argument will be the `providerState` value,
+ and `params` will be empty.
+- For pacts with **providerStates** the function will be invoked once per entry in `providerStates`
+ array with the `name` argument taken from the array entry `name` parameter, and `params` from
+ the `params` parameter.
+
+#### Command line options to control `pytest` verifying pacts
+
+Once you have written the pytest code, you need to invoke pytest with additional arguments:
+
+`--pact-broker-url=<URL>` provides the base URL of the Pact broker to retrieve pacts from for the
+provider. You must also provide `--pact-provider-name=<ProviderName>` to identify which provider to
+retrieve pacts for from the broker.
+
+The broker URL and provider name may alternatively be provided through the environment variables
+`PACT_BROKER_URL` and `PACT_PROVIDER_NAME`.
+
+You may provide `--pact-verify-consumer=<ConsumerName>` to limit
+the pacts verified to just that consumer. As with the command-line verifier, you may provide basic
+auth details in the broker URL, or through the `PACT_BROKER_AUTH` environment variable. If your broker
+requires a bearer token you may provide it with `--pact-broker-token=<TOKEN>` or the `PACT_BROKER_TOKEN`
+environment variable.
+
+`--pact-files=<file pattern>` verifies some on-disk pact JSON files identified by the wildcard pattern
+(unix glob pattern matching, use `**` to match multiple directories).
+
+If you pulled the pacts from a broker and wish to publish verification results, use `--pact-publish-results`
+to turn on publishing the results. This option also requires you to specify `--pact-provider-version=<version>`.
+
+So, for example:
+
+```bash
+# verify some local pacts in /tmp/pacts
+$ pytest --pact-files=/tmp/pacts/*.json tests/verify_pacts.py
+
+# verify some pacts in a broker for the provider MyService
+$ pytest --pact-broker-url=http://pact-broker.example/ --pact-provider-name=MyService tests/verify_pacts.py
+```
+
+If you need to see the traceback that caused a pact failure you can use the verbosity flag
+to pytest (`pytest -v`).
+
+See the "pact" section in the pytest command-line help (`pytest -h`) for all command-line options.
+
+### Pact Broker Configuration
+
+You may also specify the broker URL in the environment variable `PACT_BROKER_URL`.
+
+If HTTP Basic Auth is required for the broker, that may be provided in the URL:
+
+ pactman-verifier -b http://user:password@pact-broker.example/ ...
+ pytest --pact-broker-url=http://user:password@pact-broker.example/ ...
+
+or set in the `PACT_BROKER_AUTH` environment variable as `user:password`.
+
+If your broker needs a bearer token then you may provide that on the command line or set it in the
+environment variable `PACT_BROKER_TOKEN`.
+
+#### Filtering Broker Pacts by Tag
+
+If your consumer pacts have tags (called "consumer version tags" because they attach to specific
+versions) then you may specify the tag(s) to fetch pacts for on the command line. Multiple tags
+may be specified, and all pacts matching any tags specified will be verified. For example, to ensure
+you're verifying your Provider against the *production* pact versions from your Consumers, use:
+
+ pactman-verifier --consumer-version-tag=production -b http://pact-broker.example/ ...
+ pytest --pact-verify-consumer-tag=production --pact-broker-url=http://pact-broker.example/ ...
+
+
+# Development
+Please read [CONTRIBUTING.md](CONTRIBUTING.md)
+
+## Release History
+
+3.0.0 (FUTURE, DEPRECATION WARNINGS)
+
+- remove DEPRECATED `--pact-consumer-name` command-line option
+
+2.30.0
+
+- DELETE requests may now have query strings, thanks @MazeDeveloper
+- Nicer feedback if no pact source is specified on command line, thanks @artamonovkirill
+- Add PACT_PROVIDER_NAME to environment vars, thanks @artamonovkirill
+
+2.29.0
+
+- Added support for `**` recursive globbing with `--pact-files`, thanks @maksimt
+
+2.28.0
+
+- Fixed edge case where `fail()` was not being invoked in an exact match
+ causing the pytest reporter to not know there'd been a failure
+- Address deprecation of `semver.parse` in semver
+- Dropped Python 3.6 testing, added Python 3.8 testing
+
+2.27.0
+
+- Fix typo in pytest plugin preventing `--pact-verify-consumer-tag` from working
+- Added PATCH support
+
+2.26.0
+
+- Allow pytest verification to specify `extra_provider_headers`
+
+2.25.0
+
+- Add option to allow pytest to succeed even if a pact verification fails
+
+2.24.0
+
+- Better integration of pact failure information in pytest
+
+2.23.0
+
+- Enable setting of authentication credentials when connecting to the pact broker
+- Allow filtering of pacts fetched from broker to be filtered by consumer version tag
+- Improve the naming and organisation of the pytest command line options
+
+2.22.0
+
+- Better implementation of change in 2.21.0
+
+2.21.0
+
+- Handle warning level messages in command line output handler
+
+2.20.0
+
+- Fix pytest mode to correctly detect array element rule failure as a pytest failure
+- Allow restricting pytest verification runs to a single consumer using --pact-consumer-name
+
+2.19.0
+
+- Correct teardown of pact context manager where the pact is used in multiple
+ interactions (`with interaction1, interaction2` instead of `with pact`).
+
+2.18.0
+
+- Correct bug in cleanup that resulted in urllib mocking breaking.
+
+2.17.0
+
+- Handle absence of any provider state (!) in pytest setup.
+
+2.16.0
+
+- Delay shenanigans around checking pacts directory until pacts are actually written
+ to allow module-level pact definition without side effects.
+
+2.15.0
+
+- Fix structure of serialisation for header matching rules.
+- Add `"never"` to the `file_write_mode` options.
+- Handle x-www-form-urlencoded POST request bodies.
+
+2.14.0
+
+- Improve verbose messages to clarify what they're saying.
+
+2.13.0
+
+- Add ability to supply additional headers to provider during verification (thanks @ryallsa)
+
+2.12.1
+
+- Fix pact-python Term compatibility
+
+2.12.0
+
+- Add `Equals` and `Includes` matchers for pact v3+
+- Make verification fail if missing header specified in interaction
+- Significantly improved support for pytest provider verification of pacts
+- Turned pact state call failures into warnings rather than errors
+
+2.11.0
+
+- Ensure query param values are lists
+
+2.10.0
+
+- Allow `has_pact_with()` to accept `file_write_mode`
+- Fix bug introduced in 2.9.0 where generating multiple pacts would result in a single pact
+ being recorded
+
+2.9.0
+
+- Fix `with_request` when called with a dict query (thanks Cong)
+- Make `start_mocking()` and `stop_mocking()` optional with non-server mocking
+- Add shortcut so `python -m pactman.verifier.command_line` is just `python -m pactman`
+ (mostly used in testing before release)
+- Handle the `None` provider state
+- Ensure pact spec versions are consistent across all mocks used to generate a pact file
+
+2.8.0
+
+- Close up some edge cases in body content during mocking, and document in README
+
+2.7.0
+
+- Added `and_given()` as a method of defining additonal provider states for v3+ pacts
+- Added more tests for pact generation (serialisation) which fixed a few edge case bugs
+- Fix handling of lower-case HTTP methods in verifier (thanks Cong!)
+
+2.6.1
+
+- Fix issue where mocked `urlopen` didn't handle the correct number of positional arguments
+
+2.6.0
+
+- Fix several issues cause by a failure to detect failure in several test cases
+ (header, path and array element rules may not have been applied)
+- Fix rules applying to a single non-first element in an array
+- Fix generation of consumer / provider name in <v3 pacts
+
+2.5.0
+
+- Fix some bugs around empty array verification
+
+2.4.0
+
+- Create the pact destination dir if it's missing and its parent exists
+
+2.3.0
+
+- Fix some issues around mocking request queries and the mock's verification of same
+- Fix header regex matching in mock verification
+- Actually use the version passed in to `has_pact_with()`
+- Fix some pact v3 generation issues (thanks pan Jacek)
+
+2.2.0
+
+- Reinstate lost result output.
+
+2.1.0
+
+- Corrected the definition of request payload when there is no `body` in the request
+
+2.0.0
+
+- Correctly determine pact verification result when publishing to broker.
+
+1.2.0
+
+- Corrected use of format_path in command line error handling.
+- Tweaked README for clarity.
+
+1.1.0
+
+- Renamed the `pact-verifier` command to `pactman-verifier` to avoid
+ confusion with other pre-existing packages that provide a command-line
+ incompatible `pact-verifier` command.
+- Support verification of HEAD requests (oops).
+
+1.0.8
+
+- Corrected project URL in project metadata (thanks Jonathan Moss)
+- Fix verbose output
+
+1.0.7
+
+- Added some Trove classifiers to aid potential users.
+
+1.0.6
+
+- Corrected mis-named command-line option.
+
+1.0.5
+
+- Corrected some packaging issues
+
+1.0.4
+
+- Initial release of pactman, including ReeceTech's pact-verifier version 3.17 and pact-python version 0.17.0
+
+[consumer driven contract testing]: https://2018.pycon-au.org/talks/44811-pact-in-python/
+[context manager]: https://en.wikibooks.org/wiki/Python_Programming/Context_Managers
+[Pact]: https://www.gitbook.com/book/pact-foundation/pact/details
+[Pact Broker]: https://docs.pact.io/getting_started/sharing_pacts
+[Pact documentation]: https://docs.pact.io/
+[Pact specification]: https://github.com/pact-foundation/pact-specification
+[Pact specification version 3]: https://github.com/pact-foundation/pact-specification/tree/version-3
+[Provider States]: https://docs.pact.io/provider/using_provider_states_effectively
+[pact-provider-verifier]: https://github.com/pact-foundation/pact-provider-verifier
+
+%prep
+%autosetup -n pactman-2.30.0
+
+%build
+%py3_build
+
+%install
+%py3_install
+install -d -m755 %{buildroot}/%{_pkgdocdir}
+if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi
+if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi
+if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi
+if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi
+pushd %{buildroot}
+if [ -d usr/lib ]; then
+ find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/lib64 ]; then
+ find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/bin ]; then
+ find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/sbin ]; then
+ find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+touch doclist.lst
+if [ -d usr/share/man ]; then
+ find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst
+fi
+popd
+mv %{buildroot}/filelist.lst .
+mv %{buildroot}/doclist.lst .
+
+%files -n python3-pactman -f filelist.lst
+%dir %{python3_sitelib}/*
+
+%files help -f doclist.lst
+%{_docdir}/*
+
+%changelog
+* Wed Apr 12 2023 Python_Bot <Python_Bot@openeuler.org> - 2.30.0-1
+- Package Spec generated