Skip to content

Commit 0fca82f

Browse files
committed
Add demo stuff for pact broker
1 parent e368c32 commit 0fca82f

11 files changed

+237
-66
lines changed

broker/docker-compose.yml

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
version: '3'
2+
3+
services:
4+
5+
postgres:
6+
image: postgres
7+
healthcheck:
8+
test: psql postgres --command "select 1" -U postgres
9+
ports:
10+
- "5432:5432"
11+
environment:
12+
POSTGRES_USER: postgres
13+
POSTGRES_PASSWORD: password
14+
POSTGRES_DB: postgres
15+
16+
broker_app:
17+
image: dius/pact-broker
18+
ports:
19+
- "80:80"
20+
links:
21+
- postgres
22+
environment:
23+
PACT_BROKER_DATABASE_USERNAME: postgres
24+
PACT_BROKER_DATABASE_PASSWORD: password
25+
PACT_BROKER_DATABASE_HOST: postgres
26+
PACT_BROKER_DATABASE_NAME: postgres
27+
PACT_BROKER_BASIC_AUTH_USERNAME: pactbroker
28+
PACT_BROKER_BASIC_AUTH_PASSWORD: pactbroker
29+
30+
nginx:
31+
image: nginx:alpine
32+
links:
33+
- broker_app:broker
34+
volumes:
35+
- ./ssl/nginx.conf:/etc/nginx/conf.d/default.conf:ro
36+
- ./ssl:/etc/nginx/ssl
37+
ports:
38+
- "8443:443"

broker/ssl/nginx-selfsigned.crt

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDtTCCAp2gAwIBAgIJAPVSxq8aUpd1MA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
3+
BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
4+
aWRnaXRzIFB0eSBMdGQwHhcNMTgwMTE4MjMzMjMzWhcNMTkwMTE4MjMzMjMzWjBF
5+
MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
6+
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
7+
CgKCAQEA5vwTFJLlWmMC456Kv7uHxSqARkj5dwsb0lFoc5bGjOYvlJUu2S8F8QMc
8+
PlW2vXM7UsmBzbNgQsQh1FgRXgfNfHF80F21dILpzM/aA8a/GkJsKUZCHccQb5mq
9+
i25OrI4+XE6kSt/fwTbWRJGZgEADoIJ3wewcfzkJoeGonU+g8rYwPLq9xaHwFVFV
10+
x30KIZv5CToanHVy+aQUKg9m4VGuij22U7HzphS4IGZoaj2Uo0vpXqhWoKYrLFv2
11+
h0spP93Pr4VzoRGwlHgl2s+7qfwzRf9DhxePq9lGnqJ8TMQv1+jRITWB8jT8qW3Q
12+
t/+fWaGtkqbtgS8vGaAoXtXUZIWarQIDAQABo4GnMIGkMB0GA1UdDgQWBBSQCcqt
13+
DxAYpPkMWvMmU+DMT21RuDB1BgNVHSMEbjBsgBSQCcqtDxAYpPkMWvMmU+DMT21R
14+
uKFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV
15+
BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAPVSxq8aUpd1MAwGA1UdEwQF
16+
MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAE+ryTcny4NfIhdAwFbGjfZSsOHf0Ivt
17+
5lW0hHA7SZVcPysgAlM8sk+aZDQdNEP6eoUfpuwLvAio/kpvr9pFI0THvBm9W9MS
18+
zWmKkGrsuk8MXM0SsPi+BSz49YwAtsLFku7fsr/GNAD6+Vw+fyF+ySvUYJ2FwOEF
19+
4lYfzy1X0BA6l4RVmnO1Rv8Mn6LkzrBMe4kW0VARaBsS3hO/FW2nHMSDSkRCFjKi
20+
4qeX6RcJhHzfsZnQi2gqbVQXUvYiSjZL561UZdaybNJdSU+uOKgK2NTU1Pv6Prkh
21+
HS9Gm+yEtgSvTx/JoLkiKx31Q4GH2hoommCT0viCcnKz1eHKGYUhMP0=
22+
-----END CERTIFICATE-----

broker/ssl/nginx-selfsigned.key

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
MIIEpQIBAAKCAQEA5vwTFJLlWmMC456Kv7uHxSqARkj5dwsb0lFoc5bGjOYvlJUu
3+
2S8F8QMcPlW2vXM7UsmBzbNgQsQh1FgRXgfNfHF80F21dILpzM/aA8a/GkJsKUZC
4+
HccQb5mqi25OrI4+XE6kSt/fwTbWRJGZgEADoIJ3wewcfzkJoeGonU+g8rYwPLq9
5+
xaHwFVFVx30KIZv5CToanHVy+aQUKg9m4VGuij22U7HzphS4IGZoaj2Uo0vpXqhW
6+
oKYrLFv2h0spP93Pr4VzoRGwlHgl2s+7qfwzRf9DhxePq9lGnqJ8TMQv1+jRITWB
7+
8jT8qW3Qt/+fWaGtkqbtgS8vGaAoXtXUZIWarQIDAQABAoIBAQC3r5woz0yO3ZAN
8+
nSWvpZ0pwUuzGRMxhOcCEPUkfrG0mNUbrqtL0WZDLHsIYzdoXzu88TxFbbFORxSz
9+
/bkJ8uCJZuKf/PVxCy6MTnqMaD/OzSWgiRvI/GXoqeYC7ZypApE67NsgI/qXd1lb
10+
vAG7CK0ZtscvsulSjvRHBOIG/6z5dUAKnLJjr7uKydMHSIKNafKAEA6HGDCvIu4d
11+
J9EQzLfmpjLTkeB1DNZrv1mtNjf/kG/M/UX5a1RtOJTGvHQn/oZSUKng3DVUNBtq
12+
dEO6Pi5n88xWuxH6YAWqqDjCfqyey1Jc1rQxfnx6vRPL7+IaXRugAKFMFm8Xbp9/
13+
/9eEDCyNAoGBAPZEjYH9u2856KYUTyky8gD1TOE9gf4x4zFjK6SzBT8v1y1RdSwQ
14+
tf7ozj94OV/b9bAE3k/z2a09xYty5VBXs6MCluQTS67KgRaO9sSFtRmnupyBNk2z
15+
r3QEYuVDmJ6Dk/3ovItXqFaW8IbOZMf6Acu5aEDx4UKmb2tzGGJ7DxF/AoGBAPAc
16+
57p1yRWIG+hJMdkudXhBz+L3t2NbESWom33hi1mDMIKp3dwJmhA4kq+Uyqfl32uF
17+
Iy3z+3xr2V1BdGg1RnicfcyjHaQ4/89YB+nkOHB8muV2R57tYahOgWn6rXXxTOBs
18+
X2Vjd7ByAEFimrVfDH33inrYuIiI/cku4Xyj71HTAoGBAJeyrsBuPfFL6KW1SPYF
19+
7dDtSchNjS+6J0sa3Z18sTS1EYVW8iiMuq8lVTb/pcgIxJUCyrbRbTssG+3EfsE4
20+
5Oz7AVvJDwvCrjXpJtTz0BTXnzoc1giTMPb0ZL75HqA2SQlVPh9PheCg5dUEekw9
21+
ErIdqbynwqy9vVCg+1pel2+dAoGAR1C+fsIHFG8VottCg/fpies6HHZosIjWwfGf
22+
JTc9FTwCx3w+WeE8Mf8rihzOSCndPukPNtHVavH5YFpVgbH5GU+ZiZMU9ba8O9Aw
23+
oYZYQQixVN/Zi9mDfOK8S0baCELAC5QEjW+KmAx0CPeJbb8qTaudJLmDrYHKpttW
24+
u5dROGMCgYEAlgTZNiEeBAPQZD30CSvFUlZVCOOyu5crP9hCPA9um5FsvD9minSz
25+
yJqeMj7zapZsatAzYwHrGG6nHnTKWEBNaimR7kjTpKdKzXQaA9XeVLmeFAZ3Exad
26+
JDKTPI+asF+097sHUcVuloMOZXbD1uAZnvLWIwfsaHxs41AkF+0lmM4=
27+
-----END RSA PRIVATE KEY-----

broker/ssl/nginx.conf

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
server {
2+
listen 443 ssl default_server;
3+
server_name localhost;
4+
ssl_certificate /etc/nginx/ssl/nginx-selfsigned.crt;
5+
ssl_certificate_key /etc/nginx/ssl/nginx-selfsigned.key;
6+
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
7+
ssl_prefer_server_ciphers on;
8+
ssl_ecdh_curve secp384r1;
9+
ssl_session_cache shared:SSL:10m;
10+
ssl_stapling on;
11+
ssl_stapling_verify on;
12+
13+
location / {
14+
proxy_pass http://broker:80;
15+
proxy_set_header Host $host;
16+
proxy_set_header X-Forwarded-Scheme "https";
17+
proxy_set_header X-Forwarded-Port "443";
18+
proxy_set_header X-Forwarded-Ssl "on";
19+
proxy_set_header X-Real-IP $remote_addr;
20+
}
21+
}

client-test.py

-66
This file was deleted.
File renamed without changes.
File renamed without changes.
File renamed without changes.

