diff --git a/docs/model/models.rst b/docs/model/models.rst index 8b58fc2..67fa541 100644 --- a/docs/model/models.rst +++ b/docs/model/models.rst @@ -24,12 +24,6 @@ APIv2 :show-inheritance: -APIv1 (Deprecated) ------------------- - -.. autoclass:: starmap_client.models.QueryResponse() - :members: - Common ------ diff --git a/docs/provider/provider.rst b/docs/provider/provider.rst index fb17552..2388ca4 100644 --- a/docs/provider/provider.rst +++ b/docs/provider/provider.rst @@ -20,10 +20,3 @@ APIv2 .. autoclass:: starmap_client.providers.InMemoryMapProviderV2 :members: :special-members: __init__ - -APIv1 (deprecated) -~~~~~~~~~~~~~~~~~~ - -.. autoclass:: starmap_client.providers.InMemoryMapProviderV1 - :members: - :special-members: __init__ diff --git a/starmap_client/client.py b/starmap_client/client.py index cb00ca3..0bc6650 100644 --- a/starmap_client/client.py +++ b/starmap_client/client.py @@ -1,13 +1,12 @@ # SPDX-License-Identifier: GPL-3.0-or-later import logging -from typing import Any, Dict, Iterator, List, Optional, Type, Union +from typing import Any, Dict, Iterator, List, Optional from starmap_client.models import ( Destination, Mapping, PaginatedRawData, Policy, - QueryResponse, QueryResponseContainer, ) from starmap_client.providers import StarmapProvider @@ -16,15 +15,6 @@ log = logging.getLogger(__name__) -Q = Union[QueryResponse, QueryResponseContainer] - -API_QUERY_RESPONSE: Dict[str, Type[Q]] = { - "v1": QueryResponse, - "v2": QueryResponseContainer, - "default": QueryResponseContainer, -} - - class StarmapClient(object): """Implement the StArMap client.""" @@ -71,12 +61,12 @@ def __init__( self._provider = provider self._policies: List[Policy] = [] - def _query(self, params: Dict[str, Any]) -> Optional[Q]: + def _query(self, params: Dict[str, Any]) -> Optional[QueryResponseContainer]: qr = None if self._provider: qr = self._provider.query(params) rsp = qr or self.session.get("/query", params=params) - if isinstance(rsp, QueryResponse) or isinstance(rsp, QueryResponseContainer): + if isinstance(rsp, QueryResponseContainer): log.debug( "Returning response from the local provider %s", self._provider.__class__.__name__ ) @@ -85,10 +75,9 @@ def _query(self, params: Dict[str, Any]) -> Optional[Q]: log.error(f"Marketplace mappings not defined for {params}") return None rsp.raise_for_status() - converter = API_QUERY_RESPONSE.get(self.api_version, API_QUERY_RESPONSE["default"]) - return converter.from_json(json=rsp.json()) + return QueryResponseContainer.from_json(json=rsp.json()) - def query_image(self, nvr: str, **kwargs) -> Optional[Q]: + def query_image(self, nvr: str, **kwargs) -> Optional[QueryResponseContainer]: """ Query StArMap using an image NVR. @@ -97,7 +86,7 @@ def query_image(self, nvr: str, **kwargs) -> Optional[Q]: workflow(Workflow, optional): The desired workflow to retrieve the mappings (APIv1 Only) Returns: - Q: The query result when found or None. + QueryResponseContainer: The query result when found or None. """ return self._query(params={"image": nvr, **kwargs}) @@ -106,17 +95,16 @@ def query_image_by_name( name: str, version: Optional[str] = None, **kwargs, - ) -> Optional[Q]: + ) -> Optional[QueryResponseContainer]: """ Query StArMap using an image NVR. Args: name (str): The image name from NVR. version (str, optional): The version from NVR. - workflow(Workflow, optional): The desired workflow to retrieve the mappings (APIv1 Only) Returns: - Q: The query result when found or None. + QueryResponseContainer: The query result when found or None. """ params = {"name": name, **kwargs} if version: diff --git a/starmap_client/models.py b/starmap_client/models.py index 0ac72b2..8e4e02f 100644 --- a/starmap_client/models.py +++ b/starmap_client/models.py @@ -1,15 +1,8 @@ # SPDX-License-Identifier: GPL-3.0-or-later -import sys -from copy import deepcopy from enum import Enum -from typing import Any, Dict, List, Optional, Type +from typing import Any, Dict, List, Optional, Type, TypedDict -if sys.version_info >= (3, 8): - from typing import TypedDict # pragma: no cover -else: - from typing_extensions import TypedDict # pragma: no cover - -from attrs import Attribute, Factory, asdict, evolve, field, frozen +from attrs import Attribute, field, frozen from attrs.validators import deep_iterable, deep_mapping, instance_of, min_len, optional from starmap_client.utils import assert_is_dict, dict_merge @@ -20,7 +13,6 @@ 'Destination', 'Mapping', 'Policy', - 'QueryResponse', 'QueryResponseEntity', 'QueryResponseContainer', 'PaginatedRawData', @@ -142,7 +134,7 @@ class StarmapBaseData(MetaMixin, StarmapJSONDecodeMixin): id: Optional[str] = field(validator=optional(instance_of(str))) """ The unique ID for a StArMap model. - This field is never set on :class:`~starmap_client.models.QueryResponse`. + This field is never set on :class:`~starmap_client.models.QueryResponseEntity`. """ @@ -239,51 +231,6 @@ class Policy(StarmapBaseData): """The policy workflow name.""" -# ============================================ APIv1 =============================================== - - -@frozen -class QueryResponse(StarmapJSONDecodeMixin): - """Represent a query response from StArMap.""" - - name: str = field(validator=instance_of(str)) - """The :class:`~Policy` name.""" - - workflow: Workflow = field(converter=lambda x: Workflow(x)) - """The :class:`~Policy` workflow.""" - - clouds: Dict[str, List[Destination]] = field( - default=Factory(dict), - validator=deep_mapping( - key_validator=instance_of(str), - value_validator=deep_iterable( - member_validator=instance_of(Destination), iterable_validator=instance_of(list) - ), - mapping_validator=instance_of(dict), - ), - ) - """Dictionary with the cloud marketplaces aliases and their respective Destinations.""" - - @classmethod - def _preprocess_json(cls, json: Any) -> Dict[str, Any]: - """ - Convert the JSON format to the expected by QueryResponse. - - Params: - json (dict): A JSON containing a StArMap Query response. - Returns: - dict: The modified JSON. - """ - mappings = json.pop("mappings", {}) - for c in mappings.keys(): - if not isinstance(mappings[c], list): - raise ValueError(f"Expected mappings to be a list, got \"{type(mappings[c])}\".") - dst = [Destination.from_json(d) for d in mappings[c]] - mappings[c] = dst - json["clouds"] = mappings - return json - - # ============================================ APIv2 =============================================== @@ -429,27 +376,6 @@ def get_mapping_for_account(self, account: str) -> MappingResponseObject: raise KeyError(f"No mappings found for account name {account}") return obj - def to_classic_query_response(self) -> QueryResponse: - """Return the representation of this object as a :class:`~QueryResponse` from APIv1.""" - - def add_bc_to_dst_meta(clouds: Dict[str, List[Destination]]): - if self.billing_code_config: - bc_data = {k: asdict(v) for k, v in self.billing_code_config.items()} - for dst_list in clouds.values(): - for d in dst_list: - meta = d.meta or {} - meta["billing-code-config"] = bc_data - d = evolve(d, meta=meta) - - clouds: Dict[str, List[Destination]] = {} - for k, v in self.mappings.items(): - clouds[k] = [deepcopy(d) for d in v.destinations] - - if self.billing_code_config: - add_bc_to_dst_meta(clouds) - - return QueryResponse(name=self.name, workflow=self.workflow, clouds=clouds) - @staticmethod def _unify_meta_with_mappings(json: Dict[str, Any]) -> None: """Merge the ``meta`` data from package into the mappings.""" diff --git a/starmap_client/providers/__init__.py b/starmap_client/providers/__init__.py index 2db582d..18dbbac 100644 --- a/starmap_client/providers/__init__.py +++ b/starmap_client/providers/__init__.py @@ -1,6 +1,3 @@ # SPDX-License-Identifier: GPL-3.0-or-later from starmap_client.providers.base import StarmapProvider # noqa: F401 -from starmap_client.providers.memory import ( # noqa: F401 - InMemoryMapProviderV1, - InMemoryMapProviderV2, -) +from starmap_client.providers.memory import InMemoryMapProviderV2 # noqa: F401 diff --git a/starmap_client/providers/base.py b/starmap_client/providers/base.py index 32ef2a2..31097c3 100644 --- a/starmap_client/providers/base.py +++ b/starmap_client/providers/base.py @@ -1,9 +1,9 @@ from abc import ABC, abstractmethod from typing import Any, Dict, Generic, List, Optional, TypeVar -from starmap_client.models import QueryResponse, QueryResponseContainer, QueryResponseEntity +from starmap_client.models import QueryResponseContainer, QueryResponseEntity -T = TypeVar("T", QueryResponse, QueryResponseContainer, QueryResponseEntity) +T = TypeVar("T", QueryResponseContainer, QueryResponseEntity) class StarmapProvider(ABC, Generic[T]): diff --git a/starmap_client/providers/memory.py b/starmap_client/providers/memory.py index c6ee874..09f67ef 100644 --- a/starmap_client/providers/memory.py +++ b/starmap_client/providers/memory.py @@ -1,75 +1,10 @@ from typing import Any, Dict, List, Optional -from starmap_client.models import QueryResponse, QueryResponseContainer, QueryResponseEntity +from starmap_client.models import QueryResponseContainer, QueryResponseEntity from starmap_client.providers.base import StarmapProvider from starmap_client.providers.utils import get_image_name -class InMemoryMapProviderV1(StarmapProvider): - """Provide in memory (RAM) QueryResponse mapping objects for APIv1.""" - - api = "v1" - - def __init__( - self, map_responses: Optional[List[QueryResponse]] = None, *args, **kwargs - ) -> None: - """Crete a new InMemoryMapProvider object. - - Args: - map_responses (list, optional) - List of QueryResponse objects to load into memory. They will be - used by query to fetch the correct response based on name - and workflow. - """ - self._separator = str(kwargs.pop("separator", "+")) - self._content: Dict[str, QueryResponse] = {} - super(StarmapProvider, self).__init__() - self._boostrap(map_responses) - - def _boostrap(self, map_responses: Optional[List[QueryResponse]]) -> None: - """Initialize the internal content dictionary. - - Args: - map_responses (list, optional) - List of QueryResponse objects to load into memory. - """ - if not map_responses: - return None - - # The in memory content is made of a combination of name and workflow - for map in map_responses: - key = f"{map.name}{self._separator}{map.workflow.value}" - self._content[key] = map - - def list_content(self) -> List[QueryResponse]: - """Return a list of stored content.""" - return list(self._content.values()) - - def store(self, response: QueryResponse) -> None: - """Store/replace a single QueryResponse object. - - Args: - response (QueryResponse): - The object to store. - """ - key = f"{response.name}{self._separator}{response.workflow.value}" - self._content[key] = response - - def query(self, params: Dict[str, Any]) -> Optional[QueryResponse]: - """Return the mapping from memory according to the received params. - - Args: - params (dict): - The request params to retrieve the mapping. - Returns: - The requested mapping when found. - """ - name = params.get("name") or get_image_name(params.get("image")) - workflow = str(params.get("workflow", "")) - search_key = f"{name}{self._separator}{workflow}" - return self._content.get(search_key) - - class InMemoryMapProviderV2(StarmapProvider): """Provide in memory (RAM) QueryResponseContainer objects for APIv2.""" diff --git a/tests/data/query_v1/invalid_quer1.json b/tests/data/query_v1/invalid_quer1.json deleted file mode 100644 index b7f9583..0000000 --- a/tests/data/query_v1/invalid_quer1.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "mappings": - { - "test-marketplace": { - "destination": "test-destination/foo/bar", - "restrict_version": false, - "overwrite": false - } - - }, - "name": "sample-policy", - "workflow": "stratosphere", - "error": "Expected mappings to be a list, got \"\"" -} diff --git a/tests/data/query_v1/invalid_quer2.json b/tests/data/query_v1/invalid_quer2.json deleted file mode 100644 index 8bd1ec9..0000000 --- a/tests/data/query_v1/invalid_quer2.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "mappings": - { - "test-marketplace": "foo" - }, - "name": "sample-policy", - "workflow": "stratosphere", - "error": "Expected mappings to be a list, got \"\"" -} diff --git a/tests/data/query_v1/valid_quer1.json b/tests/data/query_v1/valid_quer1.json deleted file mode 100644 index 3605d32..0000000 --- a/tests/data/query_v1/valid_quer1.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "mappings": - { - "test-marketplace": [ - - { - "destination": "test-destination/foo/bar", - "overwrite": false, - "restrict_version": false - } - ] - }, - "workflow": "stratosphere", - "name": "sample-policy" -} diff --git a/tests/data/query_v1/valid_quer2.json b/tests/data/query_v1/valid_quer2.json deleted file mode 100644 index 02ea9ab..0000000 --- a/tests/data/query_v1/valid_quer2.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "mappings": - { - "test-marketplace": [ - { - "destination": "test-destination/foo/bar", - "overwrite": false, - "restrict_version": false - }, - { - "destination": "second-test-destination/foo/bar", - "overwrite": true, - "restrict_version": false, - "meta": {"foo": "bar"} - } - ] - }, - "workflow": "stratosphere", - "name": "sample-policy" -} diff --git a/tests/data/query_v1/valid_quer3.json b/tests/data/query_v1/valid_quer3.json deleted file mode 100644 index 267f6ba..0000000 --- a/tests/data/query_v1/valid_quer3.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "mappings": - { - "test-marketplace": [ - { - "destination": "test-destination/foo/bar", - "overwrite": false, - "restrict_version": false - }, - { - "destination": "second-test-destination/foo/bar", - "overwrite": true, - "restrict_version": false, - "meta": {"foo": "bar"} - } - ], - "another-marketplace": [ - { - "destination": "aaaaaaaaaaaaaaa", - "overwrite": false, - "restrict_version": false, - "meta": {} - }, - { - "destination": "bbbbbbbbbbbbb", - "overwrite": true, - "restrict_version": false, - "meta": {"foo": "bar"} - } - ] - }, - "workflow": "stratosphere", - "name": "sample-policy" -} diff --git a/tests/data/query_v1/valid_quer4.json b/tests/data/query_v1/valid_quer4.json deleted file mode 100644 index 8d911d9..0000000 --- a/tests/data/query_v1/valid_quer4.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "mappings": - { - "test-marketplace": [ - { - "destination": "test-destination/foo/bar", - "overwrite": false, - "restrict_version": false - } - ], - "another-marketplace": [ - { - "destination": "aaaaaaaaaaaaaaa", - "overwrite": false, - "restrict_version": false, - "meta": {} - }, - { - "destination": "bbbbbbbbbbbbb", - "overwrite": true, - "restrict_version": false, - "meta": {"foo": "bar"} - } - ] - }, - "workflow": "stratosphere", - "name": "sample-policy" -} diff --git a/tests/data/query_v1/valid_quer5.json b/tests/data/query_v1/valid_quer5.json deleted file mode 100644 index 05fad55..0000000 --- a/tests/data/query_v1/valid_quer5.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "mappings": - { - "test-marketplace": [ - { - "destination": "test-destination/foo/bar", - "overwrite": false, - "restrict_version": false - } - ], - "another-marketplace": [ - { - "destination": "aaaaaaaaaaaaaaa", - "overwrite": false, - "restrict_version": false, - "meta": {} - }, - { - "destination": "bbbbbbbbbbbbb", - "overwrite": true, - "restrict_version": false, - "meta": {"foo": "bar"} - } - ], - "third-marketplace": [ - { - "destination": "foo/bar", - "overwrite": true, - "restrict_version": false - }, - { - "architecture": "x86_64", - "destination": "this-is-a-test-destination/with-testing-information", - "overwrite": false, - "restrict_version": false - } - ] - }, - "workflow": "stratosphere", - "name": "sample-policy" -} diff --git a/tests/test_client.py b/tests/test_client.py index 6773018..2bac5db 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -9,14 +9,8 @@ from requests.exceptions import HTTPError from starmap_client import StarmapClient -from starmap_client.models import ( - Destination, - Mapping, - Policy, - QueryResponse, - QueryResponseContainer, -) -from starmap_client.providers import InMemoryMapProviderV1, InMemoryMapProviderV2 +from starmap_client.models import Destination, Mapping, Policy, QueryResponseContainer +from starmap_client.providers import InMemoryMapProviderV2 from starmap_client.session import StarmapMockSession @@ -32,11 +26,9 @@ def inject_fixtures(self, caplog: LogCaptureFixture): self._caplog = caplog def setUp(self) -> None: - self.svc_v1 = StarmapClient("https://test.starmap.com", api_version="v1") self.svc_v2 = StarmapClient("https://test.starmap.com", api_version="v2") self.mock_requests = mock.patch('starmap_client.session.requests').start() - self.mock_session_v1 = mock.patch.object(self.svc_v1, 'session').start() self.mock_session_v2 = mock.patch.object(self.svc_v2, 'session').start() self.image_name = "foo-bar" @@ -53,19 +45,6 @@ def setUp(self) -> None: def tearDown(self): mock.patch.stopall() - def test_query_image_success_APIv1(self): - fpath = "tests/data/query_v1/valid_quer1.json" - self.mock_resp_success.json.return_value = load_json(fpath) - self.mock_session_v1.get.return_value = self.mock_resp_success - - res = self.svc_v1.query_image(self.image, workflow="stratosphere") - - expected_params = {"image": self.image, "workflow": "stratosphere"} - self.mock_session_v1.get.assert_called_once_with("/query", params=expected_params) - self.mock_resp_success.raise_for_status.assert_called_once() - # Note: JSON need to be loaded twice as `from_json` pops its original data - self.assertEqual(res, QueryResponse.from_json(load_json(fpath))) - def test_query_image_success_APIv2(self): fpath = "tests/data/query_v2/query_response_container/valid_qrc1.json" self.mock_resp_success.json.return_value = load_json(fpath) @@ -79,17 +58,6 @@ def test_query_image_success_APIv2(self): # Note: JSON need to be loaded twice as `from_json` pops its original data self.assertEqual(res, QueryResponseContainer.from_json(load_json(fpath))) - def test_in_memory_query_image_APIv1(self): - fpath = "tests/data/query_v1/valid_quer1.json" - data = [QueryResponse.from_json(load_json(fpath))] - provider = InMemoryMapProviderV1(data) - - self.svc_v1 = StarmapClient("https://test.starmap.com", api_version="v1", provider=provider) - - res = self.svc_v1.query_image("sample-policy-1.0-1.raw.xz", workflow="stratosphere") - self.mock_session_v1.get.assert_not_called() - self.assertEqual(res, data[0]) - def test_in_memory_query_image_APIv2(self): fpath = "tests/data/query_v2/query_response_container/valid_qrc1.json" data = QueryResponseContainer.from_json(load_json(fpath)) @@ -98,47 +66,28 @@ def test_in_memory_query_image_APIv2(self): self.svc_v2 = StarmapClient("https://test.starmap.com", api_version="v2", provider=provider) res = self.svc_v2.query_image("product-test-1.0-1.raw.xz", workflow="stratosphere") - self.mock_session_v1.get.assert_not_called() self.assertEqual(res.responses, [data.responses[0]]) def test_in_memory_api_mismatch(self): - fpath = "tests/data/query_v1/valid_quer1.json" - data = [QueryResponse.from_json(load_json(fpath))] - provider_v1 = InMemoryMapProviderV1(data) - fpath = "tests/data/query_v2/query_response_container/valid_qrc1.json" data = QueryResponseContainer.from_json(load_json(fpath)) provider_v2 = InMemoryMapProviderV2(data) - err = "API mismatch: Provider has API v[1-2] but the client expects: v[1-2]" + err = "API mismatch: Provider has API v2 but the client expects: v1" with pytest.raises(ValueError, match=err): - StarmapClient("foo", api_version="v2", provider=provider_v1) StarmapClient("foo", api_version="v1", provider=provider_v2) def test_query_image_not_found(self): - self.mock_session_v1.get.return_value = self.mock_resp_not_found + self.mock_session_v2.get.return_value = self.mock_resp_not_found self.mock_session_v2.get.return_value = self.mock_resp_not_found - for svc in [self.svc_v1, self.svc_v2]: + for svc in [self.svc_v2, self.svc_v2]: with self._caplog.at_level(logging.ERROR): res = svc.query_image(self.image) expected_msg = "Marketplace mappings not defined for {'image': '%s'}" % self.image assert expected_msg in self._caplog.text self.assertIsNone(res) - def test_query_image_by_name_APIv1(self): - fpath = "tests/data/query_v1/valid_quer1.json" - self.mock_resp_success.json.return_value = load_json(fpath) - self.mock_session_v1.get.return_value = self.mock_resp_success - - res = self.svc_v1.query_image_by_name(name=self.image_name, workflow="stratosphere") - - expected_params = {"name": self.image_name, "workflow": "stratosphere"} - self.mock_session_v1.get.assert_called_once_with("/query", params=expected_params) - self.mock_resp_success.raise_for_status.assert_called_once() - # Note: JSON need to be loaded twice as `from_json` pops its original data - self.assertEqual(res, QueryResponse.from_json(load_json(fpath))) - def test_query_image_by_name_APIv2(self): fpath = "tests/data/query_v2/query_response_container/valid_qrc1.json" self.mock_resp_success.json.return_value = load_json(fpath) @@ -152,17 +101,6 @@ def test_query_image_by_name_APIv2(self): # Note: JSON need to be loaded twice as `from_json` pops its original data self.assertEqual(res, QueryResponseContainer.from_json(load_json(fpath))) - def test_in_memory_query_image_by_name_APIv1(self): - fpath = "tests/data/query_v1/valid_quer1.json" - data = [QueryResponse.from_json(load_json(fpath))] - provider = InMemoryMapProviderV1(data) - - self.svc_v1 = StarmapClient("https://test.starmap.com", api_version="v1", provider=provider) - - res = self.svc_v1.query_image_by_name(name="sample-policy", workflow="stratosphere") - self.mock_session_v1.get.assert_not_called() - self.assertEqual(res, data[0]) - def test_in_memory_query_image_by_name_APIv2(self): fpath = "tests/data/query_v2/query_response_container/valid_qrc1.json" data = QueryResponseContainer.from_json(load_json(fpath)) @@ -171,28 +109,9 @@ def test_in_memory_query_image_by_name_APIv2(self): self.svc_v2 = StarmapClient("https://test.starmap.com", api_version="v2", provider=provider) res = self.svc_v2.query_image_by_name(name="product-test", workflow="stratosphere") - self.mock_session_v1.get.assert_not_called() + self.mock_session_v2.get.assert_not_called() self.assertEqual(res.responses, [data.responses[0]]) - def test_query_image_by_name_version_APIv1(self): - fpath = "tests/data/query_v1/valid_quer1.json" - self.mock_resp_success.json.return_value = load_json(fpath) - self.mock_session_v1.get.return_value = self.mock_resp_success - - res = self.svc_v1.query_image_by_name( - name=self.image_name, version=self.image_version, workflow="stratosphere" - ) - - expected_params = { - "name": self.image_name, - "version": self.image_version, - "workflow": "stratosphere", - } - self.mock_session_v1.get.assert_called_once_with("/query", params=expected_params) - self.mock_resp_success.raise_for_status.assert_called_once() - # Note: JSON need to be loaded twice as `from_json` pops its original data - self.assertEqual(res, QueryResponse.from_json(load_json(fpath))) - def test_query_image_by_name_version_APIv2(self): fpath = "tests/data/query_v2/query_response_container/valid_qrc1.json" self.mock_resp_success.json.return_value = load_json(fpath) @@ -214,8 +133,8 @@ def test_policies_single_page(self): single_page = { "items": [load_json(fpath)], "nav": { - "first": "https://test.starmap.com/api/v1/policy?page=1&per_page=1", - "last": "https://test.starmap.com/api/v1/policy?page=1&per_page=1", + "first": "https://test.starmap.com/api/v2/policy?page=1&per_page=1", + "last": "https://test.starmap.com/api/v2/policy?page=1&per_page=1", "next": None, "page": 1, "per_page": 1, @@ -224,18 +143,18 @@ def test_policies_single_page(self): "total_pages": 1, }, } - self.svc_v1.POLICIES_PER_PAGE = 1 + self.svc_v2.POLICIES_PER_PAGE = 1 self.mock_resp_success.json.return_value = single_page - self.mock_session_v1.get.return_value = self.mock_resp_success + self.mock_session_v2.get.return_value = self.mock_resp_success # Iterate over all policies from StarmapClient property and # ensure each of them has a valid format. - for p in self.svc_v1.policies: + for p in self.svc_v2.policies: self.assertEqual(p, Policy.from_json(load_json(fpath))) expected_params = {"page": 1, "per_page": 1} - self.mock_session_v1.get.assert_called_once_with("policy", params=expected_params) - self.mock_session_v1.get.call_count == 1 + self.mock_session_v2.get.assert_called_once_with("policy", params=expected_params) + self.mock_session_v2.get.call_count == 1 self.mock_resp_success.raise_for_status.assert_called_once() def test_policies_multi_page(self): @@ -243,9 +162,9 @@ def test_policies_multi_page(self): page1 = { "items": [load_json(fpath)], "nav": { - "first": "https://test.starmap.com/api/v1/policy?page=1&per_page=1", - "last": "https://test.starmap.com/api/v1/policy?page=1&per_page=1", - "next": "https://test.starmap.com/api/v1/policy?page=2&per_page=1", + "first": "https://test.starmap.com/api/v2/policy?page=1&per_page=1", + "last": "https://test.starmap.com/api/v2/policy?page=1&per_page=1", + "next": "https://test.starmap.com/api/v2/policy?page=2&per_page=1", "page": 1, "per_page": 1, "previous": None, @@ -256,13 +175,13 @@ def test_policies_multi_page(self): page2 = deepcopy(page1) page2["nav"]["next"] = None page2["nav"]["page"] = 2 - self.svc_v1.POLICIES_PER_PAGE = 1 + self.svc_v2.POLICIES_PER_PAGE = 1 self.mock_resp_success.json.side_effect = [page1, page2] - self.mock_session_v1.get.return_value = self.mock_resp_success + self.mock_session_v2.get.return_value = self.mock_resp_success # Iterate over all policies from StarmapClient property and # ensure each of them has a valid format. - for p in self.svc_v1.policies: + for p in self.svc_v2.policies: self.assertEqual(p, Policy.from_json(load_json(fpath))) get_calls = [ @@ -273,17 +192,17 @@ def test_policies_multi_page(self): mock.call().raise_for_status, mock.call().json(), ] - self.mock_session_v1.get.assert_has_calls(get_calls) - self.mock_session_v1.get.call_count == 2 + self.mock_session_v2.get.assert_has_calls(get_calls) + self.mock_session_v2.get.call_count == 2 self.mock_resp_success.raise_for_status.call_count == 2 def test_policies_not_found(self): - self.svc_v1.POLICIES_PER_PAGE = 1 - self.mock_session_v1.get.return_value = self.mock_resp_not_found + self.svc_v2.POLICIES_PER_PAGE = 1 + self.mock_session_v2.get.return_value = self.mock_resp_not_found with self._caplog.at_level(logging.ERROR): with pytest.raises(StopIteration): - next(self.svc_v1.policies) + next(self.svc_v2.policies) assert "No policies registered in StArMap." in self._caplog.text @mock.patch('starmap_client.StarmapClient.policies') @@ -294,34 +213,34 @@ def test_list_policies(self, mock_policies: mock.MagicMock): mock_policies.__iter__.return_value = pol_list # Test cached policies list - self.svc_v1._policies = pol_list - res = self.svc_v1.list_policies() + self.svc_v2._policies = pol_list + res = self.svc_v2.list_policies() mock_policies.__iter__.assert_not_called() - self.assertEqual(res, self.svc_v1._policies) + self.assertEqual(res, self.svc_v2._policies) # Test uncached policies list - self.svc_v1._policies = [] - res = self.svc_v1.list_policies() + self.svc_v2._policies = [] + res = self.svc_v2.list_policies() mock_policies.__iter__.assert_called_once() self.assertEqual(res, pol_list) def test_get_policy(self): fpath = "tests/data/policy/valid_pol1.json" self.mock_resp_success.json.return_value = load_json(fpath) - self.mock_session_v1.get.return_value = self.mock_resp_success + self.mock_session_v2.get.return_value = self.mock_resp_success - res = self.svc_v1.get_policy(policy_id="policy-id") + res = self.svc_v2.get_policy(policy_id="policy-id") - self.mock_session_v1.get.assert_called_once_with("/policy/policy-id") + self.mock_session_v2.get.assert_called_once_with("/policy/policy-id") self.mock_resp_success.raise_for_status.assert_called_once() # Note: JSON need to be loaded twice as `from_json` pops its original data self.assertEqual(res, Policy.from_json(load_json(fpath))) def test_get_policy_not_found(self): - self.mock_session_v1.get.return_value = self.mock_resp_not_found + self.mock_session_v2.get.return_value = self.mock_resp_not_found with self._caplog.at_level(logging.ERROR): - res = self.svc_v1.get_policy(policy_id="policy-id") + res = self.svc_v2.get_policy(policy_id="policy-id") expected_msg = "Policy not found with ID = \"policy-id\"" assert expected_msg in self._caplog.text @@ -334,7 +253,7 @@ def test_list_mappings(self, mock_get_policy: mock.MagicMock) -> None: p = Policy.from_json(load_json(fpath)) mock_get_policy.return_value = p - res = self.svc_v1.list_mappings(policy_id="policy-id") + res = self.svc_v2.list_mappings(policy_id="policy-id") mock_get_policy.assert_called_once_with("policy-id") self.assertEqual(res, p.mappings) @@ -342,7 +261,7 @@ def test_list_mappings(self, mock_get_policy: mock.MagicMock) -> None: @mock.patch("starmap_client.StarmapClient.get_policy") def test_list_mappings_not_found(self, mock_get_policy: mock.MagicMock) -> None: mock_get_policy.return_value = None - res = self.svc_v1.list_mappings(policy_id="policy-id") + res = self.svc_v2.list_mappings(policy_id="policy-id") mock_get_policy.assert_called_once_with("policy-id") @@ -351,20 +270,20 @@ def test_list_mappings_not_found(self, mock_get_policy: mock.MagicMock) -> None: def test_get_mapping(self): fpath = "tests/data/mapping/valid_map1.json" self.mock_resp_success.json.return_value = load_json(fpath) - self.mock_session_v1.get.return_value = self.mock_resp_success + self.mock_session_v2.get.return_value = self.mock_resp_success - res = self.svc_v1.get_mapping(mapping_id="mapping-id") + res = self.svc_v2.get_mapping(mapping_id="mapping-id") - self.mock_session_v1.get.assert_called_once_with("/mapping/mapping-id") + self.mock_session_v2.get.assert_called_once_with("/mapping/mapping-id") self.mock_resp_success.raise_for_status.assert_called_once() # Note: JSON need to be loaded twice as `from_json` pops its original data self.assertEqual(res, Mapping.from_json(load_json(fpath))) def test_get_mapping_not_found(self): - self.mock_session_v1.get.return_value = self.mock_resp_not_found + self.mock_session_v2.get.return_value = self.mock_resp_not_found with self._caplog.at_level(logging.ERROR): - res = self.svc_v1.get_mapping(mapping_id="mapping-id") + res = self.svc_v2.get_mapping(mapping_id="mapping-id") expected_msg = "Marketplace Mapping not found with ID = \"mapping-id\"" assert expected_msg in self._caplog.text @@ -377,7 +296,7 @@ def test_list_destinations(self, mock_get_mapping: mock.MagicMock) -> None: m = Mapping.from_json(load_json(fpath)) mock_get_mapping.return_value = m - res = self.svc_v1.list_destinations(mapping_id="mapping-id") + res = self.svc_v2.list_destinations(mapping_id="mapping-id") mock_get_mapping.assert_called_once_with("mapping-id") self.assertEqual(res, m.destinations) @@ -385,7 +304,7 @@ def test_list_destinations(self, mock_get_mapping: mock.MagicMock) -> None: @mock.patch("starmap_client.StarmapClient.get_mapping") def test_list_destinations_not_found(self, mock_get_mapping: mock.MagicMock) -> None: mock_get_mapping.return_value = None - res = self.svc_v1.list_destinations(mapping_id="mapping-id") + res = self.svc_v2.list_destinations(mapping_id="mapping-id") mock_get_mapping.assert_called_once_with("mapping-id") @@ -394,20 +313,20 @@ def test_list_destinations_not_found(self, mock_get_mapping: mock.MagicMock) -> def test_get_destination(self): fpath = "tests/data/destination/valid_dest1.json" self.mock_resp_success.json.return_value = load_json(fpath) - self.mock_session_v1.get.return_value = self.mock_resp_success + self.mock_session_v2.get.return_value = self.mock_resp_success - res = self.svc_v1.get_destination(destination_id="destination-id") + res = self.svc_v2.get_destination(destination_id="destination-id") - self.mock_session_v1.get.assert_called_once_with("/destination/destination-id") + self.mock_session_v2.get.assert_called_once_with("/destination/destination-id") self.mock_resp_success.raise_for_status.assert_called_once() # Note: JSON need to be loaded twice as `from_json` pops its original data self.assertEqual(res, Destination.from_json(load_json(fpath))) def test_get_destination_not_found(self): - self.mock_session_v1.get.return_value = self.mock_resp_not_found + self.mock_session_v2.get.return_value = self.mock_resp_not_found with self._caplog.at_level(logging.ERROR): - res = self.svc_v1.get_destination(destination_id="destination-id") + res = self.svc_v2.get_destination(destination_id="destination-id") expected_msg = "Destination not found with ID = \"destination-id\"" assert expected_msg in self._caplog.text @@ -422,23 +341,23 @@ def test_client_requires_url_or_session(self): def test_offline_client(): """Ensure the cient can be used offline with a local provider.""" - fpath = "tests/data/query_v1/valid_quer1.json" - qr = QueryResponse.from_json(load_json(fpath)) + fpath = "tests/data/query_v2/query_response_container/valid_qrc2.json" + qrc = QueryResponseContainer.from_json(load_json(fpath)) - # The provider will have the QueryResponse from fpath - provider = InMemoryMapProviderV1([qr]) + # The provider will have the QueryResponseContainer from fpath + provider = InMemoryMapProviderV2(qrc) # The session will prevent StarmapClient to request a real server - session = StarmapMockSession("fake.starmap.url", "v1") + session = StarmapMockSession("fake.starmap.url", "v2") # Offline client - svc = StarmapClient(session=session, api_version="v1", provider=provider) + svc = StarmapClient(session=session, api_version="v2", provider=provider) assert session.json_data == {} assert session.status_code == 404 - assert svc.query_image("sample-policy-123.132-0.123", workflow="stratosphere") == qr - assert svc.query_image_by_name("sample-policy", "8.0", workflow="stratosphere") == qr + assert svc.query_image("product-test-123.132-0.123") == qrc + assert svc.query_image_by_name("product-test", "8.0") == qrc assert svc.get_destination("test") is None assert svc.get_mapping("test") is None assert svc.get_policy("test") is None diff --git a/tests/test_models.py b/tests/test_models.py index 0afbfee..a9e1122 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -11,7 +11,6 @@ Mapping, MappingResponseObject, Policy, - QueryResponse, QueryResponseContainer, QueryResponseEntity, Workflow, @@ -192,57 +191,6 @@ def test_frozen_policy(self): p.name = "test" -class TestV1QueryResponse: - @pytest.mark.parametrize( - "json_file", - [ - "tests/data/query_v1/valid_quer1.json", - "tests/data/query_v1/valid_quer2.json", - "tests/data/query_v1/valid_quer3.json", - "tests/data/query_v1/valid_quer4.json", - "tests/data/query_v1/valid_quer5.json", - ], - ) - def test_valid_query_resp_json(self, json_file: str) -> None: - data = load_json(json_file) - - # From JSON should always work - res = QueryResponse.from_json(data) - assert res - assert res.clouds - for k, v in res.clouds.items(): - assert isinstance(k, str), "Cloud names should be string" - assert isinstance(v, list), "Value of clouds should be \"List[Destination]\"." - for d in v: - assert isinstance(d, Destination), "Elements of clouds should be \"Destination\"" - - # While constructor is expected to fail when not all parameters are present - with pytest.raises(TypeError): - QueryResponse(**data) - - @pytest.mark.parametrize( - "json_file", - [ - "tests/data/query_v1/invalid_quer1.json", - "tests/data/query_v1/invalid_quer2.json", - ], - ) - def test_invalid_clouds(self, json_file) -> None: - data = load_json(json_file) - err = data.pop("error") - - with pytest.raises((TypeError, ValueError), match=err): - QueryResponse.from_json(data) - - def test_frozen_query(self): - data = load_json("tests/data/query_v1/valid_quer1.json") - - q = QueryResponse.from_json(data) - - with pytest.raises(FrozenInstanceError): - q.name = "test" - - class TestV2MappingResponseObject: @pytest.mark.parametrize( "json_file,meta,provider", @@ -354,32 +302,6 @@ def test_get_mapping_for_account(self) -> None: with pytest.raises(KeyError): q.get_mapping_for_account("foo-bar") - @pytest.mark.parametrize( - "json_file,old_api_file", - [ - ( - "tests/data/query_v2/query_response_entity/valid_qre2.json", - "tests/data/query_v2/query_response_entity/valid_qre_converted_old_api.json", - ), - ( - "tests/data/query_v2/query_response_entity/valid_qre3.json", - "tests/data/query_v2/query_response_entity/valid_qre_converted_old_api.json", - ), - ( - "tests/data/query_v2/query_response_entity/valid_qre4.json", - "tests/data/query_v2/query_response_entity/valid_qre_converted_old_api_community.json", # noqa: E501 - ), - ], - ) - def test_to_classic_query_response(self, json_file, old_api_file) -> None: - old_api_data = load_json(old_api_file) - expected_qr = QueryResponse.from_json(old_api_data) - - data = load_json(json_file) - q = QueryResponseEntity.from_json(data) - - assert q.to_classic_query_response() == expected_qr - class TestV2QueryResponseContainer: diff --git a/tests/test_providers/conftest.py b/tests/test_providers/conftest.py index 945ff1a..7b076cc 100644 --- a/tests/test_providers/conftest.py +++ b/tests/test_providers/conftest.py @@ -3,80 +3,7 @@ import pytest -from starmap_client.models import QueryResponse, QueryResponseContainer, QueryResponseEntity - -# ============================================ APIv1 =============================================== - - -@pytest.fixture -def qr1() -> Dict[str, Any]: - return { - "mappings": { - "aws-na": [ - { - "architecture": "x86_64", - "destination": "ffffffff-ffff-ffff-ffff-ffffffffffff", - "overwrite": True, - "restrict_version": False, - "meta": {"tag1": "aws-na-value1", "tag2": "aws-na-value2"}, - "tags": {"key1": "value1", "key2": "value2"}, - } - ], - "aws-emea": [ - { - "architecture": "x86_64", - "destination": "00000000-0000-0000-0000-000000000000", - "overwrite": True, - "restrict_version": False, - "meta": {"tag1": "aws-emea-value1", "tag2": "aws-emea-value2"}, - "tags": {"key3": "value3", "key4": "value4"}, - } - ], - }, - "name": "sample-product", - "workflow": "stratosphere", - } - - -@pytest.fixture -def qr2() -> Dict[str, Any]: - return { - "mappings": { - "aws-na": [ - { - "architecture": "x86_64", - "destination": "test-dest-1", - "overwrite": True, - "restrict_version": False, - "meta": {"tag1": "aws-na-value1", "tag2": "aws-na-value2"}, - "tags": {"key1": "value1", "key2": "value2"}, - } - ], - "aws-emea": [ - { - "architecture": "x86_64", - "destination": "test-dest-2", - "overwrite": True, - "restrict_version": False, - "meta": {"tag1": "aws-emea-value1", "tag2": "aws-emea-value2"}, - "tags": {"key3": "value3", "key4": "value4"}, - } - ], - }, - "name": "sample-product", - "workflow": "community", - } - - -@pytest.fixture -def qr1_object(qr1) -> QueryResponse: - return QueryResponse.from_json(qr1) - - -@pytest.fixture -def qr2_object(qr2) -> QueryResponse: - return QueryResponse.from_json(qr2) - +from starmap_client.models import QueryResponseContainer, QueryResponseEntity # ============================================ APIv2 =============================================== diff --git a/tests/test_providers/test_memory.py b/tests/test_providers/test_memory.py index 8407ee6..319cd71 100644 --- a/tests/test_providers/test_memory.py +++ b/tests/test_providers/test_memory.py @@ -2,60 +2,8 @@ import pytest -from starmap_client.models import QueryResponse, QueryResponseContainer, QueryResponseEntity -from starmap_client.providers import InMemoryMapProviderV1, InMemoryMapProviderV2 - - -class TestInMemoryMapProviderV1: - - def test_list_content(self, qr1_object: QueryResponse, qr2_object: QueryResponse) -> None: - data = [qr1_object, qr2_object] - - provider = InMemoryMapProviderV1(map_responses=data) - - assert provider.list_content() == data - - def test_store(self, qr1_object: QueryResponse, qr2_object: QueryResponse) -> None: - provider = InMemoryMapProviderV1() - - assert provider.list_content() == [] - - provider.store(qr1_object) - - assert provider.list_content() == [qr1_object] - - provider.store(qr2_object) - - assert provider.list_content() == [qr1_object, qr2_object] - - @pytest.mark.parametrize( - "params, expected", - [ - ( - {"name": "sample-product", "version": "8.0", "workflow": "stratosphere"}, - 'qr1_object', - ), - ({"name": "sample-product", "version": "8.1", "workflow": "community"}, 'qr2_object'), - ({"name": "another-product", "version": "8.2", "workflow": "stratosphere"}, None), - ({"name": "another-product", "version": "8.2", "workflow": "community"}, None), - ], - ) - def test_query( - self, - params: Dict[str, Any], - expected: Optional[str], - qr1_object: QueryResponse, - qr2_object: QueryResponse, - request: pytest.FixtureRequest, - ) -> None: - data = [qr1_object, qr2_object] - provider = InMemoryMapProviderV1(data) - - if expected is not None: - expected = request.getfixturevalue(expected) - - qr = provider.query(params) - assert qr == expected +from starmap_client.models import QueryResponseContainer, QueryResponseEntity +from starmap_client.providers import InMemoryMapProviderV2 class TestInMemoryMapProviderV2: