Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(examples): move shared fixtures to a common folder so they can b… #280

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions examples/README.md
Expand Up @@ -4,6 +4,7 @@

* [Overview](#overview)
* [broker](#broker)
* [common](#common)
* [consumer](#consumer)
* [flask_provider](#flask_provider)
* [fastapi_provider](#fastapi_provider)
Expand Down Expand Up @@ -41,6 +42,13 @@ default Example App/Example API Pact.
Running the [Pact Broker] outside the tests will mean you are able to then see the [Pact file]s submitted to the
[Pact Broker] as the various tests are performed.

## common

To avoid needing to duplicate certain fixtures, such as starting up a docker based Pact broker (to demonstrate how the
test process could work), the shared fixtures used by the pytests have all been placed into a single location.]
This means it is easier to see the relevant code for the example without having to go through the boilerplate fixtures.
See [Requiring/Loading plugins in a test module or conftest file] for further details of this approach.

## consumer

Pact is consumer-driven, which means first the contracts are created. These Pact contracts are generated during
Expand Down Expand Up @@ -205,3 +213,4 @@ without a [Pact Broker].
[Virtual Environment]: https://docs.python.org/3/tutorial/venv.html
[Sharing Pacts]: https://docs.pact.io/getting_started/sharing_pacts/]
[How to Run a Flask Application]: https://www.twilio.com/blog/how-run-flask-application
[Requiring/Loading plugins in a test module or conftest file]: https://docs.pytest.org/en/6.2.x/writing_plugins.html#requiring-loading-plugins-in-a-test-module-or-conftest-file
88 changes: 88 additions & 0 deletions examples/common/sharedfixtures.py
@@ -0,0 +1,88 @@
import pathlib

import docker
import pytest
from testcontainers.compose import DockerCompose


# This fixture is to simulate a managed Pact Broker or Pactflow account.
# For almost all purposes outside this example, you will want to use a real
# broker. See https://github.com/pact-foundation/pact_broker for further details.
@pytest.fixture(scope="session", autouse=True)
def broker(request):
version = request.config.getoption("--publish-pact")
publish = True if version else False

# If the results are not going to be published to the broker, there is
# nothing further to do anyway
if not publish:
yield
return

run_broker = request.config.getoption("--run-broker")

if run_broker:
# Start up the broker using docker-compose
print("Starting broker")
with DockerCompose("../broker", compose_file_name=["docker-compose.yml"], pull=True) as compose:
stdout, stderr = compose.get_logs()
if stderr:
print("Errors\\n:{}".format(stderr))
print("{}".format(stdout))
print("Started broker")

yield
print("Stopping broker")
print("Broker stopped")
else:
# Assuming there is a broker available already, docker-compose has been
# used manually as the --run-broker option has not been provided
yield
return


@pytest.fixture(scope="session", autouse=True)
def publish_existing_pact(broker):
"""Publish the contents of the pacts folder to the Pact Broker.

In normal usage, a Consumer would publish Pacts to the Pact Broker after
running tests - this fixture would NOT be needed.
.
Because the broker is being used standalone here, it will not contain the
required Pacts, so we must first spin up the pact-cli and publish them.

In the Pact Broker logs, this corresponds to the following entry:
PactBroker::Pacts::Service -- Creating new pact publication with params \
{:consumer_name=>"UserServiceClient", :provider_name=>"UserService", \
:revision_number=>nil, :consumer_version_number=>"1", :pact_version_sha=>nil, \
:consumer_name_in_pact=>"UserServiceClient", :provider_name_in_pact=>"UserService"}
"""
source = str(pathlib.Path.cwd().joinpath("..", "pacts").resolve())
pacts = [f"{source}:/pacts"]
envs = {
"PACT_BROKER_BASE_URL": "http://broker_app:9292",
"PACT_BROKER_USERNAME": "pactbroker",
"PACT_BROKER_PASSWORD": "pactbroker",
}

client = docker.from_env()

print("Publishing existing Pact")
client.containers.run(
remove=True,
network="broker_default",
volumes=pacts,
image="pactfoundation/pact-cli:latest",
environment=envs,
command="publish /pacts --consumer-app-version 1",
)
print("Finished publishing")


def pytest_addoption(parser):
parser.addoption(
"--publish-pact", type=str, action="store", help="Upload generated pact file to pact broker with version"
)

parser.addoption("--run-broker", type=bool, action="store", help="Whether to run broker in this test or not.")
parser.addoption("--provider-url", type=str, action="store", help="The url to our provider.")
53 changes: 6 additions & 47 deletions examples/consumer/conftest.py
@@ -1,49 +1,8 @@
import pytest
from testcontainers.compose import DockerCompose
import sys

# Load in the fixtures from common/sharedfixtures.py
sys.path.append("../common")

def pytest_addoption(parser):
parser.addoption(
"--publish-pact",
type=str,
action="store",
help="Upload generated Pact file to Pact Broker with the version provided",
)

parser.addoption("--run-broker", type=bool, action="store", help="Whether to run broker in this test or not")


# This fixture is to simulate a managed Pact Broker or Pactflow account.
# For almost all purposes outside this example, you will want to use a real
# broker. See https://github.com/pact-foundation/pact_broker for further details.
@pytest.fixture(scope="session", autouse=True)
def broker(request):
version = request.config.getoption("--publish-pact")
publish = True if version else False

# If the results are not going to be published to the broker, there is
# nothing further to do anyway
if not publish:
yield
return

run_broker = request.config.getoption("--run-broker")

if run_broker:
# Start up the broker using docker-compose
print("Starting broker")
with DockerCompose("../broker", compose_file_name=["docker-compose.yml"], pull=True) as compose:
stdout, stderr = compose.get_logs()
if stderr:
print("Errors\\n:{}".format(stderr))
print("{}".format(stdout))
print("Started broker")

yield
print("Stopping broker")
print("Broker stopped")
else:
# Assuming there is a broker available already, docker-compose has been
# used manually as the --run-broker option has not been provided
yield
return
pytest_plugins = [
"sharedfixtures",
]
97 changes: 12 additions & 85 deletions examples/fastapi_provider/tests/conftest.py
@@ -1,12 +1,17 @@
import pathlib
import sys
from multiprocessing import Process

import docker
import pytest
from testcontainers.compose import DockerCompose

from .pact_provider import run_server

# Load in the fixtures from common/sharedfixtures.py
sys.path.append("../common")

pytest_plugins = [
"sharedfixtures",
]


@pytest.fixture(scope="module")
def server():
Expand All @@ -15,86 +20,8 @@ def server():
yield proc

# Cleanup after test
proc.kill()


def pytest_addoption(parser):
parser.addoption(
"--publish-pact", type=str, action="store", help="Upload generated pact file to pact broker with version"
)

parser.addoption("--run-broker", type=bool, action="store", help="Whether to run broker in this test or not.")


@pytest.fixture(scope="session", autouse=True)
def publish_existing_pact(broker):
"""Publish the contents of the pacts folder to the Pact Broker.

In normal usage, a Consumer would publish Pacts to the Pact Broker after
running tests - this fixture would NOT be needed.
.
Because the broker is being used standalone here, it will not contain the
required Pacts, so we must first spin up the pact-cli and publish them.

In the Pact Broker logs, this corresponds to the following entry:
PactBroker::Pacts::Service -- Creating new pact publication with params \
{:consumer_name=>"UserServiceClient", :provider_name=>"UserService", \
:revision_number=>nil, :consumer_version_number=>"1", :pact_version_sha=>nil, \
:consumer_name_in_pact=>"UserServiceClient", :provider_name_in_pact=>"UserService"}
"""
source = str(pathlib.Path.cwd().joinpath("..", "pacts").resolve())
pacts = [f"{source}:/pacts"]
envs = {
"PACT_BROKER_BASE_URL": "http://broker_app:9292",
"PACT_BROKER_USERNAME": "pactbroker",
"PACT_BROKER_PASSWORD": "pactbroker",
}

client = docker.from_env()

print("Publishing existing Pact")
client.containers.run(
remove=True,
network="broker_default",
volumes=pacts,
image="pactfoundation/pact-cli:latest",
environment=envs,
command="publish /pacts --consumer-app-version 1",
)
print("Finished publishing")


# This fixture is to simulate a managed Pact Broker or Pactflow account.
# For almost all purposes outside this example, you will want to use a real
# broker. See https://github.com/pact-foundation/pact_broker for further details.
@pytest.fixture(scope="session", autouse=True)
def broker(request):
version = request.config.getoption("--publish-pact")
publish = True if version else False

# If the results are not going to be published to the broker, there is
# nothing further to do anyway
if not publish:
yield
return

run_broker = request.config.getoption("--run-broker")

if run_broker:
# Start up the broker using docker-compose
print("Starting broker")
with DockerCompose("../broker", compose_file_name=["docker-compose.yml"], pull=True) as compose:
stdout, stderr = compose.get_logs()
if stderr:
print("Errors\\n:{}".format(stderr))
print("{}".format(stdout))
print("Started broker")

yield
print("Stopping broker")
print("Broker stopped")
if sys.version_info >= (3, 7):
# multiprocessing.kill is new in 3.7
proc.kill()
else:
# Assuming there is a broker available already, docker-compose has been
# used manually as the --run-broker option has not been provided
yield
return
proc.terminate()
91 changes: 6 additions & 85 deletions examples/flask_provider/tests/conftest.py
@@ -1,87 +1,8 @@
import pathlib
import sys

import docker
import pytest
from testcontainers.compose import DockerCompose
# Load in the fixtures from common/sharedfixtures.py
sys.path.append("../common")


def pytest_addoption(parser):
parser.addoption(
"--publish-pact", type=str, action="store", help="Upload generated pact file to pact broker with version"
)

parser.addoption("--run-broker", type=bool, action="store", help="Whether to run broker in this test or not.")


@pytest.fixture(scope="session", autouse=True)
def publish_existing_pact(broker):
"""Publish the contents of the pacts folder to the Pact Broker.

In normal usage, a Consumer would publish Pacts to the Pact Broker after
running tests - this fixture would NOT be needed.
.
Because the broker is being used standalone here, it will not contain the
required Pacts, so we must first spin up the pact-cli and publish them.

In the Pact Broker logs, this corresponds to the following entry:
PactBroker::Pacts::Service -- Creating new pact publication with params \
{:consumer_name=>"UserServiceClient", :provider_name=>"UserService", \
:revision_number=>nil, :consumer_version_number=>"1", :pact_version_sha=>nil, \
:consumer_name_in_pact=>"UserServiceClient", :provider_name_in_pact=>"UserService"}
"""
source = str(pathlib.Path.cwd().joinpath("..", "pacts").resolve())
pacts = [f"{source}:/pacts"]
envs = {
"PACT_BROKER_BASE_URL": "http://broker_app:9292",
"PACT_BROKER_USERNAME": "pactbroker",
"PACT_BROKER_PASSWORD": "pactbroker",
}

client = docker.from_env()

print("Publishing existing Pact")
client.containers.run(
remove=True,
network="broker_default",
volumes=pacts,
image="pactfoundation/pact-cli:latest",
environment=envs,
command="publish /pacts --consumer-app-version 1",
)
print("Finished publishing")


# This fixture is to simulate a managed Pact Broker or Pactflow account.
# For almost all purposes outside this example, you will want to use a real
# broker. See https://github.com/pact-foundation/pact_broker for further details.
@pytest.fixture(scope="session", autouse=True)
def broker(request):
version = request.config.getoption("--publish-pact")
publish = True if version else False

# If the results are not going to be published to the broker, there is
# nothing further to do anyway
if not publish:
yield
return

run_broker = request.config.getoption("--run-broker")

if run_broker:
# Start up the broker using docker-compose
print("Starting broker")
with DockerCompose("../broker", compose_file_name=["docker-compose.yml"], pull=True) as compose:
stdout, stderr = compose.get_logs()
if stderr:
print("Errors\\n:{}".format(stderr))
print("{}".format(stdout))
print("Started broker")

yield
print("Stopping broker")
print("Broker stopped")
else:
# Assuming there is a broker available already, docker-compose has been
# used manually as the --run-broker option has not been provided
yield
return
pytest_plugins = [
"sharedfixtures",
]