From 311e608f61d4709b524363f66285b0b1e1593005 Mon Sep 17 00:00:00 2001 From: James Quartly Date: Tue, 15 Mar 2022 22:13:03 +0000 Subject: [PATCH 1/3] Add a timeout to HTTP POST connects and reads Both timeout are hardcoded to 10 seconds. Later commits will make this configurable. This doesn't put a timeout around _all_ of the HTTP POST requests in the codebase. --- reportportal_client/service.py | 23 +++++++++++++++++++---- tests/test_service.py | 8 ++++++-- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/reportportal_client/service.py b/reportportal_client/service.py index 32cca95a..6a5060d1 100644 --- a/reportportal_client/service.py +++ b/reportportal_client/service.py @@ -190,6 +190,7 @@ def __init__(self, self.is_skipped_an_issue = is_skipped_an_issue self.base_url_v1 = uri_join(self.endpoint, "api/v1", self.project) self.base_url_v2 = uri_join(self.endpoint, "api/v2", self.project) + self.post_timeout = (10, 10) self.session = requests.Session() if retries: @@ -228,7 +229,13 @@ def start_launch(self, "rerunOf": rerunOf } url = uri_join(self.base_url_v2, "launch") - r = self.session.post(url=url, json=data, verify=self.verify_ssl) + r = self.session.request( + method='POST', + url=url, + json=data, + verify=self.verify_ssl, + timeout=self.post_timeout + ) self.launch_id = _get_id(r) logger.debug("start_launch - ID: %s", self.launch_id) return self.launch_id @@ -354,7 +361,13 @@ def start_test_item(self, url = uri_join(self.base_url_v2, "item", parent_item_id) else: url = uri_join(self.base_url_v2, "item") - r = self.session.post(url=url, json=data, verify=self.verify_ssl) + r = self.session.request( + method='POST', + url=url, + json=data, + verify=self.verify_ssl, + timeout=self.post_timeout + ) item_id = _get_id(r) logger.debug("start_test_item - ID: %s", item_id) @@ -508,10 +521,12 @@ def _log_batch(self, log_data, force=False): files.extend(attachments) for i in range(POST_LOGBATCH_RETRY_COUNT): try: - r = self.session.post( + r = self.session.request( + method='POST', url=url, files=files, - verify=self.verify_ssl + verify=self.verify_ssl, + timeout=self.post_timeout ) logger.debug("log_batch response: %s", r.text) self._batch_logs = [] diff --git a/tests/test_service.py b/tests/test_service.py index f942e3a1..fbe63f1d 100644 --- a/tests/test_service.py +++ b/tests/test_service.py @@ -254,9 +254,11 @@ def test_start_item(self, rp_service): 'codeRef': None, 'testCaseId': None}, url='http://endpoint/api/v2/project/item', + method='POST', + timeout=(10, 10), verify=True) - rp_service.session.post.assert_called_with(**expected_result) + rp_service.session.request.assert_called_with(**expected_result) assert rp_start == 123 start_item_optional = [ @@ -299,6 +301,8 @@ def test_start_item_code_optional_params(self, rp_service, field_name, 'codeRef': None, 'testCaseId': None}, url='http://endpoint/api/v2/project/item', + method='POST', + timeout=(10, 10), verify=True) expected_result['json'][expected_name] = expected_value - rp_service.session.post.assert_called_with(**expected_result) + rp_service.session.request.assert_called_with(**expected_result) From 2b35b76afe74670161ef5164b736aa93cad0f3d7 Mon Sep 17 00:00:00 2001 From: James Quartly Date: Tue, 15 Mar 2022 23:17:01 +0000 Subject: [PATCH 2/3] Make timeout configurable upon Construction --- reportportal_client/service.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/reportportal_client/service.py b/reportportal_client/service.py index 6a5060d1..77f02856 100644 --- a/reportportal_client/service.py +++ b/reportportal_client/service.py @@ -167,6 +167,7 @@ def __init__(self, verify_ssl=True, retries=None, max_pool_size=50, + post_timeout=(10, 10), **kwargs): """Init the service class. @@ -181,6 +182,9 @@ def __init__(self, verify_ssl: option to not verify ssl certificates max_pool_size: option to set the maximum number of connections to save in the pool. + post_timeout: a float in seconds for the connect and read + timeout. Use a Tuple to specific connect and + read separately. """ self._batch_logs = [] self.endpoint = endpoint @@ -190,7 +194,7 @@ def __init__(self, self.is_skipped_an_issue = is_skipped_an_issue self.base_url_v1 = uri_join(self.endpoint, "api/v1", self.project) self.base_url_v2 = uri_join(self.endpoint, "api/v2", self.project) - self.post_timeout = (10, 10) + self.post_timeout = post_timeout self.session = requests.Session() if retries: From f654350484e1692e70993269dd39b46771fc6231 Mon Sep 17 00:00:00 2001 From: James Quartly Date: Tue, 5 Apr 2022 16:06:11 +0100 Subject: [PATCH 3/3] Add timeouts to HTTP GETs --- reportportal_client/service.py | 32 ++++++++++++++++++++++---------- tests/test_service.py | 24 +++++++++++++----------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/reportportal_client/service.py b/reportportal_client/service.py index 14360c54..85e0681c 100644 --- a/reportportal_client/service.py +++ b/reportportal_client/service.py @@ -167,7 +167,7 @@ def __init__(self, verify_ssl=True, retries=None, max_pool_size=50, - post_timeout=(10, 10), + http_timeout=(10, 10), **kwargs): """Init the service class. @@ -182,7 +182,7 @@ def __init__(self, verify_ssl: option to not verify ssl certificates max_pool_size: option to set the maximum number of connections to save in the pool. - post_timeout: a float in seconds for the connect and read + http_timeout: a float in seconds for the connect and read timeout. Use a Tuple to specific connect and read separately. """ @@ -194,7 +194,7 @@ def __init__(self, self.is_skipped_an_issue = is_skipped_an_issue self.base_url_v1 = uri_join(self.endpoint, "api/v1", self.project) self.base_url_v2 = uri_join(self.endpoint, "api/v2", self.project) - self.post_timeout = post_timeout + self.http_timeout = http_timeout self.session = requests.Session() if retries: @@ -238,7 +238,7 @@ def start_launch(self, url=url, json=data, verify=self.verify_ssl, - timeout=self.post_timeout + timeout=self.http_timeout ) self.launch_id = _get_id(r) logger.debug("start_launch - ID: %s", self.launch_id) @@ -281,7 +281,11 @@ def get_launch_info(self, max_retries=5): for _ in range(max_retries): logger.debug("get_launch_info - ID: %s", self.launch_id) - resp = self.session.get(url=url, verify=self.verify_ssl) + resp = self.session.request( + method='GET', + url=url, + verify=self.verify_ssl, + timeout=self.http_timeout) if resp.status_code == 200: launch_info = _get_json(resp) @@ -371,7 +375,7 @@ def start_test_item(self, url=url, json=data, verify=self.verify_ssl, - timeout=self.post_timeout + timeout=self.http_timeout ) item_id = _get_id(r) @@ -440,8 +444,11 @@ def get_item_id_by_uuid(self, uuid): :return str: Test item id """ url = uri_join(self.base_url_v1, "item", "uuid", uuid) - return _get_json(self.session.get( - url=url, verify=self.verify_ssl))["id"] + return _get_json(self.session.request( + method='GET', + url=url, + verify=self.verify_ssl, + timeout=self.http_timeout))["id"] def get_project_settings(self): """ @@ -450,7 +457,12 @@ def get_project_settings(self): :return: json body """ url = uri_join(self.base_url_v1, "settings") - r = self.session.get(url=url, json={}, verify=self.verify_ssl) + r = self.session.request( + method='GET', + url=url, + json={}, + verify=self.verify_ssl, + timeout=self.http_timeout) logger.debug("settings") return _get_json(r) @@ -531,7 +543,7 @@ def _log_batch(self, log_data, force=False): url=url, files=files, verify=self.verify_ssl, - timeout=self.post_timeout + timeout=self.http_timeout ) logger.debug("log_batch response: %s", r.text) self._batch_logs = [] diff --git a/tests/test_service.py b/tests/test_service.py index 37100e98..3e514e49 100644 --- a/tests/test_service.py +++ b/tests/test_service.py @@ -109,15 +109,17 @@ def test_get_launch_info(self, rp_service, monkeypatch): mock_resp = mock.Mock() mock_resp.status_code = 200 - mock_get = mock.Mock(return_value=mock_resp) - monkeypatch.setattr(rp_service.session, 'get', mock_get) + mock_request = mock.Mock(return_value=mock_resp) + monkeypatch.setattr(rp_service.session, 'request', mock_request) monkeypatch.setattr(rp_service, 'launch_id', '1234-cafe') launch_id = rp_service.get_launch_info() - mock_get.assert_called_once_with( + mock_request.assert_called_once_with( + method='GET', url='{0}/launch/uuid/{1}'.format(rp_service.base_url_v1, rp_service.launch_id), - verify=rp_service.verify_ssl) + verify=rp_service.verify_ssl, + timeout=(10, 10)) assert launch_id == {'id': 112} def test_get_launch_info_launch_id_none(self, rp_service, monkeypatch): @@ -145,12 +147,12 @@ def test_get_launch_info_wrong_launch_id(self, rp_service, monkeypatch): object with mocked session. :param monkeypatch: Pytest fixture to safely set/delete an attribute """ - mock_get = mock.Mock() - monkeypatch.setattr(rp_service.session, 'get', mock_get) + mock_request = mock.Mock() + monkeypatch.setattr(rp_service.session, 'request', mock_request) monkeypatch.setattr(rp_service, 'launch_id', '1234') launch_info = rp_service.get_launch_info() - expect(mock_get.call_count == 5) + expect(mock_request.call_count == 5) expect(launch_info == {}) assert_expectations() @@ -168,13 +170,13 @@ def test_get_launch_info_1st_failed(self, rp_service, monkeypatch): mock_resp1.status_code = 404 mock_resp2 = mock.Mock() mock_resp2.status_code = 200 - mock_get = mock.Mock() - mock_get.side_effect = [mock_resp1, mock_resp2] - monkeypatch.setattr(rp_service.session, 'get', mock_get) + mock_request = mock.Mock() + mock_request.side_effect = [mock_resp1, mock_resp2] + monkeypatch.setattr(rp_service.session, 'request', mock_request) monkeypatch.setattr(rp_service, 'launch_id', '1234') launch_info = rp_service.get_launch_info() - expect(mock_get.call_count == 2) + expect(mock_request.call_count == 2) expect(launch_info == {'id': 112}) assert_expectations()