Skip to content

Commit

Permalink
feat: added support for message provider using pact broker (#257)
Browse files Browse the repository at this point in the history
* feat: added support for message provider using pact broker

* fix: added new line

* fix: update tests to support pact-broker runs
fix: updated message_pact to wait writing contract process to finish

* fix: removed time from import
  • Loading branch information
pulphix authored Sep 5, 2021
1 parent 43fedd1 commit 08f0dc0
Show file tree
Hide file tree
Showing 12 changed files with 206 additions and 14 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ define messaging
cd examples/message
pip install -r requirements.txt
pip install -e ../../
pytest
./run_pytest.sh
endef
export messaging

Expand Down
81 changes: 75 additions & 6 deletions examples/message/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,6 @@ def test_throw_exception_handler(pact):

## Provider

Note: The current example only tests the consumer side.
In the future, provider tests will also be included.

```
+-------------------+ +-----------+
|(Message Provider) | message | (Pact) |
Expand All @@ -110,10 +107,82 @@ In the future, provider tests will also be included.
+-------------------+ +-----------+
```

## E2E Messaging
```python
import pytest
from pact import MessageProvider

def document_created_handler():
return {
"event": "ObjectCreated:Put",
"documentName": "document.doc",
"creator": "TP",
"documentType": "microsoft-word"
}


def test_verify_success():
provider = MessageProvider(
message_providers={
'A document created successfully': document_created_handler
},
provider='ContentProvider',
consumer='DetectContentLambda',
pact_dir='pacts'

)
with provider:
provider.verify()
```


### Provider with pact broker
```python
import pytest
from pact import MessageProvider


PACT_BROKER_URL = "http://localhost"
PACT_BROKER_USERNAME = "pactbroker"
PACT_BROKER_PASSWORD = "pactbroker"
PACT_DIR = "pacts"


@pytest.fixture
def default_opts():
return {
'broker_username': PACT_BROKER_USERNAME,
'broker_password': PACT_BROKER_PASSWORD,
'broker_url': PACT_BROKER_URL,
'publish_version': '3',
'publish_verification_results': False
}

def document_created_handler():
return {
"event": "ObjectCreated:Put",
"documentName": "document.doc",
"creator": "TP",
"documentType": "microsoft-word"
}

Note: The current example only tests the consumer side.
In the future, provider tests will also be included.
def test_verify_from_broker(default_opts):
provider = MessageProvider(
message_providers={
'A document created successfully': document_created_handler,
},
provider='ContentProvider',
consumer='DetectContentLambda',
pact_dir='pacts'

)

with pytest.raises(AssertionError):
with provider:
provider.verify_with_broker(**default_opts)

```

## E2E Messaging

```
+-------------------+ +-----------+ +-------------------+
Expand Down
52 changes: 52 additions & 0 deletions examples/message/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@

from testcontainers.compose import DockerCompose

import pytest


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

parser.addoption(
"--provider-url", type=str, action="store",
help="The url to our provider."
)

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
# Do not do this yourself but setup one of the above
# https://github.com/pact-foundation/pact_broker
@pytest.fixture(scope='session', autouse=True)
def broker(request):
version = request.config.getoption('--publish-pact')
publish = True if version else False

# yield
if not publish:
yield
return

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

if not run_broker:
yield
return
else:
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(stdout)
yield
2 changes: 1 addition & 1 deletion examples/message/run_pytest.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash
set -o pipefail

pytest
pytest --run-broker True --publish-pact 2

# publish to broker assuming broker is active
# pytest tests/consumer/test_message_consumer.py::test_publish_to_broker --publish-pact 2
6 changes: 0 additions & 6 deletions examples/message/tests/conftest.py

This file was deleted.

2 changes: 2 additions & 0 deletions examples/message/tests/consumer/test_message_consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ def test_publish_to_broker(pact):
`pytest tests/consumer/test_message_consumer.py::test_publish_pact_to_broker --publish-pact 2`
"""
cleanup_json(PACT_FILE)

expected_event = {
"event": "ObjectCreated:Delete",
"documentName": "document.doc",
Expand Down
32 changes: 32 additions & 0 deletions examples/message/tests/provider/test_message_provider.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
import pytest
from pact import MessageProvider

PACT_BROKER_URL = "http://localhost"
PACT_BROKER_USERNAME = "pactbroker"
PACT_BROKER_PASSWORD = "pactbroker"
PACT_DIR = "pacts"


@pytest.fixture
def default_opts():
return {
'broker_username': PACT_BROKER_USERNAME,
'broker_password': PACT_BROKER_PASSWORD,
'broker_url': PACT_BROKER_URL,
'publish_version': '3',
'publish_verification_results': False
}


def document_created_handler():
return {
Expand Down Expand Up @@ -49,3 +65,19 @@ def test_verify_failure_when_a_provider_missing():
with pytest.raises(AssertionError):
with provider:
provider.verify()


def test_verify_from_broker(default_opts):
provider = MessageProvider(
message_providers={
'A document created successfully': document_created_handler,
'A document deleted successfully': document_deleted_handler
},
provider='ContentProvider',
consumer='DetectContentLambda',
pact_dir='pacts'

)

with provider:
provider.verify_with_broker(**default_opts)
1 change: 1 addition & 0 deletions pact/message_pact.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ def write_to_pact_file(self):
]

self._message_process = Popen(command)
self._message_process.wait()

def _insert_message_if_complete(self):
"""
Expand Down
19 changes: 19 additions & 0 deletions pact/message_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,25 @@ def verify(self):
return_code, _ = verifier.verify_pacts(pact_files, verbose=False)
assert (return_code == 0), f'Expected returned_code = 0, actual = {return_code}'

def verify_with_broker(self, enable_pending=False, include_wip_pacts_since=None, **kwargs):
"""Use Broker to verify.
Args:
broker_username ([String]): broker username
broker_password ([String]): broker password
broker_url ([String]): url of broker
enable_pending ([Boolean])
include_wip_pacts_since ([String])
publish_version ([String])
"""
verifier = Verifier(provider=self.provider,
provider_base_url=self._proxy_url())

return_code, _ = verifier.verify_with_broker(enable_pending, include_wip_pacts_since, **kwargs)

assert (return_code == 0), f'Expected returned_code = 0, actual = {return_code}'

def __enter__(self):
"""
Enter a Python context.
Expand Down
1 change: 1 addition & 0 deletions pact/verifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from pact.verify_wrapper import VerifyWrapper, path_exists, expand_directories


class Verifier(object):
"""A Pact Verifier."""

Expand Down
19 changes: 19 additions & 0 deletions tests/test_message_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from pact.message_provider import MessageProvider
from pact import message_provider as message_provider


class MessageProviderTestCase(TestCase):
def _mock_response(
self,
Expand Down Expand Up @@ -33,6 +34,13 @@ def setUp(self):
'a document created successfully': self.message_handler
}
)
self.options = {
'broker_username': "test",
'broker_password': "test",
'broker_url': "http://localhost",
'publish_version': '3',
'publish_verification_results': False
}

def test_init(self):
self.assertIsInstance(self.provider, MessageProvider)
Expand All @@ -50,6 +58,17 @@ def test_verify(self, mock_verify_pacts):
assert mock_verify_pacts.call_count == 1
mock_verify_pacts.assert_called_with(f'{self.provider.pact_dir}/{self.provider._pact_file()}', verbose=False)

@patch('pact.Verifier.verify_with_broker', return_value=(0, 'logs'))
def test_verify_with_broker(self, mock_verify_pacts):
self.provider.verify_with_broker(**self.options)

assert mock_verify_pacts.call_count == 1
mock_verify_pacts.assert_called_with(False, None, broker_username="test",
broker_password="test",
broker_url="http://localhost",
publish_version='3',
publish_verification_results=False)


class MessageProviderContextManagerTestCase(MessageProviderTestCase):
def setUp(self):
Expand Down
3 changes: 3 additions & 0 deletions tests/test_verifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
from pact.verifier import Verifier
from pact.verify_wrapper import VerifyWrapper


def assertVerifyCalled(mock_wrapper, *pacts, **options):
tc = unittest.TestCase()
tc.assertEqual(mock_wrapper.call_count, 1)

mock_wrapper.assert_called_once_with(*pacts, **options)


class VerifierPactsTestCase(TestCase):

def setUp(self):
Expand Down Expand Up @@ -130,6 +132,7 @@ def test_passes_include_wip_pacts_since_value(self, mock_path_exists, mock_wrapp
mock_wrapper.call_args.kwargs,
)


class VerifierBrokerTestCase(TestCase):

def setUp(self):
Expand Down

0 comments on commit 08f0dc0

Please sign in to comment.