From 497e3c66aa974a5c0dddfb65d339b40df478bb65 Mon Sep 17 00:00:00 2001 From: Olivier Vignaud Date: Tue, 23 Dec 2025 09:40:45 +0100 Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=91=BD=EF=B8=8F=20MSA-15087:=20Change?= =?UTF-8?q?=20exists=20to=20getProfile=20by=20Ref.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- msa_sdk/profile.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/msa_sdk/profile.py b/msa_sdk/profile.py index fcd357f..fd2c115 100644 --- a/msa_sdk/profile.py +++ b/msa_sdk/profile.py @@ -41,7 +41,6 @@ def exist(self, reference) -> bool: True if the profile exists, False otherwise. """ self.action = 'Check Profile exist by reference' - self.path = '{}/v1/exist/{}'.format(self.api_path, reference) - self._call_post() - result = json.loads(self.content) - return result.get('exist', False) \ No newline at end of file + self.path = '{}/ref?extRef={}'.format(self.api_path, reference) + self._call_get() + return self.response.status_code == 200 \ No newline at end of file From 51c0f4125d3fd07d57932f055c44eb8c40d7106f Mon Sep 17 00:00:00 2001 From: Olivier Vignaud Date: Tue, 23 Dec 2025 09:59:23 +0100 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=8E=A8=20MSA-15087:=20Add=20type=20hi?= =?UTF-8?q?nt=20in=20msa=5Fapi.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- msa_sdk/msa_api.py | 18 ++++++++++-------- msa_sdk/profile.py | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/msa_sdk/msa_api.py b/msa_sdk/msa_api.py index 7101542..1b92c0d 100644 --- a/msa_sdk/msa_api.py +++ b/msa_sdk/msa_api.py @@ -4,15 +4,17 @@ import os import random import sys +from typing import Optional import requests +from requests import Response from msa_sdk import constants from msa_sdk import context logger = logging.getLogger("msa-sdk") -def host_port(): +def host_port() -> tuple[str, str]: """ Hostname and port of the API. @@ -37,11 +39,11 @@ class MSA_API(): # pylint: disable=invalid-name def __init__(self): """Initialize.""" - self.url = 'http://{}:{}/ubi-api-rest'.format(*host_port()) - self.path = "" - self.response = None - self.log_response = True - self._content = "" + self.url: str = 'http://{}:{}/ubi-api-rest'.format(*host_port()) + self.path: str = "" + self.response: Optional[Response] = None + self.log_response: bool = True + self._content: str = "" self.action = self.__class__ @classmethod @@ -224,7 +226,7 @@ def check_response(self): """ - if not self.response.ok: + if self.response is not None and not self.response.ok: json_response = self.response.json() self._content = self.process_content(self.FAILED, self.action, json_response['message']) @@ -329,7 +331,7 @@ def _call_delete(self) -> None: self._content = self.response.text self.check_response() - def add_trace_headers(self, headers): + def add_trace_headers(self, headers: dict[str, str]): """Add W3C trace headers.""" if 'TRACEID' not in context: t, s = self.create_trace_id() diff --git a/msa_sdk/profile.py b/msa_sdk/profile.py index fd2c115..fc52d00 100644 --- a/msa_sdk/profile.py +++ b/msa_sdk/profile.py @@ -43,4 +43,4 @@ def exist(self, reference) -> bool: self.action = 'Check Profile exist by reference' self.path = '{}/ref?extRef={}'.format(self.api_path, reference) self._call_get() - return self.response.status_code == 200 \ No newline at end of file + return self.response is not None and getattr(self.response, "status_code", None) == 200 \ No newline at end of file From 4ab04baa829c6a3b3d05dfc699aeaf6aa8864ac6 Mon Sep 17 00:00:00 2001 From: Olivier Vignaud Date: Tue, 23 Dec 2025 09:59:41 +0100 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=A7=AA=20MSA-15087:=20Fix=20unit=20te?= =?UTF-8?q?st.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_profie.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_profie.py b/tests/test_profie.py index ad0022f..18e1fb6 100644 --- a/tests/test_profie.py +++ b/tests/test_profie.py @@ -11,10 +11,10 @@ def test_exist(profile_fixture): """ Test exist profile by reference """ - with patch('msa_sdk.msa_api.MSA_API._call_post') as mock_call_post: + with patch('msa_sdk.msa_api.MSA_API._call_get') as mock_call_get: profile = profile_fixture reference = "test1" profile.exist(reference) - assert profile.path == "/profile/v1/exist/test1" - mock_call_post.assert_called_once() \ No newline at end of file + assert profile.path == "/profile/ref?extRef={}".format(reference) + mock_call_get.assert_called_once() \ No newline at end of file From 9da2bf579d1e7f6086a0a87f065c852b5093849d Mon Sep 17 00:00:00 2001 From: Olivier Vignaud Date: Tue, 23 Dec 2025 10:21:16 +0100 Subject: [PATCH 4/5] =?UTF-8?q?=F0=9F=8E=A8=20MSA-15087:=20Rewrite=20retur?= =?UTF-8?q?n=20handling=20in=20profile/exists.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- msa_sdk/profile.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/msa_sdk/profile.py b/msa_sdk/profile.py index fc52d00..11d42e1 100644 --- a/msa_sdk/profile.py +++ b/msa_sdk/profile.py @@ -4,8 +4,7 @@ The Profile class inherits from MSA_API and provides methods to check the existence of profiles and perform other profile-related operations. """ - -import json +from urllib.parse import urlencode from msa_sdk.msa_api import MSA_API @@ -41,6 +40,13 @@ def exist(self, reference) -> bool: True if the profile exists, False otherwise. """ self.action = 'Check Profile exist by reference' - self.path = '{}/ref?extRef={}'.format(self.api_path, reference) + url_encoded = urlencode({'extRef': reference}) + self.path = '{}/ref?{}'.format(self.api_path, url_encoded) self._call_get() - return self.response is not None and getattr(self.response, "status_code", None) == 200 \ No newline at end of file + if self.response is None: + raise Exception("No response received from the server.") + if self.response.status_code == 404: + return False + if self.response.status_code == 200: + return True + raise Exception("Unexpected response code: {}".format(self.response.status_code)) \ No newline at end of file From 1e2571754cd69a6c4d0d0c99fa92a9df3a5abaa5 Mon Sep 17 00:00:00 2001 From: Olivier Vignaud Date: Tue, 23 Dec 2025 10:38:36 +0100 Subject: [PATCH 5/5] =?UTF-8?q?=F0=9F=A7=AA=20MSA-15087:=20Rewrite=20tests?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_profie.py | 20 ----------------- tests/test_profile_exist.py | 45 +++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 20 deletions(-) delete mode 100644 tests/test_profie.py create mode 100644 tests/test_profile_exist.py diff --git a/tests/test_profie.py b/tests/test_profie.py deleted file mode 100644 index 18e1fb6..0000000 --- a/tests/test_profie.py +++ /dev/null @@ -1,20 +0,0 @@ -""" -Test Profile -""" - -from unittest.mock import patch - -from util import profile_fixture - - -def test_exist(profile_fixture): - """ - Test exist profile by reference - """ - with patch('msa_sdk.msa_api.MSA_API._call_get') as mock_call_get: - profile = profile_fixture - reference = "test1" - profile.exist(reference) - - assert profile.path == "/profile/ref?extRef={}".format(reference) - mock_call_get.assert_called_once() \ No newline at end of file diff --git a/tests/test_profile_exist.py b/tests/test_profile_exist.py new file mode 100644 index 0000000..d83adc5 --- /dev/null +++ b/tests/test_profile_exist.py @@ -0,0 +1,45 @@ +import pytest + +from msa_sdk.profile import Profile + + +class DummyResponse: + def __init__(self, status_code): + self.status_code = status_code + +class DummyProfile(Profile): + def _call_get(self): + # This will be set in the test + pass + +def test_exist_returns_true(monkeypatch): + profile = DummyProfile() + def fake_call_get(): + profile.response = DummyResponse(200) + profile._call_get = fake_call_get + assert profile.exist('ref1') is True + +def test_exist_returns_false(monkeypatch): + profile = DummyProfile() + def fake_call_get(): + profile.response = DummyResponse(404) + profile._call_get = fake_call_get + assert profile.exist('ref2') is False + + +def test_exist_raises_no_response(monkeypatch): + profile = DummyProfile() + def fake_call_get(): + profile.response = None + profile._call_get = fake_call_get + with pytest.raises(Exception, match="No response received from the server."): + profile.exist('ref3') + + +def test_exist_raises_unexpected_code(monkeypatch): + profile = DummyProfile() + def fake_call_get(): + profile.response = DummyResponse(500) + profile._call_get = fake_call_get + with pytest.raises(Exception, match="Unexpected response code: 500"): + profile.exist('ref4')