diff options
author | Michal Jagiello <michal.jagiello@t-mobile.pl> | 2023-12-19 09:34:03 +0100 |
---|---|---|
committer | Michal Jagiello <michal.jagiello@t-mobile.pl> | 2023-12-19 09:44:36 +0100 |
commit | 4474aafa07d378be7c896821e2af86c3deb1e2d3 (patch) | |
tree | 40ae6afe627cd2447a0ece5c6894c2b15fe8eb7e | |
parent | ec7d9491a6f4cfa90e1140cc51975c98b6a555e8 (diff) |
Refactor CPS module url creation
Switch from string formatting into urllib urljoin.
Fix issue with invalid CPS requests urls
Issue-ID: INT-2277
Signed-off-by: Michal Jagiello <michal.jagiello@t-mobile.pl>
Change-Id: I37583aa3517be6cc27ed547ca6b11b19d6ccaca7
-rw-r--r-- | src/onapsdk/cps/anchor.py | 30 | ||||
-rw-r--r-- | src/onapsdk/cps/cps_element.py | 2 | ||||
-rw-r--r-- | src/onapsdk/cps/dataspace.py | 30 | ||||
-rw-r--r-- | src/onapsdk/cps/schemaset.py | 3 | ||||
-rw-r--r-- | src/onapsdk/version.py | 2 | ||||
-rw-r--r-- | tests/test_cps.py | 48 | ||||
-rw-r--r-- | tests/test_version.py | 2 |
7 files changed, 67 insertions, 50 deletions
diff --git a/src/onapsdk/cps/anchor.py b/src/onapsdk/cps/anchor.py index 2a5c49f..f1917b7 100644 --- a/src/onapsdk/cps/anchor.py +++ b/src/onapsdk/cps/anchor.py @@ -14,6 +14,7 @@ # limitations under the License. from typing import Any, Dict, TYPE_CHECKING +from urllib.parse import urljoin from .cps_element import CpsElement @@ -57,12 +58,14 @@ class Anchor(CpsElement): str: Anchor url """ - return f"{self._url}/dataspaces/{self.schema_set.dataspace.name}/anchors/{self.name}" + return urljoin(self._url, + f"dataspaces/{self.schema_set.dataspace.name}/anchors/{self.name}/") def delete(self) -> None: """Delete anchor.""" + # For some reason CPS API does not strip ending '/' character so it has to be removed here. self.send_message( - "DELETE", f"Delete {self.name} anchor", self.url, auth=self.auth + "DELETE", f"Delete {self.name} anchor", self.url.rstrip("/"), auth=self.auth ) def create_node(self, node_data: str) -> None: @@ -77,7 +80,7 @@ class Anchor(CpsElement): self.send_message( "POST", f"Create {self.name} anchor node", - f"{self.url}/nodes", + urljoin(self.url, "nodes"), data=node_data, auth=self.auth, ) @@ -100,8 +103,9 @@ class Anchor(CpsElement): return self.send_message_json( "GET", f"Get {self.name} anchor node with {xpath} xpath", - f"{self.url}/node?xpath={xpath}" - f"&descendants={descendants}", + urljoin(self.url, "node"), + params={"xpath": xpath, + "descendants": descendants}, auth=self.auth ) @@ -120,7 +124,8 @@ class Anchor(CpsElement): self.send_message( "PATCH", f"Update {self.name} anchor node with {xpath} xpath", - f"{self.url}/nodes?xpath={xpath}", + urljoin(self.url, "nodes"), + params={"xpath": xpath}, data=node_data, auth=self.auth, ) @@ -138,7 +143,8 @@ class Anchor(CpsElement): self.send_message( "PUT", f"Replace {self.name} anchor node with {xpath} xpath", - f"{self.url}/nodes?xpath={xpath}", + urljoin(self.url, "nodes"), + params={"xpath": xpath}, data=node_data, auth=self.auth, ) @@ -154,7 +160,8 @@ class Anchor(CpsElement): self.send_message( "POST", f"Add element to {self.name} anchor node with {xpath} xpath", - f"{self.url}/list-nodes?xpath={xpath}", + urljoin(self.url, "list-nodes"), + params={"xpath": xpath}, data=node_data, auth=self.auth, ) @@ -176,7 +183,9 @@ class Anchor(CpsElement): return self.send_message_json( "GET", f"Get {self.name} anchor node with {query} query", - f"{self.url}/nodes/query?cps-path={query}&include-descendants={include_descendants}", + urljoin(self.url, "nodes/query"), + params={"cps-path": query, + "include-descendants": include_descendants}, auth=self.auth, ) @@ -192,6 +201,7 @@ class Anchor(CpsElement): self.send_message( "DELETE", f"Delete {self.name} anchor nodes with {xpath} xpath", - f"{self.url}/nodes?xpath={xpath}", + urljoin(self.url, "nodes"), + params={"xpath": xpath}, auth=self.auth, ) diff --git a/src/onapsdk/cps/cps_element.py b/src/onapsdk/cps/cps_element.py index edcabc7..1aaa25d 100644 --- a/src/onapsdk/cps/cps_element.py +++ b/src/onapsdk/cps/cps_element.py @@ -22,5 +22,5 @@ from onapsdk.onap_service import OnapService class CpsElement(OnapService): """Mother Class of all CPS elements.""" - _url: str = urljoin(settings.CPS_URL, f"cps/api/{settings.CPS_VERSION}") + _url: str = urljoin(settings.CPS_URL, f"cps/api/{settings.CPS_VERSION}/") auth: tuple = settings.CPS_AUTH diff --git a/src/onapsdk/cps/dataspace.py b/src/onapsdk/cps/dataspace.py index e595598..112dbca 100644 --- a/src/onapsdk/cps/dataspace.py +++ b/src/onapsdk/cps/dataspace.py @@ -15,8 +15,9 @@ from functools import wraps from typing import Any, BinaryIO, Dict, Iterable, Union -from ..exceptions import (APIError, ResourceNotFound) +from urllib.parse import urljoin +from ..exceptions import (APIError, ResourceNotFound) from .anchor import Anchor from .cps_element import CpsElement from .schemaset import SchemaSet, SchemaSetModuleReference @@ -52,7 +53,7 @@ class Dataspace(CpsElement): str: Dataspace url """ - return f"{self._url}/dataspaces/{self.name}" + return urljoin(self._url, f"dataspaces/{self.name}/") def exception_handler(function): # pylint: disable= no-self-argument """Exception handler. @@ -84,7 +85,8 @@ class Dataspace(CpsElement): cls.send_message( "POST", f"Create {dataspace_name} dataspace", - f"{cls._url}/dataspaces?dataspace-name={dataspace_name}", + urljoin(cls._url, "dataspaces"), + params={"dataspace-name": dataspace_name}, auth=cls.auth ) return Dataspace(dataspace_name) @@ -104,7 +106,7 @@ class Dataspace(CpsElement): dataspace_data = cls.send_message_json( "GET", f"Get {dataspace_name} dataspace", - f"{cls._url}/admin/dataspaces/{dataspace_name}", + urljoin(cls._url, f"admin/dataspaces/{dataspace_name}/"), auth=cls.auth ) return Dataspace(name=dataspace_data["name"]) @@ -123,8 +125,10 @@ class Dataspace(CpsElement): """ self.send_message( "POST", - "Get all CPS dataspace schemasets", - f"{self.url}/anchors/?schema-set-name={schema_set.name}&anchor-name={anchor_name}", + f"Create {anchor_name} anchor", + urljoin(self.url, "anchors"), + params={"schema-set-name": schema_set.name, + "anchor-name": anchor_name}, auth=self.auth ) return Anchor(name=anchor_name, schema_set=schema_set) @@ -143,7 +147,7 @@ class Dataspace(CpsElement): for anchor_data in self.send_message_json(\ "GET",\ "Get all CPS dataspace anchors",\ - f"{self.url}/anchors",\ + urljoin(self.url, "anchors"),\ auth=self.auth\ ): yield Anchor(name=anchor_data["name"], @@ -171,7 +175,7 @@ class Dataspace(CpsElement): anchor_data: Dict[str, Any] = self.send_message_json( "GET", f"Get {anchor_name} anchor", - f"{self.url}/anchors/{anchor_name}", + urljoin(self.url, f"anchors/{anchor_name}"), auth=self.auth ) return Anchor(name=anchor_data["name"], @@ -188,7 +192,7 @@ class Dataspace(CpsElement): self.send_message( "DELETE", f"Delete {anchor_name} anchor", - f"{self.url}/anchors/{anchor_name}", + urljoin(self.url, f"anchors/{anchor_name}"), auth=self.auth ) @@ -206,7 +210,7 @@ class Dataspace(CpsElement): schema_set_data: Dict[str, Any] = self.send_message_json( "GET", f"Get CPS dataspace {schema_set_name} schemaset", - f"{self._url}/dataspaces/{self.name}/schema-sets/{schema_set_name}", + urljoin(self._url, f"dataspaces/{self.name}/schema-sets/{schema_set_name}"), auth=self.auth ) return SchemaSet( @@ -242,7 +246,8 @@ class Dataspace(CpsElement): self.send_message( "POST", "Create schema set", - f"{self._url}/dataspaces/{self.name}/schema-sets?schema-set-name={schema_set_name}", + urljoin(self._url, f"dataspaces/{self.name}/schema-sets"), + params={"schema-set-name": schema_set_name}, files={"file": schema_set}, headers={}, # Leave headers empty to fill it correctly by `requests` library auth=self.auth @@ -254,6 +259,7 @@ class Dataspace(CpsElement): self.send_message( "DELETE", f"Delete {self.name} dataspace", - f"{self._url}/dataspaces?dataspace-name={self.name}", + urljoin(self._url, "dataspaces"), + params={"dataspace-name": self.name}, auth=self.auth ) diff --git a/src/onapsdk/cps/schemaset.py b/src/onapsdk/cps/schemaset.py index b94cd60..171fbe3 100644 --- a/src/onapsdk/cps/schemaset.py +++ b/src/onapsdk/cps/schemaset.py @@ -15,6 +15,7 @@ from dataclasses import dataclass from typing import List, Optional, TYPE_CHECKING +from urllib.parse import urljoin from .cps_element import CpsElement @@ -69,6 +70,6 @@ class SchemaSet(CpsElement): self.send_message( "DELETE", f"Delete {self.name} schema set", - f"{self._url}/dataspaces/{self.dataspace.name}/schema-sets/{self.name}", + urljoin(self._url, f"dataspaces/{self.dataspace.name}/schema-sets/{self.name}"), auth=self.auth ) diff --git a/src/onapsdk/version.py b/src/onapsdk/version.py index 6fd109a..b82b975 100644 --- a/src/onapsdk/version.py +++ b/src/onapsdk/version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "12.7.2" +__version__ = "12.7.3" diff --git a/tests/test_cps.py b/tests/test_cps.py index be9ed12..9be0940 100644 --- a/tests/test_cps.py +++ b/tests/test_cps.py @@ -177,7 +177,7 @@ def test_anchor_delete(mock_send_message): anchor.delete() mock_send_message.assert_called_once() url = mock_send_message.call_args[0][2] - assert anchor.url in url + assert anchor.url.rstrip("/") in url @mock.patch("onapsdk.cps.Anchor.send_message") def test_anchor_create_node(mock_send_message): @@ -192,71 +192,71 @@ def test_anchor_get_node(mock_send_message_json): anchor = Anchor(name="test_anchor", schema_set=mock.MagicMock()) anchor.get_node("test-xpath") mock_send_message_json.assert_called_once() - url = mock_send_message_json.call_args[0][2] - assert "xpath=test-xpath" in url - assert "descendants=0" in url + params = mock_send_message_json.call_args.kwargs["params"] + assert "xpath" in params and params["xpath"] == "test-xpath" + assert "descendants" in params and params["descendants"] == 0 mock_send_message_json.reset_mock() anchor.get_node("test-xpath-2", descendants=-1) mock_send_message_json.assert_called_once() - url = mock_send_message_json.call_args[0][2] - assert "xpath=test-xpath-2" in url - assert "descendants=-1" in url + params = mock_send_message_json.call_args.kwargs["params"] + assert "xpath" in params and params["xpath"] == "test-xpath-2" + assert "descendants" in params and params["descendants"] == -1 mock_send_message_json.reset_mock() anchor.get_node("test-xpath-3", descendants=2) mock_send_message_json.assert_called_once() - url = mock_send_message_json.call_args[0][2] - assert "xpath=test-xpath-3" in url - assert "descendants=2" in url + params = mock_send_message_json.call_args.kwargs["params"] + assert "xpath" in params and params["xpath"] == "test-xpath-3" + assert "descendants" in params and params["descendants"] == 2 @mock.patch("onapsdk.cps.Anchor.send_message") def test_anchor_update_node(mock_send_message): anchor = Anchor(name="test_anchor", schema_set=mock.MagicMock()) anchor.update_node("test-xpath", '{"test": "data"}') mock_send_message.assert_called_once() - url = mock_send_message.call_args[0][2] - assert "xpath=test-xpath" in url + params = mock_send_message.call_args.kwargs["params"] + assert "xpath" in params and params["xpath"] == "test-xpath" @mock.patch("onapsdk.cps.Anchor.send_message") def test_anchor_replace_node(mock_send_message): anchor = Anchor(name="test_anchor", schema_set=mock.MagicMock()) anchor.replace_node("test-xpath", '{"test": "data"}') mock_send_message.assert_called_once() - url = mock_send_message.call_args[0][2] - assert "xpath=test-xpath" in url + params = mock_send_message.call_args.kwargs["params"] + assert "xpath" in params and params["xpath"] == "test-xpath" @mock.patch("onapsdk.cps.Anchor.send_message") def test_anchor_add_list_node(mock_send_message): anchor = Anchor(name="test_anchor", schema_set=mock.MagicMock()) anchor.add_list_node("test-xpath", '{"test": "data"}') mock_send_message.assert_called_once() - url = mock_send_message.call_args[0][2] - assert "xpath=test-xpath" in url + params = mock_send_message.call_args.kwargs["params"] + assert "xpath" in params and params["xpath"] == "test-xpath" @mock.patch("onapsdk.cps.Anchor.send_message_json") def test_anchor_query_node(mock_send_message_json): anchor = Anchor(name="test_anchor", schema_set=mock.MagicMock()) anchor.query_node("/test-query") mock_send_message_json.assert_called_once() - url = mock_send_message_json.call_args[0][2] - assert "cps-path=/test-query" in url - assert "include-descendants=False" in url + params = mock_send_message_json.call_args.kwargs["params"] + assert "cps-path" in params and params["cps-path"] == "/test-query" + assert "include-descendants" in params and params["include-descendants"] is False mock_send_message_json.reset_mock() anchor.query_node("/test-query1", include_descendants=True) mock_send_message_json.assert_called_once() - url = mock_send_message_json.call_args[0][2] - assert "cps-path=/test-query1" in url - assert "include-descendants=True" in url + params = mock_send_message_json.call_args.kwargs["params"] + assert "cps-path" in params and params["cps-path"] == "/test-query1" + assert "include-descendants" in params and params["include-descendants"] is True @mock.patch("onapsdk.cps.Anchor.send_message") def test_anchor_delete_nodes(mock_send_message): anchor = Anchor(name="test_anchor", schema_set=mock.MagicMock()) anchor.delete_nodes("test-xpath") mock_send_message.assert_called_once() - url = mock_send_message.call_args[0][2] - assert "xpath=test-xpath" in url + params = mock_send_message.call_args.kwargs["params"] + assert "xpath" in params and params["xpath"] == "test-xpath" @mock.patch("onapsdk.cps.Dataspace.send_message") def test_dataspace_create_anchor_except(mock_send_message_json): diff --git a/tests/test_version.py b/tests/test_version.py index 600e562..bf3b69b 100644 --- a/tests/test_version.py +++ b/tests/test_version.py @@ -17,4 +17,4 @@ import onapsdk.version as version def test_version(): """Check version is the right one.""" - assert version.__version__ == '12.7.2' + assert version.__version__ == '12.7.3' |