Skip to content

Commit 6cdbfa2

Browse files
committed
SDK-1076: Update SignedRequest and SignedRequestBuilder with payload function, and write unit tests
1 parent 2b1d4cb commit 6cdbfa2

File tree

2 files changed

+266
-13
lines changed

2 files changed

+266
-13
lines changed

yoti_python_sdk/http.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
import uuid
1515
import time
1616

17-
try:
17+
try: # pragma: no cover
1818
from urllib.parse import urlencode
19-
except ImportError:
19+
except ImportError: # pragma: no cover
2020
from urlparse import urlencode
2121

2222
HTTP_POST = "POST"
@@ -70,11 +70,11 @@ def prepare(self):
7070

7171
def execute(self):
7272
"""
73-
Creates and sends a PreparedRequest in a requests Session, returning the requests Response object
73+
Send the signed request, returning the requests Response object
7474
"""
75-
prepared = self.prepare()
76-
with requests.Session() as s:
77-
return s.send(prepared)
75+
return requests.request(
76+
url=self.url, method=self.method, data=self.data, headers=self.headers
77+
)
7878

7979
@staticmethod
8080
def builder():
@@ -120,6 +120,13 @@ def with_endpoint(self, endpoint):
120120
self.__endpoint = endpoint
121121
return self
122122

123+
def with_payload(self, payload):
124+
"""
125+
Sets the payload for the signed request. Must be a valid JSON string
126+
"""
127+
self.__payload = payload
128+
return self
129+
123130
def with_param(self, name, value):
124131
"""
125132
Sets a query param to be used with the endpoint
@@ -144,6 +151,9 @@ def with_http_method(self, http_method):
144151
"""
145152
Sets the HTTP method to be used in the request
146153
"""
154+
if http_method not in HTTP_SUPPORTED_METHODS:
155+
raise ValueError("{} is an unsupported HTTP method".format(http_method))
156+
147157
self.__http_method = http_method
148158
return self
149159

@@ -158,7 +168,7 @@ def with_get(self):
158168
"""
159169
Sets the HTTP method for a GET request
160170
"""
161-
self.__http_method = HTTP_GET
171+
self.with_http_method(HTTP_GET)
162172
return self
163173

164174
def __append_query_params(self, query_params=None):
@@ -216,12 +226,6 @@ def __create_request(http_method, path, content):
216226
:param content:
217227
:return:
218228
"""
219-
if http_method not in HTTP_SUPPORTED_METHODS:
220-
raise ValueError(
221-
"{} is not in the list of supported methods: {}".format(
222-
http_method, HTTP_SUPPORTED_METHODS
223-
)
224-
)
225229

226230
request = "{}&{}".format(http_method, path)
227231

