Skip to content

Commit 4d98ecd

Browse files
authored
Update to modern python tooling (#57)
Modern python has standardisde around poetry for dependency management. Before starting to develop new features I wanted to set a baseline python version at python 3.7. Alongside this migration to poetry for dependency management, I have also migrated all of the test suite to pytest. I did this mostly as a way to really get some good exposure on the code base via the tests but to also modernise the testing tooling in use. github action support has also been added as that will be used for the CI pipeline going forward which will run this new test suite.
1 parent 7cee345 commit 4d98ecd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2894
-1453
lines changed

.github/workflows/tests.yml

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Python Testing
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
13+
strategy:
14+
matrix:
15+
python-version: [3.7, 3.8, 3.9, 3.10, 3.11]
16+
17+
steps:
18+
- uses: actions/checkout@v2
19+
20+
- name: Set up Python ${{ matrix.python-version }}
21+
uses: actions/setup-python@v2
22+
with:
23+
python-version: ${{ matrix.python-version }}
24+
25+
- name: Install Poetry
26+
run: curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py | python -
27+
28+
- name: Install dependencies
29+
run: poetry install
30+
31+
- name: Run tests with pytest
32+
run: tox -e py${{ matrix.python-version/./ }}-pytest

AUTHORS

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
2+
Mikey Waites <[email protected]>

README.md

+14-14
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
1-
Python WireMock Admin API Client
2-
================================
1+
# Python WireMock Admin API Client
32

43
This is a python admin API client to a standalone WireMock server.
54

65
[![Build Status](https://travis-ci.org/wiremock/python-wiremock.svg?branch=master)](https://travis-ci.org/wiremock/python-wiremock)
76
[![Coverage Status](https://coveralls.io/repos/github/wiremock/python-wiremock/badge.svg?branch=master)](https://coveralls.io/github/wiremock/python-wiremock?branch=master)
87
[![Docs](https://img.shields.io/badge/docs-latest-brightgreen.svg)](http://wiremock.readthedocs.org/)
98

10-
11-
Install as Dependency
12-
--------------------
9+
## Install as Dependency
1310

1411
To install:
1512

1613
pip install wiremock
1714

18-
19-
Documentation
20-
-------------
15+
## Documentation
2116

2217
wiremock documentation can be found at http://wiremock.readthedocs.org/
2318

24-
25-
Pull Requests
26-
-------------
19+
## Pull Requests
2720

2821
General Rules:
29-
- All Tests must pass
30-
- Coverage shouldn't decrease
31-
- All Pull Requests should be rebased against master **before** submitting the PR.
22+
23+
- All Tests must pass
24+
- Coverage shouldn't decrease
25+
- All Pull Requests should be rebased against master **before** submitting the PR.
26+
27+
## Development
28+
29+
Setup the project using poetry.
30+
31+
`poetry install`

poetry.lock

+862
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
[tool.poetry]
2+
name = "wiremock"
3+
version = "2.3.1"
4+
description = "Wiremock Admin API Client"
5+
authors = ["Cody Lee <[email protected]>", "Mike Waites <[email protected]>"]
6+
license = "OSI Approved :: Apache Software License"
7+
packages = [{include = "wiremock"}]
8+
readme = "README.md"
9+
classifiers=[
10+
"Development Status :: 5 - Production/Stable",
11+
"Environment :: Web Environment",
12+
"Environment :: Other Environment",
13+
"Environment :: Plugins",
14+
"Intended Audience :: Developers",
15+
"License :: OSI Approved :: Apache Software License",
16+
"Operating System :: OS Independent",
17+
"Natural Language :: English",
18+
"Programming Language :: Python :: 3.7",
19+
"Programming Language :: Python :: 3.8",
20+
"Programming Language :: Python :: 3.9",
21+
"Programming Language :: Python :: 3.10",
22+
"Programming Language :: Python :: 3.11",
23+
"Programming Language :: Python :: Implementation",
24+
"Topic :: Internet :: WWW/HTTP",
25+
"Topic :: Software Development :: Testing,",
26+
"Topic :: Software Development :: Testing :: Unit",
27+
"Topic :: Software Development :: Testing :: Mocking",
28+
"Topic :: Software Development :: Quality Assurance",
29+
"Topic :: Software Development :: Libraries :: Python Modules",
30+
]
31+
32+
[tool.poetry.dependencies]
33+
python = "^3.7 | ^3.8 | ^3.9 | ^3.10 | ^3.11"
34+
requests = "^2.20.0"
35+
36+
[tool.poetry.group.dev.dependencies]
37+
black = "^23.3.0"
38+
coverage = "^7.2.3"
39+
pytest-coverage = "^0.0"
40+
python-coveralls = "^2.9.3"
41+
responses = "^0.23.1"
42+
tox = "^4.4.12"
43+
watchdog = "^3.0.0"
44+
wheel = "^0.40.0"
45+
pytest = "^7.3.1"
46+
47+
48+
[tool.pytest.ini_options]
49+
markers = [
50+
"unit: marks tests as unit tests",
51+
"mappings",
52+
"nearmisses",
53+
"resource",
54+
"serialization",
55+
]
56+
57+
[build-system]
58+
requires = ["poetry-core"]
59+
build-backend = "poetry.core.masonry.api"
60+
61+
62+
[tool.black]
63+
exclude = '''
64+
/(
65+
\.git
66+
| \.hg
67+
| \.mypy_cache
68+
| \.tox
69+
| \.venv
70+
| _build
71+
| buck-out
72+
| build
73+
| dist
74+
)/
75+
'''
76+
include = '\.pyi?$'
77+
line-length = 88

run_coverage.sh

-4
This file was deleted.

run_tests.sh

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#!/bin/sh
22

33
rm -Rf build/ dist/ wiremock.egg-info coverage/ wiremock/tests/coverage/ html/ || true
4-
echo -e 'y\n' | pip uninstall wiremock
5-
nosetests -vv -w wiremock/tests --attr=unit
4+
poetry run pytest --cov=wiremock --tb=short

tests/conftest.py

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import pytest
2+
3+
from wiremock.base import RestClient
4+
from wiremock.constants import Config
5+
6+
7+
@pytest.fixture
8+
def client():
9+
Config.base_url = "http://localhost/__admin"
10+
Config.timeout = 1
11+
return RestClient()
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import pytest
2+
from requests import Response
3+
4+
from wiremock.exceptions import UnexpectedResponseException
5+
6+
7+
# Helpers
8+
def create_dummy_response(status_code=200):
9+
resp = Response()
10+
resp.status_code = status_code
11+
return resp
12+
13+
14+
def test_handle_response(client):
15+
for status_code in [200, 201, 204]:
16+
resp = create_dummy_response(status_code)
17+
returned = client.handle_response(resp)
18+
assert returned == resp
19+
20+
resp = create_dummy_response(203)
21+
with pytest.raises(UnexpectedResponseException):
22+
client.handle_response(resp)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
import pytest
2+
import responses
3+
4+
from wiremock.client import (
5+
AllMappings,
6+
Mapping,
7+
MappingMeta,
8+
MappingRequest,
9+
MappingResponse,
10+
Mappings,
11+
)
12+
13+
14+
@pytest.mark.unit
15+
@pytest.mark.mappings
16+
@pytest.mark.resource
17+
@responses.activate
18+
def test_create_mapping():
19+
e = MappingResponse(body="test", status=200)
20+
resp = e.get_json_data()
21+
responses.add(
22+
responses.POST, "http://localhost/__admin/mappings", json=resp, status=200
23+
)
24+
25+
m = Mapping(
26+
priority=1,
27+
request=MappingRequest(url="test", method="GET"),
28+
response=MappingResponse(status=200, body="test"),
29+
)
30+
31+
r = Mappings.create_mapping(m)
32+
assert isinstance(r, MappingResponse)
33+
assert r.status == 200
34+
assert r.body == "test"
35+
36+
37+
@pytest.mark.unit
38+
@pytest.mark.mappings
39+
@pytest.mark.resource
40+
@responses.activate
41+
def test_retrieve_all_mappings():
42+
e = AllMappings(
43+
mappings=[
44+
Mapping(id="1234-5678", priority=1),
45+
],
46+
meta=MappingMeta(total=1),
47+
)
48+
resp = e.get_json_data()
49+
responses.add(
50+
responses.GET,
51+
"http://localhost/__admin/mappings",
52+
json=resp,
53+
status=200,
54+
)
55+
56+
r = Mappings.retrieve_all_mappings()
57+
assert isinstance(r, AllMappings)
58+
assert isinstance(r.meta, MappingMeta)
59+
assert 1 == r.meta.total
60+
61+
62+
@pytest.mark.unit
63+
@pytest.mark.mappings
64+
@pytest.mark.resource
65+
@responses.activate
66+
def test_retrieve_mapping():
67+
e = Mapping(id="1234-5678", priority=1)
68+
resp = e.get_json_data()
69+
responses.add(
70+
responses.GET,
71+
"http://localhost/__admin/mappings/1234-5678",
72+
json=resp,
73+
status=200,
74+
)
75+
76+
r = Mappings.retrieve_mapping(e)
77+
assert isinstance(r, Mapping)
78+
assert "1234-5678" == r.id
79+
assert 1 == r.priority
80+
81+
82+
@pytest.mark.unit
83+
@pytest.mark.mappings
84+
@pytest.mark.resource
85+
@responses.activate
86+
def test_update_mapping():
87+
e = Mapping(id="1234-5678", priority=1)
88+
resp = e.get_json_data()
89+
responses.add(
90+
responses.PUT,
91+
"http://localhost/__admin/mappings/1234-5678",
92+
json=resp,
93+
status=200,
94+
)
95+
96+
r = Mappings.update_mapping(e)
97+
assert isinstance(r, Mapping)
98+
assert "1234-5678" == r.id
99+
assert 1 == r.priority
100+
101+
102+
@pytest.mark.unit
103+
@pytest.mark.mappings
104+
@pytest.mark.resource
105+
@responses.activate
106+
def test_persist_mappings():
107+
responses.add(
108+
responses.POST,
109+
"http://localhost/__admin/mappings/save",
110+
body="",
111+
status=200,
112+
)
113+
114+
r = Mappings.persist_mappings()
115+
assert r.status_code == 200
116+
117+
118+
@pytest.mark.unit
119+
@pytest.mark.mappings
120+
@pytest.mark.resource
121+
@responses.activate
122+
def test_reset_mappings():
123+
responses.add(
124+
responses.POST,
125+
"http://localhost/__admin/mappings/reset",
126+
body="",
127+
status=200,
128+
)
129+
130+
r = Mappings.reset_mappings()
131+
assert r.status_code == 200
132+
133+
134+
@pytest.mark.unit
135+
@pytest.mark.mappings
136+
@pytest.mark.resource
137+
@responses.activate
138+
def test_delete_all_mappings():
139+
responses.add(
140+
responses.DELETE,
141+
"http://localhost/__admin/mappings",
142+
body="",
143+
status=200,
144+
)
145+
146+
r = Mappings.delete_all_mappings()
147+
assert r.status_code == 200
148+
149+
150+
@pytest.mark.unit
151+
@pytest.mark.mappings
152+
@pytest.mark.resource
153+
@responses.activate
154+
def test_delete_mapping():
155+
e = Mapping(id="1234-5678", priority=1)
156+
responses.add(
157+
responses.DELETE,
158+
"http://localhost/__admin/mappings/1234-5678",
159+
body="",
160+
status=200,
161+
)
162+
163+
r = Mappings.delete_mapping(e)
164+
assert r.status_code == 200
165+
166+
167+
@pytest.mark.unit
168+
@pytest.mark.mappings
169+
@pytest.mark.resource
170+
@responses.activate
171+
def test_delete_mapping_by_metadata():
172+
responses.add(
173+
responses.POST,
174+
"http://localhost/__admin/mappings/remove-by-metadata",
175+
body="{}",
176+
status=200,
177+
)
178+
179+
r = Mappings.delete_mapping_by_metadata(
180+
{
181+
"matchesJsonPath": {
182+
"expression": "$.some.key",
183+
"equalTo": "SomeValue",
184+
},
185+
}
186+
)
187+
188+
assert r.status_code == 200

0 commit comments

Comments
 (0)