Skip to content

Commit 013f37d

Browse files
committed
Record tests for replay in CI
All tests will now be recorded to let it run in CI without interaction with a real phpIPAM instance. For that we import `vcr` in all and `pytest` in some test cases. Each test get a `vcr.use_casssette` decorator to save the cassette as expected. In `conftest` we define some methods to sanitize the recordings and one method to create the cassette name.
1 parent 7a42586 commit 013f37d

30 files changed

+2401
-20
lines changed

tests/__init__.py

Whitespace-only changes.

tests/conftest.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
"""Provide some base configurations for tests."""
2+
import inspect
3+
import pytest
4+
import py.path
5+
import re
6+
from urllib.parse import urlparse, urlunparse
7+
8+
TEST_CASES_PATH = py.path.local(__file__).realpath() / '..' / 'test_cases'
9+
10+
11+
def find_all_test_cases():
12+
"""Generate list of test cases.
13+
14+
:yield: generates each test case as list item
15+
:rtype: str
16+
"""
17+
for c in TEST_CASES_PATH.listdir(sort=True):
18+
c = c.basename
19+
if c.endswith('.py'):
20+
yield c.replace('.py', '')
21+
22+
23+
TEST_CASES = list(find_all_test_cases())
24+
25+
26+
def pytest_addoption(parser):
27+
"""Change command line options defaults.
28+
29+
We want run our tests only in three modes
30+
`live` - interact with an existing API
31+
`record` - interact with an existing API and record the interactions
32+
`replay` - replay previouly recorded interactions with API
33+
34+
:param parser: A parser object
35+
:type parser: object parser
36+
"""
37+
parser.addoption(
38+
"--vcrmode",
39+
action="store",
40+
default="replay",
41+
choices=["replay", "record", "live"],
42+
help="mode for vcr recording; one of ['replay', 'record', 'live']",
43+
)
44+
45+
46+
@pytest.fixture
47+
def vcrmode(request):
48+
"""Return vcrmode of a request.
49+
50+
:param request: A request object
51+
:type request: object request
52+
:return: vcrmode
53+
:rtype: str
54+
"""
55+
return request.config.getoption("vcrmode")
56+
57+
58+
def cassette_name(test_name=None):
59+
"""Generate cassette_name."""
60+
return 'tests/fixtures/{0}.yml'.format(test_name)
61+
62+
63+
FILTER_REQUEST_HEADERS = ['Authorization', 'Cookie', 'Token']
64+
FILTER_RESPONSE_HEADERS = ['Apipie-Checksum', 'Date', 'ETag', 'Server', 'Set-Cookie', 'Via', 'X-Powered-By', 'X-Request-Id', 'X-Runtime']
65+
66+
67+
def filter_response(response):
68+
"""Filter headers before recording.
69+
70+
:param response: A response object where we want to filter the headers from.
71+
:type response: object response
72+
:return: response
73+
:rtype: object response
74+
"""
75+
for header in FILTER_RESPONSE_HEADERS:
76+
# headers should be case insensitive, but for some reason they weren't for me
77+
response['headers'].pop(header.lower(), None)
78+
response['headers'].pop(header, None)
79+
80+
return response
81+
82+
83+
def filter_request_uri(request):
84+
"""Filter uri before recording.
85+
86+
:param request: A request object where we want to filter the uri from.
87+
:type request: object request
88+
:return: request
89+
:rtype: object request
90+
"""
91+
request.uri = urlunparse(urlparse(request.uri)._replace(netloc="ipam.example.org"))
92+
return request
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
interactions:
2+
- request:
3+
body: null
4+
headers:
5+
Accept:
6+
- '*/*'
7+
Accept-Encoding:
8+
- gzip, deflate
9+
Connection:
10+
- keep-alive
11+
Content-Length:
12+
- '0'
13+
User-Agent:
14+
- python-requests/2.24.0
15+
method: POST
16+
uri: https://ipam.example.org/api/ansible/user
17+
response:
18+
body:
19+
string: !!binary |
20+
H4sIAAAAAAAAAw3NTQqDMBAG0KuUb53IZCpCZt/SXaF/CzciySxsUYuJVBDvXg/weCvCGBXCRAZp
21+
DkFTguRpVoPY5hayIo8fHSBIL+tPzfXyvoVnPZw12uV3rx4eBrp8u0l3CSYm65yl8sAkRy9cYjPI
22+
Xb8vVJDb/o6954ZzAAAA
23+
headers:
24+
Cache-Control:
25+
- no-cache
26+
Connection:
27+
- Keep-Alive
28+
Content-Encoding:
29+
- gzip
30+
Content-Type:
31+
- application/json; charset=utf-8
32+
Date:
33+
- Wed, 04 Nov 2020 13:39:24 GMT
34+
Expires:
35+
- Thu, 19 Nov 1981 08:52:00 GMT
36+
Keep-Alive:
37+
- timeout=5, max=100
38+
Pragma:
39+
- no-cache
40+
Server:
41+
- Apache/2.4.37 (centos) OpenSSL/1.1.1c
42+
Set-Cookie:
43+
- phpipam=rtcrr3al96v1m7oro2vnsc0lc4; expires=Thu, 05-Nov-2020 13:39:24 GMT;
44+
Max-Age=86400; path=/; HttpOnly
45+
Transfer-Encoding:
46+
- chunked
47+
Vary:
48+
- Accept-Encoding
49+
X-Powered-By:
50+
- PHP/7.2.24
51+
status:
52+
code: 200
53+
message: OK
54+
- request:
55+
body: null
56+
headers:
57+
Accept:
58+
- '*/*'
59+
Accept-Encoding:
60+
- gzip, deflate
61+
Connection:
62+
- keep-alive
63+
User-Agent:
64+
- python-requests/2.24.0
65+
method: GET
66+
uri: https://ipam.example.org/api/ansible/addresses/search/10.10.0.4
67+
response:
68+
body:
69+
string: !!binary |
70+
H4sIAAAAAAAAA6tWSs5PSVWyMjIw0FEqLk1OTi0uVrJKS8wpTtVRygVyEtOBskqOKSlFQI5CXn6J
71+
Qlp+aV6Kko5SSWYuUMpAz8DAtBYAByXdEUcAAAA=
72+
headers:
73+
Cache-Control:
74+
- no-cache
75+
Connection:
76+
- Keep-Alive
77+
Content-Encoding:
78+
- gzip
79+
Content-Type:
80+
- application/json; charset=utf-8
81+
Date:
82+
- Wed, 04 Nov 2020 13:39:24 GMT
83+
Expires:
84+
- Thu, 19 Nov 1981 08:52:00 GMT
85+
Keep-Alive:
86+
- timeout=5, max=100
87+
Pragma:
88+
- no-cache
89+
Server:
90+
- Apache/2.4.37 (centos) OpenSSL/1.1.1c
91+
Set-Cookie:
92+
- phpipam=vl2d6ijho4ddb26e964bhfd8gn; expires=Thu, 05-Nov-2020 13:39:24 GMT;
93+
Max-Age=86400; path=/; HttpOnly
94+
Transfer-Encoding:
95+
- chunked
96+
Vary:
97+
- Accept-Encoding
98+
X-Powered-By:
99+
- PHP/7.2.24
100+
status:
101+
code: 200
102+
message: OK
103+
version: 1
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
interactions:
2+
- request:
3+
body: null
4+
headers:
5+
Accept:
6+
- '*/*'
7+
Accept-Encoding:
8+
- gzip, deflate
9+
Connection:
10+
- keep-alive
11+
Content-Length:
12+
- '0'
13+
User-Agent:
14+
- python-requests/2.24.0
15+
method: POST
16+
uri: https://ipam.example.org/api/ansible/user
17+
response:
18+
body:
19+
string: !!binary |
20+
H4sIAAAAAAAAA6tWSs5PSVWyMjUw0FEqLk1OTi0uVrJKS8wpTtVRygVyEtOBskqeeWWJOZkpCqXF
21+
qUV5ibmpCvlFCgWJxcXl+UUpSjpKJZm5QFUGegYG5rUApmB0WFIAAAA=
22+
headers:
23+
Cache-Control:
24+
- no-cache
25+
Connection:
26+
- close
27+
Content-Encoding:
28+
- gzip
29+
Content-Type:
30+
- application/json; charset=utf-8
31+
Date:
32+
- Wed, 04 Nov 2020 13:39:17 GMT
33+
Expires:
34+
- Thu, 19 Nov 1981 08:52:00 GMT
35+
Pragma:
36+
- no-cache
37+
Server:
38+
- Apache/2.4.37 (centos) OpenSSL/1.1.1c
39+
Set-Cookie:
40+
- phpipam=ushkqmr1t9bhu636sohm3qjdmg; expires=Thu, 05-Nov-2020 13:39:17 GMT;
41+
Max-Age=86400; path=/; HttpOnly
42+
Transfer-Encoding:
43+
- chunked
44+
Vary:
45+
- Accept-Encoding
46+
X-Powered-By:
47+
- PHP/7.2.24
48+
status:
49+
code: 500
50+
message: Internal Server Error
51+
- request:
52+
body: null
53+
headers:
54+
Accept:
55+
- '*/*'
56+
Accept-Encoding:
57+
- gzip, deflate
58+
Connection:
59+
- keep-alive
60+
Content-Length:
61+
- '0'
62+
User-Agent:
63+
- python-requests/2.24.0
64+
method: POST
65+
uri: https://ipam.example.org/api/ansible/user
66+
response:
67+
body:
68+
string: !!binary |
69+
H4sIAAAAAAAAA6tWSs5PSVWyMjUw0FEqLk1OTi0uVrJKS8wpTtVRygVyEtOBskqeeWWJOZkpCqXF
70+
qUV5ibmpCvlFCgWJxcXl+UUpSjpKJZm5QFUGegYGprUAJAJCalIAAAA=
71+
headers:
72+
Cache-Control:
73+
- no-cache
74+
Connection:
75+
- close
76+
Content-Encoding:
77+
- gzip
78+
Content-Type:
79+
- application/json; charset=utf-8
80+
Date:
81+
- Wed, 04 Nov 2020 13:39:17 GMT
82+
Expires:
83+
- Thu, 19 Nov 1981 08:52:00 GMT
84+
Pragma:
85+
- no-cache
86+
Server:
87+
- Apache/2.4.37 (centos) OpenSSL/1.1.1c
88+
Set-Cookie:
89+
- phpipam=tpi619vqreehocgqhe8b0fe9fe; expires=Thu, 05-Nov-2020 13:39:17 GMT;
90+
Max-Age=86400; path=/; HttpOnly
91+
Transfer-Encoding:
92+
- chunked
93+
Vary:
94+
- Accept-Encoding
95+
X-Powered-By:
96+
- PHP/7.2.24
97+
status:
98+
code: 500
99+
message: Internal Server Error
100+
version: 1
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
interactions:
2+
- request:
3+
body: null
4+
headers:
5+
Accept:
6+
- '*/*'
7+
Accept-Encoding:
8+
- gzip, deflate
9+
Connection:
10+
- keep-alive
11+
Content-Length:
12+
- '0'
13+
User-Agent:
14+
- python-requests/2.24.0
15+
method: POST
16+
uri: https://ipam.example.org/api/ansible/user
17+
response:
18+
body:
19+
string: !!binary |
20+
H4sIAAAAAAAAAw3NSwrCMBQF0K3IHSdyE8WSN1ecCf4GTqQkb1DFVpoUC6V7tws4nAmxSwrxpEEe
21+
YtScIaUf1CDVpYZMKN1bWwjy3Yb983R8nePt0R402fF32V0DDHT8Nr0uEp6e1jnL7cpTNkFchdmg
22+
NJ9l4Zqs5j/I4HhEdAAAAA==
23+
headers:
24+
Cache-Control:
25+
- no-cache
26+
Connection:
27+
- Keep-Alive
28+
Content-Encoding:
29+
- gzip
30+
Content-Type:
31+
- application/json; charset=utf-8
32+
Date:
33+
- Wed, 04 Nov 2020 13:39:17 GMT
34+
Expires:
35+
- Thu, 19 Nov 1981 08:52:00 GMT
36+
Keep-Alive:
37+
- timeout=5, max=100
38+
Pragma:
39+
- no-cache
40+
Server:
41+
- Apache/2.4.37 (centos) OpenSSL/1.1.1c
42+
Set-Cookie:
43+
- phpipam=1a4mihglov6rns984mldh8nhdi; expires=Thu, 05-Nov-2020 13:39:17 GMT;
44+
Max-Age=86400; path=/; HttpOnly
45+
Transfer-Encoding:
46+
- chunked
47+
Vary:
48+
- Accept-Encoding
49+
X-Powered-By:
50+
- PHP/7.2.24
51+
status:
52+
code: 200
53+
message: OK
54+
version: 1

0 commit comments

Comments
 (0)