Skip to content

Commit e181205

Browse files
authored
Merge pull request #49 from cloudblue/testing_tools
Add testing tools and move to mkdocs.
2 parents 3f40bfc + 6313817 commit e181205

35 files changed

Lines changed: 2088 additions & 1650 deletions

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ jobs:
5252
run: |
5353
python -m pip install --upgrade pip
5454
pip install poetry
55-
poetry install
55+
poetry install --no-root
5656
- name: Testing
5757
run: |
5858
poetry run pytest

.github/workflows/deploy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
run: |
1818
python -m pip install --upgrade pip
1919
pip install poetry
20-
poetry install
20+
poetry install --no-root
2121
- name: Linting
2222
run: |
2323
poetry run flake8

.readthedocs.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Required
2+
version: 2
3+
4+
build:
5+
os: ubuntu-20.04
6+
tools:
7+
python: "3.9"
8+
9+
mkdocs:
10+
configuration: mkdocs.yml
11+
12+
python:
13+
install:
14+
- requirements: requirements/docs.txt
15+
- method: pip
16+
path: .

connect/client/testing/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#
2+
# This file is part of the Ingram Micro CloudBlue Connect Python OpenAPI Client.
3+
#
4+
# Copyright (c) 2021 Ingram Micro. All Rights Reserved.
5+
#
6+
from connect.client.testing.fluent import AsyncConnectClientMocker, ConnectClientMocker # noqa

connect/client/testing/fixtures.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import pytest
2+
3+
from connect.client.testing import AsyncConnectClientMocker, ConnectClientMocker
4+
5+
6+
@pytest.fixture
7+
def client_mocker_factory(request):
8+
mocker = None
9+
10+
def _wrapper(base_url='http://localhost'):
11+
mocker = ConnectClientMocker(base_url)
12+
mocker.start()
13+
return mocker
14+
15+
def _finalizer():
16+
if mocker: # pragma: no cover
17+
mocker.reset()
18+
19+
request.addfinalizer(_finalizer)
20+
return _wrapper
21+
22+
23+
@pytest.fixture
24+
def async_client_mocker_factory(request):
25+
mocker = None
26+
27+
def _wrapper(base_url='http://localhost'):
28+
mocker = AsyncConnectClientMocker(base_url)
29+
mocker.start()
30+
return mocker
31+
32+
def _finalizer():
33+
if mocker: # pragma: no cover
34+
mocker.reset()
35+
36+
request.addfinalizer(_finalizer)
37+
return _wrapper

