From cf61a40e453af42a0545e8f93f92f7819f8ceb71 Mon Sep 17 00:00:00 2001 From: Mike Geeves Date: Mon, 20 Dec 2021 16:42:11 +0000 Subject: [PATCH] fix(consumer): ensure a description is provided for all interactions --- examples/broker/docker-compose.yml | 13 ++++++++++++- pact/pact.py | 7 +++++++ tests/test_pact.py | 20 ++++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/examples/broker/docker-compose.yml b/examples/broker/docker-compose.yml index 801e60886..b5d5316cd 100644 --- a/examples/broker/docker-compose.yml +++ b/examples/broker/docker-compose.yml @@ -1,4 +1,4 @@ -version: '3' +version: '3.9' services: # A PostgreSQL database for the Broker to store Pacts and verification results @@ -32,6 +32,13 @@ services: PACT_BROKER_DATABASE_NAME: postgres PACT_BROKER_BASIC_AUTH_USERNAME: pactbroker PACT_BROKER_BASIC_AUTH_PASSWORD: pactbroker + # The Pact Broker provides a healthcheck endpoint which we will use to wait + # for it to become available before starting up + healthcheck: + test: [ "CMD", "wget", "-q", "--tries=1", "--spider", "http://pactbroker:pactbroker@localhost:9292/diagnostic/status/heartbeat" ] + interval: 1s + timeout: 2s + retries: 5 # An NGINX reverse proxy in front of the Broker on port 8443, to be able to # terminate with SSL @@ -44,3 +51,7 @@ services: - ./ssl:/etc/nginx/ssl ports: - "8443:443" + restart: always + depends_on: + broker_app: + condition: service_healthy diff --git a/pact/pact.py b/pact/pact.py index a6ec2cdec..bc9af31a0 100644 --- a/pact/pact.py +++ b/pact/pact.py @@ -13,6 +13,7 @@ from .broker import Broker from .constants import MOCK_SERVICE_PATH from .matchers import from_term +from .verify_wrapper import PactException class Pact(Broker): @@ -165,6 +166,12 @@ def given(self, provider_state): def setup(self): """Configure the Mock Service to ready it for a test.""" try: + # First, check that the interactions are all complete + for interaction in self._interactions: + missing_fields = [f for f in self.MANDATORY_FIELDS if f not in interaction] + if missing_fields: + raise PactException(f"Interaction incomplete, missing field(s): {', '.join(missing_fields)}") + interactions_uri = f"{self.uri}/interactions" resp = requests.delete( interactions_uri, headers=self.HEADERS, verify=False diff --git a/tests/test_pact.py b/tests/test_pact.py index b5405cceb..af642c523 100644 --- a/tests/test_pact.py +++ b/tests/test_pact.py @@ -11,6 +11,7 @@ from pact.constants import MOCK_SERVICE_PATH from pact.pact import Pact, FromTerms, Request, Response from pact import pact as pact +from pact.verify_wrapper import PactException class PactTestCase(TestCase): @@ -559,6 +560,25 @@ def test_context_raises_error(self): self.assertFalse(self.mock_verify.called) +class PactContextManagerSetupTestCase(PactTestCase): + def test_definition_without_description(self): + # Description (populated from "given") is listed in the MANDATORY_FIELDS. + # Make sure if it isn't there that an exception is raised + pact = Pact(self.consumer, self.provider) + (pact.given("A request without a description") + .with_request('GET', '/path') + .will_respond_with(200, body='success')) + + self.assertEqual(len(pact._interactions), 1) + + self.assertTrue('description' not in pact._interactions[0]) + + # By using "with", __enter__ will call the setup method that will verify if this is present + with self.assertRaises(PactException): + with pact: + pact.verify() + + class FromTermsTestCase(TestCase): def test_json(self): with self.assertRaises(NotImplementedError):