yoti_python_sdk/tests/test_http.py

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
try:
2+
from unittest import mock
3+
except ImportError:
4+
import mock
5+
6+
from yoti_python_sdk.http import SignedRequest
7+
from yoti_python_sdk.crypto import Crypto
8+
from yoti_python_sdk.tests import conftest
9+
from requests import PreparedRequest
10+
11+
from yoti_python_sdk.tests.mocks import mocked_requests_get
12+
13+
import pytest
14+
import json
15+
16+
17+
@pytest.fixture(scope="module")
18+
def json_payload():
19+
payload = {"Hello": "World"}
20+
return json.dumps(payload).encode()
21+
22+
23+
@pytest.fixture(scope="module")
24+
def valid_base_url():
25+
return "https://localhost:8443/api/v1"
26+
27+
28+
@pytest.fixture(scope="module")
29+
def valid_endpoint():
30+
return "/profile"
31+
32+
33+
@pytest.fixture(scope="module")
34+
def expected_request_headers():
35+
return ["X-Yoti-Auth-Key", "X-Yoti-Auth-Digest", "X-Yoti-SDK", "X-Yoti-SDK-Version"]
36+
37+
38+
def test_create_signed_request_get_required_properties(
39+
valid_base_url, valid_endpoint, expected_request_headers
40+
):
41+
http_method = "GET"
42+
43+
signed_request = (
44+
SignedRequest.builder()
45+
.with_pem_file(conftest.PEM_FILE_PATH)
46+
.with_base_url(valid_base_url)
47+
.with_endpoint(valid_endpoint)
48+
.with_http_method(http_method)
49+
.build()
50+
)
51+
52+
assert (valid_base_url + valid_endpoint) in signed_request.url
53+
assert signed_request.method == http_method
54+
assert signed_request.data is None
55+
56+
header_keys = signed_request.headers.keys()
57+
for header in expected_request_headers:
58+
assert header in header_keys
59+
60+
61+
def test_create_signed_request_missing_pem_file(valid_base_url, valid_endpoint):
62+
http_method = "GET"
63+
64+
with pytest.raises(ValueError) as ex:
65+
(
66+
SignedRequest.builder()
67+
.with_base_url(valid_base_url)
68+
.with_endpoint(valid_endpoint)
69+
.with_http_method(http_method)
70+
.build()
71+
)
72+
73+
assert "PEM file" in str(ex.value)
74+
75+
76+
def test_create_signed_request_missing_base_url(valid_endpoint):
77+
http_method = "GET"
78+
79+
with pytest.raises(ValueError) as ex:
80+
(
81+
SignedRequest.builder()
82+
.with_pem_file(conftest.PEM_FILE_PATH)
83+
.with_endpoint(valid_endpoint)
84+
.with_http_method(http_method)
85+
.build()
86+
)
87+
88+
assert "Base URL" in str(ex.value)
89+
90+
91+
def test_create_signed_request_missing_endpoint(valid_base_url):
92+
http_method = "GET"
93+
94+
with pytest.raises(ValueError) as ex:
95+
(
96+
SignedRequest.builder()
97+
.with_pem_file(conftest.PEM_FILE_PATH)
98+
.with_base_url(valid_base_url)
99+
.with_http_method(http_method)
100+
.build()
101+
)
102+
103+
assert "Endpoint" in str(ex.value)
104+
105+
106+
def test_create_signed_request_missing_http_method(valid_base_url, valid_endpoint):
107+
with pytest.raises(ValueError) as ex:
108+
(
109+
SignedRequest.builder()
110+
.with_pem_file(conftest.PEM_FILE_PATH)
111+
.with_base_url(valid_base_url)
112+
.with_endpoint(valid_endpoint)
113+
.build()
114+
)
115+
116+
assert "HTTP method" in str(ex.value)
117+
118+
119+
def test_create_signed_request_with_invalid_http_method():
120+
121+
with pytest.raises(ValueError) as ex:
122+
SignedRequest.builder().with_http_method("INVALID").build()
123+
124+
assert str(ex.value) == "INVALID is an unsupported HTTP method"
125+
126+
127+
def test_create_signed_request_with_payload(
128+
valid_base_url, valid_endpoint, json_payload
129+
):
130+
http_method = "POST"
131+
132+
signed_request = (
133+
SignedRequest.builder()
134+
.with_pem_file(conftest.PEM_FILE_PATH)
135+
.with_base_url(valid_base_url)
136+
.with_endpoint(valid_endpoint)
137+
.with_http_method(http_method)
138+
.with_payload(json_payload)
139+
.build()
140+
)
141+
142+
assert signed_request.data == json_payload
143+
144+
145+
def test_create_signed_request_with_header(valid_base_url, valid_endpoint):
146+
http_method = "POST"
147+
148+
signed_request = (
149+
SignedRequest.builder()
150+
.with_pem_file(conftest.PEM_FILE_PATH)
151+
.with_base_url(valid_base_url)
152+
.with_endpoint(valid_endpoint)
153+
.with_http_method(http_method)
154+
.with_header("My-Http-Header", "someValue")
155+
.build()
156+
)
157+
158+
headers = signed_request.headers
159+
160+
assert "My-Http-Header" in headers
161+
assert headers["My-Http-Header"] == "someValue"
162+
163+
164+
def test_create_signed_request_with_query_param(valid_base_url, valid_endpoint):
165+
http_method = "POST"
166+
167+
signed_request = (
168+
SignedRequest.builder()
169+
.with_pem_file(conftest.PEM_FILE_PATH)
170+
.with_base_url(valid_base_url)
171+
.with_endpoint(valid_endpoint)
172+
.with_http_method(http_method)
173+
.with_param("sdkId", "mySdkId")
174+
.build()
175+
)
176+
177+
assert "sdkId=mySdkId" in signed_request.url
178+
179+
180+
def test_create_signed_request_with_crypto_object(valid_base_url, valid_endpoint):
181+
http_method = "GET"
182+
crypto = Crypto.read_pem_file(conftest.PEM_FILE_PATH)
183+
184+
(
185+
SignedRequest.builder()
186+
.with_pem_file(crypto)
187+
.with_base_url(valid_base_url)
188+
.with_endpoint(valid_endpoint)
189+
.with_http_method(http_method)
190+
.build()
191+
)
192+
193+
194+
def test_create_signed_request_with_get_convenience_method(
195+
valid_base_url, valid_endpoint
196+
):
197+
(
198+
SignedRequest.builder()
199+
.with_pem_file(conftest.PEM_FILE_PATH)
200+
.with_base_url(valid_base_url)
201+
.with_endpoint(valid_endpoint)
202+
.with_get()
203+
.build()
204+
)
205+
206+
207+
def test_create_signed_request_with_post_convenience_method(
208+
valid_base_url, valid_endpoint, json_payload
209+
):
210+
(
211+
SignedRequest.builder()
212+
.with_pem_file(conftest.PEM_FILE_PATH)
213+
.with_base_url(valid_base_url)
214+
.with_endpoint(valid_endpoint)
215+
.with_post()
216+
.with_payload(json_payload)
217+
.build()
218+
)
219+
220+
221+
def test_create_prepared_request_from_signed_request(valid_base_url, valid_endpoint):
222+
signed_request = (
223+
SignedRequest.builder()
224+
.with_pem_file(conftest.PEM_FILE_PATH)
225+
.with_base_url(valid_base_url)
226+
.with_endpoint(valid_endpoint)
227+
.with_post()
228+
.build()
229+
)
230+
231+
prepared_request = signed_request.prepare()
232+
assert isinstance(prepared_request, PreparedRequest)
233+
234+
235+
@mock.patch("requests.request", side_effect=mocked_requests_get)
236+
def test_execute_signed_request(valid_base_url, valid_endpoint):
237+
signed_request = (
238+
SignedRequest.builder()
239+
.with_pem_file(conftest.PEM_FILE_PATH)
240+
.with_base_url(valid_base_url)
241+
.with_endpoint(valid_endpoint)
242+
.with_post()
243+
.build()
244+
)
245+
246+
response = signed_request.execute()
247+
248+
assert response.status_code == 200
249+
assert response.text is not None

0 commit comments

Comments
 (0)