connect/client/testing/fluent.py

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
#
2+
# This file is part of the Ingram Micro CloudBlue Connect Python OpenAPI Client.
3+
#
4+
# Copyright (c) 2021 Ingram Micro. All Rights Reserved.
5+
#
6+
import httpx
7+
8+
import responses
9+
10+
from pytest import MonkeyPatch
11+
12+
from pytest_httpx import HTTPXMock
13+
from pytest_httpx._httpx_mock import _PytestAsyncTransport
14+
15+
from connect.client.fluent import _ConnectClientBase
16+
from connect.client.testing.models import CollectionMock, NSMock
17+
18+
19+
class ConnectClientMocker(_ConnectClientBase):
20+
def __init__(self, base_url):
21+
super().__init__('api_key', endpoint=base_url)
22+
self._mocker = responses.RequestsMock()
23+
24+
def get(
25+
self,
26+
url,
27+
status_code=200,
28+
return_value=None,
29+
headers=None,
30+
):
31+
return self.mock(
32+
'get',
33+
url,
34+
status_code=status_code,
35+
return_value=return_value,
36+
headers=headers,
37+
)
38+
39+
def create(
40+
self,
41+
url,
42+
status_code=201,
43+
return_value=None,
44+
headers=None,
45+
):
46+
47+
return self.mock(
48+
'post',
49+
url,
50+
status_code=status_code,
51+
return_value=return_value,
52+
headers=headers,
53+
)
54+
55+
def update(
56+
self,
57+
url,
58+
status_code=201,
59+
return_value=None,
60+
headers=None,
61+
):
62+
63+
return self.mock(
64+
'put',
65+
url,
66+
status_code=status_code,
67+
return_value=return_value,
68+
headers=headers,
69+
)
70+
71+
def delete(
72+
self,
73+
url,
74+
status_code=204,
75+
return_value=None,
76+
headers=None,
77+
):
78+
79+
return self.mock(
80+
'delete',
81+
url,
82+
status_code=status_code,
83+
return_value=return_value,
84+
headers=headers,
85+
)
86+
87+
def mock(
88+
self,
89+
method,
90+
path,
91+
status_code=200,
92+
return_value=None,
93+
headers=None,
94+
):
95+
url = f'{self.endpoint}/{path}'
96+
97+
kwargs = {
98+
'method': method.upper(),
99+
'url': url,
100+
'status': status_code,
101+
'headers': headers,
102+
}
103+
104+
if isinstance(return_value, (dict, list, tuple)):
105+
kwargs['json'] = return_value
106+
else:
107+
kwargs['body'] = return_value
108+
109+
self._mocker.add(**kwargs)
110+
111+
def start(self):
112+
self._mocker.start()
113+
114+
def reset(self, success=True):
115+
self._mocker.stop(allow_assert=success)
116+
self._mocker.reset()
117+
118+
def __enter__(self):
119+
self.start()
120+
return self
121+
122+
def __exit__(self, exc_type, value, traceback):
123+
self.reset(success=exc_type is None)
124+
125+
def _get_collection_class(self):
126+
return CollectionMock
127+
128+
def _get_namespace_class(self):
129+
return NSMock
130+
131+
132+
class AsyncConnectClientMocker(ConnectClientMocker):
133+
def __init__(self, base_url):
134+
super().__init__(base_url)
135+
self._monkeypatch = None
136+
self._mocker = None
137+
138+
def start(self):
139+
self._monkeypatch = MonkeyPatch()
140+
self._mocker = HTTPXMock()
141+
142+
mocker = self._mocker
143+
144+
self._monkeypatch.setattr(
145+
httpx.AsyncClient,
146+
'_transport_for_url',
147+
lambda self, url: _PytestAsyncTransport(mocker),
148+
)
149+
150+
def reset(self, success=True):
151+
self._mocker.reset(success)
152+
self._monkeypatch.undo()
153+
self._mocker = None
154+
self._monkeypatch = None
155+
156+
def mock(
157+
self,
158+
method,
159+
path,
160+
status_code=200,
161+
return_value=None,
162+
headers=None,
163+
):
164+
url = f'{self.endpoint}/{path}'
165+
166+
kwargs = {
167+
'method': method.upper(),
168+
'url': url,
169+
'status_code': status_code,
170+
'headers': headers,
171+
}
172+
173+
if isinstance(return_value, (dict, list, tuple)):
174+
kwargs['json'] = return_value
175+
else:
176+
kwargs['content'] = return_value.encode() if return_value else None
177+
178+
self._mocker.add_response(**kwargs)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#
2+
# This file is part of the Ingram Micro CloudBlue Connect Python OpenAPI Client.
3+
#
4+
# Copyright (c) 2021 Ingram Micro. All Rights Reserved.
5+
#
6+
from connect.client.testing.models.base import ( # noqa
7+
ActionMock,
8+
CollectionMock,
9+
NSMock,
10+
ResourceMock,
11+
)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#
2+
# This file is part of the Ingram Micro CloudBlue Connect Python OpenAPI Client.
3+
#
4+
# Copyright (c) 2021 Ingram Micro. All Rights Reserved.
5+
#
6+
from connect.client.models.base import _ActionBase, _CollectionBase, _NSBase, _ResourceBase
7+
from connect.client.testing.models.mixins import (
8+
ActionMixin,
9+
CollectionMixin,
10+
ResourceMixin,
11+
)
12+
from connect.client.testing.models.resourceset import ResourceSetMock
13+
14+
15+
class NSMock(_NSBase):
16+
def _get_collection_class(self):
17+
return CollectionMock
18+
19+
def _get_namespace_class(self):
20+
return NSMock
21+
22+
23+
class CollectionMock(_CollectionBase, CollectionMixin):
24+
def _get_resource_class(self):
25+
return ResourceMock
26+
27+
def _get_resourceset_class(self):
28+
return ResourceSetMock
29+
30+
def _get_action_class(self):
31+
return ActionMock
32+
33+
34+
class ResourceMock(_ResourceBase, ResourceMixin):
35+
def _get_collection_class(self):
36+
return CollectionMock
37+
38+
def _get_action_class(self):
39+
return ActionMock
40+
41+
42+
class ActionMock(_ActionBase, ActionMixin):
43+
pass

0 commit comments

Comments
 (0)