diff --git a/lib/openstack_query/queries/query_wrapper.py b/lib/openstack_query/queries/query_wrapper.py index c031f854d..044cfb36f 100644 --- a/lib/openstack_query/queries/query_wrapper.py +++ b/lib/openstack_query/queries/query_wrapper.py @@ -1,11 +1,9 @@ -from enums.query.props.prop_enum import PropEnum from openstack_query.query_output import QueryOutput from openstack_query.query_builder import QueryBuilder from openstack_query.query_parser import QueryParser from openstack_query.query_methods import QueryMethods from openstack_query.query_base import QueryBase -from openstack_query.runners.query_runner import QueryRunner # pylint:disable=too-few-public-methods @@ -18,18 +16,17 @@ class QueryWrapper(QueryMethods, QueryBase): QueryWrapper is a base class for all Query subclasses """ - def __init__(self, query_runner: QueryRunner, prop_enum_cls: PropEnum): - self.runner = query_runner - self.output = QueryOutput(prop_enum_cls) - self.parser = QueryParser(prop_enum_cls) + def __init__(self): + self.output = QueryOutput(self.prop_mapping) + self.parser = QueryParser(self.prop_mapping) self.builder = QueryBuilder( - prop_enum_cls, + self.prop_mapping, self._get_client_side_handlers().to_list(), self._get_server_side_handler(), ) super().__init__( builder=self.builder, - runner=self.runner, + runner=self.query_runner, parser=self.parser, output=self.output, ) diff --git a/lib/openstack_query/queries/server_query.py b/lib/openstack_query/queries/server_query.py index 15a26f061..588e4b5ae 100644 --- a/lib/openstack_query/queries/server_query.py +++ b/lib/openstack_query/queries/server_query.py @@ -1,3 +1,5 @@ +from typing import Type + from structs.query.query_client_side_handlers import QueryClientSideHandlers from enums.query.props.server_properties import ServerProperties @@ -22,8 +24,6 @@ from openstack_query.time_utils import TimeUtils -# pylint:disable=too-few-public-methods - class ServerQuery(QueryWrapper): """ @@ -31,8 +31,13 @@ class ServerQuery(QueryWrapper): Define property mappings, kwarg mappings and filter function mappings related to servers here """ - prop_enum_cls = ServerProperties - runner_cls = ServerRunner + @property + def prop_mapping(self) -> Type[ServerProperties]: + return ServerProperties + + @property + def query_runner(self) -> ServerRunner: + return ServerRunner(self.prop_mapping) def _get_server_side_handler(self) -> ServerSideHandler: """ diff --git a/lib/openstack_query/queries/user_query.py b/lib/openstack_query/queries/user_query.py index c027c1b40..9ef135e1f 100644 --- a/lib/openstack_query/queries/user_query.py +++ b/lib/openstack_query/queries/user_query.py @@ -1,3 +1,5 @@ +from typing import Type + from structs.query.query_client_side_handlers import QueryClientSideHandlers from enums.query.props.user_properties import UserProperties @@ -17,24 +19,25 @@ from openstack_query.runners.user_runner import UserRunner -# pylint:disable=too-few-public-methods - - class UserQuery(QueryWrapper): """ Query class for querying Openstack User objects. Define property mappings, kwarg mappings and filter function mappings related to users here """ - def __init__( - self, prop_enum_cls: UserProperties = None, query_runner: UserRunner = None - ): - prop_enum_cls = UserProperties if prop_enum_cls is None else prop_enum_cls - query_runner = ( - UserRunner(prop_enum_cls) if query_runner is None else query_runner - ) + @property + def prop_mapping(self) -> Type[UserProperties]: + """ + Property enum class for users + """ + return UserProperties - super().__init__(query_runner=query_runner, prop_enum_cls=prop_enum_cls) + @property + def query_runner(self) -> UserRunner: + """ + Constructs a QueryRunner class for users + """ + return UserRunner(self.prop_mapping) def _get_server_side_handler(self) -> ServerSideHandler: """ diff --git a/lib/openstack_query/query_base.py b/lib/openstack_query/query_base.py index 0b87b7e86..dc89b1226 100644 --- a/lib/openstack_query/query_base.py +++ b/lib/openstack_query/query_base.py @@ -1,9 +1,12 @@ from abc import ABC, abstractmethod -from structs.query.query_client_side_handlers import QueryClientSideHandlers +from typing import Type +from typing import TypeVar from openstack_query.handlers.server_side_handler import ServerSideHandler +from openstack_query.runners.query_runner import QueryRunner +from structs.query.query_client_side_handlers import QueryClientSideHandlers -# pylint:disable=too-few-public-methods +AnyPropEnum = TypeVar("AnyPropEnum", bound=Type["PropEnum"]) class QueryBase(ABC): @@ -12,6 +15,20 @@ class QueryBase(ABC): server-side, client-side and property handlers correctly """ + @property + @abstractmethod + def prop_mapping(self) -> Type[AnyPropEnum]: + """ + Returns the correct mapping for a given query class + """ + + @property + @abstractmethod + def query_runner(self) -> QueryRunner: + """ + Returns an instance for a given query class + """ + @abstractmethod def _get_server_side_handler(self) -> ServerSideHandler: """ diff --git a/lib/openstack_query/runners/query_runner.py b/lib/openstack_query/runners/query_runner.py index 81f2b08ac..a0e835101 100644 --- a/lib/openstack_query/runners/query_runner.py +++ b/lib/openstack_query/runners/query_runner.py @@ -1,18 +1,17 @@ -from abc import abstractmethod -import time import logging -from typing import Optional, List, Any, Dict, Callable - -from enums.cloud_domains import CloudDomains +import time +from abc import abstractmethod +from typing import Optional, List, Any, Dict, Callable, Type -from openstack_api.openstack_wrapper_base import OpenstackWrapperBase -from openstack_api.openstack_connection import OpenstackConnection from custom_types.openstack_query.aliases import ( - PropFunc, ServerSideFilters, ClientSideFilterFunc, OpenstackResourceObj, ) +from enums.cloud_domains import CloudDomains +from enums.query.props.prop_enum import PropEnum +from openstack_api.openstack_connection import OpenstackConnection +from openstack_api.openstack_wrapper_base import OpenstackWrapperBase logger = logging.getLogger(__name__) @@ -29,9 +28,9 @@ class QueryRunner(OpenstackWrapperBase): _LIMIT_FOR_PAGINATION = 1000 _PAGINATION_CALL_LIMIT = 1000 - def __init__(self, marker_prop_func: PropFunc, connection_cls=OpenstackConnection): + def __init__(self, prop_enum: Type[PropEnum], connection_cls=OpenstackConnection): OpenstackWrapperBase.__init__(self, connection_cls) - self._page_marker_prop_func = marker_prop_func + self._prop_enum = prop_enum def run( self, @@ -155,7 +154,7 @@ def _run_paginated_query( if i == self._LIMIT_FOR_PAGINATION - 1: # restart the for loop with marker set paginated_filters.update( - {"marker": self._page_marker_prop_func(resource)} + {"marker": self._prop_enum.get_prop_mapping(resource)} ) logger.debug( "page limit reached: %s - setting new marker: %s", diff --git a/lib/openstack_query/runners/user_runner.py b/lib/openstack_query/runners/user_runner.py index 3c669ea39..4c9e4d486 100644 --- a/lib/openstack_query/runners/user_runner.py +++ b/lib/openstack_query/runners/user_runner.py @@ -9,7 +9,6 @@ from exceptions.parse_query_error import ParseQueryError from exceptions.enum_mapping_error import EnumMappingError -from enums.query.props.user_properties import UserProperties from enums.user_domains import UserDomains logger = logging.getLogger(__name__) @@ -25,14 +24,6 @@ class UserRunner(QueryRunner): DEFAULT_DOMAIN = UserDomains.STFC - @staticmethod - def _get_marker(obj: User) -> str: - """ - This method returns the marker value for a User object, required for pagination - :param obj: An Server object to get the marker property for - """ - return UserProperties.get_prop_mapping("id")(obj) - def _parse_meta_params( self, conn: OpenstackConnection, from_domain: Optional[UserDomains] = None ) -> Dict: diff --git a/tests/lib/openstack_query/queries/test_server_query.py b/tests/lib/openstack_query/queries/test_server_query.py new file mode 100644 index 000000000..121c02233 --- /dev/null +++ b/tests/lib/openstack_query/queries/test_server_query.py @@ -0,0 +1,23 @@ +from unittest.mock import patch + +from enums.query.props.server_properties import ServerProperties +from openstack_query.queries.server_query import ServerQuery + + +def test_server_query_enum_type(): + """ + Checks that server query returns the correct PropEnum type + """ + assert ServerQuery().prop_mapping == ServerProperties + + +def test_server_query_runner_is_initialized(): + """ + Checks that server query runner is initialized + with the correct prop_mapping + """ + with patch("openstack_query.queries.server_query.ServerRunner") as constructor: + runner = ServerQuery().query_runner + + constructor.assert_called_with(ServerProperties) + assert runner == constructor.return_value diff --git a/tests/lib/openstack_query/queries/test_user_query.py b/tests/lib/openstack_query/queries/test_user_query.py new file mode 100644 index 000000000..02ca8033f --- /dev/null +++ b/tests/lib/openstack_query/queries/test_user_query.py @@ -0,0 +1,23 @@ +from unittest.mock import patch + +from enums.query.props.user_properties import UserProperties +from openstack_query.queries.user_query import UserQuery + + +def test_user_query_enum_type(): + """ + Checks that server query returns the correct PropEnum type + """ + assert UserQuery().prop_mapping == UserProperties + + +def test_user_query_runner_is_initialized(): + """ + Checks that server query runner is initialized + with the correct prop_mapping + """ + with patch("openstack_query.queries.user_query.UserRunner") as constructor: + runner = UserQuery().query_runner + + constructor.assert_called_with(UserProperties) + assert runner == constructor.return_value diff --git a/tests/lib/openstack_query/runners/test_query_runner.py b/tests/lib/openstack_query/runners/test_query_runner.py index 1661baa2f..aeb125ad9 100644 --- a/tests/lib/openstack_query/runners/test_query_runner.py +++ b/tests/lib/openstack_query/runners/test_query_runner.py @@ -1,5 +1,5 @@ import unittest -from unittest.mock import MagicMock, patch +from unittest.mock import MagicMock, patch, Mock from parameterized import parameterized from openstack_query.runners.query_runner import QueryRunner @@ -15,16 +15,13 @@ def setUp(self): """ super().setUp() self.mocked_connection = MagicMock() - self.mock_page_func = self._mock_page_func + self.mock_prop_enum = Mock() + self.mock_prop_enum.get_prop_mapping = lambda mock_obj: mock_obj["id"] self.instance = QueryRunner( - marker_prop_func=self.mock_page_func, connection_cls=self.mocked_connection + prop_enum=self.mock_prop_enum, connection_cls=self.mocked_connection ) self.conn = self.mocked_connection.return_value.__enter__.return_value - def _mock_page_func(self, mock_obj): - """simple mock func which returns "id" key from given dict""" - return mock_obj["id"] - @patch("openstack_query.runners.query_runner.QueryRunner._apply_client_side_filter") @patch("openstack_query.runners.query_runner.QueryRunner._run_query") @patch("openstack_query.runners.query_runner.QueryRunner._parse_meta_params")