tests/conftest.py

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
def pytest_addoption(parser):
3+
parser.addoption(
4+
"--publish-pact-ver", type=str, action="store",
5+
help="Upload generated pact file to pact broker with version"
6+
)

tests/test_client.py

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
"""pact test for user service client"""
2+
3+
import json
4+
import logging
5+
import os
6+
import sys
7+
8+
import pytest
9+
import requests
10+
from requests.auth import HTTPBasicAuth
11+
12+
from pact_python_demo.client import UserClient
13+
from pact import Consumer, Like, Provider, Term
14+
15+
log = logging.getLogger(__name__)
16+
logging.basicConfig(level=logging.INFO)
17+
18+
19+
PACT_UPLOAD_URL = (
20+
"http://127.0.0.1/pacts/provider/UserService/consumer"
21+
"/UserServiceClient/version"
22+
)
23+
PACT_FILE = "userserviceclient-userservice.json"
24+
PACT_BROKER_USERNAME = "pactbroker"
25+
PACT_BROKER_PASSWORD = "pactbroker"
26+
27+
PACT_MOCK_HOST = 'localhost'
28+
PACT_MOCK_PORT = 1234
29+
PACT_DIR = os.path.dirname(os.path.realpath(__file__))
30+
31+
@pytest.fixture
32+
def client():
33+
return UserClient(
34+
'http://{host}:{port}'
35+
.format(host=PACT_MOCK_HOST, port=PACT_MOCK_PORT)
36+
)
37+
38+
39+
def push_to_broker(version):
40+
"""TODO: see if we can dynamically learn the pact file name, version, etc."""
41+
with open(os.path.join(PACT_DIR, PACT_FILE), 'rb') as pact_file:
42+
pact_file_json = json.load(pact_file)
43+
44+
basic_auth = HTTPBasicAuth(PACT_BROKER_USERNAME, PACT_BROKER_PASSWORD)
45+
46+
log.info("Uploading pact file to pact broker...")
47+
48+
r = requests.put(
49+
"{}/{}".format(PACT_UPLOAD_URL, version),
50+
auth=basic_auth,
51+
json=pact_file_json
52+
)
53+
if not r.ok:
54+
log.error("Error uploading: %s", r.content)
55+
r.raise_for_status()
56+
57+
58+
@pytest.fixture(scope='session')
59+
def pact(request):
60+
pact = Consumer('UserServiceClient').has_pact_with(
61+
Provider('UserService'), host_name=PACT_MOCK_HOST, port=PACT_MOCK_PORT,
62+
pact_dir=PACT_DIR)
63+
pact.start_service()
64+
yield pact
65+
pact.stop_service()
66+
67+
version = request.config.getoption('--publish-pact-ver')
68+
if not request.node.testsfailed and version:
69+
push_to_broker(version)
70+
71+
72+
def test_get_user_non_admin(pact, client):
73+
expected = {
74+
'name': 'UserA',
75+
'id': Term(
76+
r'^[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}\Z',
77+
'00000000-0000-4000-a000-000000000000'
78+
),
79+
'created_on': Term(
80+
r'\d+-\d+-\d+T\d+:\d+:\d+',
81+
'2016-12-15T20:16:01'
82+
),
83+
'admin': False
84+
}
85+
86+
(pact
87+
.given('UserA exists and is not an administrator')
88+
.upon_receiving('a request for UserA')
89+
.with_request('get', '/users/UserA')
90+
.will_respond_with(200, body=Like(expected)))
91+
92+
with pact:
93+
result = client.get_user('UserA')
94+
95+
# assert something with the result, for ex, did I process 'result' properly?
96+
# or was I able to deserialize correctly? etc.
97+
98+
99+
def test_get_non_existing_user(pact, client):
100+
(pact
101+
.given('UserA does not exist')
102+
.upon_receiving('a request for UserA')
103+
.with_request('get', '/users/UserA')
104+
.will_respond_with(404))
105+
106+
with pact:
107+
result = client.get_user('UserA')
108+
109+
assert result is None

verify_pact.sh

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/bash
2+
VERSION=$1
3+
if [ -x $VERSION ]; then
4+
echo "ERROR: You must specify a provider version"
5+
exit
6+
fi
7+
8+
pipenv run pact-verifier --provider-base-url=http://localhost:5001 \
9+
--pact-url="http://127.0.0.1/pacts/provider/UserService/consumer/UserServiceClient/latest" \
10+
--provider-states-setup-url=http://localhost:5001/_pact/provider_states \
11+
--provider-app-version $VERSION \
12+
--pact-broker-username pactbroker \
13+
--pact-broker-password pactbroker \
14+
--publish-verification-results

0 commit comments

Comments
 (0)