From d838863195386ceb127761ff005d2fbf6bf39261 Mon Sep 17 00:00:00 2001 From: Martin Malina Date: Thu, 9 Nov 2023 12:45:32 +0100 Subject: [PATCH] refactor(RHTAPBUGS-919): reuse session in pyxis api calls In my testing, when running this script against qa Pyxis with an sbom that has 113 components, this will yield around 27 % of script runtime reduction. Signed-off-by: Martin Malina --- pyxis/pyxis.py | 18 +++++++---- pyxis/test_pyxis.py | 73 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 73 insertions(+), 18 deletions(-) diff --git a/pyxis/pyxis.py b/pyxis/pyxis.py index d3ba48f..2689902 100644 --- a/pyxis/pyxis.py +++ b/pyxis/pyxis.py @@ -9,14 +9,15 @@ LOGGER = logging.getLogger("pyxis") +session = None -def _get_session(pyxis_url: str, auth_required: bool = True) -> requests.Session: + +def _get_session(auth_required: bool = True) -> requests.Session: """Create a Pyxis http session with auth based on env variables. Auth is optional and can be set to use either API key or certificate + key. Args: - url (str): Pyxis API URL auth_required (bool): Whether authentication should be required for the session Raises: @@ -62,7 +63,9 @@ def post(url: str, body: Dict[str, Any]) -> requests.Response: :return: Pyxis response """ - session = _get_session(url) + global session + if session is None: + session = _get_session() LOGGER.debug(f"POST request URL: {url}") LOGGER.debug(f"POST request body: {body}") @@ -119,7 +122,9 @@ def put(url: str, body: Dict[str, Any]) -> Dict[str, Any]: :return: Pyxis response """ - session = _get_session(url) + global session + if session is None: + session = _get_session() LOGGER.debug(f"PATCH Pyxis request: {url}") resp = session.put(url, json=body) @@ -144,7 +149,10 @@ def get(url: str, params: Optional[Dict[str, str]] = None, auth_required: bool = :return: Pyxis GET request response """ - session = _get_session(url, auth_required=auth_required) + global session + if session is None: + session = _get_session() + LOGGER.debug(f"GET Pyxis request url: {url}") LOGGER.debug(f"GET Pyxis request params: {params}") resp = session.get(url, params=params) diff --git a/pyxis/test_pyxis.py b/pyxis/test_pyxis.py index 154deb2..97e5691 100644 --- a/pyxis/test_pyxis.py +++ b/pyxis/test_pyxis.py @@ -19,7 +19,8 @@ def test_get_session_cert(mock_path_exists: MagicMock, monkeypatch: Any) -> None mock_path_exists.return_value = True monkeypatch.setenv("PYXIS_CERT_PATH", "/path/to/cert.pem") monkeypatch.setenv("PYXIS_KEY_PATH", "/path/to/key.key") - session = pyxis._get_session("test") + + session = pyxis._get_session() assert session.cert == ("/path/to/cert.pem", "/path/to/key.key") @@ -31,28 +32,42 @@ def test_get_session_cert_not_exist(mock_path_exists: MagicMock, monkeypatch: An monkeypatch.setenv("PYXIS_KEY_PATH", "/path/to/key.key") with pytest.raises(Exception): - pyxis._get_session("test") + pyxis._get_session() def test_get_session_no_auth(monkeypatch: Any) -> None: - session = pyxis._get_session("test", auth_required=False) + session = pyxis._get_session(auth_required=False) + assert session.cert is None +@patch("pyxis.session", None) +@patch("pyxis._get_session") +def test_post(mock_get_session: MagicMock) -> None: + resp = pyxis.post(API_URL, {}) + + assert resp == mock_get_session.return_value.post.return_value + mock_get_session.assert_called_once_with() + + +@patch("pyxis.session") @patch("pyxis._get_session") -def test_post(mock_session: MagicMock) -> None: +def test_post_existing_session(mock_get_session, mock_session: MagicMock) -> None: resp = pyxis.post(API_URL, {}) - assert resp == mock_session.return_value.post.return_value + assert resp == mock_session.post.return_value + mock_get_session.assert_not_called() +@patch("pyxis.session", None) @patch("pyxis._get_session") -def test_post_error(mock_session: MagicMock) -> None: +def test_post_error(mock_get_session: MagicMock) -> None: response = Response() response.status_code = 400 - mock_session.return_value.post.return_value.raise_for_status.side_effect = HTTPError( + mock_get_session.return_value.post.return_value.raise_for_status.side_effect = HTTPError( response=response ) + with pytest.raises(HTTPError): pyxis.post(API_URL, {}) @@ -111,31 +126,61 @@ def test_graphql_query__pyxis_error(mock_post: MagicMock): mock_post.assert_called_once_with(API_URL, REQUEST_BODY) +@patch("pyxis.session", None) @patch("pyxis._get_session") -def test_put(mock_session: MagicMock) -> None: - mock_session.return_value.put.return_value.json.return_value = {"key": "val"} +def test_put(mock_get_session: MagicMock) -> None: + mock_get_session.return_value.put.return_value.json.return_value = {"key": "val"} + resp = pyxis.put(API_URL, {}) assert resp == {"key": "val"} + mock_get_session.assert_called_once_with() +@patch("pyxis.session") @patch("pyxis._get_session") -def test_put_error(mock_session: MagicMock) -> None: +def test_put_existing_session(mock_get_session, mock_session: MagicMock) -> None: + mock_session.put.return_value.json.return_value = {"key": "val"} + + resp = pyxis.put(API_URL, {}) + + assert resp == {"key": "val"} + mock_get_session.assert_not_called() + + +@patch("pyxis.session", None) +@patch("pyxis._get_session") +def test_put_error(mock_get_session: MagicMock) -> None: response = Response() response.status_code = 400 - mock_session.return_value.put.return_value.raise_for_status.side_effect = HTTPError( + mock_get_session.return_value.put.return_value.raise_for_status.side_effect = HTTPError( response=response ) + with pytest.raises(HTTPError): pyxis.put(API_URL, {}) +@patch("pyxis.session", None) @patch("pyxis._get_session") -def test_get(mock_session: MagicMock) -> None: - mock_session.return_value.get.return_value = {"key": "val"} +def test_get(mock_get_session: MagicMock) -> None: + mock_get_session.return_value.get.return_value = {"key": "val"} + resp = pyxis.get(API_URL) assert resp == {"key": "val"} + mock_get_session.assert_called_once_with() + + +@patch("pyxis.session") +@patch("pyxis._get_session") +def test_get_existing_session(mock_get_session, mock_session: MagicMock) -> None: + mock_session.get.return_value = {"key": "val"} + + resp = pyxis.get(API_URL) + + assert resp == {"key": "val"} + mock_get_session.assert_not_called() def test_add_session_retries() -> None: @@ -143,12 +188,14 @@ def test_add_session_retries() -> None: total = 3 backoff_factor = 0.5 session = Session() + pyxis.add_session_retries( session, total=total, backoff_factor=backoff_factor, status_forcelist=status_forcelist, ) + assert session.adapters["http://"].max_retries.total == total assert session.adapters["http://"].max_retries.backoff_factor == backoff_factor assert session.adapters["http://"].max_retries.status_forcelist == status_forcelist