Skip to content

Commit

Permalink
chore(tests): use long-lived pact broker
Browse files Browse the repository at this point in the history
The initial implementation of the compatibility suite spun up and down
the Pact Broker for each scenario, which also resulting in flaky tests
in CI.

This refactor uses a session pytest fixture which will spin up the
broker once, and keep re-using it. Functionality to 'reset' the broker
between tests has also been added.

Signed-off-by: JP-Ellis <[email protected]>
  • Loading branch information
JP-Ellis committed Mar 22, 2024
1 parent 63b30f9 commit a67d66c
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 10 deletions.
66 changes: 56 additions & 10 deletions tests/v3/compatibility_suite/test_v1_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
import logging
import pickle
import re
import shutil
import signal
import subprocess
import sys
import time
from contextvars import ContextVar
from pathlib import Path
from threading import Thread
from typing import Any, Generator, NoReturn
from typing import Any, Generator, NoReturn, Union

import pytest
import requests
Expand All @@ -34,13 +36,52 @@

logger = logging.getLogger(__name__)

reset_broker_var = ContextVar("reset_broker", default=True)
"""
This context variable is used to determine whether the Pact broker should be
cleaned up. It is used to ensure that the broker is only cleaned up once, even
if a step is run multiple times.
All scenarios which make use of the Pact broker should set this to `True` at the
start of the scenario.
"""


@pytest.fixture()
def verifier() -> Verifier:
"""Return a new Verifier."""
return Verifier()


@pytest.fixture(scope="session")
def broker_url(request: pytest.FixtureRequest) -> Generator[URL, Any, None]:
"""
Fixture to run the Pact broker.
This inspects whether the `--broker-url` option has been given. If it has,
it is assumed that the broker is already running and simply returns the
given URL.
Otherwise, the Pact broker is started in a container. The URL of the
containerised broker is then returned.
"""
broker_url: Union[str, None] = request.config.getoption("--broker-url")

# If we have been given a broker URL, there's nothing more to do here and we
# can return early.
if broker_url:
yield URL(broker_url)
return

with DockerCompose(
Path(__file__).parent / "util",
compose_file_name="pact-broker.yml",
pull=True,
) as _:
yield URL("http://pactbroker:pactbroker@localhost:9292")
return


################################################################################
## Scenario
################################################################################
Expand Down Expand Up @@ -76,6 +117,7 @@ def test_incorrect_request_is_made_to_provider() -> None:
)
def test_verifying_a_simple_http_request_via_a_pact_broker() -> None:
"""Verifying a simple HTTP request via a Pact broker."""
reset_broker_var.set(True) # noqa: FBT003


@scenario(
Expand All @@ -84,6 +126,7 @@ def test_verifying_a_simple_http_request_via_a_pact_broker() -> None:
)
def test_verifying_a_simple_http_request_via_a_pact_broker_with_publishing() -> None:
"""Verifying a simple HTTP request via a Pact broker with publishing."""
reset_broker_var.set(True) # noqa: FBT003


@scenario(
Expand All @@ -92,6 +135,7 @@ def test_verifying_a_simple_http_request_via_a_pact_broker_with_publishing() ->
)
def test_verifying_multiple_pact_files_via_a_pact_broker() -> None:
"""Verifying multiple Pact files via a Pact broker."""
reset_broker_var.set(True) # noqa: FBT003


@scenario(
Expand All @@ -100,6 +144,7 @@ def test_verifying_multiple_pact_files_via_a_pact_broker() -> None:
)
def test_incorrect_request_is_made_to_provider_via_a_pact_broker() -> None:
"""Incorrect request is made to provider via a Pact broker."""
reset_broker_var.set(True) # noqa: FBT003


@scenario(
Expand Down Expand Up @@ -475,6 +520,7 @@ def a_pact_file_for_interaction_is_to_be_verified(
)
def a_pact_file_for_interaction_is_to_be_verified_from_a_pact_broker(
interaction_definitions: dict[int, InteractionDefinition],
broker_url: URL,
verifier: Verifier,
interaction: int,
temp_dir: Path,
Expand All @@ -491,18 +537,18 @@ def a_pact_file_for_interaction_is_to_be_verified_from_a_pact_broker(
defn.add_to_pact(pact, f"interaction {interaction}")

pacts_dir = temp_dir / "pacts"
if pacts_dir.exists():
shutil.rmtree(pacts_dir)
pacts_dir.mkdir(exist_ok=True, parents=True)
pact.write_file(pacts_dir)

with DockerCompose(
Path(__file__).parent / "util",
compose_file_name="pact-broker.yml",
pull=True,
) as _:
pact_broker = PactBroker(URL("http://pactbroker:pactbroker@localhost:9292"))
pact_broker.publish(pacts_dir)
verifier.broker_source(pact_broker.url)
yield pact_broker
pact_broker = PactBroker(broker_url)
if reset_broker_var.get():
pact_broker.reset()
reset_broker_var.set(False) # noqa: FBT003
pact_broker.publish(pacts_dir)
verifier.broker_source(pact_broker.url)
yield pact_broker


@given("publishing of verification results is enabled")
Expand Down
19 changes: 19 additions & 0 deletions tests/v3/compatibility_suite/util/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,25 @@ def _install(self) -> None:
msg = "pact-broker not found"
raise NotImplementedError(msg)

def reset(self) -> None:
"""
Reset the Pact Broker.
This function will reset the Pact Broker by deleting all pacts and
verification results.
"""
requests.delete(
str(
self.url
/ "integrations"
/ "provider"
/ self.provider
/ "consumer"
/ self.consumer
),
timeout=2,
)

def publish(self, directory: Path | str, version: str | None = None) -> None:
"""
Publish the interactions to the Pact Broker.
Expand Down

0 comments on commit a67d66c

Please sign in to comment.