From 0bdd77b1d152bde71a0625b5e7c347ee204d1a63 Mon Sep 17 00:00:00 2001 From: anish-mudaraddi Date: Tue, 25 Feb 2025 19:31:40 +0000 Subject: [PATCH 1/4] refactor client-side handlers combine all client-side handlers into one. - We don't get any benefits from separate client-side handlers. - separate out client-side filter functions into standalone - found in client_side_filters.py - makes adding new filter functions easy - refactor client-side tests so its easier to add new ones --- openstackquery/enums/query_presets.py | 115 +++----- openstackquery/enums/query_types.py | 3 + .../handlers/client_side_filters.py | 244 +++++++++++++++++ .../handlers/client_side_handler.py | 38 ++- .../handlers/client_side_handler_datetime.py | 142 ---------- .../handlers/client_side_handler_generic.py | 69 ----- .../handlers/client_side_handler_integer.py | 76 ----- .../handlers/client_side_handler_string.py | 35 --- openstackquery/mappings/flavor_mapping.py | 67 ++--- openstackquery/mappings/hypervisor_mapping.py | 69 ++--- openstackquery/mappings/image_mapping.py | 91 ++---- openstackquery/mappings/mapping_interface.py | 10 +- openstackquery/mappings/project_mapping.py | 59 ++-- openstackquery/mappings/server_mapping.py | 102 +++---- openstackquery/mappings/user_mapping.py | 59 ++-- openstackquery/query_base.py | 9 +- openstackquery/query_blocks/query_builder.py | 128 +++++---- openstackquery/query_blocks/query_chainer.py | 4 +- openstackquery/query_factory.py | 2 +- .../structs/query_client_side_handlers.py | 34 --- tests/enums/{props => }/conftest.py | 0 tests/enums/test_query_presets.py | 259 ++++-------------- tests/enums/test_query_types.py | 124 +++------ tests/enums/test_sort_order.py | 31 +-- tests/handlers/conftest.py | 51 ++++ ...ime.py => test_client_datetime_filters.py} | 69 ++--- tests/handlers/test_client_generic_filters.py | 73 +++++ tests/handlers/test_client_integer_filters.py | 50 ++++ tests/handlers/test_client_list_filters.py | 73 +++++ tests/handlers/test_client_side_handler.py | 56 ++-- .../test_client_side_handler_generic.py | 129 --------- .../test_client_side_handler_integer.py | 100 ------- .../test_client_side_handler_string.py | 80 ------ tests/handlers/test_client_string_filters.py | 30 ++ tests/mappings/conftest.py | 35 ++- tests/mappings/test_flavor_mapping.py | 84 ++---- tests/mappings/test_hypervisor_mapping.py | 68 ++--- tests/mappings/test_image_mapping.py | 133 +++------ tests/mappings/test_project_mapping.py | 51 +--- tests/mappings/test_server_mapping.py | 92 ++----- tests/mappings/test_user_mapping.py | 53 +--- tests/query_blocks/test_query_builder.py | 59 ++-- tests/query_blocks/test_query_chainer.py | 4 +- tests/test_query_factory.py | 2 +- 44 files changed, 1128 insertions(+), 1934 deletions(-) create mode 100644 openstackquery/handlers/client_side_filters.py delete mode 100644 openstackquery/handlers/client_side_handler_datetime.py delete mode 100644 openstackquery/handlers/client_side_handler_generic.py delete mode 100644 openstackquery/handlers/client_side_handler_integer.py delete mode 100644 openstackquery/handlers/client_side_handler_string.py delete mode 100644 openstackquery/structs/query_client_side_handlers.py rename tests/enums/{props => }/conftest.py (100%) create mode 100644 tests/handlers/conftest.py rename tests/handlers/{test_client_side_handler_datetime.py => test_client_datetime_filters.py} (58%) create mode 100644 tests/handlers/test_client_generic_filters.py create mode 100644 tests/handlers/test_client_integer_filters.py create mode 100644 tests/handlers/test_client_list_filters.py delete mode 100644 tests/handlers/test_client_side_handler_generic.py delete mode 100644 tests/handlers/test_client_side_handler_integer.py delete mode 100644 tests/handlers/test_client_side_handler_string.py create mode 100644 tests/handlers/test_client_string_filters.py diff --git a/openstackquery/enums/query_presets.py b/openstackquery/enums/query_presets.py index 08a8bad..1a02500 100644 --- a/openstackquery/enums/query_presets.py +++ b/openstackquery/enums/query_presets.py @@ -6,108 +6,65 @@ # pylint: disable=too-few-public-methods -class QueryPresetsGeneric(EnumWithAliases): +class QueryPresets(EnumWithAliases): """ Enum class which holds generic query comparison operators """ + # generic comparisons EQUAL_TO = auto() NOT_EQUAL_TO = auto() ANY_IN = auto() NOT_ANY_IN = auto() - @staticmethod - def _get_aliases(): - """ - A method that returns all valid string alias mappings - """ - return { - QueryPresetsGeneric.EQUAL_TO: ["equal", "=="], - QueryPresetsGeneric.NOT_EQUAL_TO: ["not_equal", "!="], - QueryPresetsGeneric.ANY_IN: ["in"], - QueryPresetsGeneric.NOT_ANY_IN: ["not_in"], - } - - -class QueryPresetsInteger(EnumWithAliases): - """ - Enum class which holds integer/float comparison operators - """ - + # integer comparisons GREATER_THAN = auto() GREATER_THAN_OR_EQUAL_TO = auto() LESS_THAN = auto() LESS_THAN_OR_EQUAL_TO = auto() - @staticmethod - def _get_aliases(): - """ - A method that returns all valid string alias mappings - """ - return { - QueryPresetsInteger.LESS_THAN: ["<"], - QueryPresetsInteger.GREATER_THAN: [">"], - QueryPresetsInteger.GREATER_THAN_OR_EQUAL_TO: [">="], - QueryPresetsInteger.LESS_THAN_OR_EQUAL_TO: ["<="], - } - - -class QueryPresetsDateTime(EnumWithAliases): - """ - Enum class which holds datetime comparison operators - """ - + # datetime comparisons OLDER_THAN = auto() OLDER_THAN_OR_EQUAL_TO = auto() YOUNGER_THAN = auto() YOUNGER_THAN_OR_EQUAL_TO = auto() - @staticmethod - def _get_aliases(): - """ - A method that returns all valid string alias mappings - """ - return { - QueryPresetsDateTime.YOUNGER_THAN: ["<"], - QueryPresetsDateTime.OLDER_THAN: [">"], - QueryPresetsDateTime.OLDER_THAN_OR_EQUAL_TO: [">="], - QueryPresetsDateTime.YOUNGER_THAN_OR_EQUAL_TO: ["<="], - } - - -class QueryPresetsString(EnumWithAliases): - """ - Enum class which holds string comparison operators - """ - + # string comparisons MATCHES_REGEX = auto() + # list comparisons + CONTAINS = auto() + NOT_CONTAINS = auto() + @staticmethod def _get_aliases(): """ A method that returns all valid string alias mappings """ - return {QueryPresetsString.MATCHES_REGEX: ["regex", "match_regex"]} - - -def get_preset_from_string(val: str): - """ - function that takes a string and returns a preset Enum if that string is an alias for that preset - :param val: a string alias to convert - """ - for preset_cls in [ - QueryPresetsGeneric, - QueryPresetsString, - QueryPresetsDateTime, - QueryPresetsInteger, - ]: - try: - return preset_cls.from_string(val) - except ParseQueryError: - continue - raise ParseQueryError(f"Could not find preset that matches alias {val}.") - - -QueryPresets = Union[ - QueryPresetsGeneric, QueryPresetsDateTime, QueryPresetsString, QueryPresetsInteger -] + return { + QueryPresets.EQUAL_TO: ["equal", "=="], + QueryPresets.NOT_EQUAL_TO: ["not_equal", "!="], + QueryPresets.ANY_IN: ["in"], + QueryPresets.NOT_ANY_IN: ["not_in"], + QueryPresets.LESS_THAN: ["less", "<"], + QueryPresets.GREATER_THAN: ["greater", "more_than", "more", ">"], + QueryPresets.GREATER_THAN_OR_EQUAL_TO: [ + "greater_or_equal", + "more_than_or_equal_to", + "more_or_equal", + ">=", + ], + QueryPresets.LESS_THAN_OR_EQUAL_TO: ["less_or_equal", "<="], + QueryPresets.YOUNGER_THAN: ["younger", "newer_than", "newer"], + QueryPresets.OLDER_THAN: ["older"], + QueryPresets.OLDER_THAN_OR_EQUAL_TO: ["older_or_equal"], + QueryPresets.YOUNGER_THAN_OR_EQUAL_TO: [ + "younger_or_equal", + "newer_than_or_equal_to", + "newer_or_equal", + "<=", + ], + QueryPresets.MATCHES_REGEX: ["match_regex", "regex", "re"], + # QueryPresets.CONTAINS: ["list_contains", "has"], + # QueryPresets.NOT_CONTAINS: ["list_not_contains", "has_not"] + } diff --git a/openstackquery/enums/query_types.py b/openstackquery/enums/query_types.py index 8a93cb9..fe8e4a3 100644 --- a/openstackquery/enums/query_types.py +++ b/openstackquery/enums/query_types.py @@ -39,6 +39,9 @@ def _get_aliases() -> Dict: "projectquery", ], QueryTypes.SERVER_QUERY: [ + "vm", + "vms", + "vmquery", "server", "servers", "serverquery", diff --git a/openstackquery/handlers/client_side_filters.py b/openstackquery/handlers/client_side_filters.py new file mode 100644 index 0000000..65fb81e --- /dev/null +++ b/openstackquery/handlers/client_side_filters.py @@ -0,0 +1,244 @@ +from typing import Union, Any, List +from datetime import datetime +import re + +from openstackquery.time_utils import TimeUtils +from openstackquery.aliases import PropValue + + +def prop_older_than( + prop: Union[str, None], + days: int = 0, + hours: int = 0, + minutes: int = 0, + seconds: int = 0, +): + """ + Filter function which returns True if property older than a relative amount of time since current time. + + :param prop: prop value to check against - in UTC time + :param days: (Optional) relative number of days since current time to compare against + :param hours: (Optional) relative number of hours since current time to compare against + :param minutes: (Optional) relative number of minutes since current time to compare against + :param seconds: (Optional) relative number of seconds since current time to compare against + + By default, all time args are set to 0, i.e. now. Setting this to 10 seconds would mean 10 seconds in the past. + You must give at least one non-zero argument (days, hours, minutes, seconds) otherwise a + MissingMandatoryArgument exception will be thrown + """ + if prop is None: + return False + prop_timestamp = datetime.strptime(prop, "%Y-%m-%dT%H:%M:%SZ").timestamp() + given_timestamp = TimeUtils.get_timestamp_in_seconds(days, hours, minutes, seconds) + + return prop_timestamp < given_timestamp + + +def prop_younger_than_or_equal_to( + prop: Union[str, None], + days: int = 0, + hours: int = 0, + minutes: int = 0, + seconds: int = 0, +): + """ + Filter function which returns True if property younger than or equal to a relative amount of time since + current time + :param prop: prop value to check against - in UTC time + :param days: (Optional) relative number of days since current time to compare against + :param hours: (Optional) relative number of hours since current time to compare against + :param minutes: (Optional) relative number of minutes since current time to compare against + :param seconds: (Optional) relative number of seconds since current time to compare against + + By default, all time args are set to 0, i.e. now. Setting this to 10 seconds would mean 10 seconds in the past. + You must give at least one non-zero argument (days, hours, minutes, seconds) otherwise a + MissingMandatoryArgument exception will be thrown + """ + if prop is None: + return False + prop_timestamp = datetime.strptime(prop, "%Y-%m-%dT%H:%M:%SZ").timestamp() + given_timestamp = TimeUtils.get_timestamp_in_seconds(days, hours, minutes, seconds) + return prop_timestamp >= given_timestamp + + +def prop_younger_than( + prop: Union[str, None], + days: int = 0, + hours: int = 0, + minutes: int = 0, + seconds: int = 0, +): + """ + Filter function which returns True if property younger than a relative amount of time since current time + :param prop: prop value to check against - in UTC time + :param days: (Optional) relative number of days since current time to compare against + :param hours: (Optional) relative number of hours since current time to compare against + :param minutes: (Optional) relative number of minutes since current time to compare against + :param seconds: (Optional) relative number of seconds since current time to compare against + + By default, all time args are set to 0, i.e. now. Setting this to 10 seconds would mean 10 seconds in the past. + You must give at least one non-zero argument (days, hours, minutes, seconds) otherwise a + MissingMandatoryArgument exception will be thrown + """ + if prop is None: + return False + prop_datetime = datetime.strptime(prop, "%Y-%m-%dT%H:%M:%SZ").timestamp() + return prop_datetime > TimeUtils.get_timestamp_in_seconds( + days, hours, minutes, seconds + ) + + +def prop_older_than_or_equal_to( + prop: Union[str, None], + days: int = 0, + hours: int = 0, + minutes: int = 0, + seconds: int = 0, +): + """ + Filter function which returns True if property older than or equal to a relative amount of time since current + time + :param prop: prop value to check against - in UTC time + :param days: (Optional) relative number of days since current time to compare against + :param hours: (Optional) relative number of hours since current time to compare against + :param minutes: (Optional) relative number of minutes since current time to compare against + :param seconds: (Optional) relative number of seconds since current time to compare against + + By default, all time args are set to 0, i.e. now. Setting this to 10 seconds would mean 10 seconds in the past. + You must give at least one non-zero argument (days, hours, minutes, seconds) otherwise a + MissingMandatoryArgument exception will be thrown + """ + if prop is None: + return False + prop_datetime = datetime.strptime(prop, "%Y-%m-%dT%H:%M:%SZ").timestamp() + return prop_datetime <= TimeUtils.get_timestamp_in_seconds( + days, hours, minutes, seconds + ) + + +def prop_not_any_in(prop: Any, values: List[PropValue]) -> bool: + """ + Filter function which returns true if a prop does not match any in a given list + :param prop: prop value to check against + :param values: a list of values to check against + """ + if len(values) == 0: + raise TypeError("values list must contain at least one item to match against") + res = any(prop == val for val in values) + return not res + + +def prop_any_in(prop: Any, values: List[PropValue]) -> bool: + """ + Filter function which returns true if a prop matches any in a given list + :param prop: prop value to check against + :param values: a list of values to check against + """ + if len(values) == 0: + raise TypeError("values list must contain at least one item to match against") + return any(prop == val for val in values) + + +def prop_not_equal_to(prop: Any, value: PropValue) -> bool: + """ + Filter function which returns true if a prop is not equal to a given value + :param prop: prop value to check against + :param value: given value to check against + """ + return not prop == value + + +def prop_equal_to(prop: Any, value: PropValue) -> bool: + """ + Filter function which returns true if a prop is equal to a given value + :param prop: prop value to check against + :param value: given value to check against + """ + return prop == value + + +def prop_less_than(prop: Union[int, float, None], value: Union[int, float]) -> bool: + """ + Filter function which returns true if a prop is less than a given value + :param prop: prop value to check against + :param value: given value to check against + """ + if prop is None: + return False + return prop < value + + +def prop_greater_than(prop: Union[int, float, None], value: Union[int, float]) -> bool: + """ + Filter function which returns true if a prop is greater than a given value + :param prop: prop value to check against + :param value: given value to check against + """ + if prop is None: + return False + return prop > value + + +def prop_less_than_or_equal_to( + prop: Union[int, float, None], value: Union[int, float] +) -> bool: + """ + Filter function which returns true if a prop is less than or equal to a given value + :param prop: prop value to check against + :param value: given value to check against + """ + if prop is None: + return False + return prop <= value + + +def prop_greater_than_or_equal_to( + prop: Union[int, float, None], value: Union[int, float] +) -> bool: + """ + Filter function which returns true if a prop is greater than or equal to a given value + :param prop: prop value to check against + :param value: given value to check against + """ + if prop is None: + return False + return prop >= value + + +def prop_matches_regex(prop: Union[str, None], value: str) -> bool: + """ + Filter function which returns true if a prop matches a regex pattern + :param prop: prop value to check against + :param value: a string which can be converted into a valid regex pattern to run + """ + if prop is None: + return False + res = re.match(re.compile(rf"{value}"), prop) + return bool(res) + + +def prop_list_contains(prop: Union[List, None], values: Union[PropValue, List]) -> bool: + """ + Filter function which returns true if a prop (a list) contains a value or sublist + :param prop: prop list to check against + :param values: a value or sublist of values to check if the prop list contains it + :return: + """ + if prop is None: + return False + + if isinstance(values, list): + return all(item in prop for item in values) + return values in prop + + +def prop_list_not_contains( + prop: Union[List, None], values: Union[PropValue, List] +) -> bool: + """ + Filter function which returns true if a prop (a list) DOES NOT contain a given value or sublist + :param prop: prop list to check against + :param values: a value or sublist of values to check if the prop list contains it + :return: + """ + return not prop_list_contains(prop, values) diff --git a/openstackquery/handlers/client_side_handler.py b/openstackquery/handlers/client_side_handler.py index 9d12d71..a9d7f2a 100644 --- a/openstackquery/handlers/client_side_handler.py +++ b/openstackquery/handlers/client_side_handler.py @@ -12,7 +12,24 @@ PropFunc, FilterParams, OpenstackResourceObj, - ClientSideFilterMappings, +) + +from openstackquery.handlers.client_side_filters import ( + prop_older_than, + prop_younger_than, + prop_older_than_or_equal_to, + prop_younger_than_or_equal_to, + prop_any_in, + prop_not_any_in, + prop_equal_to, + prop_not_equal_to, + prop_less_than, + prop_greater_than, + prop_greater_than_or_equal_to, + prop_less_than_or_equal_to, + prop_matches_regex, + prop_list_contains, + prop_list_not_contains, ) from openstackquery.enums.query_presets import QueryPresets @@ -30,11 +47,26 @@ class ClientSideHandler(HandlerBase): def __init__( self, - filter_mappings: ClientSideFilterMappings, preset_prop_mappings: ClientSidePresetPropertyMappings, ): self._filter_function_mappings = preset_prop_mappings - self._filter_functions = filter_mappings + self._filter_functions = { + QueryPresets.OLDER_THAN: prop_older_than, + QueryPresets.YOUNGER_THAN: prop_younger_than, + QueryPresets.OLDER_THAN_OR_EQUAL_TO: prop_older_than_or_equal_to, + QueryPresets.YOUNGER_THAN_OR_EQUAL_TO: prop_younger_than_or_equal_to, + QueryPresets.ANY_IN: prop_any_in, + QueryPresets.EQUAL_TO: prop_equal_to, + QueryPresets.NOT_ANY_IN: prop_not_any_in, + QueryPresets.NOT_EQUAL_TO: prop_not_equal_to, + QueryPresets.GREATER_THAN: prop_greater_than, + QueryPresets.LESS_THAN: prop_less_than, + QueryPresets.GREATER_THAN_OR_EQUAL_TO: prop_greater_than_or_equal_to, + QueryPresets.LESS_THAN_OR_EQUAL_TO: prop_less_than_or_equal_to, + QueryPresets.MATCHES_REGEX: prop_matches_regex, + QueryPresets.CONTAINS: prop_list_contains, + QueryPresets.NOT_CONTAINS: prop_list_not_contains, + } def get_supported_props(self, preset: QueryPresets) -> Union[List, List[PropEnum]]: """ diff --git a/openstackquery/handlers/client_side_handler_datetime.py b/openstackquery/handlers/client_side_handler_datetime.py deleted file mode 100644 index 53458e3..0000000 --- a/openstackquery/handlers/client_side_handler_datetime.py +++ /dev/null @@ -1,142 +0,0 @@ -from typing import Union -from datetime import datetime - -from openstackquery.enums.query_presets import QueryPresetsDateTime - -from openstackquery.aliases import ClientSidePresetPropertyMappings - -from openstackquery.time_utils import TimeUtils -from openstackquery.handlers.client_side_handler import ClientSideHandler - -# pylint: disable=too-many-arguments,too-few-public-methods - - -class ClientSideHandlerDateTime(ClientSideHandler): - """ - Client Side handler for Date Time related queries. - This class stores a dictionary which maps a Date Time preset/prop pairs to a filter function - Filter functions which map to QueryPresetsDateTime are defined here - """ - - def __init__(self, preset_prop_mappings: ClientSidePresetPropertyMappings): - filter_mappings = { - QueryPresetsDateTime.OLDER_THAN: self._prop_older_than, - QueryPresetsDateTime.YOUNGER_THAN: self._prop_younger_than, - QueryPresetsDateTime.OLDER_THAN_OR_EQUAL_TO: self._prop_older_than_or_equal_to, - QueryPresetsDateTime.YOUNGER_THAN_OR_EQUAL_TO: self._prop_younger_than_or_equal_to, - } - super().__init__(filter_mappings, preset_prop_mappings) - - @staticmethod - def _prop_older_than( - prop: Union[str, None], - days: int = 0, - hours: int = 0, - minutes: int = 0, - seconds: int = 0, - ): - """ - Filter function which returns True if property older than a relative amount of time since current time. - - :param prop: prop value to check against - in UTC time - :param days: (Optional) relative number of days since current time to compare against - :param hours: (Optional) relative number of hours since current time to compare against - :param minutes: (Optional) relative number of minutes since current time to compare against - :param seconds: (Optional) relative number of seconds since current time to compare against - - By default, all time args are set to 0, i.e. now. Setting this to 10 seconds would mean 10 seconds in the past. - You must give at least one non-zero argument (days, hours, minutes, seconds) otherwise a - MissingMandatoryArgument exception will be thrown - """ - if prop is None: - return False - prop_timestamp = datetime.strptime(prop, "%Y-%m-%dT%H:%M:%SZ").timestamp() - given_timestamp = TimeUtils.get_timestamp_in_seconds( - days, hours, minutes, seconds - ) - - return prop_timestamp < given_timestamp - - @staticmethod - def _prop_younger_than_or_equal_to( - prop: Union[str, None], - days: int = 0, - hours: int = 0, - minutes: int = 0, - seconds: int = 0, - ): - """ - Filter function which returns True if property younger than or equal to a relative amount of time since - current time - :param prop: prop value to check against - in UTC time - :param days: (Optional) relative number of days since current time to compare against - :param hours: (Optional) relative number of hours since current time to compare against - :param minutes: (Optional) relative number of minutes since current time to compare against - :param seconds: (Optional) relative number of seconds since current time to compare against - - By default, all time args are set to 0, i.e. now. Setting this to 10 seconds would mean 10 seconds in the past. - You must give at least one non-zero argument (days, hours, minutes, seconds) otherwise a - MissingMandatoryArgument exception will be thrown - """ - if prop is None: - return False - prop_timestamp = datetime.strptime(prop, "%Y-%m-%dT%H:%M:%SZ").timestamp() - given_timestamp = TimeUtils.get_timestamp_in_seconds( - days, hours, minutes, seconds - ) - return prop_timestamp >= given_timestamp - - @staticmethod - def _prop_younger_than( - prop: Union[str, None], - days: int = 0, - hours: int = 0, - minutes: int = 0, - seconds: int = 0, - ): - """ - Filter function which returns True if property younger than a relative amount of time since current time - :param prop: prop value to check against - in UTC time - :param days: (Optional) relative number of days since current time to compare against - :param hours: (Optional) relative number of hours since current time to compare against - :param minutes: (Optional) relative number of minutes since current time to compare against - :param seconds: (Optional) relative number of seconds since current time to compare against - - By default, all time args are set to 0, i.e. now. Setting this to 10 seconds would mean 10 seconds in the past. - You must give at least one non-zero argument (days, hours, minutes, seconds) otherwise a - MissingMandatoryArgument exception will be thrown - """ - if prop is None: - return False - prop_datetime = datetime.strptime(prop, "%Y-%m-%dT%H:%M:%SZ").timestamp() - return prop_datetime > TimeUtils.get_timestamp_in_seconds( - days, hours, minutes, seconds - ) - - @staticmethod - def _prop_older_than_or_equal_to( - prop: Union[str, None], - days: int = 0, - hours: int = 0, - minutes: int = 0, - seconds: int = 0, - ): - """ - Filter function which returns True if property older than or equal to a relative amount of time since current - time - :param prop: prop value to check against - in UTC time - :param days: (Optional) relative number of days since current time to compare against - :param hours: (Optional) relative number of hours since current time to compare against - :param minutes: (Optional) relative number of minutes since current time to compare against - :param seconds: (Optional) relative number of seconds since current time to compare against - - By default, all time args are set to 0, i.e. now. Setting this to 10 seconds would mean 10 seconds in the past. - You must give at least one non-zero argument (days, hours, minutes, seconds) otherwise a - MissingMandatoryArgument exception will be thrown - """ - if prop is None: - return False - prop_datetime = datetime.strptime(prop, "%Y-%m-%dT%H:%M:%SZ").timestamp() - return prop_datetime <= TimeUtils.get_timestamp_in_seconds( - days, hours, minutes, seconds - ) diff --git a/openstackquery/handlers/client_side_handler_generic.py b/openstackquery/handlers/client_side_handler_generic.py deleted file mode 100644 index 5117655..0000000 --- a/openstackquery/handlers/client_side_handler_generic.py +++ /dev/null @@ -1,69 +0,0 @@ -from typing import Any, List -from openstackquery.aliases import ClientSidePresetPropertyMappings, PropValue - -from openstackquery.enums.query_presets import QueryPresetsGeneric -from openstackquery.handlers.client_side_handler import ClientSideHandler - -# pylint: disable=too-few-public-methods - - -class ClientSideHandlerGeneric(ClientSideHandler): - """ - Client Side handler for 'Generic' queries. - This class stores a dictionary which maps a Generic preset/prop pairs to a filter function - Filter functions which map to QueryPresetsGeneric are defined here - """ - - def __init__(self, preset_prop_mappings: ClientSidePresetPropertyMappings): - filter_mappings = { - QueryPresetsGeneric.ANY_IN: self._prop_any_in, - QueryPresetsGeneric.EQUAL_TO: self._prop_equal_to, - QueryPresetsGeneric.NOT_ANY_IN: self._prop_not_any_in, - QueryPresetsGeneric.NOT_EQUAL_TO: self._prop_not_equal_to, - } - super().__init__(filter_mappings, preset_prop_mappings) - - @staticmethod - def _prop_not_any_in(prop: Any, values: List[PropValue]) -> bool: - """ - Filter function which returns true if a prop does not match any in a given list - :param prop: prop value to check against - :param values: a list of values to check against - """ - if len(values) == 0: - raise TypeError( - "values list must contain at least one item to match against" - ) - res = any(prop == val for val in values) - return not res - - @staticmethod - def _prop_any_in(prop: Any, values: List[PropValue]) -> bool: - """ - Filter function which returns true if a prop matches any in a given list - :param prop: prop value to check against - :param values: a list of values to check against - """ - if len(values) == 0: - raise TypeError( - "values list must contain at least one item to match against" - ) - return any(prop == val for val in values) - - @staticmethod - def _prop_not_equal_to(prop: Any, value: PropValue) -> bool: - """ - Filter function which returns true if a prop is not equal to a given value - :param prop: prop value to check against - :param value: given value to check against - """ - return not prop == value - - @staticmethod - def _prop_equal_to(prop: Any, value: PropValue) -> bool: - """ - Filter function which returns true if a prop is equal to a given value - :param prop: prop value to check against - :param value: given value to check against - """ - return prop == value diff --git a/openstackquery/handlers/client_side_handler_integer.py b/openstackquery/handlers/client_side_handler_integer.py deleted file mode 100644 index 804ea25..0000000 --- a/openstackquery/handlers/client_side_handler_integer.py +++ /dev/null @@ -1,76 +0,0 @@ -from typing import Union -from openstackquery.aliases import ClientSidePresetPropertyMappings - -from openstackquery.enums.query_presets import QueryPresetsInteger -from openstackquery.handlers.client_side_handler import ClientSideHandler - -# pylint: disable=too-few-public-methods - - -class ClientSideHandlerInteger(ClientSideHandler): - """ - Client Side handler for Integer related queries. - This class stores a dictionary which maps an Integer preset/prop pairs to a filter function - Filter functions which map to QueryPresetsInteger are defined here - """ - - def __init__(self, preset_prop_mappings: ClientSidePresetPropertyMappings): - filter_mappings = { - QueryPresetsInteger.GREATER_THAN: self._prop_greater_than, - QueryPresetsInteger.LESS_THAN: self._prop_less_than, - QueryPresetsInteger.GREATER_THAN_OR_EQUAL_TO: self._prop_greater_than_or_equal_to, - QueryPresetsInteger.LESS_THAN_OR_EQUAL_TO: self._prop_less_than_or_equal_to, - } - super().__init__(filter_mappings, preset_prop_mappings) - - @staticmethod - def _prop_less_than( - prop: Union[int, float, None], value: Union[int, float] - ) -> bool: - """ - Filter function which returns true if a prop is less than a given value - :param prop: prop value to check against - :param value: given value to check against - """ - if prop is None: - return False - return prop < value - - @staticmethod - def _prop_greater_than( - prop: Union[int, float, None], value: Union[int, float] - ) -> bool: - """ - Filter function which returns true if a prop is greater than a given value - :param prop: prop value to check against - :param value: given value to check against - """ - if prop is None: - return False - return prop > value - - @staticmethod - def _prop_less_than_or_equal_to( - prop: Union[int, float, None], value: Union[int, float] - ) -> bool: - """ - Filter function which returns true if a prop is less than or equal to a given value - :param prop: prop value to check against - :param value: given value to check against - """ - if prop is None: - return False - return prop <= value - - @staticmethod - def _prop_greater_than_or_equal_to( - prop: Union[int, float, None], value: Union[int, float] - ) -> bool: - """ - Filter function which returns true if a prop is greater than or equal to a given value - :param prop: prop value to check against - :param value: given value to check against - """ - if prop is None: - return False - return prop >= value diff --git a/openstackquery/handlers/client_side_handler_string.py b/openstackquery/handlers/client_side_handler_string.py deleted file mode 100644 index 68253d0..0000000 --- a/openstackquery/handlers/client_side_handler_string.py +++ /dev/null @@ -1,35 +0,0 @@ -import re - -from typing import Union -from openstackquery.aliases import ClientSidePresetPropertyMappings - -from openstackquery.enums.query_presets import QueryPresetsString -from openstackquery.handlers.client_side_handler import ClientSideHandler - -# pylint: disable=too-few-public-methods - - -class ClientSideHandlerString(ClientSideHandler): - """ - Client Side handler for String related queries. - This class stores a dictionary which maps a String preset/prop pairs to a filter function - Filter functions which map to QueryPresetsString are defined here - """ - - def __init__(self, preset_prop_mappings: ClientSidePresetPropertyMappings): - filter_mappings = { - QueryPresetsString.MATCHES_REGEX: self._prop_matches_regex, - } - super().__init__(filter_mappings, preset_prop_mappings) - - @staticmethod - def _prop_matches_regex(prop: Union[str, None], value: str) -> bool: - """ - Filter function which returns true if a prop matches a regex pattern - :param prop: prop value to check against - :param value: a string which can be converted into a valid regex pattern to run - """ - if prop is None: - return False - res = re.match(re.compile(rf"{value}"), prop) - return bool(res) diff --git a/openstackquery/mappings/flavor_mapping.py b/openstackquery/mappings/flavor_mapping.py index 5df6274..2f819fc 100644 --- a/openstackquery/mappings/flavor_mapping.py +++ b/openstackquery/mappings/flavor_mapping.py @@ -1,24 +1,12 @@ from typing import Type - from aliases import QueryChainMappings -from openstackquery.structs.query_client_side_handlers import QueryClientSideHandlers from openstackquery.enums.props.server_properties import ServerProperties from openstackquery.enums.props.flavor_properties import FlavorProperties -from openstackquery.enums.query_presets import ( - QueryPresetsGeneric, - QueryPresetsInteger, - QueryPresetsString, -) +from openstackquery.enums.query_presets import QueryPresets from openstackquery.handlers.server_side_handler import ServerSideHandler -from openstackquery.handlers.client_side_handler_generic import ( - ClientSideHandlerGeneric, -) -from openstackquery.handlers.client_side_handler_integer import ( - ClientSideHandlerInteger, -) -from openstackquery.handlers.client_side_handler_string import ClientSideHandlerString +from openstackquery.handlers.client_side_handler import ClientSideHandler from openstackquery.mappings.mapping_interface import MappingInterface from openstackquery.runners.flavor_runner import FlavorRunner @@ -66,17 +54,17 @@ def get_server_side_handler() -> ServerSideHandler: """ return ServerSideHandler( { - QueryPresetsGeneric.EQUAL_TO: { + QueryPresets.EQUAL_TO: { FlavorProperties.FLAVOR_IS_PUBLIC: lambda value: { "is_public": value } }, - QueryPresetsGeneric.NOT_EQUAL_TO: { + QueryPresets.NOT_EQUAL_TO: { FlavorProperties.FLAVOR_IS_PUBLIC: lambda value: { "is_public": not value } }, - QueryPresetsInteger.LESS_THAN_OR_EQUAL_TO: { + QueryPresets.LESS_THAN_OR_EQUAL_TO: { FlavorProperties.FLAVOR_DISK: lambda value: {"minDisk": int(value)}, FlavorProperties.FLAVOR_RAM: lambda value: {"minRam": int(value)}, }, @@ -84,13 +72,11 @@ def get_server_side_handler() -> ServerSideHandler: ) @staticmethod - def get_client_side_handlers() -> QueryClientSideHandlers: + def get_client_side_handler() -> ClientSideHandler: """ - method to configure a set of client-side handlers which can be used to get local filter functions - corresponding to valid preset-property pairs. These filter functions can be used to filter results after - listing all servers. + This function returns a client-side handler object which can be used to handle filtering results locally. + This function maps which properties are valid for each filter preset. """ - integer_prop_list = [ FlavorProperties.FLAVOR_RAM, FlavorProperties.FLAVOR_DISK, @@ -98,30 +84,17 @@ def get_client_side_handlers() -> QueryClientSideHandlers: FlavorProperties.FLAVOR_SWAP, FlavorProperties.FLAVOR_VCPU, ] - - return QueryClientSideHandlers( + return ClientSideHandler( # set generic query preset mappings - generic_handler=ClientSideHandlerGeneric( - { - QueryPresetsGeneric.EQUAL_TO: ["*"], - QueryPresetsGeneric.NOT_EQUAL_TO: ["*"], - QueryPresetsGeneric.ANY_IN: ["*"], - QueryPresetsGeneric.NOT_ANY_IN: ["*"], - } - ), - # set string query preset mappings - string_handler=ClientSideHandlerString( - {QueryPresetsString.MATCHES_REGEX: [FlavorProperties.FLAVOR_NAME]} - ), - # set datetime query preset mappings - datetime_handler=None, - # set integer query preset mappings - integer_handler=ClientSideHandlerInteger( - { - QueryPresetsInteger.LESS_THAN: integer_prop_list, - QueryPresetsInteger.LESS_THAN_OR_EQUAL_TO: integer_prop_list, - QueryPresetsInteger.GREATER_THAN: integer_prop_list, - QueryPresetsInteger.GREATER_THAN_OR_EQUAL_TO: integer_prop_list, - } - ), + { + QueryPresets.EQUAL_TO: ["*"], + QueryPresets.NOT_EQUAL_TO: ["*"], + QueryPresets.ANY_IN: ["*"], + QueryPresets.NOT_ANY_IN: ["*"], + QueryPresets.MATCHES_REGEX: [FlavorProperties.FLAVOR_NAME], + QueryPresets.LESS_THAN: integer_prop_list, + QueryPresets.LESS_THAN_OR_EQUAL_TO: integer_prop_list, + QueryPresets.GREATER_THAN: integer_prop_list, + QueryPresets.GREATER_THAN_OR_EQUAL_TO: integer_prop_list, + } ) diff --git a/openstackquery/mappings/hypervisor_mapping.py b/openstackquery/mappings/hypervisor_mapping.py index bad7f81..a67b47f 100644 --- a/openstackquery/mappings/hypervisor_mapping.py +++ b/openstackquery/mappings/hypervisor_mapping.py @@ -3,23 +3,15 @@ from aliases import QueryChainMappings from openstackquery.enums.props.hypervisor_properties import HypervisorProperties from openstackquery.enums.props.server_properties import ServerProperties -from openstackquery.enums.query_presets import ( - QueryPresetsGeneric, - QueryPresetsString, - QueryPresetsInteger, -) -from openstackquery.handlers.client_side_handler_generic import ( - ClientSideHandlerGeneric, -) -from openstackquery.handlers.client_side_handler_string import ClientSideHandlerString -from openstackquery.handlers.client_side_handler_integer import ClientSideHandlerInteger +from openstackquery.enums.query_presets import QueryPresets + +from openstackquery.handlers.client_side_handler import ClientSideHandler from openstackquery.handlers.server_side_handler import ServerSideHandler from openstackquery.mappings.mapping_interface import MappingInterface from openstackquery.runners.hypervisor_runner import HypervisorRunner from openstackquery.runners.runner_wrapper import RunnerWrapper -from openstackquery.structs.query_client_side_handlers import QueryClientSideHandlers class HypervisorMapping(MappingInterface): @@ -70,11 +62,10 @@ def get_server_side_handler() -> ServerSideHandler: return ServerSideHandler({}) @staticmethod - def get_client_side_handlers() -> QueryClientSideHandlers: + def get_client_side_handler() -> ClientSideHandler: """ - method to configure a set of client-side handlers which can be used to get local filter functions - corresponding to valid preset-property pairs. These filter functions can be used to filter results after - listing all hypervisors. + This function returns a client-side handler object which can be used to handle filtering results locally. + This function maps which properties are valid for each filter preset. """ integer_prop_list = [ HypervisorProperties.VCPUS_AVAIL, @@ -87,36 +78,20 @@ def get_client_side_handlers() -> QueryClientSideHandlers: HypervisorProperties.DISK_GB_SIZE, HypervisorProperties.MEMORY_MB_SIZE, ] - - return QueryClientSideHandlers( - # set generic query preset mappings - generic_handler=ClientSideHandlerGeneric( - { - QueryPresetsGeneric.EQUAL_TO: ["*"], - QueryPresetsGeneric.NOT_EQUAL_TO: ["*"], - QueryPresetsGeneric.ANY_IN: ["*"], - QueryPresetsGeneric.NOT_ANY_IN: ["*"], - } - ), - # set string query preset mappings - string_handler=ClientSideHandlerString( - { - QueryPresetsString.MATCHES_REGEX: [ - HypervisorProperties.HYPERVISOR_IP, - HypervisorProperties.HYPERVISOR_NAME, - HypervisorProperties.HYPERVISOR_DISABLED_REASON, - ] - } - ), - # set datetime query preset mappings - datetime_handler=None, - # set integer query preset mappings - integer_handler=ClientSideHandlerInteger( - { - QueryPresetsInteger.LESS_THAN: integer_prop_list, - QueryPresetsInteger.LESS_THAN_OR_EQUAL_TO: integer_prop_list, - QueryPresetsInteger.GREATER_THAN: integer_prop_list, - QueryPresetsInteger.GREATER_THAN_OR_EQUAL_TO: integer_prop_list, - } - ), + return ClientSideHandler( + { + QueryPresets.EQUAL_TO: ["*"], + QueryPresets.NOT_EQUAL_TO: ["*"], + QueryPresets.ANY_IN: ["*"], + QueryPresets.NOT_ANY_IN: ["*"], + QueryPresets.MATCHES_REGEX: [ + HypervisorProperties.HYPERVISOR_IP, + HypervisorProperties.HYPERVISOR_NAME, + HypervisorProperties.HYPERVISOR_DISABLED_REASON, + ], + QueryPresets.LESS_THAN: integer_prop_list, + QueryPresets.GREATER_THAN: integer_prop_list, + QueryPresets.LESS_THAN_OR_EQUAL_TO: integer_prop_list, + QueryPresets.GREATER_THAN_OR_EQUAL_TO: integer_prop_list, + } ) diff --git a/openstackquery/mappings/image_mapping.py b/openstackquery/mappings/image_mapping.py index 4ce6c0a..fa6ccf7 100644 --- a/openstackquery/mappings/image_mapping.py +++ b/openstackquery/mappings/image_mapping.py @@ -3,28 +3,14 @@ from aliases import QueryChainMappings from openstackquery.enums.props.image_properties import ImageProperties from openstackquery.enums.props.server_properties import ServerProperties -from openstackquery.enums.query_presets import ( - QueryPresetsGeneric, - QueryPresetsDateTime, - QueryPresetsInteger, - QueryPresetsString, -) -from openstackquery.handlers.client_side_handler_datetime import ( - ClientSideHandlerDateTime, -) -from openstackquery.handlers.client_side_handler_generic import ( - ClientSideHandlerGeneric, -) -from openstackquery.handlers.client_side_handler_integer import ( - ClientSideHandlerInteger, -) -from openstackquery.handlers.client_side_handler_string import ClientSideHandlerString +from openstackquery.enums.query_presets import QueryPresets + +from openstackquery.handlers.client_side_handler import ClientSideHandler from openstackquery.handlers.server_side_handler import ServerSideHandler from openstackquery.mappings.mapping_interface import MappingInterface from openstackquery.runners.image_runner import ImageRunner from openstackquery.time_utils import TimeUtils -from openstackquery.structs.query_client_side_handlers import QueryClientSideHandlers class ImageMapping(MappingInterface): @@ -67,11 +53,11 @@ def get_server_side_handler() -> ServerSideHandler: """ return ServerSideHandler( { - QueryPresetsGeneric.EQUAL_TO: { + QueryPresets.EQUAL_TO: { ImageProperties.IMAGE_NAME: lambda value: {"name": value}, ImageProperties.IMAGE_STATUS: lambda value: {"status": value}, }, - QueryPresetsGeneric.ANY_IN: { + QueryPresets.ANY_IN: { ImageProperties.IMAGE_NAME: lambda values: [ {"name": value} for value in values ], @@ -79,7 +65,7 @@ def get_server_side_handler() -> ServerSideHandler: {"status": value} for value in values ], }, - QueryPresetsDateTime.OLDER_THAN: { + QueryPresets.OLDER_THAN: { ImageProperties.IMAGE_CREATION_DATE: lambda func=TimeUtils.convert_to_timestamp, **kwargs: { "created_at": f"lt:{func(**kwargs)}" }, @@ -87,7 +73,7 @@ def get_server_side_handler() -> ServerSideHandler: "updated_at": f"lt:{func(**kwargs)}" }, }, - QueryPresetsDateTime.OLDER_THAN_OR_EQUAL_TO: { + QueryPresets.OLDER_THAN_OR_EQUAL_TO: { ImageProperties.IMAGE_CREATION_DATE: lambda func=TimeUtils.convert_to_timestamp, **kwargs: { "created_at": f"lte:{func(**kwargs)}" }, @@ -95,7 +81,7 @@ def get_server_side_handler() -> ServerSideHandler: "updated_at": f"lte:{func(**kwargs)}" }, }, - QueryPresetsDateTime.YOUNGER_THAN: { + QueryPresets.YOUNGER_THAN: { ImageProperties.IMAGE_CREATION_DATE: lambda func=TimeUtils.convert_to_timestamp, **kwargs: { "created_at": f"gt:{func(**kwargs)}" }, @@ -103,7 +89,7 @@ def get_server_side_handler() -> ServerSideHandler: "updated_at": f"gt:{func(**kwargs)}" }, }, - QueryPresetsDateTime.YOUNGER_THAN_OR_EQUAL_TO: { + QueryPresets.YOUNGER_THAN_OR_EQUAL_TO: { ImageProperties.IMAGE_CREATION_DATE: lambda func=TimeUtils.convert_to_timestamp, **kwargs: { "created_at": f"gte:{func(**kwargs)}" }, @@ -111,21 +97,20 @@ def get_server_side_handler() -> ServerSideHandler: "updated_at": f"gte:{func(**kwargs)}" }, }, - QueryPresetsInteger.GREATER_THAN_OR_EQUAL_TO: { + QueryPresets.GREATER_THAN_OR_EQUAL_TO: { ImageProperties.IMAGE_SIZE: lambda value: {"size_min": int(value)} }, - QueryPresetsInteger.LESS_THAN_OR_EQUAL_TO: { + QueryPresets.LESS_THAN_OR_EQUAL_TO: { ImageProperties.IMAGE_SIZE: lambda value: {"size_max": int(value)} }, } ) @staticmethod - def get_client_side_handlers() -> QueryClientSideHandlers: + def get_client_side_handler() -> ClientSideHandler: """ - method to configure a set of client-side handlers which can be used to get local filter functions - corresponding to valid preset-property pairs. These filter functions can be used to filter results after - listing all servers. + This function returns a client-side handler object which can be used to handle filtering results locally. + This function maps which properties are valid for each filter preset. """ integer_prop_list = [ ImageProperties.IMAGE_SIZE, @@ -138,36 +123,20 @@ def get_client_side_handlers() -> QueryClientSideHandlers: ImageProperties.IMAGE_LAST_UPDATED_DATE, ] - return QueryClientSideHandlers( - # set generic query preset mappings - generic_handler=ClientSideHandlerGeneric( - { - QueryPresetsGeneric.EQUAL_TO: ["*"], - QueryPresetsGeneric.NOT_EQUAL_TO: ["*"], - QueryPresetsGeneric.ANY_IN: ["*"], - QueryPresetsGeneric.NOT_ANY_IN: ["*"], - } - ), - # set string query preset mappings - string_handler=ClientSideHandlerString( - {QueryPresetsString.MATCHES_REGEX: [ImageProperties.IMAGE_NAME]} - ), - # set datetime query preset mappings - datetime_handler=ClientSideHandlerDateTime( - { - QueryPresetsDateTime.YOUNGER_THAN: date_prop_list, - QueryPresetsDateTime.YOUNGER_THAN_OR_EQUAL_TO: date_prop_list, - QueryPresetsDateTime.OLDER_THAN: date_prop_list, - QueryPresetsDateTime.OLDER_THAN_OR_EQUAL_TO: date_prop_list, - } - ), - # set integer query preset mappings - integer_handler=ClientSideHandlerInteger( - { - QueryPresetsInteger.LESS_THAN: integer_prop_list, - QueryPresetsInteger.LESS_THAN_OR_EQUAL_TO: integer_prop_list, - QueryPresetsInteger.GREATER_THAN: integer_prop_list, - QueryPresetsInteger.GREATER_THAN_OR_EQUAL_TO: integer_prop_list, - } - ), + return ClientSideHandler( + { + QueryPresets.EQUAL_TO: ["*"], + QueryPresets.NOT_EQUAL_TO: ["*"], + QueryPresets.ANY_IN: ["*"], + QueryPresets.NOT_ANY_IN: ["*"], + QueryPresets.MATCHES_REGEX: [ImageProperties.IMAGE_NAME], + QueryPresets.YOUNGER_THAN: date_prop_list, + QueryPresets.YOUNGER_THAN_OR_EQUAL_TO: date_prop_list, + QueryPresets.OLDER_THAN: date_prop_list, + QueryPresets.OLDER_THAN_OR_EQUAL_TO: date_prop_list, + QueryPresets.LESS_THAN: integer_prop_list, + QueryPresets.LESS_THAN_OR_EQUAL_TO: integer_prop_list, + QueryPresets.GREATER_THAN: integer_prop_list, + QueryPresets.GREATER_THAN_OR_EQUAL_TO: integer_prop_list, + } ) diff --git a/openstackquery/mappings/mapping_interface.py b/openstackquery/mappings/mapping_interface.py index b2f0a71..41b8e45 100644 --- a/openstackquery/mappings/mapping_interface.py +++ b/openstackquery/mappings/mapping_interface.py @@ -3,8 +3,9 @@ from aliases import QueryChainMappings from openstackquery.enums.props.prop_enum import PropEnum -from openstackquery.structs.query_client_side_handlers import QueryClientSideHandlers from openstackquery.runners.runner_wrapper import RunnerWrapper + +from openstackquery.handlers.client_side_handler import ClientSideHandler from openstackquery.handlers.server_side_handler import ServerSideHandler @@ -32,11 +33,10 @@ def get_server_side_handler() -> ServerSideHandler: @staticmethod @abstractmethod - def get_client_side_handlers() -> QueryClientSideHandlers: + def get_client_side_handler() -> ClientSideHandler: """ - Should return a dataclass where each attribute maps to a client-side filter handler. These objects can be used - to get a filter function to filter a list of openstack resource objects after gathering them using openstacksdk - command + This function returns a client-side handler object which can be used to handle filtering results locally. + This function maps which properties are valid for each filter preset. """ @staticmethod diff --git a/openstackquery/mappings/project_mapping.py b/openstackquery/mappings/project_mapping.py index 19bd2d1..acec729 100644 --- a/openstackquery/mappings/project_mapping.py +++ b/openstackquery/mappings/project_mapping.py @@ -1,20 +1,12 @@ from typing import Type - from aliases import QueryChainMappings -from openstackquery.structs.query_client_side_handlers import QueryClientSideHandlers +from openstackquery.enums.query_presets import QueryPresets from openstackquery.enums.props.project_properties import ProjectProperties -from openstackquery.enums.query_presets import ( - QueryPresetsGeneric, - QueryPresetsString, -) from openstackquery.enums.props.server_properties import ServerProperties from openstackquery.handlers.server_side_handler import ServerSideHandler -from openstackquery.handlers.client_side_handler_generic import ( - ClientSideHandlerGeneric, -) -from openstackquery.handlers.client_side_handler_string import ClientSideHandlerString +from openstackquery.handlers.client_side_handler import ClientSideHandler from openstackquery.mappings.mapping_interface import MappingInterface from openstackquery.runners.project_runner import ProjectRunner @@ -60,7 +52,7 @@ def get_server_side_handler() -> ServerSideHandler: """ return ServerSideHandler( { - QueryPresetsGeneric.EQUAL_TO: { + QueryPresets.EQUAL_TO: { ProjectProperties.PROJECT_ID: lambda value: {"id": value}, ProjectProperties.PROJECT_DOMAIN_ID: lambda value: { "domain_id": value @@ -76,7 +68,7 @@ def get_server_side_handler() -> ServerSideHandler: "parent_id": value }, }, - QueryPresetsGeneric.NOT_EQUAL_TO: { + QueryPresets.NOT_EQUAL_TO: { ProjectProperties.PROJECT_IS_ENABLED: lambda value: { "is_enabled": not value }, @@ -84,7 +76,7 @@ def get_server_side_handler() -> ServerSideHandler: "is_domain": not value }, }, - QueryPresetsGeneric.ANY_IN: { + QueryPresets.ANY_IN: { ProjectProperties.PROJECT_ID: lambda values: [ {"id": value} for value in values ], @@ -102,34 +94,21 @@ def get_server_side_handler() -> ServerSideHandler: ) @staticmethod - def get_client_side_handlers() -> QueryClientSideHandlers: + def get_client_side_handler() -> ClientSideHandler: """ - method to configure a set of client-side handlers which can be used to get local filter functions - corresponding to valid preset-property pairs. These filter functions can be used to filter results after - listing all servers. + This function returns a client-side handler object which can be used to handle filtering results locally. + This function maps which properties are valid for each filter preset. """ - return QueryClientSideHandlers( - # set generic query preset mappings - generic_handler=ClientSideHandlerGeneric( - { - QueryPresetsGeneric.EQUAL_TO: ["*"], - QueryPresetsGeneric.NOT_EQUAL_TO: ["*"], - QueryPresetsGeneric.ANY_IN: ["*"], - QueryPresetsGeneric.NOT_ANY_IN: ["*"], - } - ), - # set string query preset mappings - string_handler=ClientSideHandlerString( - { - QueryPresetsString.MATCHES_REGEX: [ - ProjectProperties.PROJECT_NAME, - ProjectProperties.PROJECT_DESCRIPTION, - ] - } - ), - # set datetime query preset mappings - datetime_handler=None, - # set integer query preset mappings - integer_handler=None, + return ClientSideHandler( + { + QueryPresets.EQUAL_TO: ["*"], + QueryPresets.NOT_EQUAL_TO: ["*"], + QueryPresets.ANY_IN: ["*"], + QueryPresets.NOT_ANY_IN: ["*"], + QueryPresets.MATCHES_REGEX: [ + ProjectProperties.PROJECT_NAME, + ProjectProperties.PROJECT_DESCRIPTION, + ], + } ) diff --git a/openstackquery/mappings/server_mapping.py b/openstackquery/mappings/server_mapping.py index bb78348..a2b897e 100644 --- a/openstackquery/mappings/server_mapping.py +++ b/openstackquery/mappings/server_mapping.py @@ -1,30 +1,18 @@ from typing import Type - from aliases import QueryChainMappings -from openstackquery.structs.query_client_side_handlers import QueryClientSideHandlers from openstackquery.enums.props.server_properties import ServerProperties -from openstackquery.enums.query_presets import ( - QueryPresetsGeneric, - QueryPresetsDateTime, - QueryPresetsString, -) +from openstackquery.enums.query_presets import QueryPresets + from openstackquery.enums.props.user_properties import UserProperties from openstackquery.enums.props.project_properties import ProjectProperties from openstackquery.enums.props.flavor_properties import FlavorProperties from openstackquery.enums.props.image_properties import ImageProperties from openstackquery.enums.props.hypervisor_properties import HypervisorProperties +from openstackquery.handlers.client_side_handler import ClientSideHandler from openstackquery.handlers.server_side_handler import ServerSideHandler -from openstackquery.handlers.client_side_handler_generic import ( - ClientSideHandlerGeneric, -) -from openstackquery.handlers.client_side_handler_string import ClientSideHandlerString -from openstackquery.handlers.client_side_handler_datetime import ( - ClientSideHandlerDateTime, -) - from openstackquery.mappings.mapping_interface import MappingInterface from openstackquery.runners.server_runner import ServerRunner @@ -79,7 +67,7 @@ def get_server_side_handler() -> ServerSideHandler: """ return ServerSideHandler( { - QueryPresetsGeneric.EQUAL_TO: { + QueryPresets.EQUAL_TO: { ServerProperties.USER_ID: lambda value: {"user_id": value}, ServerProperties.SERVER_ID: lambda value: {"uuid": value}, ServerProperties.SERVER_NAME: lambda value: {"hostname": value}, @@ -94,7 +82,7 @@ def get_server_side_handler() -> ServerSideHandler: ServerProperties.IMAGE_ID: lambda value: {"image": value}, ServerProperties.PROJECT_ID: lambda value: {"project_id": value}, }, - QueryPresetsGeneric.ANY_IN: { + QueryPresets.ANY_IN: { ServerProperties.USER_ID: lambda values: [ {"user_id": value} for value in values ], @@ -123,12 +111,12 @@ def get_server_side_handler() -> ServerSideHandler: {"project_id": value} for value in values ], }, - QueryPresetsDateTime.OLDER_THAN_OR_EQUAL_TO: { + QueryPresets.OLDER_THAN_OR_EQUAL_TO: { ServerProperties.SERVER_LAST_UPDATED_DATE: lambda func=TimeUtils.convert_to_timestamp, **kwargs: { "changes-before": func(**kwargs) } }, - QueryPresetsDateTime.YOUNGER_THAN_OR_EQUAL_TO: { + QueryPresets.YOUNGER_THAN_OR_EQUAL_TO: { ServerProperties.SERVER_LAST_UPDATED_DATE: lambda func=TimeUtils.convert_to_timestamp, **kwargs: { "changes-since": func(**kwargs) } @@ -137,52 +125,36 @@ def get_server_side_handler() -> ServerSideHandler: ) @staticmethod - def get_client_side_handlers() -> QueryClientSideHandlers: + def get_client_side_handler() -> ClientSideHandler: """ - method to configure a set of client-side handlers which can be used to get local filter functions - corresponding to valid preset-property pairs. These filter functions can be used to filter results after - listing all servers. + This function returns a client-side handler object which can be used to handle filtering results locally. + This function maps which properties are valid for each filter preset. """ - return QueryClientSideHandlers( - # set generic query preset mappings - generic_handler=ClientSideHandlerGeneric( - { - QueryPresetsGeneric.EQUAL_TO: ["*"], - QueryPresetsGeneric.NOT_EQUAL_TO: ["*"], - QueryPresetsGeneric.ANY_IN: ["*"], - QueryPresetsGeneric.NOT_ANY_IN: ["*"], - } - ), - # set string query preset mappings - string_handler=ClientSideHandlerString( - { - QueryPresetsString.MATCHES_REGEX: [ - ServerProperties.SERVER_NAME, - ServerProperties.ADDRESSES, - ] - } - ), - # set datetime query preset mappings - datetime_handler=ClientSideHandlerDateTime( - { - QueryPresetsDateTime.OLDER_THAN: [ - ServerProperties.SERVER_CREATION_DATE, - ServerProperties.SERVER_LAST_UPDATED_DATE, - ], - QueryPresetsDateTime.YOUNGER_THAN: [ - ServerProperties.SERVER_CREATION_DATE, - ServerProperties.SERVER_LAST_UPDATED_DATE, - ], - QueryPresetsDateTime.YOUNGER_THAN_OR_EQUAL_TO: [ - ServerProperties.SERVER_CREATION_DATE, - ServerProperties.SERVER_LAST_UPDATED_DATE, - ], - QueryPresetsDateTime.OLDER_THAN_OR_EQUAL_TO: [ - ServerProperties.SERVER_CREATION_DATE, - ServerProperties.SERVER_LAST_UPDATED_DATE, - ], - } - ), - # set integer query preset mappings - integer_handler=None, + return ClientSideHandler( + { + QueryPresets.EQUAL_TO: ["*"], + QueryPresets.NOT_EQUAL_TO: ["*"], + QueryPresets.ANY_IN: ["*"], + QueryPresets.NOT_ANY_IN: ["*"], + QueryPresets.MATCHES_REGEX: [ + ServerProperties.SERVER_NAME, + ServerProperties.ADDRESSES, + ], + QueryPresets.OLDER_THAN: [ + ServerProperties.SERVER_CREATION_DATE, + ServerProperties.SERVER_LAST_UPDATED_DATE, + ], + QueryPresets.YOUNGER_THAN: [ + ServerProperties.SERVER_CREATION_DATE, + ServerProperties.SERVER_LAST_UPDATED_DATE, + ], + QueryPresets.YOUNGER_THAN_OR_EQUAL_TO: [ + ServerProperties.SERVER_CREATION_DATE, + ServerProperties.SERVER_LAST_UPDATED_DATE, + ], + QueryPresets.OLDER_THAN_OR_EQUAL_TO: [ + ServerProperties.SERVER_CREATION_DATE, + ServerProperties.SERVER_LAST_UPDATED_DATE, + ], + } ) diff --git a/openstackquery/mappings/user_mapping.py b/openstackquery/mappings/user_mapping.py index 5670bd5..4e6e4eb 100644 --- a/openstackquery/mappings/user_mapping.py +++ b/openstackquery/mappings/user_mapping.py @@ -1,22 +1,12 @@ from typing import Type - from aliases import QueryChainMappings -from openstackquery.structs.query_client_side_handlers import QueryClientSideHandlers from openstackquery.enums.props.user_properties import UserProperties -from openstackquery.enums.query_presets import ( - QueryPresetsGeneric, - QueryPresetsString, -) from openstackquery.enums.props.server_properties import ServerProperties +from openstackquery.enums.query_presets import QueryPresets from openstackquery.handlers.server_side_handler import ServerSideHandler - - -from openstackquery.handlers.client_side_handler_generic import ( - ClientSideHandlerGeneric, -) -from openstackquery.handlers.client_side_handler_string import ClientSideHandlerString +from openstackquery.handlers.client_side_handler import ClientSideHandler from openstackquery.mappings.mapping_interface import MappingInterface from openstackquery.runners.user_runner import UserRunner @@ -63,12 +53,12 @@ def get_server_side_handler() -> ServerSideHandler: """ return ServerSideHandler( { - QueryPresetsGeneric.EQUAL_TO: { + QueryPresets.EQUAL_TO: { UserProperties.USER_DOMAIN_ID: lambda value: {"domain_id": value}, UserProperties.USER_NAME: lambda value: {"name": value}, UserProperties.USER_ID: lambda value: {"id": value}, }, - QueryPresetsGeneric.ANY_IN: { + QueryPresets.ANY_IN: { UserProperties.USER_DOMAIN_ID: lambda values: [ {"domain_id": value} for value in values ], @@ -83,33 +73,20 @@ def get_server_side_handler() -> ServerSideHandler: ) @staticmethod - def get_client_side_handlers() -> QueryClientSideHandlers: + def get_client_side_handler() -> ClientSideHandler: """ - method to configure a set of client-side handlers which can be used to get local filter functions - corresponding to valid preset-property pairs. These filter functions can be used to filter results after - listing all users. + This function returns a client-side handler object which can be used to handle filtering results locally. + This function maps which properties are valid for each filter preset. """ - return QueryClientSideHandlers( - # set generic query preset mappings - generic_handler=ClientSideHandlerGeneric( - { - QueryPresetsGeneric.EQUAL_TO: ["*"], - QueryPresetsGeneric.NOT_EQUAL_TO: ["*"], - QueryPresetsGeneric.ANY_IN: ["*"], - QueryPresetsGeneric.NOT_ANY_IN: ["*"], - } - ), - # set string query preset mappings - string_handler=ClientSideHandlerString( - { - QueryPresetsString.MATCHES_REGEX: [ - UserProperties.USER_EMAIL, - UserProperties.USER_NAME, - ] - } - ), - # set datetime query preset mappings - datetime_handler=None, - # set integer query preset mappings - integer_handler=None, + return ClientSideHandler( + { + QueryPresets.EQUAL_TO: ["*"], + QueryPresets.NOT_EQUAL_TO: ["*"], + QueryPresets.ANY_IN: ["*"], + QueryPresets.NOT_ANY_IN: ["*"], + QueryPresets.MATCHES_REGEX: [ + UserProperties.USER_EMAIL, + UserProperties.USER_NAME, + ], + } ) diff --git a/openstackquery/query_base.py b/openstackquery/query_base.py index 20240f5..31ff81a 100644 --- a/openstackquery/query_base.py +++ b/openstackquery/query_base.py @@ -1,6 +1,6 @@ from abc import ABC, abstractmethod -from openstackquery.structs.query_client_side_handlers import QueryClientSideHandlers +from openstackquery.handlers.client_side_handler import ClientSideHandler from openstackquery.handlers.server_side_handler import ServerSideHandler @@ -19,9 +19,10 @@ def _get_server_side_handler(self) -> ServerSideHandler: """ @abstractmethod - def _get_client_side_handlers(self) -> QueryClientSideHandlers: + def _get_client_side_handler(self) -> ClientSideHandler: """ - Should return a dataclass where each attribute maps to a client-side filter handler. These objects can be used - to get a filter function to filter a list of openstack resource objects after gathering them using openstacksdk + Should return a client-side filter handler object. This object can be used to get filter functions to filter + a list of openstack objects. + To get a filter function to filter a list of openstack resource objects after gathering them using openstacksdk command """ diff --git a/openstackquery/query_blocks/query_builder.py b/openstackquery/query_blocks/query_builder.py index fa735ff..ba8fb2e 100644 --- a/openstackquery/query_blocks/query_builder.py +++ b/openstackquery/query_blocks/query_builder.py @@ -5,7 +5,6 @@ from openstackquery.handlers.server_side_handler import ServerSideHandler from openstackquery.enums.query_presets import QueryPresets -from openstackquery.enums.query_presets import get_preset_from_string from openstackquery.enums.props.prop_enum import PropEnum from openstackquery.exceptions.query_preset_mapping_error import QueryPresetMappingError @@ -32,10 +31,10 @@ class QueryBuilder: def __init__( self, prop_enum_cls: Type[PropEnum], - client_side_handlers: List[ClientSideHandler], + client_side_handler: ClientSideHandler, server_side_handler: Optional[ServerSideHandler], ): - self._client_side_handlers = client_side_handlers + self._client_side_handler = client_side_handler self._prop_enum_cls = prop_enum_cls self._server_side_handler = server_side_handler @@ -99,7 +98,7 @@ def _parse_where_inputs(self, preset, prop): :param prop: Name of property that the query preset will act on """ if isinstance(preset, str): - preset = get_preset_from_string(preset) + preset = QueryPresets.from_string(preset) if isinstance(prop, str): prop = self._prop_enum_cls.from_string(prop) return preset, prop @@ -118,6 +117,8 @@ def parse_where( :param preset_kwargs: A set of arguments to pass to configure filter function and filter kwargs """ preset, prop = self._parse_where_inputs(preset, prop) + self._validate_where(preset, prop) + prop_func = self._prop_enum_cls.get_prop_mapping(prop) if not prop_func: @@ -135,8 +136,7 @@ def parse_where( """ ) - preset_handler = self._get_preset_handler(preset, prop) - client_side_filter = preset_handler.get_filter_func( + client_side_filter = self._client_side_handler.get_filter_func( preset=preset, prop=prop, prop_func=prop_func, @@ -176,6 +176,62 @@ def parse_where( server_side_filters=server_side_filters, ) + def _validate_where(self, preset: QueryPresets, prop: PropEnum) -> None: + """ + helper function for parse_where + validates that the given property can be used with given preset, raises errors if not + :param preset: A given preset that describes the query type + :param prop: A prop which the preset will act on + """ + + # Most likely we have forgotten to add a mapping for a preset at the client-side + # All presets should have a client-side handler associated to it + if not self._client_side_handler.preset_known(preset): + logger.error( + "Error: If you are here as a developer " + "you have likely not forgotten to instantiate a client-side handler for the " + "preset '%s'", + preset.name, + ) + + logger.error( + "Error: If you are here as a user - double check whether the preset '%s' is compatible" + "with the resource you're querying.\n " + "i.e. using LESS_THAN for querying Users " + "(as users holds no query-able properties which are of an integer type).\n " + "However, if you believe it should, please raise an issue with the repo maintainer.", + preset.name, + ) + + raise QueryPresetMappingError( + f"No client-side handler found for preset '{preset.name}' - property '{prop.name}' pair " + f"- resource likely does not support querying using this preset" + ) + + if not self._client_side_handler.check_supported(preset, prop): + logger.error( + "Error: if you are here as a developer " + "you have likely forgotten to add client-side mappings for the preset '%s' and property '%s' " + "under mappings/_mapping", + preset.name, + prop.name, + ) + + logger.error( + "Error: If you are here as a user - double check whether the property '%s' can be used " + "with the preset '%s' \n" + "i.e. using LESS_THAN with a string property like SERVER_NAME won't work " + "(server_name holds strings, and preset LESS_THAN only works on integers.)\n " + "However, if you believe the preset and property should be used together please raise an " + "issue with the repo maintainer", + prop.name, + preset.name, + ) + + raise QueryPresetMappingError( + f"No client-side handler found which supports preset '{preset.name}' and property '{prop.name}" + ) + def _add_filter( self, client_side_filter: ClientSideFilterFunc, @@ -218,63 +274,3 @@ def _add_filter( for current_server_filter in self.server_side_filters for new_server_filter in server_side_filters ] - - def _get_preset_handler( - self, preset: QueryPresets, prop: PropEnum - ) -> ClientSideHandler: - """ - method which returns a preset handler object which supports the corresponding preset and property pair - :param preset: A given preset that describes the query type - :param prop: A prop which the preset will act on - """ - - # Most likely we have forgotten to add a mapping for a preset at the client-side - # All presets should have a client-side handler associated to it - if not any(i.preset_known(preset) for i in self._client_side_handlers): - logger.error( - "Error: If you are here as a developer " - "you have likely not forgotten to instantiate a client-side handler for the " - "preset '%s'", - preset.name, - ) - - logger.error( - "Error: If you are here as a user - double check whether the preset '%s' is compatible" - "with the resource you're querying.\n " - "i.e. using LESS_THAN for querying Users " - "(as users holds no query-able properties which are of an integer type).\n " - "However, if you believe it should, please raise an issue with the repo maintainer.", - preset.name, - ) - - raise QueryPresetMappingError( - f"No client-side handler found for preset '{preset.name}' - property '{prop.name}' pair " - f"- resource likely does not support querying using this preset" - ) - - for i in self._client_side_handlers: - if i.check_supported(preset, prop): - return i - - logger.error( - "Error: if you are here as a developer " - "you have likely forgotten to add client-side mappings for the preset '%s' and property '%s' " - "under mappings/_mapping", - preset.name, - prop.name, - ) - - logger.error( - "Error: If you are here as a user - double check whether the property '%s' can be used " - "with the preset '%s' \n" - "i.e. using LESS_THAN with a string property like SERVER_NAME won't work " - "(server_name holds strings, and preset LESS_THAN only works on integers.)\n " - "However, if you believe the preset and property should be used together please raise an " - "issue with the repo maintainer", - prop.name, - preset.name, - ) - - raise QueryPresetMappingError( - f"No client-side handler found which supports preset '{preset.name}' and property '{prop.name}" - ) diff --git a/openstackquery/query_blocks/query_chainer.py b/openstackquery/query_blocks/query_chainer.py index 12b1e47..d419ef1 100644 --- a/openstackquery/query_blocks/query_chainer.py +++ b/openstackquery/query_blocks/query_chainer.py @@ -1,8 +1,8 @@ from typing import Tuple, List, Optional, Union, Dict +from openstackquery.enums.query_presets import QueryPresets from openstackquery.aliases import PropValue, QueryChainMappings from openstackquery.enums.props.prop_enum import PropEnum -from openstackquery.enums.query_presets import QueryPresetsGeneric from openstackquery.enums.query_types import QueryTypes from openstackquery.exceptions.query_chaining_error import QueryChainingError @@ -126,7 +126,7 @@ def parse_then( ) return new_query.where( - QueryPresetsGeneric.ANY_IN, + QueryPresets.ANY_IN, link_props[1], values=search_values, ) diff --git a/openstackquery/query_factory.py b/openstackquery/query_factory.py index 08ed6a9..bc5dc29 100644 --- a/openstackquery/query_factory.py +++ b/openstackquery/query_factory.py @@ -29,7 +29,7 @@ def build_query_deps(mapping_cls: Type[MappingInterface]) -> QueryComponents: parser = QueryParser(prop_mapping) builder = QueryBuilder( prop_enum_cls=prop_mapping, - client_side_handlers=mapping_cls.get_client_side_handlers().to_list(), + client_side_handler=mapping_cls.get_client_side_handler(), server_side_handler=mapping_cls.get_server_side_handler(), ) executor = QueryExecutor( diff --git a/openstackquery/structs/query_client_side_handlers.py b/openstackquery/structs/query_client_side_handlers.py deleted file mode 100644 index 3021b99..0000000 --- a/openstackquery/structs/query_client_side_handlers.py +++ /dev/null @@ -1,34 +0,0 @@ -from typing import List, Optional -from dataclasses import dataclass, fields - -from openstackquery.handlers.client_side_handler import ClientSideHandler -from openstackquery.handlers.client_side_handler_generic import ( - ClientSideHandlerGeneric, -) -from openstackquery.handlers.client_side_handler_string import ClientSideHandlerString -from openstackquery.handlers.client_side_handler_datetime import ( - ClientSideHandlerDateTime, -) -from openstackquery.handlers.client_side_handler_integer import ( - ClientSideHandlerInteger, -) - - -@dataclass -class QueryClientSideHandlers: - """ - Stores client side preset handlers - """ - - generic_handler: ClientSideHandlerGeneric - string_handler: ClientSideHandlerString - datetime_handler: Optional[ClientSideHandlerDateTime] - integer_handler: Optional[ClientSideHandlerInteger] - - def to_list(self) -> List[ClientSideHandler]: - values = [] - for field in fields(self): - value = getattr(self, field.name) - if value: - values.append(value) - return values diff --git a/tests/enums/props/conftest.py b/tests/enums/conftest.py similarity index 100% rename from tests/enums/props/conftest.py rename to tests/enums/conftest.py diff --git a/tests/enums/test_query_presets.py b/tests/enums/test_query_presets.py index a017c2d..d8b36aa 100644 --- a/tests/enums/test_query_presets.py +++ b/tests/enums/test_query_presets.py @@ -1,222 +1,59 @@ import pytest -from openstackquery.enums.query_presets import ( - QueryPresetsGeneric, - QueryPresetsInteger, - QueryPresetsString, - QueryPresetsDateTime, - get_preset_from_string, -) +from openstackquery.enums.query_presets import QueryPresets from openstackquery.exceptions.parse_query_error import ParseQueryError @pytest.mark.parametrize( - "preset_string", ["equal_to", "Equal_To", "EqUaL_tO", "equal", "=="] -) -def test_equal_to_serialization(preset_string): - """ - Tests that variants of EQUAL_TO can be serialized - """ - assert ( - QueryPresetsGeneric.from_string(preset_string) is QueryPresetsGeneric.EQUAL_TO - ) - - -@pytest.mark.parametrize( - "preset_string", ["not_equal_to", "Not_Equal_To", "NoT_EqUaL_tO", "not_equal", "!="] -) -def test_not_equal_to_serialization(preset_string): - """ - Tests that variants of NOT_EQUAL_TO can be serialized - """ - assert ( - QueryPresetsGeneric.from_string(preset_string) - is QueryPresetsGeneric.NOT_EQUAL_TO - ) - - -@pytest.mark.parametrize( - "preset_string", ["greater_than", "Greater_Than", "GrEaTer_ThAn", ">"] -) -def test_greater_than_serialization(preset_string): - """ - Tests that variants of GREATER_THAN can be serialized - """ - assert ( - QueryPresetsInteger.from_string(preset_string) - is QueryPresetsInteger.GREATER_THAN - ) - - -@pytest.mark.parametrize( - "preset_string", - [ - "greater_than_or_equal_to", - "Greater_Than_Or_Equal_To", - "GrEaTer_ThAn_Or_EqUaL_tO", - ">=", - ], -) -def test_greater_than_or_equal_to_serialization(preset_string): - """ - Tests that variants of GREATER_THAN_OR_EQUAL_TO can be serialized - """ - assert ( - QueryPresetsInteger.from_string(preset_string) - is QueryPresetsInteger.GREATER_THAN_OR_EQUAL_TO - ) - - -@pytest.mark.parametrize("preset_string", ["less_than", "Less_Than", "LeSs_ThAn", "<"]) -def test_less_than_serialization(preset_string): - """ - Tests that variants of LESS_THAN can be serialized - """ - assert ( - QueryPresetsInteger.from_string(preset_string) is QueryPresetsInteger.LESS_THAN - ) - - -@pytest.mark.parametrize( - "preset_string", - ["less_than_or_equal_to", "Less_Than_Or_Equal_To", "LeSs_ThAn_Or_EqUaL_tO", "<="], -) -def test_less_than_or_equal_to_serialization(preset_string): - """ - Tests that variants of LESS_THAN_OR_EQUAL_TO can be serialized - """ - assert ( - QueryPresetsInteger.from_string(preset_string) - is QueryPresetsInteger.LESS_THAN_OR_EQUAL_TO - ) - - -@pytest.mark.parametrize( - "preset_string", ["older_than", "Older_Than", "OlDeR_ThAn", ">"] -) -def test_older_than_serialization(preset_string): - """ - Tests that variants of OLDER_THAN can be serialized - """ - assert ( - QueryPresetsDateTime.from_string(preset_string) - is QueryPresetsDateTime.OLDER_THAN - ) - - -@pytest.mark.parametrize( - "preset_string", + "expected_prop,test_values", [ - "older_than_or_equal_to", - "Older_Than_Or_Equal_To", - "OlDeR_ThAn_Or_EqUaL_To", - ">=", + (QueryPresets.EQUAL_TO, ["equal_to", "equal", "=="]), + (QueryPresets.NOT_EQUAL_TO, ["not_equal_to", "not_equal", "!="]), + ( + QueryPresets.GREATER_THAN, + ["greater_than", "greater", "more_than", "more", ">"], + ), + ( + QueryPresets.GREATER_THAN_OR_EQUAL_TO, + [ + "greater_than_or_equal_to", + "greater_or_equal", + "more_than_or_equal_to", + "more_or_equal", + ">=", + ], + ), + (QueryPresets.LESS_THAN, ["less_than", "less", "<"]), + ( + QueryPresets.LESS_THAN_OR_EQUAL_TO, + ["less_than_or_equal_to", "less_or_equal", "<="], + ), + (QueryPresets.OLDER_THAN, ["older_than", "older"]), + ( + QueryPresets.OLDER_THAN_OR_EQUAL_TO, + ["older_than_or_equal_to", "older_or_equal"], + ), + (QueryPresets.YOUNGER_THAN, ["younger_than", "younger", "newer_than", "newer"]), + ( + QueryPresets.YOUNGER_THAN_OR_EQUAL_TO, + [ + "younger_than_or_equal_to", + "younger_or_equal", + "newer_than_or_equal_to", + "newer_or_equal", + ], + ), + (QueryPresets.ANY_IN, ["any_in", "in"]), + (QueryPresets.NOT_ANY_IN, ["not_any_in", "not_in"]), + (QueryPresets.MATCHES_REGEX, ["matches_regex", "match_regex", "regex", "re"]), ], ) -def test_older_than_or_equal_to_serialization(preset_string): - """ - Tests that variants of OLDER_THAN_OR_EQUAL_TO can be serialized - """ - assert ( - QueryPresetsDateTime.from_string(preset_string) - is QueryPresetsDateTime.OLDER_THAN_OR_EQUAL_TO - ) - - -@pytest.mark.parametrize( - "preset_string", ["younger_than", "Younger_Than", "YoUnGeR_ThAn", "<"] -) -def test_younger_than_serialization(preset_string): - """ - Tests that variants of YOUNGER_THAN can be serialized - """ - assert ( - QueryPresetsDateTime.from_string(preset_string) - is QueryPresetsDateTime.YOUNGER_THAN - ) - - -@pytest.mark.parametrize( - "preset_string", - [ - "younger_than_or_equal_to", - "Younger_Than_Or_Equal_To", - "YoUngEr_ThAn_Or_EqUaL_To", - "<=", - ], -) -def test_younger_than_or_equal_to_serialization(preset_string): - """ - Tests that variants of YOUNGER_THAN_OR_EQUAL_TO can be serialized - """ - assert ( - QueryPresetsDateTime.from_string(preset_string) - is QueryPresetsDateTime.YOUNGER_THAN_OR_EQUAL_TO - ) - - -@pytest.mark.parametrize("preset_string", ["any_in", "Any_In", "AnY_In", "in"]) -def test_any_in_serialization(preset_string): - """ - Tests that variants of ANY_IN can be serialized - """ - assert QueryPresetsGeneric.from_string(preset_string) is QueryPresetsGeneric.ANY_IN - - -@pytest.mark.parametrize( - "preset_string", ["not_any_in", "Not_Any_In", "NoT_AnY_In", "not_in"] -) -def test_not_any_in_serialization(preset_string): - """ - Tests that variants of NOT_ANY_IN can be serialized - """ - assert ( - QueryPresetsGeneric.from_string(preset_string) is QueryPresetsGeneric.NOT_ANY_IN - ) - - -@pytest.mark.parametrize( - "preset_string", - ["matches_regex", "Matches_Regex", "MaTcHeS_ReGeX", "regex", "match_regex"], -) -def test_matches_regex_serialization(preset_string): - """ - Tests that variants of MATCHES_REGEX can be serialized - """ - assert ( - QueryPresetsString.from_string(preset_string) - is QueryPresetsString.MATCHES_REGEX - ) - - -def test_invalid_serialization(): - """ - Tests that error is raised when passes invalid string to all preset classes - """ - for enum_cls in [ - QueryPresetsInteger, - QueryPresetsString, - QueryPresetsDateTime, - QueryPresetsGeneric, - ]: - with pytest.raises(ParseQueryError): - enum_cls.from_string("some-invalid-string") - - -@pytest.mark.parametrize( - "alias, expected_preset", - [ - ("equal_to", QueryPresetsGeneric.EQUAL_TO), - ("matches_regex", QueryPresetsString.MATCHES_REGEX), - ("older_than", QueryPresetsDateTime.OLDER_THAN), - ("greater_than", QueryPresetsInteger.GREATER_THAN), - ], -) -def test_get_preset_from_string_valid(alias, expected_preset): - """ - Tests that get_preset_from_string works for a valid preset alias from each preset type - """ - assert get_preset_from_string(alias) == expected_preset +def test_query_presets_serialization( + expected_prop, test_values, property_variant_generator +): + """Test all query preset name formats can be correctly serialized.""" + for variant in property_variant_generator(test_values): + assert QueryPresets.from_string(variant) is expected_prop def test_get_preset_from_string_invalid(): @@ -224,4 +61,4 @@ def test_get_preset_from_string_invalid(): Tests that get_preset_from_string returns error if given an invalid alias """ with pytest.raises(ParseQueryError): - get_preset_from_string("invalid-alias") + QueryPresets.from_string("invalid-alias") diff --git a/tests/enums/test_query_types.py b/tests/enums/test_query_types.py index 99666d2..88e68fe 100644 --- a/tests/enums/test_query_types.py +++ b/tests/enums/test_query_types.py @@ -5,102 +5,44 @@ @pytest.mark.parametrize( - "query_type", + "expected_prop,test_values", [ - "Flavor_Query", - "FlAvOr_Query", - "flavor_query", - "flavor", - "flavors", - "flavorquery", + (QueryTypes.FLAVOR_QUERY, ["flavor_query", "flavor", "flavors", "flavorquery"]), + ( + QueryTypes.PROJECT_QUERY, + ["project_query", "project", "projects", "projectquery"], + ), + ( + QueryTypes.SERVER_QUERY, + [ + "server_query", + "vm", + "vms", + "vmquery", + "server", + "servers", + "serverquery", + ], + ), + (QueryTypes.USER_QUERY, ["user_query", "user", "users", "userquery"]), + (QueryTypes.IMAGE_QUERY, ["image_query", "image", "images", "imagequery"]), + ( + QueryTypes.HYPERVISOR_QUERY, + ["hypervisor_query", "hypervisor", "hypervisors", "hypervisorquery"], + ), ], ) -def test_flavor_query_serialization(query_type): - """ - Tests that variants of FLAVOR_QUERY can be serialized - """ - assert QueryTypes.from_string(query_type) is QueryTypes.FLAVOR_QUERY - - -@pytest.mark.parametrize( - "query_type", - [ - "Server_Query", - "SeRvEr_QuErY", - "server_query", - "server", - "servers", - "serverquery", - ], -) -def test_server_query_serialization(query_type): - """ - Tests that variants of SERVER_QUERY can be serialized - """ - assert QueryTypes.from_string(query_type) is QueryTypes.SERVER_QUERY - - -@pytest.mark.parametrize( - "query_type", - [ - "Project_Query", - "PrOjEcT_Query", - "project_query", - "project", - "projects", - "projectquery", - ], -) -def test_project_query_serialization(query_type): - """ - Tests that variants of PROJECT_QUERY can be serialized - """ - assert QueryTypes.from_string(query_type) is QueryTypes.PROJECT_QUERY - - -@pytest.mark.parametrize( - "query_type", - ["User_Query", "UsEr_QuEry", "user_query", "user", "users", "userquery"], -) -def test_user_query_serialization(query_type): - """ - Tests that variants of USER_QUERY can be serialized - """ - assert QueryTypes.from_string(query_type) is QueryTypes.USER_QUERY - - -@pytest.mark.parametrize( - "query_type", - ["Image_Query", "ImAgE_QuEry", "image_query", "image", "images", "imagequery"], -) -def test_image_query_serialization(query_type): - """ - Tests that variants of IMAGE_QUERY can be serialized - """ - assert QueryTypes.from_string(query_type) is QueryTypes.IMAGE_QUERY - - -@pytest.mark.parametrize( - "query_type", - [ - "Hypervisor_Query", - "HyPeRvIsOr_QuErY", - "hypervisor_query", - "hypervisor", - "hypervisors", - "hypervisorquery", - ], -) -def test_hypervisor_query_serialization(query_type): - """ - Tests that variants of HYPERVISOR_QUERY can be serialized - """ - assert QueryTypes.from_string(query_type) is QueryTypes.HYPERVISOR_QUERY +def test_query_presets_serialization( + expected_prop, test_values, property_variant_generator +): + """Test all query preset name formats can be correctly serialized.""" + for variant in property_variant_generator(test_values): + assert QueryTypes.from_string(variant) is expected_prop -def test_invalid_serialization(): +def test_get_preset_from_string_invalid(): """ - Tests that error is raised when passes invalid string + Tests that get_preset_from_string returns error if given an invalid alias """ with pytest.raises(ParseQueryError): - QueryTypes.from_string("some-invalid-string") + QueryTypes.from_string("invalid-alias") diff --git a/tests/enums/test_sort_order.py b/tests/enums/test_sort_order.py index 15592d2..6eb097d 100644 --- a/tests/enums/test_sort_order.py +++ b/tests/enums/test_sort_order.py @@ -4,25 +4,24 @@ from openstackquery.exceptions.parse_query_error import ParseQueryError -@pytest.mark.parametrize("sort_order_type", ["asc", "Asc", "Ascending"]) -def test_asc_serialization(sort_order_type): - """ - Tests that variants of ASC can be serialized - """ - assert SortOrder.from_string(sort_order_type) is SortOrder.ASC - - -@pytest.mark.parametrize("sort_order_type", ["desc", "Desc", "Descending"]) -def test_desc_serialization(sort_order_type): - """ - Tests that variants of DESC can be serialized - """ - assert SortOrder.from_string(sort_order_type) is SortOrder.DESC +@pytest.mark.parametrize( + "expected_prop,test_values", + [ + (SortOrder.ASC, ["asc", "ascending"]), + (SortOrder.DESC, ["desc", "descending"]), + ], +) +def test_sort_order_serialization( + expected_prop, test_values, property_variant_generator +): + """Test all sort order name formats can be correctly serialized.""" + for variant in property_variant_generator(test_values): + assert SortOrder.from_string(variant) is expected_prop def test_get_preset_from_string_invalid(): """ - Tests that error is raised when passed invalid string + Tests that get_preset_from_string returns error if given an invalid alias """ with pytest.raises(ParseQueryError): - SortOrder.from_string("some-invalid-string") + SortOrder.from_string("invalid-alias") diff --git a/tests/handlers/conftest.py b/tests/handlers/conftest.py new file mode 100644 index 0000000..84343b0 --- /dev/null +++ b/tests/handlers/conftest.py @@ -0,0 +1,51 @@ +from unittest.mock import MagicMock, NonCallableMock + +import pytest + +from openstackquery.handlers.client_side_handler import ClientSideHandler +from openstackquery.enums.query_presets import QueryPresets +from tests.mocks.mocked_props import MockProperties + + +@pytest.fixture(scope="function", name="filter_test_instance") +def instance_fixture(): + """ + Returns an instance with a mocked filter function mappings + """ + + # sets filter function mappings so that PROP_1 is valid for all client_side + _filter_function_mappings = { + preset: [MockProperties.PROP_1] for preset in QueryPresets + } + + return ClientSideHandler(_filter_function_mappings) + + +@pytest.fixture(scope="function", name="run_client_filter_test") +def run_client_filter_test_fixture(filter_test_instance): + """ + fixture to run a test cases for each client-side filter function + """ + + def _run_client_filter_test(preset, prop_value, mock_filter_func_kwargs): + """ + runs a test case by calling get_filter_func for generic handler + with a given preset, prop return value and value to compare against. + :param preset: preset (mapped to filter func we want to test) + :param prop_value: property value to test filter func with + :param mock_filter_func_kwargs: extra arguments to setup/configure filter function + + """ + prop_func = MagicMock() + prop_func.return_value = prop_value + + filter_func = filter_test_instance.get_filter_func( + preset, MockProperties.PROP_1, prop_func, mock_filter_func_kwargs + ) + + mock_obj = NonCallableMock() + res = filter_func(mock_obj) + prop_func.assert_called_once_with(mock_obj) + return res + + return _run_client_filter_test diff --git a/tests/handlers/test_client_side_handler_datetime.py b/tests/handlers/test_client_datetime_filters.py similarity index 58% rename from tests/handlers/test_client_side_handler_datetime.py rename to tests/handlers/test_client_datetime_filters.py index aa8cf7a..9cb937f 100644 --- a/tests/handlers/test_client_side_handler_datetime.py +++ b/tests/handlers/test_client_datetime_filters.py @@ -1,45 +1,34 @@ from unittest.mock import patch, NonCallableMock, MagicMock, call import pytest -from openstackquery.handlers.client_side_handler_datetime import ( - ClientSideHandlerDateTime, -) -from openstackquery.enums.query_presets import QueryPresetsDateTime +from openstackquery.enums.query_presets import QueryPresets from tests.mocks.mocked_props import MockProperties -@pytest.fixture(name="instance") -def instance_fixture(): - """ - Returns an instance with a mocked filter function mappings - """ - - # sets filter function mappings so that PROP_1 is valid for all client_side - _filter_function_mappings = { - preset: [MockProperties.PROP_1] for preset in QueryPresetsDateTime - } - return ClientSideHandlerDateTime(_filter_function_mappings) - - -@pytest.fixture(name="run_prop_test_case") -def run_prop_test_case_fixture(instance): +@pytest.fixture(name="run_client_dt_filter_test") +def run_client_dt_filter_test_fixture(filter_test_instance): """ fixture to run a test cases for each client-side filter function """ @patch("openstackquery.time_utils.TimeUtils.get_timestamp_in_seconds") - @patch("openstackquery.handlers.client_side_handler_datetime.datetime") - def _run_prop_test_case( - preset_to_test, prop_value, to_compare, mock_datetime, mock_get_timestamp + @patch("openstackquery.handlers.client_side_filters.datetime") + def _run_client_dt_filter_test( + preset, prop_value, mock_current_time, mock_datetime, mock_get_timestamp ): """ - runs a test case by calling get_filter_func for datetime handler + runs a test case by calling get_filter_func for datetime related filters with a given preset, prop return value and value to compare against. + :param preset: preset (mapped to filter func we want to test) + :param prop_value: property value to test filter func with + :param mock_current_time: mock value for current timestamp + :param mock_datetime: mock datetime object + :param mock_get_timestamp: mock get_timestamp_in_seconds function """ # we mock and set the timestamp return values manually since it's difficult testing datetime mock_datetime.strptime.return_value.timestamp.return_value = prop_value - mock_get_timestamp.return_value = to_compare + mock_get_timestamp.return_value = mock_current_time # mock the kwargs - they won't be used days, hours, mins, secs = ( @@ -51,8 +40,8 @@ def _run_prop_test_case( mock_kwargs = {"days": days, "hours": hours, "minutes": mins, "seconds": secs} prop_func = MagicMock() - filter_func = instance.get_filter_func( - preset_to_test, MockProperties.PROP_1, prop_func, mock_kwargs + filter_func = filter_test_instance.get_filter_func( + preset, MockProperties.PROP_1, prop_func, mock_kwargs ) mock_obj = NonCallableMock() @@ -66,58 +55,48 @@ def _run_prop_test_case( return res - return _run_prop_test_case - - -def test_check_supported_all_presets(instance): - """ - Tests that client_side_handler_datetime supports all DateTime QueryPresets - """ - assert all( - instance.check_supported(preset, MockProperties.PROP_1) - for preset in QueryPresetsDateTime - ) + return _run_client_dt_filter_test -def test_prop_older_than(run_prop_test_case): +def test_prop_older_than(run_client_dt_filter_test): """ Tests prop_older_than client-side-filter with different values This essentially compares two numbers (number of seconds) and if the prop value is lower, it returns True because older timestamps have fewer seconds passed since 1970 than newer ones """ for i, expected in [(200, False), (400, True), (300, False)]: - assert run_prop_test_case(QueryPresetsDateTime.OLDER_THAN, 300, i) == expected + assert run_client_dt_filter_test(QueryPresets.OLDER_THAN, 300, i) == expected -def test_prop_younger_than(run_prop_test_case): +def test_prop_younger_than(run_client_dt_filter_test): """ Tests younger_than client-side-filter with different values This essentially compares two numbers (number of seconds) and if the prop value is lower, it returns True because newer timestamps have more seconds passed since 1970 than older ones """ for i, expected in [(200, True), (400, False), (300, False)]: - assert run_prop_test_case(QueryPresetsDateTime.YOUNGER_THAN, 300, i) == expected + assert run_client_dt_filter_test(QueryPresets.YOUNGER_THAN, 300, i) == expected -def test_prop_younger_than_or_equal_to(run_prop_test_case): +def test_prop_younger_than_or_equal_to(run_client_dt_filter_test): """ Tests prop_younger_than_or_equal_to client-side-filter with different values Same as prop_younger_than, but if equal will also return True """ for i, expected in [(200, True), (400, False), (300, True)]: assert ( - run_prop_test_case(QueryPresetsDateTime.YOUNGER_THAN_OR_EQUAL_TO, 300, i) + run_client_dt_filter_test(QueryPresets.YOUNGER_THAN_OR_EQUAL_TO, 300, i) == expected ) -def test_prop_older_than_or_equal_to(run_prop_test_case): +def test_prop_older_than_or_equal_to(run_client_dt_filter_test): """ Tests prop_older_than_or_equal_to client-side-filter with different values Same as prop_older_than, but if equal will also return True """ for i, expected in [(200, False), (400, True), (300, True)]: assert ( - run_prop_test_case(QueryPresetsDateTime.OLDER_THAN_OR_EQUAL_TO, 300, i) + run_client_dt_filter_test(QueryPresets.OLDER_THAN_OR_EQUAL_TO, 300, i) == expected ) diff --git a/tests/handlers/test_client_generic_filters.py b/tests/handlers/test_client_generic_filters.py new file mode 100644 index 0000000..2a34050 --- /dev/null +++ b/tests/handlers/test_client_generic_filters.py @@ -0,0 +1,73 @@ +import pytest +from openstackquery.exceptions.query_preset_mapping_error import QueryPresetMappingError +from openstackquery.enums.query_presets import QueryPresets + + +@pytest.fixture(name="test_corpus") +def corpus_fixture(): + """ + Returns a set of arguments to test against + """ + return [1, "foo", None, {"a": "b"}] + + +def test_prop_equal_to(run_client_filter_test, test_corpus): + """ + Tests that method prop_equal_to functions expectedly + """ + for i in test_corpus: + assert run_client_filter_test(QueryPresets.EQUAL_TO, i, {"value": i}) + assert not run_client_filter_test( + QueryPresets.EQUAL_TO, i, {"value": "not_equal"} + ) + + +def test_prop_not_equal_to(run_client_filter_test, test_corpus): + """ + Tests that method not_prop_equal_to functions expectedly + """ + for i in test_corpus: + assert run_client_filter_test( + QueryPresets.NOT_EQUAL_TO, i, {"value": "not_equal"} + ) + assert not run_client_filter_test(QueryPresets.NOT_EQUAL_TO, i, {"value": i}) + + +def test_prop_any_in(run_client_filter_test): + """ + Tests that method prop_any_in functions expectedly + """ + assert run_client_filter_test( + QueryPresets.ANY_IN, "val3", {"values": ["val1", "val2", "val3"]} + ) + assert not run_client_filter_test( + QueryPresets.ANY_IN, "val4", {"values": ["val1", "val2", "val3"]} + ) + + +def test_prop_any_in_empty_list(run_client_filter_test): + """ + Tests that method prop_any_in when given empty list raise error + """ + with pytest.raises(QueryPresetMappingError): + run_client_filter_test(QueryPresets.ANY_IN, "val3", {"values": []}) + + +def test_prop_not_any_in(run_client_filter_test): + """ + Tests that method prop_any_not_in functions expectedly + """ + assert run_client_filter_test( + QueryPresets.NOT_ANY_IN, "val4", {"values": ["val1", "val2", "val3"]} + ) + assert not run_client_filter_test( + QueryPresets.NOT_ANY_IN, "val3", {"values": ["val1", "val2", "val3"]} + ) + + +def test_prop_not_any_in_empty_list(run_client_filter_test): + """ + Tests that method prop_any_not_in when given empty list raise error + """ + with pytest.raises(QueryPresetMappingError): + run_client_filter_test(QueryPresets.NOT_ANY_IN, "val3", {"values": []}) diff --git a/tests/handlers/test_client_integer_filters.py b/tests/handlers/test_client_integer_filters.py new file mode 100644 index 0000000..a41ecda --- /dev/null +++ b/tests/handlers/test_client_integer_filters.py @@ -0,0 +1,50 @@ +from openstackquery.enums.query_presets import QueryPresets + + +def test_prop_less_than(run_client_filter_test): + """ + Tests that method prop_less_than functions expectedly + Returns True if val1 is less than val2 + """ + for i, expected in (1, True), (2, False): + assert ( + run_client_filter_test(QueryPresets.LESS_THAN, i, {"value": 2}) == expected + ) + + +def test_prop_greater_than(run_client_filter_test): + """ + Tests that method prop_greater_than functions expectedly + Returns True if val1 is greater than val2 + """ + for i, expected in (1, False), (2, False), (3, True): + assert ( + run_client_filter_test(QueryPresets.GREATER_THAN, i, {"value": 2}) + == expected + ) + + +def test_prop_less_than_or_equal_to(run_client_filter_test): + """ + Tests that method prop_less_than_or_equal_to functions expectedly + Returns True if val1 is less than or equal to val2 + """ + for i, expected in (1, True), (2, True), (3, False): + assert ( + run_client_filter_test(QueryPresets.LESS_THAN_OR_EQUAL_TO, i, {"value": 2}) + == expected + ) + + +def test_prop_greater_than_or_equal_to(run_client_filter_test): + """ + Tests that method prop_greater_than_or_equal_to functions expectedly + Returns True if val1 is greater than or equal to val2 + """ + for i, expected in (1, False), (2, True), (3, True): + assert ( + run_client_filter_test( + QueryPresets.GREATER_THAN_OR_EQUAL_TO, i, {"value": 2} + ) + == expected + ) diff --git a/tests/handlers/test_client_list_filters.py b/tests/handlers/test_client_list_filters.py new file mode 100644 index 0000000..8d2b05a --- /dev/null +++ b/tests/handlers/test_client_list_filters.py @@ -0,0 +1,73 @@ +import pytest +from openstackquery.enums.query_presets import QueryPresets + + +@pytest.mark.parametrize( + "prop_list,values,expected", + [ + # Single value tests + ([1, 2, 3], 2, True), # Value in list + ([1, 2, 3], 4, False), # Value not in list + (["a", "b", "c"], "b", True), # String value in list + (["a", "b", "c"], "d", False), # String value not in list + # Sublist tests + ([1, 2, 3, 4], [1, 3], True), # All values from sublist in prop list + ([1, 2, 3], [1, 4], False), # Some values from sublist not in prop list + (["a", "b", "c", "d"], ["a", "c"], True), # String sublist all in prop list + (["a", "b", "c"], ["a", "d"], False), # String sublist partially in prop list + # Edge cases + ([1, 2, 3], [], True), # Empty sublist (all() on empty is True) + ([], [], True), # Empty lists + ([], 1, False), # Empty prop list with value + ([], [1, 2], False), # Empty prop list with sublist + (None, 1, False), # None prop list with value + (None, [1, 2], False), # None prop list with sublist + # Special cases + ([1, 2, 2, 3], 2, True), # Duplicate values in prop list + ([1, 2, 2, 3], [2, 3], True), # Sublist with duplicate in prop list + ([1, "string", True], "string", True), # Mixed types value + ([1, "string", True], [1, True], True), # Mixed types sublist + ], +) +def test_prop_list_contains(prop_list, values, expected, run_client_filter_test): + """Test prop_list_contains function with various inputs""" + assert ( + run_client_filter_test(QueryPresets.CONTAINS, prop_list, {"values": values}) + == expected + ) + + +# Test cases for prop_list_not_contains +@pytest.mark.parametrize( + "prop_list, values, expected", + [ + # Single value tests + ([1, 2, 3], 2, False), # Value in list + ([1, 2, 3], 4, True), # Value not in list + (["a", "b", "c"], "b", False), # String value in list + (["a", "b", "c"], "d", True), # String value not in list + # Sublist tests + ([1, 2, 3, 4], [1, 3], False), # All values from sublist in prop list + ([1, 2, 3], [1, 4], True), # Some values from sublist not in prop list + (["a", "b", "c", "d"], ["a", "c"], False), # String sublist all in prop list + (["a", "b", "c"], ["a", "d"], True), # String sublist partially in prop list + # Edge cases + ([1, 2, 3], [], False), # Empty sublist + ([], [], False), # Empty lists + ([], 1, True), # Empty prop list with value + ([], [1, 2], True), # Empty prop list with sublist + (None, 1, True), # None prop list with value + (None, [1, 2], True), # None prop list with sublist + # Special cases + ([1, 2, 2, 3], 2, False), # Duplicate values in prop list + ([1, 2, 2, 3], [2, 3], False), # Sublist with duplicate in prop list + ([1, "string", True], "string", False), # Mixed types value + ([1, "string", True], [1, True], False), # Mixed types sublist + ], +) +def test_prop_list_not_contains(prop_list, values, expected, run_client_filter_test): + """Test prop_list_not_contains function with various inputs""" + assert ( + run_client_filter_test(QueryPresets.NOT_CONTAINS, prop_list, {"values": values}) + == expected + ) diff --git a/tests/handlers/test_client_side_handler.py b/tests/handlers/test_client_side_handler.py index 7789908..a995dd7 100644 --- a/tests/handlers/test_client_side_handler.py +++ b/tests/handlers/test_client_side_handler.py @@ -11,38 +11,28 @@ from tests.mocks.mocked_props import MockProperties -@pytest.fixture(name="mock_preset_prop_mappings") -def preset_prop_mappings_fixture(): - """ - Sets up a set of mock mappings of valid presets for handler against a - list of mock properties that preset can work on - """ - return { - MockQueryPresets.ITEM_1: ["*"], - MockQueryPresets.ITEM_2: [MockProperties.PROP_1, MockProperties.PROP_2], - MockQueryPresets.ITEM_3: [MockProperties.PROP_3, MockProperties.PROP_4], - } - - -@pytest.fixture(name="mock_filter") +@pytest.fixture(name="mock_filter_fn") def mock_filter_instance(): """ - Returns a mocked filter that will always fail + Returns a mocked filter function """ - return MagicMock() @pytest.fixture(name="instance") -def instance_fixture(mock_preset_prop_mappings, mock_filter): +def instance_fixture(mock_filter_fn): """ Returns a function that will setup a client_side_handler with mocks """ - - mock_filter_mappings = { - MockQueryPresets.ITEM_1: mock_filter, - } - return ClientSideHandler(mock_filter_mappings, mock_preset_prop_mappings) + client_side_handler = ClientSideHandler( + { + MockQueryPresets.ITEM_1: ["*"], + MockQueryPresets.ITEM_2: [MockProperties.PROP_1, MockProperties.PROP_2], + MockQueryPresets.ITEM_3: [MockProperties.PROP_3, MockProperties.PROP_4], + } + ) + client_side_handler._filter_functions = {MockQueryPresets.ITEM_1: mock_filter_fn} + return client_side_handler def test_get_supported_props(instance): @@ -124,7 +114,7 @@ def _get_filter_func_runner(mock_prop_func, mock_filter_func_kwargs=None): return _get_filter_func_runner -def test_get_filter_func_valid_kwargs(get_filter_func_runner, mock_filter): +def test_get_filter_func_valid_kwargs(get_filter_func_runner, mock_filter_fn): """ Tests calling get_filter_func with valid kwargs. get_filter_func will get a simple stub method that will output whatever value that kwarg "out" holds @@ -134,7 +124,7 @@ def test_get_filter_func_valid_kwargs(get_filter_func_runner, mock_filter): res = get_filter_func_runner(mock_prop_func, mock_kwargs) - mock_filter.assert_has_calls( + mock_filter_fn.assert_has_calls( [ # first call from _check_filter_func call(None, **mock_kwargs), @@ -142,10 +132,10 @@ def test_get_filter_func_valid_kwargs(get_filter_func_runner, mock_filter): call(mock_prop_func.return_value, **mock_kwargs), ] ) - assert res == mock_filter.return_value + assert res == mock_filter_fn.return_value -def test_get_filter_func_valid_kwargs_no_params(mock_filter, get_filter_func_runner): +def test_get_filter_func_valid_kwargs_no_params(get_filter_func_runner, mock_filter_fn): """ Tests calling get_filter_func with valid kwargs - filter takes no extra params. get_filter_func will get a simple stub method that will output whatever value that kwarg "out" holds @@ -155,7 +145,7 @@ def test_get_filter_func_valid_kwargs_no_params(mock_filter, get_filter_func_run res = get_filter_func_runner(mock_prop_func, mock_kwargs) - mock_filter.assert_has_calls( + mock_filter_fn.assert_has_calls( [ # first call from _check_filter_func call(None), @@ -163,10 +153,10 @@ def test_get_filter_func_valid_kwargs_no_params(mock_filter, get_filter_func_run call(mock_prop_func.return_value), ] ) - assert res == mock_filter.return_value + assert res == mock_filter_fn.return_value -def test_get_filter_func_prop_func_raises_error(mock_filter, get_filter_func_runner): +def test_get_filter_func_prop_func_raises_error(get_filter_func_runner, mock_filter_fn): """ Tests calling get_filter_func with prop func that raises AttributeError when invoked filter_func_wrapper should return False in this case @@ -177,7 +167,7 @@ def test_get_filter_func_prop_func_raises_error(mock_filter, get_filter_func_run res = get_filter_func_runner(mock_prop_func, mock_kwargs) - mock_filter.assert_has_calls( + mock_filter_fn.assert_has_calls( [ # first call from _check_filter_func call(None), @@ -224,14 +214,14 @@ def test_get_filter_func_prop_invalid(instance): @pytest.mark.parametrize("error_type", [ParseQueryError, TypeError, NameError]) -def test_get_filter_func_filter_raises_error(error_type, instance, mock_filter): +def test_get_filter_func_filter_raises_error(error_type, instance, mock_filter_fn): """ Tests get_filter_func method when filter function raises an error. Should raise QueryPresetMappingError """ mock_prop_func = MagicMock() mock_kwargs = {"arg1": "val1", "arg2": "val2"} - mock_filter.side_effect = error_type + mock_filter_fn.side_effect = error_type with pytest.raises(QueryPresetMappingError): instance.get_filter_func( @@ -241,4 +231,4 @@ def test_get_filter_func_filter_raises_error(error_type, instance, mock_filter): mock_kwargs, ) - mock_filter.assert_called_once_with(None, **mock_kwargs) + mock_filter_fn.assert_called_once_with(None, **mock_kwargs) diff --git a/tests/handlers/test_client_side_handler_generic.py b/tests/handlers/test_client_side_handler_generic.py deleted file mode 100644 index 3ea8c6f..0000000 --- a/tests/handlers/test_client_side_handler_generic.py +++ /dev/null @@ -1,129 +0,0 @@ -from unittest.mock import NonCallableMock, MagicMock -import pytest - -from openstackquery.exceptions.query_preset_mapping_error import QueryPresetMappingError -from openstackquery.handlers.client_side_handler_generic import ( - ClientSideHandlerGeneric, -) -from openstackquery.enums.query_presets import QueryPresetsGeneric -from tests.mocks.mocked_props import MockProperties - - -@pytest.fixture(name="instance") -def instance_fixture(): - """ - Returns an instance with a mocked filter function mappings - """ - - # sets filter function mappings so that PROP_1 is valid for all client_side - _filter_function_mappings = { - preset: [MockProperties.PROP_1] for preset in QueryPresetsGeneric - } - return ClientSideHandlerGeneric(_filter_function_mappings) - - -@pytest.fixture(name="run_prop_test_case") -def run_prop_test_case_fixture(instance): - """ - fixture to run a test cases for each client-side filter function - """ - - def _run_prop_test_case(preset_to_test, prop_value, mock_kwargs): - """ - runs a test case by calling get_filter_func for generic handler - with a given preset, prop return value and value to compare against. - """ - - prop_func = MagicMock() - prop_func.return_value = prop_value - - filter_func = instance.get_filter_func( - preset_to_test, MockProperties.PROP_1, prop_func, mock_kwargs - ) - - mock_obj = NonCallableMock() - res = filter_func(mock_obj) - prop_func.assert_called_once_with(mock_obj) - return res - - return _run_prop_test_case - - -@pytest.fixture(name="test_corpus") -def corpus_fixture(): - """ - Returns a set of arguments to test against - """ - return [1, "foo", None, {"a": "b"}] - - -def test_check_supported_all_presets(instance): - """ - Tests that client_side_handler_generic supports all generic QueryPresets - """ - assert all( - instance.check_supported(preset, MockProperties.PROP_1) - for preset in QueryPresetsGeneric - ) - - -def test_prop_equal_to(run_prop_test_case, test_corpus): - """ - Tests that method prop_equal_to functions expectedly - """ - for i in test_corpus: - assert run_prop_test_case(QueryPresetsGeneric.EQUAL_TO, i, {"value": i}) - assert not run_prop_test_case( - QueryPresetsGeneric.EQUAL_TO, i, {"value": "not_equal"} - ) - - -def test_prop_not_equal_to(run_prop_test_case, test_corpus): - """ - Tests that method not_prop_equal_to functions expectedly - """ - for i in test_corpus: - assert run_prop_test_case( - QueryPresetsGeneric.NOT_EQUAL_TO, i, {"value": "not_equal"} - ) - assert not run_prop_test_case(QueryPresetsGeneric.NOT_EQUAL_TO, i, {"value": i}) - - -def test_prop_any_in(run_prop_test_case): - """ - Tests that method prop_any_in functions expectedly - """ - assert run_prop_test_case( - QueryPresetsGeneric.ANY_IN, "val3", {"values": ["val1", "val2", "val3"]} - ) - assert not run_prop_test_case( - QueryPresetsGeneric.ANY_IN, "val4", {"values": ["val1", "val2", "val3"]} - ) - - -def test_prop_any_in_empty_list(run_prop_test_case): - """ - Tests that method prop_any_in when given empty list raise error - """ - with pytest.raises(QueryPresetMappingError): - run_prop_test_case(QueryPresetsGeneric.ANY_IN, "val3", {"values": []}) - - -def test_prop_not_any_in(run_prop_test_case): - """ - Tests that method prop_any_not_in functions expectedly - """ - assert run_prop_test_case( - QueryPresetsGeneric.NOT_ANY_IN, "val4", {"values": ["val1", "val2", "val3"]} - ) - assert not run_prop_test_case( - QueryPresetsGeneric.NOT_ANY_IN, "val3", {"values": ["val1", "val2", "val3"]} - ) - - -def test_prop_not_any_in_empty_list(run_prop_test_case): - """ - Tests that method prop_any_not_in when given empty list raise error - """ - with pytest.raises(QueryPresetMappingError): - run_prop_test_case(QueryPresetsGeneric.NOT_ANY_IN, "val3", {"values": []}) diff --git a/tests/handlers/test_client_side_handler_integer.py b/tests/handlers/test_client_side_handler_integer.py deleted file mode 100644 index 55b5d3f..0000000 --- a/tests/handlers/test_client_side_handler_integer.py +++ /dev/null @@ -1,100 +0,0 @@ -from unittest.mock import NonCallableMock, MagicMock -import pytest - -from openstackquery.handlers.client_side_handler_integer import ( - ClientSideHandlerInteger, -) -from openstackquery.enums.query_presets import QueryPresetsInteger -from tests.mocks.mocked_props import MockProperties - - -@pytest.fixture(name="instance") -def instance_fixture(): - """ - Returns an instance with a mocked filter function mappings - """ - - # sets filter function mappings so that PROP_1 is valid for all client_side - _filter_function_mappings = { - preset: [MockProperties.PROP_1] for preset in QueryPresetsInteger - } - return ClientSideHandlerInteger(_filter_function_mappings) - - -@pytest.fixture(name="run_prop_test_case") -def run_prop_test_case_fixture(instance): - """ - fixture to run a test cases for each client-side filter function - """ - - def _run_prop_test_case(preset_to_test, prop_value, filter_value): - """ - runs a test case by calling get_filter_func for generic handler - with a given preset, prop return value and value to compare against. - """ - mock_kwargs = {"value": filter_value} - prop_func = MagicMock() - prop_func.return_value = prop_value - - filter_func = instance.get_filter_func( - preset_to_test, MockProperties.PROP_1, prop_func, mock_kwargs - ) - - mock_obj = NonCallableMock() - res = filter_func(mock_obj) - prop_func.assert_called_once_with(mock_obj) - return res - - return _run_prop_test_case - - -def test_check_supported_all_presets(instance): - """ - Tests that client_side_handler_integer supports all integer QueryPresets - """ - assert ( - instance.check_supported(preset, MockProperties.PROP_1) - for preset in QueryPresetsInteger - ) - - -def test_prop_less_than(run_prop_test_case): - """ - Tests that method prop_less_than functions expectedly - Returns True if val1 is less than val2 - """ - for i, expected in (1, True), (2, False): - assert run_prop_test_case(QueryPresetsInteger.LESS_THAN, i, 2) == expected - - -def test_prop_greater_than(run_prop_test_case): - """ - Tests that method prop_greater_than functions expectedly - Returns True if val1 is greater than val2 - """ - for i, expected in (1, False), (2, False), (3, True): - assert run_prop_test_case(QueryPresetsInteger.GREATER_THAN, i, 2) == expected - - -def test_prop_less_than_or_equal_to(run_prop_test_case): - """ - Tests that method prop_less_than_or_equal_to functions expectedly - Returns True if val1 is less than or equal to val2 - """ - for i, expected in (1, True), (2, True), (3, False): - assert ( - run_prop_test_case(QueryPresetsInteger.LESS_THAN_OR_EQUAL_TO, i, 2) - == expected - ) - - -def test_prop_greater_than_or_equal_to(run_prop_test_case): - """ - Tests that method prop_greater_than_or_equal_to functions expectedly - Returns True if val1 is greater than or equal to val2 - """ - for i, expected in (1, False), (2, True), (3, True): - assert ( - run_prop_test_case(QueryPresetsInteger.GREATER_THAN_OR_EQUAL_TO, i, 2) - == expected - ) diff --git a/tests/handlers/test_client_side_handler_string.py b/tests/handlers/test_client_side_handler_string.py deleted file mode 100644 index c0df78a..0000000 --- a/tests/handlers/test_client_side_handler_string.py +++ /dev/null @@ -1,80 +0,0 @@ -from unittest.mock import NonCallableMock, MagicMock -import pytest - -from openstackquery.enums.query_presets import QueryPresetsString -from openstackquery.handlers.client_side_handler_string import ClientSideHandlerString -from tests.mocks.mocked_props import MockProperties - - -@pytest.fixture(name="instance") -def instance_fixture(): - """ - Prepares an instance to be used in tests - """ - _filter_function_mappings = { - preset: [MockProperties.PROP_1] for preset in QueryPresetsString - } - return ClientSideHandlerString(_filter_function_mappings) - - -@pytest.fixture(name="run_prop_test_case") -def run_prop_test_case_fixture(instance): - """ - fixture to run a test cases for each client-side filter function - """ - - def _run_prop_test_case(preset_to_test, prop_value, filter_value): - """ - runs a test case by calling get_filter_func for generic handler - with a given preset, prop return value and value to compare against. - """ - mock_kwargs = {"value": filter_value} - prop_func = MagicMock() - prop_func.return_value = prop_value - - filter_func = instance.get_filter_func( - preset_to_test, MockProperties.PROP_1, prop_func, mock_kwargs - ) - - mock_obj = NonCallableMock() - res = filter_func(mock_obj) - prop_func.assert_called_once_with(mock_obj) - return res - - return _run_prop_test_case - - -def test_check_supported_all_presets(instance): - """ - Tests that client_side_handler_string supports all string QueryPresets - """ - assert ( - instance.check_supported(preset, MockProperties.PROP_1) - for preset in QueryPresetsString - ) - - -@pytest.mark.parametrize( - "regex_string, test_prop, expected", - [ - # "Numeric digits only", - ("[0-9]+", "123", True), - # "Alphabetic characters only", - ("[A-Za-z]+", "abc", True), - # "No alphabetic characters", - ("[A-Za-z]+", "123", False), - # "Alphabetic and numeric characters", - ("[A-Za-z0-9]+", "abc123", True), - # "Empty string, no match", - ("[0-9]+", "", False), - ], -) -def test_prop_matches_regex(regex_string, test_prop, expected, run_prop_test_case): - """ - Tests that method prop_matches_regex functions expectedly - with valid regex patterns - Returns True if test_prop matches given regex pattern regex_string - """ - assert ( - run_prop_test_case(QueryPresetsString.MATCHES_REGEX, test_prop, regex_string) - == expected - ) diff --git a/tests/handlers/test_client_string_filters.py b/tests/handlers/test_client_string_filters.py new file mode 100644 index 0000000..02bc0bd --- /dev/null +++ b/tests/handlers/test_client_string_filters.py @@ -0,0 +1,30 @@ +import pytest +from openstackquery.enums.query_presets import QueryPresets + + +@pytest.mark.parametrize( + "regex_string, test_prop, expected", + [ + # "Numeric digits only", + ("[0-9]+", "123", True), + # "Alphabetic characters only", + ("[A-Za-z]+", "abc", True), + # "No alphabetic characters", + ("[A-Za-z]+", "123", False), + # "Alphabetic and numeric characters", + ("[A-Za-z0-9]+", "abc123", True), + # "Empty string, no match", + ("[0-9]+", "", False), + ], +) +def test_prop_matches_regex(regex_string, test_prop, expected, run_client_filter_test): + """ + Tests that method prop_matches_regex functions expectedly - with valid regex patterns + Returns True if test_prop matches given regex pattern regex_string + """ + assert ( + run_client_filter_test( + QueryPresets.MATCHES_REGEX, test_prop, {"value": regex_string} + ) + == expected + ) diff --git a/tests/mappings/conftest.py b/tests/mappings/conftest.py index ddfbee6..51cdace 100644 --- a/tests/mappings/conftest.py +++ b/tests/mappings/conftest.py @@ -3,9 +3,9 @@ from openstackquery.aliases import ClientSidePresetPropertyMappings from openstackquery.enums.props.prop_enum import PropEnum -from openstackquery.enums.query_presets import QueryPresets, QueryPresetsGeneric +from openstackquery.enums.query_presets import QueryPresets from openstackquery.handlers.client_side_handler import ClientSideHandler -from openstackquery.handlers.server_side_handler import ServerSideHandler +from openstackquery.mappings.mapping_interface import MappingInterface @pytest.fixture(scope="function", name="client_side_test_mappings") @@ -67,8 +67,7 @@ def server_side_test_mappings_fixture(client_side_match): """ def _server_side_test_case( - server_side_handler: ServerSideHandler, - client_side_handler: ClientSideHandler, + mapping_cls: MappingInterface, preset_to_test: QueryPresets, expected_mappings: Dict[PropEnum, str], test_case: Tuple = ("test", "test"), @@ -77,13 +76,14 @@ def _server_side_test_case( Tests server side handler mappings are correct, and line up to the expected server side params for equal to params. Also tests that server-side mapping has equivalent client-side mapping. - :param server_side_handler: server-side handler to test - :param client_side_handler: equivalent client-side handler to test + :param mapping_cls: mapping object to test :param preset_to_test: preset to test against :param expected_mappings: dictionary mapping expected properties to the filter param they should output :param test_case: tuple of value to test mapping with and expected value that it will map to when running get_filters """ + server_side_handler = mapping_cls.get_server_side_handler() + client_side_handler = mapping_cls.get_client_side_handler() supported_props = server_side_handler.get_supported_props(preset_to_test) assert all( key_to_check in supported_props for key_to_check in expected_mappings @@ -109,8 +109,7 @@ def server_side_test_any_in_mappings_fixture( """ def _server_side_any_in_test_case( - server_side_handler: ServerSideHandler, - client_side_handler: ClientSideHandler, + mapping_cls: MappingInterface, expected_mappings: Dict[PropEnum, str], test_cases: Dict, ): @@ -118,15 +117,14 @@ def _server_side_any_in_test_case( Tests server side handler mappings for ANY_IN preset are correct, and line up to the expected server side params for equal to params. Will test with one and with multiple values Also tests that server-side mapping has equivalent client-side mapping. - :param server_side_handler: server-side handler to test - :param client_side_handler: equivalent client-side handler to test + :param mapping_cls: mapping object to test :param expected_mappings: dictionary mapping expected properties to the filter param they should output :param test_cases: tuple of value to test mapping with and expected value that it will map to when running get_filters """ - supported_props = server_side_handler.get_supported_props( - QueryPresetsGeneric.ANY_IN - ) + server_side_handler = mapping_cls.get_server_side_handler() + client_side_handler = mapping_cls.get_client_side_handler() + supported_props = server_side_handler.get_supported_props(QueryPresets.ANY_IN) assert all( key_to_check in supported_props for key_to_check in expected_mappings @@ -134,7 +132,7 @@ def _server_side_any_in_test_case( for prop, expected in expected_mappings.items(): # test with one value server_filter = server_side_handler.get_filters( - QueryPresetsGeneric.ANY_IN, + QueryPresets.ANY_IN, prop, {"values": [list(test_cases.keys())[0]]}, ) @@ -142,7 +140,7 @@ def _server_side_any_in_test_case( # test with multiple values server_filter = server_side_handler.get_filters( - QueryPresetsGeneric.ANY_IN, + QueryPresets.ANY_IN, prop, {"values": list(test_cases.keys())}, ) @@ -152,16 +150,15 @@ def _server_side_any_in_test_case( # EQUAL_TO should have the same mappings for ANY_IN server_side_test_mappings( - server_side_handler, - client_side_handler, - QueryPresetsGeneric.EQUAL_TO, + mapping_cls, + QueryPresets.EQUAL_TO, expected_mappings, test_case=(list(test_cases.keys())[0], list(test_cases.values())[0]), ) client_side_match( client_side_handler, - QueryPresetsGeneric.ANY_IN, + QueryPresets.ANY_IN, list(expected_mappings.keys()), ) diff --git a/tests/mappings/test_flavor_mapping.py b/tests/mappings/test_flavor_mapping.py index c2b95fc..0adbc8a 100644 --- a/tests/mappings/test_flavor_mapping.py +++ b/tests/mappings/test_flavor_mapping.py @@ -1,10 +1,6 @@ from openstackquery.enums.props.flavor_properties import FlavorProperties from openstackquery.enums.props.server_properties import ServerProperties -from openstackquery.enums.query_presets import ( - QueryPresetsGeneric, - QueryPresetsString, - QueryPresetsInteger, -) +from openstackquery.enums.query_presets import QueryPresets from openstackquery.handlers.server_side_handler import ServerSideHandler from openstackquery.mappings.flavor_mapping import FlavorMapping from openstackquery.runners.flavor_runner import FlavorRunner @@ -31,16 +27,15 @@ def test_get_server_side_handler_returns_correct_type(): assert isinstance(FlavorMapping.get_server_side_handler(), ServerSideHandler) -def test_server_side_handler_mappings_equal_to(server_side_test_mappings): +def test_server_side_handler_mappings(server_side_test_mappings): """ Tests server side handler mappings are correct, and line up to the expected server side params for equal to params """ mappings = {FlavorProperties.FLAVOR_IS_PUBLIC: "is_public"} server_side_test_mappings( - FlavorMapping.get_server_side_handler(), - FlavorMapping.get_client_side_handlers().generic_handler, - QueryPresetsGeneric.EQUAL_TO, + FlavorMapping, + QueryPresets.EQUAL_TO, mappings, test_case=(True, True), ) @@ -56,27 +51,24 @@ def test_server_side_handler_less_than_or_equal_to(server_side_test_mappings): FlavorProperties.FLAVOR_RAM: "minRam", } server_side_test_mappings( - FlavorMapping.get_server_side_handler(), - FlavorMapping.get_client_side_handlers().integer_handler, - QueryPresetsInteger.LESS_THAN_OR_EQUAL_TO, + FlavorMapping, + QueryPresets.LESS_THAN_OR_EQUAL_TO, mappings, (10, 10), ) # with strings which can convert to ints server_side_test_mappings( - FlavorMapping.get_server_side_handler(), - FlavorMapping.get_client_side_handlers().integer_handler, - QueryPresetsInteger.LESS_THAN_OR_EQUAL_TO, + FlavorMapping, + QueryPresets.LESS_THAN_OR_EQUAL_TO, mappings, ("10", 10), ) # with floats which can convert to ints server_side_test_mappings( - FlavorMapping.get_server_side_handler(), - FlavorMapping.get_client_side_handlers().integer_handler, - QueryPresetsInteger.LESS_THAN_OR_EQUAL_TO, + FlavorMapping, + QueryPresets.LESS_THAN_OR_EQUAL_TO, mappings, (10.0, 10), ) @@ -91,53 +83,18 @@ def test_server_side_handler_not_equal_to(server_side_test_mappings): FlavorProperties.FLAVOR_IS_PUBLIC: "is_public", } server_side_test_mappings( - FlavorMapping.get_server_side_handler(), - FlavorMapping.get_client_side_handlers().generic_handler, - QueryPresetsGeneric.NOT_EQUAL_TO, + FlavorMapping, + QueryPresets.NOT_EQUAL_TO, mappings, (True, False), ) -def test_client_side_handlers_generic(client_side_test_mappings): +def test_client_side_handlers(client_side_test_mappings): """ Tests client side handler mappings are correct, and line up to the expected client side params for generic presets """ - handler = FlavorMapping.get_client_side_handlers().generic_handler - mappings = { - QueryPresetsGeneric.EQUAL_TO: ["*"], - QueryPresetsGeneric.NOT_EQUAL_TO: ["*"], - QueryPresetsGeneric.ANY_IN: ["*"], - QueryPresetsGeneric.NOT_ANY_IN: ["*"], - } - client_side_test_mappings(handler, mappings) - - -def test_client_side_handlers_string(client_side_test_mappings): - """ - Tests client side handler mappings are correct, and line up to the expected - client side params for string presets - """ - handler = FlavorMapping.get_client_side_handlers().string_handler - mappings = {QueryPresetsString.MATCHES_REGEX: [FlavorProperties.FLAVOR_NAME]} - client_side_test_mappings(handler, mappings) - - -def test_client_side_handlers_datetime(): - """ - Tests client side handler mappings are correct, and line up to the expected - shouldn't create a datetime handler because there are no datetime related properties for Flavor - """ - handler = FlavorMapping.get_client_side_handlers().datetime_handler - assert not handler - - -def test_client_side_handlers_integer(client_side_test_mappings): - """ - Tests client side handler mappings are correct, and line up to the expected - client side params for integer presets - """ integer_prop_list = [ FlavorProperties.FLAVOR_RAM, FlavorProperties.FLAVOR_DISK, @@ -145,12 +102,17 @@ def test_client_side_handlers_integer(client_side_test_mappings): FlavorProperties.FLAVOR_SWAP, FlavorProperties.FLAVOR_VCPU, ] - handler = FlavorMapping.get_client_side_handlers().integer_handler + handler = FlavorMapping.get_client_side_handler() mappings = { - QueryPresetsInteger.LESS_THAN: integer_prop_list, - QueryPresetsInteger.LESS_THAN_OR_EQUAL_TO: integer_prop_list, - QueryPresetsInteger.GREATER_THAN: integer_prop_list, - QueryPresetsInteger.GREATER_THAN_OR_EQUAL_TO: integer_prop_list, + QueryPresets.LESS_THAN: integer_prop_list, + QueryPresets.LESS_THAN_OR_EQUAL_TO: integer_prop_list, + QueryPresets.GREATER_THAN: integer_prop_list, + QueryPresets.GREATER_THAN_OR_EQUAL_TO: integer_prop_list, + QueryPresets.MATCHES_REGEX: [FlavorProperties.FLAVOR_NAME], + QueryPresets.EQUAL_TO: ["*"], + QueryPresets.NOT_EQUAL_TO: ["*"], + QueryPresets.ANY_IN: ["*"], + QueryPresets.NOT_ANY_IN: ["*"], } client_side_test_mappings(handler, mappings) diff --git a/tests/mappings/test_hypervisor_mapping.py b/tests/mappings/test_hypervisor_mapping.py index 75faf1b..036891b 100644 --- a/tests/mappings/test_hypervisor_mapping.py +++ b/tests/mappings/test_hypervisor_mapping.py @@ -1,10 +1,6 @@ from openstackquery.enums.props.hypervisor_properties import HypervisorProperties from openstackquery.enums.props.server_properties import ServerProperties -from openstackquery.enums.query_presets import ( - QueryPresetsGeneric, - QueryPresetsString, - QueryPresetsInteger, -) +from openstackquery.enums.query_presets import QueryPresets from openstackquery.handlers.server_side_handler import ServerSideHandler from openstackquery.mappings.hypervisor_mapping import HypervisorMapping from openstackquery.runners.hypervisor_runner import HypervisorRunner @@ -31,38 +27,7 @@ def test_get_server_side_handler_returns_correct_type(): assert isinstance(HypervisorMapping.get_server_side_handler(), ServerSideHandler) -def test_client_side_handlers_generic(client_side_test_mappings): - """ - Tests client side handler mappings are correct, and line up to the expected - client side params for generic presets - """ - handler = HypervisorMapping.get_client_side_handlers().generic_handler - mappings = { - QueryPresetsGeneric.EQUAL_TO: ["*"], - QueryPresetsGeneric.NOT_EQUAL_TO: ["*"], - QueryPresetsGeneric.ANY_IN: ["*"], - QueryPresetsGeneric.NOT_ANY_IN: ["*"], - } - client_side_test_mappings(handler, mappings) - - -def test_client_side_handlers_string(client_side_test_mappings): - """ - Tests client side handler mappings are correct, and line up to the expected - client side params for string presets - """ - expected_mappings = [ - HypervisorProperties.HYPERVISOR_IP, - HypervisorProperties.HYPERVISOR_NAME, - HypervisorProperties.HYPERVISOR_DISABLED_REASON, - ] - - handler = HypervisorMapping.get_client_side_handlers().string_handler - mappings = {QueryPresetsString.MATCHES_REGEX: expected_mappings} - client_side_test_mappings(handler, mappings) - - -def test_client_side_handlers_integer(client_side_test_mappings): +def test_client_side_handlers(client_side_test_mappings): """ Tests client side handler mappings are correct shouldn't create an integer handler because there are no integer related properties for Server @@ -78,26 +43,27 @@ def test_client_side_handlers_integer(client_side_test_mappings): HypervisorProperties.DISK_GB_SIZE, HypervisorProperties.MEMORY_MB_SIZE, ] + string_prop_list = [ + HypervisorProperties.HYPERVISOR_IP, + HypervisorProperties.HYPERVISOR_NAME, + HypervisorProperties.HYPERVISOR_DISABLED_REASON, + ] - handler = HypervisorMapping.get_client_side_handlers().integer_handler + handler = HypervisorMapping.get_client_side_handler() mappings = { - QueryPresetsInteger.LESS_THAN: integer_prop_list, - QueryPresetsInteger.GREATER_THAN: integer_prop_list, - QueryPresetsInteger.GREATER_THAN_OR_EQUAL_TO: integer_prop_list, - QueryPresetsInteger.LESS_THAN_OR_EQUAL_TO: integer_prop_list, + QueryPresets.LESS_THAN: integer_prop_list, + QueryPresets.GREATER_THAN: integer_prop_list, + QueryPresets.GREATER_THAN_OR_EQUAL_TO: integer_prop_list, + QueryPresets.LESS_THAN_OR_EQUAL_TO: integer_prop_list, + QueryPresets.MATCHES_REGEX: string_prop_list, + QueryPresets.EQUAL_TO: ["*"], + QueryPresets.NOT_EQUAL_TO: ["*"], + QueryPresets.ANY_IN: ["*"], + QueryPresets.NOT_ANY_IN: ["*"], } client_side_test_mappings(handler, mappings) -def test_client_side_handlers_datetime(): - """ - Tests client side handler mappings are correct, and line up to the expected - shouldn't create a datetime handler because there are no datetime related properties for Hypervisor - """ - handler = HypervisorMapping.get_client_side_handlers().datetime_handler - assert not handler - - def test_get_chain_mappings(): """ Tests get_chain_mapping outputs correctly diff --git a/tests/mappings/test_image_mapping.py b/tests/mappings/test_image_mapping.py index 508775c..37d43df 100644 --- a/tests/mappings/test_image_mapping.py +++ b/tests/mappings/test_image_mapping.py @@ -2,12 +2,8 @@ from openstackquery.enums.props.server_properties import ServerProperties from openstackquery.enums.props.image_properties import ImageProperties -from openstackquery.enums.query_presets import ( - QueryPresetsGeneric, - QueryPresetsString, - QueryPresetsInteger, - QueryPresetsDateTime, -) +from openstackquery.enums.query_presets import QueryPresets + from openstackquery.handlers.server_side_handler import ServerSideHandler from openstackquery.mappings.image_mapping import ImageMapping from openstackquery.runners.image_runner import ImageRunner @@ -45,9 +41,8 @@ def test_server_side_handler_mappings_equal_to(server_side_test_mappings): } server_side_test_mappings( - ImageMapping.get_server_side_handler(), - ImageMapping.get_client_side_handlers().generic_handler, - QueryPresetsGeneric.EQUAL_TO, + ImageMapping, + QueryPresets.EQUAL_TO, mappings, test_case=(True, True), ) @@ -67,8 +62,7 @@ def test_server_side_handler_mappings_any_in(server_side_any_in_mappings): ImageProperties.IMAGE_STATUS: "status", } server_side_any_in_mappings( - ImageMapping.get_server_side_handler(), - ImageMapping.get_client_side_handlers().generic_handler, + ImageMapping, mappings, {"test1": "test1", "test2": "test2"}, ) @@ -88,9 +82,8 @@ def test_server_side_handler_mappings_older_than_or_equal_to( ImageProperties.IMAGE_LAST_UPDATED_DATE: "updated_at", } server_side_test_mappings( - ImageMapping.get_server_side_handler(), - ImageMapping.get_client_side_handlers().datetime_handler, - QueryPresetsDateTime.OLDER_THAN_OR_EQUAL_TO, + ImageMapping, + QueryPresets.OLDER_THAN_OR_EQUAL_TO, mappings, ("test", "lte:test"), ) @@ -110,9 +103,8 @@ def test_server_side_handler_mappings_older_than( ImageProperties.IMAGE_LAST_UPDATED_DATE: "updated_at", } server_side_test_mappings( - ImageMapping.get_server_side_handler(), - ImageMapping.get_client_side_handlers().datetime_handler, - QueryPresetsDateTime.OLDER_THAN, + ImageMapping, + QueryPresets.OLDER_THAN, mappings, ("test", "lt:test"), ) @@ -132,9 +124,8 @@ def test_server_side_handler_mappings_younger_than_or_equal_to( ImageProperties.IMAGE_LAST_UPDATED_DATE: "updated_at", } server_side_test_mappings( - ImageMapping.get_server_side_handler(), - ImageMapping.get_client_side_handlers().datetime_handler, - QueryPresetsDateTime.YOUNGER_THAN_OR_EQUAL_TO, + ImageMapping, + QueryPresets.YOUNGER_THAN_OR_EQUAL_TO, mappings, ("test", "gte:test"), ) @@ -154,9 +145,8 @@ def test_server_side_handler_mappings_younger_than( ImageProperties.IMAGE_LAST_UPDATED_DATE: "updated_at", } server_side_test_mappings( - ImageMapping.get_server_side_handler(), - ImageMapping.get_client_side_handlers().datetime_handler, - QueryPresetsDateTime.YOUNGER_THAN, + ImageMapping, + QueryPresets.YOUNGER_THAN, mappings, ("test", "gt:test"), ) @@ -171,27 +161,24 @@ def test_server_side_handler_less_than_or_equal_to(server_side_test_mappings): ImageProperties.IMAGE_SIZE: "size_max", } server_side_test_mappings( - ImageMapping.get_server_side_handler(), - ImageMapping.get_client_side_handlers().integer_handler, - QueryPresetsInteger.LESS_THAN_OR_EQUAL_TO, + ImageMapping, + QueryPresets.LESS_THAN_OR_EQUAL_TO, mappings, (10, 10), ) # with strings which can convert to ints server_side_test_mappings( - ImageMapping.get_server_side_handler(), - ImageMapping.get_client_side_handlers().integer_handler, - QueryPresetsInteger.LESS_THAN_OR_EQUAL_TO, + ImageMapping, + QueryPresets.LESS_THAN_OR_EQUAL_TO, mappings, ("10", 10), ) # with floats which can convert to ints server_side_test_mappings( - ImageMapping.get_server_side_handler(), - ImageMapping.get_client_side_handlers().integer_handler, - QueryPresetsInteger.LESS_THAN_OR_EQUAL_TO, + ImageMapping, + QueryPresets.LESS_THAN_OR_EQUAL_TO, mappings, (10.0, 10), ) @@ -206,97 +193,61 @@ def test_server_side_handler_greater_than_or_equal_to(server_side_test_mappings) ImageProperties.IMAGE_SIZE: "size_min", } server_side_test_mappings( - ImageMapping.get_server_side_handler(), - ImageMapping.get_client_side_handlers().integer_handler, - QueryPresetsInteger.GREATER_THAN_OR_EQUAL_TO, + ImageMapping, + QueryPresets.GREATER_THAN_OR_EQUAL_TO, mappings, (10, 10), ) # with strings which can convert to ints server_side_test_mappings( - ImageMapping.get_server_side_handler(), - ImageMapping.get_client_side_handlers().integer_handler, - QueryPresetsInteger.GREATER_THAN_OR_EQUAL_TO, + ImageMapping, + QueryPresets.GREATER_THAN_OR_EQUAL_TO, mappings, ("10", 10), ) # with floats which can convert to ints server_side_test_mappings( - ImageMapping.get_server_side_handler(), - ImageMapping.get_client_side_handlers().integer_handler, - QueryPresetsInteger.GREATER_THAN_OR_EQUAL_TO, + ImageMapping, + QueryPresets.GREATER_THAN_OR_EQUAL_TO, mappings, (10.0, 10), ) -def test_client_side_handlers_generic(client_side_test_mappings): +def test_client_side_handler(client_side_test_mappings): """ Tests client side handler mappings are correct, and line up to the expected client side params for generic presets """ - handler = ImageMapping.get_client_side_handlers().generic_handler - mappings = { - QueryPresetsGeneric.EQUAL_TO: ["*"], - QueryPresetsGeneric.NOT_EQUAL_TO: ["*"], - QueryPresetsGeneric.ANY_IN: ["*"], - QueryPresetsGeneric.NOT_ANY_IN: ["*"], - } - client_side_test_mappings(handler, mappings) - - -def test_client_side_handlers_string(client_side_test_mappings): - """ - Tests client side handler mappings are correct, and line up to the expected - client side params for string presets - """ - handler = ImageMapping.get_client_side_handlers().string_handler - mappings = { - QueryPresetsString.MATCHES_REGEX: [ - ImageProperties.IMAGE_NAME, - ] - } - client_side_test_mappings(handler, mappings) - - -def test_client_side_handlers_datetime(client_side_test_mappings): - """ - Tests client side handler mappings are correct, and line up to the expected - client side params for string presets - """ date_prop_list = [ ImageProperties.IMAGE_CREATION_DATE, ImageProperties.IMAGE_LAST_UPDATED_DATE, ] - handler = ImageMapping.get_client_side_handlers().datetime_handler - mappings = { - QueryPresetsDateTime.OLDER_THAN: date_prop_list, - QueryPresetsDateTime.OLDER_THAN_OR_EQUAL_TO: date_prop_list, - QueryPresetsDateTime.YOUNGER_THAN: date_prop_list, - QueryPresetsDateTime.YOUNGER_THAN_OR_EQUAL_TO: date_prop_list, - } - client_side_test_mappings(handler, mappings) - - -def test_client_side_handlers_integer(client_side_test_mappings): - """ - Tests client side handler mappings are correct - shouldn't create an integer handler because there are no integer related properties for Server - """ integer_prop_list = [ ImageProperties.IMAGE_SIZE, ImageProperties.IMAGE_MINIMUM_RAM, ImageProperties.IMAGE_MINIMUM_DISK, ImageProperties.IMAGE_CREATION_PROGRESS, ] - handler = ImageMapping.get_client_side_handlers().integer_handler + handler = ImageMapping.get_client_side_handler() mappings = { - QueryPresetsInteger.LESS_THAN: integer_prop_list, - QueryPresetsInteger.GREATER_THAN: integer_prop_list, - QueryPresetsInteger.GREATER_THAN_OR_EQUAL_TO: integer_prop_list, - QueryPresetsInteger.LESS_THAN_OR_EQUAL_TO: integer_prop_list, + QueryPresets.EQUAL_TO: ["*"], + QueryPresets.NOT_EQUAL_TO: ["*"], + QueryPresets.ANY_IN: ["*"], + QueryPresets.NOT_ANY_IN: ["*"], + QueryPresets.MATCHES_REGEX: [ + ImageProperties.IMAGE_NAME, + ], + QueryPresets.OLDER_THAN: date_prop_list, + QueryPresets.OLDER_THAN_OR_EQUAL_TO: date_prop_list, + QueryPresets.YOUNGER_THAN: date_prop_list, + QueryPresets.YOUNGER_THAN_OR_EQUAL_TO: date_prop_list, + QueryPresets.LESS_THAN: integer_prop_list, + QueryPresets.GREATER_THAN: integer_prop_list, + QueryPresets.GREATER_THAN_OR_EQUAL_TO: integer_prop_list, + QueryPresets.LESS_THAN_OR_EQUAL_TO: integer_prop_list, } client_side_test_mappings(handler, mappings) diff --git a/tests/mappings/test_project_mapping.py b/tests/mappings/test_project_mapping.py index 72f95fd..cc185cf 100644 --- a/tests/mappings/test_project_mapping.py +++ b/tests/mappings/test_project_mapping.py @@ -1,9 +1,7 @@ from openstackquery.enums.props.project_properties import ProjectProperties from openstackquery.enums.props.server_properties import ServerProperties -from openstackquery.enums.query_presets import ( - QueryPresetsGeneric, - QueryPresetsString, -) +from openstackquery.enums.query_presets import QueryPresets + from openstackquery.handlers.server_side_handler import ServerSideHandler from openstackquery.mappings.project_mapping import ProjectMapping from openstackquery.runners.project_runner import ProjectRunner @@ -45,9 +43,8 @@ def test_server_side_handler_mappings_equal_to(server_side_test_mappings): } server_side_test_mappings( - ProjectMapping.get_server_side_handler(), - ProjectMapping.get_client_side_handlers().generic_handler, - QueryPresetsGeneric.EQUAL_TO, + ProjectMapping, + QueryPresets.EQUAL_TO, mappings, test_case=(True, True), ) @@ -64,9 +61,8 @@ def test_server_side_handler_mappings_not_equal_to(server_side_test_mappings): } server_side_test_mappings( - ProjectMapping.get_server_side_handler(), - ProjectMapping.get_client_side_handlers().generic_handler, - QueryPresetsGeneric.NOT_EQUAL_TO, + ProjectMapping, + QueryPresets.NOT_EQUAL_TO, mappings, test_case=(True, False), ) @@ -89,8 +85,7 @@ def test_server_side_handler_mappings_any_in(server_side_any_in_mappings): } server_side_any_in_mappings( - ProjectMapping.get_server_side_handler(), - ProjectMapping.get_client_side_handlers().generic_handler, + ProjectMapping, mappings, {"test1": "test1", "test2": "test2"}, ) @@ -101,12 +96,12 @@ def test_client_side_handlers_generic(client_side_test_mappings): Tests client side handler mappings are correct, and line up to the expected client side params for generic presets """ - handler = ProjectMapping.get_client_side_handlers().generic_handler + handler = ProjectMapping.get_client_side_handler() mappings = { - QueryPresetsGeneric.EQUAL_TO: ["*"], - QueryPresetsGeneric.NOT_EQUAL_TO: ["*"], - QueryPresetsGeneric.ANY_IN: ["*"], - QueryPresetsGeneric.NOT_ANY_IN: ["*"], + QueryPresets.EQUAL_TO: ["*"], + QueryPresets.NOT_EQUAL_TO: ["*"], + QueryPresets.ANY_IN: ["*"], + QueryPresets.NOT_ANY_IN: ["*"], } client_side_test_mappings(handler, mappings) @@ -116,9 +111,9 @@ def test_client_side_handlers_string(client_side_test_mappings): Tests client side handler mappings are correct, and line up to the expected client side params for string presets """ - handler = ProjectMapping.get_client_side_handlers().string_handler + handler = ProjectMapping.get_client_side_handler() mappings = { - QueryPresetsString.MATCHES_REGEX: [ + QueryPresets.MATCHES_REGEX: [ ProjectProperties.PROJECT_NAME, ProjectProperties.PROJECT_DESCRIPTION, ] @@ -126,24 +121,6 @@ def test_client_side_handlers_string(client_side_test_mappings): client_side_test_mappings(handler, mappings) -def test_client_side_handlers_datetime(): - """ - Tests client side handler mappings are correct, and line up to the expected - shouldn't create a datetime handler because there are no datetime related properties for Project - """ - handler = ProjectMapping.get_client_side_handlers().datetime_handler - assert not handler - - -def test_client_side_handlers_integer(): - """ - Tests client side handler mappings are correct, and line up to the expected - shouldn't create a datetime handler because there are no datetime related properties for Project - """ - handler = ProjectMapping.get_client_side_handlers().integer_handler - assert not handler - - def test_get_chain_mappings(): """ Tests get_chain_mapping outputs correctly diff --git a/tests/mappings/test_server_mapping.py b/tests/mappings/test_server_mapping.py index aee0b9d..18c5977 100644 --- a/tests/mappings/test_server_mapping.py +++ b/tests/mappings/test_server_mapping.py @@ -6,11 +6,8 @@ from openstackquery.enums.props.project_properties import ProjectProperties from openstackquery.enums.props.server_properties import ServerProperties from openstackquery.enums.props.user_properties import UserProperties -from openstackquery.enums.query_presets import ( - QueryPresetsGeneric, - QueryPresetsDateTime, - QueryPresetsString, -) +from openstackquery.enums.query_presets import QueryPresets + from openstackquery.handlers.server_side_handler import ServerSideHandler from openstackquery.mappings.server_mapping import ServerMapping from openstackquery.runners.server_runner import ServerRunner @@ -54,9 +51,8 @@ def test_server_side_handler_mappings_equal_to(server_side_test_mappings): ServerProperties.PROJECT_ID: "project_id", } server_side_test_mappings( - ServerMapping.get_server_side_handler(), - ServerMapping.get_client_side_handlers().generic_handler, - QueryPresetsGeneric.EQUAL_TO, + ServerMapping, + QueryPresets.EQUAL_TO, mappings, ) @@ -82,8 +78,7 @@ def test_server_side_handler_mappings_any_in(server_side_any_in_mappings): ServerProperties.PROJECT_ID: "project_id", } server_side_any_in_mappings( - ServerMapping.get_server_side_handler(), - ServerMapping.get_client_side_handlers().generic_handler, + ServerMapping, mappings, {"test1": "test1", "test2": "test2"}, ) @@ -102,9 +97,8 @@ def test_server_side_handler_mappings_older_than_or_equal_to( ServerProperties.SERVER_LAST_UPDATED_DATE: "changes-before", } server_side_test_mappings( - ServerMapping.get_server_side_handler(), - ServerMapping.get_client_side_handlers().datetime_handler, - QueryPresetsDateTime.OLDER_THAN_OR_EQUAL_TO, + ServerMapping, + QueryPresets.OLDER_THAN_OR_EQUAL_TO, mappings, ) @@ -125,9 +119,8 @@ def test_server_side_handler_mappings_younger_than_or_equal_to( ServerProperties.SERVER_LAST_UPDATED_DATE: "changes-since", } server_side_test_mappings( - ServerMapping.get_server_side_handler(), - ServerMapping.get_client_side_handlers().datetime_handler, - QueryPresetsDateTime.YOUNGER_THAN_OR_EQUAL_TO, + ServerMapping, + QueryPresets.YOUNGER_THAN_OR_EQUAL_TO, mappings, ) @@ -140,67 +133,28 @@ def test_client_side_handlers_generic(client_side_test_mappings): Tests client side handler mappings are correct, and line up to the expected client side params for generic presets """ - handler = ServerMapping.get_client_side_handlers().generic_handler - mappings = { - QueryPresetsGeneric.EQUAL_TO: ["*"], - QueryPresetsGeneric.NOT_EQUAL_TO: ["*"], - QueryPresetsGeneric.ANY_IN: ["*"], - QueryPresetsGeneric.NOT_ANY_IN: ["*"], - } - client_side_test_mappings(handler, mappings) - - -def test_client_side_handlers_string(client_side_test_mappings): - """ - Tests client side handler mappings are correct, and line up to the expected - client side params for string presets - """ - handler = ServerMapping.get_client_side_handlers().string_handler + handler = ServerMapping.get_client_side_handler() + date_props = [ + ServerProperties.SERVER_LAST_UPDATED_DATE, + ServerProperties.SERVER_CREATION_DATE, + ] mappings = { - QueryPresetsString.MATCHES_REGEX: [ + QueryPresets.EQUAL_TO: ["*"], + QueryPresets.NOT_EQUAL_TO: ["*"], + QueryPresets.ANY_IN: ["*"], + QueryPresets.NOT_ANY_IN: ["*"], + QueryPresets.MATCHES_REGEX: [ ServerProperties.SERVER_NAME, ServerProperties.ADDRESSES, - ] - } - client_side_test_mappings(handler, mappings) - - -def test_client_side_handlers_datetime(client_side_test_mappings): - """ - Tests client side handler mappings are correct, and line up to the expected - client side params for string presets - """ - handler = ServerMapping.get_client_side_handlers().datetime_handler - mappings = { - QueryPresetsDateTime.OLDER_THAN_OR_EQUAL_TO: [ - ServerProperties.SERVER_LAST_UPDATED_DATE, - ServerProperties.SERVER_CREATION_DATE, - ], - QueryPresetsDateTime.YOUNGER_THAN_OR_EQUAL_TO: [ - ServerProperties.SERVER_LAST_UPDATED_DATE, - ServerProperties.SERVER_CREATION_DATE, - ], - QueryPresetsDateTime.YOUNGER_THAN: [ - ServerProperties.SERVER_LAST_UPDATED_DATE, - ServerProperties.SERVER_CREATION_DATE, - ], - QueryPresetsDateTime.OLDER_THAN: [ - ServerProperties.SERVER_LAST_UPDATED_DATE, - ServerProperties.SERVER_CREATION_DATE, ], + QueryPresets.OLDER_THAN_OR_EQUAL_TO: date_props, + QueryPresets.YOUNGER_THAN_OR_EQUAL_TO: date_props, + QueryPresets.YOUNGER_THAN: date_props, + QueryPresets.OLDER_THAN: date_props, } client_side_test_mappings(handler, mappings) -def test_client_side_handlers_integer(): - """ - Tests client side handler mappings are correct - shouldn't create an integer handler because there are no integer related properties for Server - """ - handler = ServerMapping.get_client_side_handlers().integer_handler - assert not handler - - def test_get_chain_mappings(): """ Tests get_chain_mapping outputs correctly diff --git a/tests/mappings/test_user_mapping.py b/tests/mappings/test_user_mapping.py index 3643693..167985c 100644 --- a/tests/mappings/test_user_mapping.py +++ b/tests/mappings/test_user_mapping.py @@ -1,6 +1,6 @@ from openstackquery.enums.props.server_properties import ServerProperties from openstackquery.enums.props.user_properties import UserProperties -from openstackquery.enums.query_presets import QueryPresetsGeneric, QueryPresetsString +from openstackquery.enums.query_presets import QueryPresets from openstackquery.handlers.server_side_handler import ServerSideHandler from openstackquery.mappings.user_mapping import UserMapping from openstackquery.runners.user_runner import UserRunner @@ -39,9 +39,8 @@ def test_server_side_handler_mappings_equal_to(server_side_test_mappings): } server_side_test_mappings( - UserMapping.get_server_side_handler(), - UserMapping.get_client_side_handlers().generic_handler, - QueryPresetsGeneric.EQUAL_TO, + UserMapping, + QueryPresets.EQUAL_TO, mappings, ) @@ -62,8 +61,7 @@ def test_server_side_handler_mappings_any_in(server_side_any_in_mappings): } server_side_any_in_mappings( - UserMapping.get_server_side_handler(), - UserMapping.get_client_side_handlers().generic_handler, + UserMapping, mappings, {"test1": "test1", "test2": "test2"}, ) @@ -74,49 +72,20 @@ def test_client_side_handlers_generic(client_side_test_mappings): Tests client side handler mappings are correct, and line up to the expected client side params for generic presets """ - handler = UserMapping.get_client_side_handlers().generic_handler + handler = UserMapping.get_client_side_handler() mappings = { - QueryPresetsGeneric.EQUAL_TO: ["*"], - QueryPresetsGeneric.NOT_EQUAL_TO: ["*"], - QueryPresetsGeneric.ANY_IN: ["*"], - QueryPresetsGeneric.NOT_ANY_IN: ["*"], - } - client_side_test_mappings(handler, mappings) - - -def test_client_side_handlers_string(client_side_test_mappings): - """ - Tests client side handler mappings are correct, and line up to the expected - client side params for string presets - """ - handler = UserMapping.get_client_side_handlers().string_handler - mappings = { - QueryPresetsString.MATCHES_REGEX: [ + QueryPresets.EQUAL_TO: ["*"], + QueryPresets.NOT_EQUAL_TO: ["*"], + QueryPresets.ANY_IN: ["*"], + QueryPresets.NOT_ANY_IN: ["*"], + QueryPresets.MATCHES_REGEX: [ UserProperties.USER_EMAIL, UserProperties.USER_NAME, - ] + ], } client_side_test_mappings(handler, mappings) -def test_client_side_handlers_integer(): - """ - Tests client side handler mappings are correct - shouldn't create an integer handler because there are no integer related properties for User - """ - handler = UserMapping.get_client_side_handlers().integer_handler - assert not handler - - -def test_client_side_handlers_datetime(): - """ - Tests client side handler mappings are correct - shouldn't create a datetime handler because there are no datetime related properties for User - """ - handler = UserMapping.get_client_side_handlers().datetime_handler - assert not handler - - def test_get_chain_mappings(): """ Tests get_chain_mapping outputs correctly diff --git a/tests/query_blocks/test_query_builder.py b/tests/query_blocks/test_query_builder.py index bc5c1fe..0ffc9de 100644 --- a/tests/query_blocks/test_query_builder.py +++ b/tests/query_blocks/test_query_builder.py @@ -12,21 +12,10 @@ from tests.mocks.mocked_props import MockProperties -@pytest.fixture(name="mock_invalid_client_handler") -def mock_invalid_client_handler_fixture(): +@pytest.fixture(name="mock_client_side_handler") +def mock_client_handler_fixture(): """ - Return a client handler - mocks one handler which does not contain preset - """ - mock_invalid_client_handler = MagicMock() - mock_invalid_client_handler.preset_known.return_value = False - mock_invalid_client_handler.check_supported.return_value = False - return mock_invalid_client_handler - - -@pytest.fixture(name="mock_valid_client_handler") -def mock_valid_client_handler_fixture(): - """ - Return a client handler - mocks one handler which does contain preset + Return a client handler """ def _mock_preset_known(preset): @@ -52,26 +41,22 @@ def mock_valid_server_handler_fixture(): @pytest.fixture(name="instance") -def instance_fixture( - mock_server_side_handler, mock_invalid_client_handler, mock_valid_client_handler -): +def instance_fixture(mock_server_side_handler, mock_client_side_handler): """ Returns an instance with mocked client_side_handlers and server_side_handler injects """ - client_handlers = [mock_invalid_client_handler, mock_valid_client_handler] - return QueryBuilder( prop_enum_cls=MockProperties, - client_side_handlers=client_handlers, + client_side_handler=mock_client_side_handler, server_side_handler=mock_server_side_handler, ) @pytest.fixture(name="parse_where_runner") def parse_where_runner_fixture( - instance, mock_server_side_handler, mock_valid_client_handler + instance, mock_server_side_handler, mock_client_side_handler ): """ This is a helper function that runs test cases of parse_where, where we expect it to complete successfully, @@ -101,7 +86,7 @@ def _parse_where_runner( - if left blank it creates a new instance """ mock_server_side_handler.get_filters.return_value = mock_get_filter_return - mock_valid_client_handler.get_filter_func.return_value = ( + mock_client_side_handler.get_filter_func.return_value = ( mock_get_filter_func_return ) @@ -110,7 +95,7 @@ def _parse_where_runner( MockQueryPresets.ITEM_1, MockProperties.PROP_1, mock_kwargs ) - mock_valid_client_handler.get_filter_func.assert_called_once_with( + mock_client_side_handler.get_filter_func.assert_called_once_with( preset=MockQueryPresets.ITEM_1, prop=MockProperties.PROP_1, prop_func=mock_get_prop_mapping.return_value, @@ -333,14 +318,12 @@ def test_parse_where_multi_filter_set_conflicting_add_multi( def test_parse_where_preset_unknown(instance): """ - Tests that parse_where errors if no handler found which supports given preset + Tests that parse_where errors if given preset not supported """ # when preset_known returns false - with patch.object(MockProperties, "get_prop_mapping") as mock_prop_func: - with pytest.raises(QueryPresetMappingError): - instance.parse_where(MockQueryPresets.ITEM_2, MockProperties.PROP_1) - mock_prop_func.assert_called_once_with(MockProperties.PROP_1) + with pytest.raises(QueryPresetMappingError): + instance.parse_where(MockQueryPresets.ITEM_2, MockProperties.PROP_1) def test_parse_where_preset_misconfigured(instance): @@ -350,10 +333,8 @@ def test_parse_where_preset_misconfigured(instance): """ # when preset_known returns True, but client_side filter missing - with patch.object(MockProperties, "get_prop_mapping") as mock_prop_func: - with pytest.raises(QueryPresetMappingError): - instance.parse_where(MockQueryPresets.ITEM_3, MockProperties.PROP_1) - mock_prop_func.assert_called_once_with(MockProperties.PROP_1) + with pytest.raises(QueryPresetMappingError): + instance.parse_where(MockQueryPresets.ITEM_3, MockProperties.PROP_1) def test_parse_where_prop_invalid(instance): @@ -396,12 +377,12 @@ def test_server_filter_fallback(instance): assert res == ["some-client-side-filter"] -@patch("openstackquery.query_blocks.query_builder.get_preset_from_string") +@patch("openstackquery.query_blocks.query_builder.QueryPresets") def test_parse_where_with_string_aliases( - mock_get_preset_from_string, + mock_query_presets, instance, mock_server_side_handler, - mock_valid_client_handler, + mock_client_side_handler, ): """ tests parse_where works when using string aliases as input for preset and prop. @@ -411,12 +392,12 @@ def test_parse_where_with_string_aliases( mock_kwargs = {"arg1": "val1"} mock_server_side_handler.get_filters.return_value = mock_server_filters - mock_valid_client_handler.get_filter_func.return_value = mock_client_filter_func + mock_client_side_handler.get_filter_func.return_value = mock_client_filter_func mock_prop_from_string = MagicMock() mock_prop_from_string.return_value = MockProperties.PROP_1 - mock_get_preset_from_string.return_value = MockQueryPresets.ITEM_1 + mock_query_presets.from_string.return_value = MockQueryPresets.ITEM_1 mock_get_prop_mapping = MagicMock() @@ -427,10 +408,10 @@ def test_parse_where_with_string_aliases( ): instance.parse_where("mock-preset", "mock-prop", mock_kwargs) - mock_get_preset_from_string.assert_called_once_with("mock-preset") + mock_query_presets.from_string.assert_called_once_with("mock-preset") mock_prop_from_string.assert_called_once_with("mock-prop") - mock_valid_client_handler.get_filter_func.assert_called_once_with( + mock_client_side_handler.get_filter_func.assert_called_once_with( preset=MockQueryPresets.ITEM_1, prop=MockProperties.PROP_1, prop_func=mock_get_prop_mapping.return_value, diff --git a/tests/query_blocks/test_query_chainer.py b/tests/query_blocks/test_query_chainer.py index cc1aee5..10bdac7 100644 --- a/tests/query_blocks/test_query_chainer.py +++ b/tests/query_blocks/test_query_chainer.py @@ -2,7 +2,7 @@ import pytest -from openstackquery.enums.query_presets import QueryPresetsGeneric +from openstackquery.enums.query_presets import QueryPresets from openstackquery.exceptions.query_chaining_error import QueryChainingError from openstackquery.query_blocks.query_chainer import QueryChainer from tests.mocks.mocked_props import MockProperties @@ -89,7 +89,7 @@ def _run_parse_then_query_valid( ) mock_query_api.return_value.where.assert_called_once_with( - QueryPresetsGeneric.ANY_IN, + QueryPresets.ANY_IN, MockProperties.PROP_2, values=["val1", "val2", "val3"], ) diff --git a/tests/test_query_factory.py b/tests/test_query_factory.py index 01e72e4..33c9bb6 100644 --- a/tests/test_query_factory.py +++ b/tests/test_query_factory.py @@ -39,7 +39,7 @@ def _run_build_query_deps_test_case( mock_parser.assert_called_once_with(mock_prop_mapping) mock_builder.assert_called_once_with( prop_enum_cls=mock_prop_mapping, - client_side_handlers=mock_mapping_cls.get_client_side_handlers.return_value.to_list.return_value, + client_side_handler=mock_mapping_cls.get_client_side_handler.return_value, server_side_handler=mock_mapping_cls.get_server_side_handler.return_value, ) mock_chainer.assert_called_once_with( From dce7052440be2b0bdfa927cf66cb156359245f81 Mon Sep 17 00:00:00 2001 From: anish-mudaraddi Date: Tue, 25 Feb 2025 20:28:27 +0000 Subject: [PATCH 2/4] update docs update docs to match change to client-side-handlers --- docs/developer_docs/ADDING_NEW_PRESETS.md | 127 ++++++++++------------ docs/developer_docs/ADDING_NEW_QUERIES.md | 69 ++++++------ docs/user_docs/PRESETS.md | 57 +++------- 3 files changed, 105 insertions(+), 148 deletions(-) diff --git a/docs/developer_docs/ADDING_NEW_PRESETS.md b/docs/developer_docs/ADDING_NEW_PRESETS.md index 7455742..bf4ea4d 100644 --- a/docs/developer_docs/ADDING_NEW_PRESETS.md +++ b/docs/developer_docs/ADDING_NEW_PRESETS.md @@ -1,26 +1,24 @@ -# Adding New Preset To An Existing Preset Group +# Adding A New Preset -## **1. Add the preset name to the corresponding enum class in `openstackquery/enums/query_presets.py`** +## **1. Add the preset name to the QueryPresets enum class in `openstackquery/enums/query_presets.py`** e.g. ```python -class QueryPresetsGeneric(QueryPresets): +class QueryPresets(EnumWithAliases): """ Enum class which holds generic query comparison operators """ EQUAL_TO = auto() ... - NEW_PRESET = auto() # <- we add this line to repesent a new preset enum belonging to the 'Generic' group + NEW_PRESET = auto() # <- we add this line to represent a new preset enum belonging to the 'Generic' group ``` (Optional) Add alias mappings for the preset - see [Adding Aliases](ADDING_ALIASES.md) -## **2. Edit the corresponding handler class in `openstackquery/handlers/client_side_handler_.py`.** +## **2. Create a function to act as the client-side filter function for your new query preset -Here you must: -- add a 'client-side' filter function as a method -- add the mapping between the enum and filter function in self._filter_functions. +Client-side filter functions are located in `openstackquery/handlers/client_side_filters.py` The filter function must: - **take as input at least one parameter - `prop`**: @@ -30,32 +28,41 @@ The filter function must: - `True` if the prop passes filter - `False` if not -e.g. editing `client_side_handler_generic.py` ```python -class ClientSideHandlerGeneric(ClientSideHandler): -... +def prop_new_preset_filter_func(self, prop: Any, arg1, arg2): + """ + A new preset filter - takes a property value, performs some logic and returns a boolean if + property passes a filter or not + :param prop: property value to check + :param arg1: some arg the filter uses + :param arg2: some other arg the filter uses + :returns: True or False + """ + # Define your filter logic here +``` -def __init__(self, filter_function_mappings: PresetPropMappings): - super().__init__(filter_function_mappings) +## **3. Edit the corresponding handler class in `openstackquery/handlers/client_side_handler.py`.** - self._filter_functions = { - QueryPresetsGeneric.EQUAL_TO: self._prop_equal_to, - ... - QueryPresetsGeneric.NEW_PRESET: self._new_preset_filter_func # <- 2) add the enum-to-function mapping - } +Here you must: +- add a 'client-side' filter function as a method +- add the mapping between the enum and filter function in self._filter_functions. + +e.g. editing `client_side_handler_generic.py` +```python +from openstackquery.handlers.client_side_filters import ( + prop_new_preset_filter_func # newly made filter func +) +class ClientSideHandler(HandlerBase): ... -def _new_preset_filter_func(self, prop: Any, arg1, arg2): - """ - A new preset filter - takes a property value, performs some logic and returns a boolean if - property passes a filter or not - :param prop: property value to check - :param arg1: some arg the filter uses - :param arg2: some other arg the filter uses - :returns: True or False - """ - ... # Define your preset logic here +def __init__(self, preset_prop_mappings: ClientSidePresetPropertyMappings): + self._filter_functions = { + QueryPresets.EQUAL_TO: self._prop_equal_to, + ... + QueryPresets.NEW_PRESET: prop_new_preset_filter_func # <- 2) add the enum-to-function mapping + } +... ``` ## **3. Edit the query class mappings for each Query class you wish to use the preset in** @@ -76,24 +83,22 @@ class ServerMapping(MappingInterface): ... @staticmethod - def get_client_side_handlers() -> ServerSideHandler: + def get_client_side_handler() -> ClientSideHandler: ... - return QueryClientSideHandlers( - # set generic query preset mappings - generic_handler=ClientSideHandlerGeneric( - { - # Line below maps EQUAL_TO preset on all available properties - # ["*"] - represents all props - QueryPresetsGeneric.EQUAL_TO: ["*"], - ... - # Line below maps our 'new preset' to two properties which the preset can run on - # Running the preset on any other property leads to an error - QueryPresetsGeneric.NEW_PRESET: [ - ServerProperties.SERVER_ID, - ServerProperties.SERVER_NAME - ] - } - ), + return ClientSideHandler( + + { + # Line below maps EQUAL_TO preset on all available properties + # ["*"] - represents all props + QueryPresets.EQUAL_TO: ["*"], + # ... + # Line below maps our 'new preset' to two properties which the preset can run on + # Running the preset on any other property leads to an error + QueryPresets.NEW_PRESET: [ + ServerProperties.SERVER_ID, + ServerProperties.SERVER_NAME + ] + } ) ... ``` @@ -110,40 +115,20 @@ e.g. Adding server-side mapping for `QueryPresetsGeneric.NEW_PRESET` to `ServerQ ```python class ServerMapping(MappingInterface): - ... + #... @staticmethod def get_server_side_handler() -> ServerSideHandler: - ... + #... return ServerSideHandler( { - QueryPresetsGeneric.NEW_PRESET: { + #... + QueryPresets.NEW_PRESET: { # adding a server-side mapping for NEW_PRESET when given SERVER_ID ServerProperties.SERVER_ID: lambda value, arg1, arg2: {"server-side-kwarg": value, "server-side-arg1": arg1, "server-side-arg2": arg2} } } - ... + ) + #... ``` - -# **Adding a new preset group** - -As stated above - presets are grouped based on the datatype of the property the act on. If you need another preset -group - you can add one like so: - -1. Create a new preset group class in `openstackquery/enums/query_presets.py` - - it inherits from base class QueryPresets - - -2. Create new client side handler in `openstackquery/handlers/client_side_handler_.py` - - it inherits from base class `ClientSideHandler` - `openstackquery/handlers/client_side_handler.py`. - - -3. Add your preset as a attribute in query_client_side_handlers dataclass - - located in `openstackquery/structs/query_client_side_handlers.py` - - -4. Follow steps mentioned above to add new presets to the new preset group class you've created - -5. Edit `QueryPresets` type declaration at the bottom of the file `openstackquery/enums/query_presets.py` and add your new -preset class to it diff --git a/docs/developer_docs/ADDING_NEW_QUERIES.md b/docs/developer_docs/ADDING_NEW_QUERIES.md index eb48a9c..e1ee47f 100644 --- a/docs/developer_docs/ADDING_NEW_QUERIES.md +++ b/docs/developer_docs/ADDING_NEW_QUERIES.md @@ -16,7 +16,7 @@ class ResourceProperties(PropEnum): # add enums for each property you found here like so PROP_1 = auto() # replace `PROP_1` with property name - ... + # ... @staticmethod def get_prop_mapping(prop): @@ -62,18 +62,20 @@ class ResourceRunner(RunnerWrapper): def _parse_meta_params( self, - conn: OpenstackConnection + conn: OpenstackConnection, # define meta params that could be passed # they should all be optional, if no meta-params are passed, the query should still work with default values meta_param_1 = None, meta_param_2 = None, - ... + # ... ): + pass # Define logic here that will alter the keyword arguments that will be passed to the openstacksdk command # based on the meta-parameter values passed in. This method should return a dictionary which will be merged with # server-side filters and be used when calling the specific openstacksdk query which gets the resources being queried for - ... + + # ... def _run_query( self, @@ -153,55 +155,46 @@ we can add mapping like so: ... return { # Here we map the prop_1 enum stored in ResourceProperties to the user_id enum stored in UserProperties + # Values must be a list - because a query property may map to multiple other query properties # These two properties MUST store the same info - ResourceProperties.PROP_1: UserProperties.USER_ID, + ResourceProperties.PROP_1: [UserProperties.USER_ID], } ... ``` -### 3d. Set the client_side_handlers +### 3d. Set the client_side_handler We must define which preset-property pair can be used together when calling `where()` on this Query class. -The `get_client_side_handlers` class is where we define these mappings. -This class creates a Dataclass called `QueryClientSideHandlers` from the mappings we define. +The `get_client_side_handler` class is where we define these mappings. +This class creates an object of `ClientSideHandler` from which mappings can be stored. Here you must: 1. Evaluate which presets you want to the query to accept and which properties they should work on -2. You must add the presets like so: +2. Add the presets like so: ```python - - def get_client_side_handlers() -> ServerSideHandler: + # This is required - at least one preset mapping must be defined here + def get_client_side_handlers() -> ClientSideHandler: ... - return QueryClientSideHandlers( - # generic_handler = set preset-property mappings that belong to generic presets - # This is required - at least one preset mapping must be defined here - generic_handler=ClientSideHandlerGeneric( - { - # Line below maps EQUAL_TO preset on all available properties - # ["*"] - represents all props - QueryPresetsGeneric.EQUAL_TO: ["*"], - ... - } - ), - # do the same for each of these (all optional) - string_handler=ClientSideHandlerString( - { - # Line Below maps MATCHES_REGEX preset on PROP_1 only - # All other properties are invalid - QueryPresetsString.MATCHES_REGEX: [ResourceProperties.PROP_1] - } - ), - # we don't want any datetime presets to be valid - so set it to None - datetime_handler=None, - - # we don't want any integer presets to be valid - so set it to None - integer_handler=None + return ClientSideHandler( + { + # Line below maps EQUAL_TO preset on all available properties + # ["*"] - represents all props + QueryPresets.EQUAL_TO: ["*"], + #... + + # Line Below maps MATCHES_REGEX preset on PROP_1 only + # All other properties are invalid + QueryPresets.MATCHES_REGEX: [ResourceProperties.PROP_1] + + #... + # keep going until all presets you want to allow are mapped + } ) - ... + # ... ``` -## 3e (Optional) Map client-side filters +## 3e (Optional) Map server-side filters To add a server-side filter you must: 1. Read the Openstack API documentation for each Query the preset works on @@ -234,7 +227,7 @@ will call `QueryFactory` with the `ResourceMapping` class we just created. e.g. Add this function to `openstackquery/api/query_objects.py` (as usual, replace `Resource` with the name of the openstack resource your querying) ```python -def ResourceQuery() -> QueryAPI: +def ResourceQuery() -> "QueryAPI": """ Simple helper function to setup a query using a factory """ diff --git a/docs/user_docs/PRESETS.md b/docs/user_docs/PRESETS.md index 261793e..9a5f16f 100644 --- a/docs/user_docs/PRESETS.md +++ b/docs/user_docs/PRESETS.md @@ -15,47 +15,26 @@ q2 = q1.where(preset="ANY_IN", prop="status", values=["ERROR", "SHUTOFF"]) # Reference -## QueryPresetsGeneric -QueryPresetsGeneric has the following presets: - -| Aliases | Description | Extra Parameters | -|----------------------------------|--------------------------------------------------------------------------------------|---------------------------------------------------------------| -| `any_in`, `in` | Finds objects which have a property matching any of a given set of values | `values: List` - a list of property values to compare against | -| `not_any_in`, `not_in` | Finds objects which have a property that does not match any of a given set of values | `values: List` - a list of property values to compare against | -| `equal_to`, `equal`, `==` | Finds objects which have a property matching a given value | `value` - a single value to compare against | -| `not_equal_to` `not_equal`, `!=` | Finds objects which have a property that does not match a given value | `value` - a single value to compare against | - - -## QueryPresetsString -QueryPresetsString has the following presets: - -| Aliases | Description | Extra Parameters | -|-----------------------------------------|------------------------------------------------------------------|---------------------------------------------------------------------| -| `matches_regex`, `regex`, `match_regex` | Finds objects which have a property that matches a regex pattern | `value: str` - a string which can be converted into a regex pattern | - - -## QueryPresetsInteger -QueryPresetsInteger has the following presets: - -| Aliases | Description | Extra Parameters | -|----------------------------------|-----------------------------------------------------------------------------------------|-------------------------------------------------------------------------------| -| `greater_than`, `>` | Finds objects which have an integer/float property greater than a threshold | `value: Union[int, float]` - an integer or float threshold to compare against | -| `less_than`, `<` | Finds objects which have an integer/float property less than a threshold | `value: Union[int, float]` - an integer or float threshold to compare against | -| `greater_than_or_equal_to`, `>=` | Finds objects which have an integer/float property greater than or equal to a threshold | `value: Union[int, float]` - an integer or float threshold to compare against | -| `less_than_or_equal_to`, `<=` | Finds objects which have an integer/float property less than or equal to a threshold | `value: Union[int, float]` - an integer or float threshold to compare against | - - -## QueryPresetsDateTime -QueryPresetsDateTime has the following presets: - -| Aliases | Description | Extra Parameters | -|----------------------------------|--------------------------------------------------------------------------------------------------------|------------------| -| `older_than`, `>` | Finds objects which have an datetime property older than a given relative time threshold | see below | -| `younger_than`, `<` | Finds objects which have an datetime property younger than a given relative time threshold | see below | -| `older_than_or_equal_to`, `>=` | Finds objects which have an datetime property older than or equal to a given relative time threshold | see below | -| `younger_than_or_equal_to`, `<=` | Finds objects which have an datetime property younger than or equal to a given relative time threshold | see below | +Query Library supports the following presets: + +| Aliases (case insensitive) | Description | Extra Parameters | +|----------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------| +| `any_in`, `in` | Finds objects which have a property matching any of a given set of values | `values: List` - a list of property values to compare against | +| `not_any_in`, `not_in` | Finds objects which have a property that does not match any of a given set of values | `values: List` - a list of property values to compare against | +| `equal_to`, `equal`, `==` | Finds objects which have a property matching a given value | `value` - a single value to compare against | +| `not_equal_to` `not_equal`, `!=` | Finds objects which have a property that does not match a given value | `value` - a single value to compare against | +| `matches_regex`, `regex`, `match_regex`, `re` | Finds objects which have a property that matches a regex pattern | `value: str` - a string which can be converted into a regex pattern | +| `greater_than`, `>` | Finds objects which have an integer/float property greater than a threshold | `value: Union[int, float]` - an integer or float threshold to compare against | +| `less_than`, `<` | Finds objects which have an integer/float property less than a threshold | `value: Union[int, float]` - an integer or float threshold to compare against | +| `greater_than_or_equal_to`, `greater_or_equal`
`more_than_or_equal_to`, `more_or_equal`, `>=` | Finds objects which have an integer/float property greater than or equal to a threshold | `value: Union[int, float]` - an integer or float threshold to compare against | +| `less_than_or_equal_to`, `less_or_equal`, `<=` | Finds objects which have an integer/float property less than or equal to a threshold | `value: Union[int, float]` - an integer or float threshold to compare against | +| `older_than`, `older`, `>` | Finds objects which have an datetime property older than a given relative time threshold | * (see below) | +| `younger_than`, `younger`, `newer_than`, `newer`, `<` | Finds objects which have an datetime property younger than a given relative time threshold | * (see below) | +| `older_than_or_equal_to`, `older_or_equal`, `>=` | Finds objects which have an datetime property older than or equal to a given relative time threshold | * (see below) | +| `younger_than_or_equal_to`, `<=` | Finds objects which have an datetime property younger than or equal to a given relative time threshold | * (see below) | ### Extra Parameters +"*" -> Datetime Parameters - `days: int` - (Optional) relative number of days since current time to compare against - `hours: int` - (Optional) relative number of hours since current time to compare against - `minutes: int` - (Optional) relative number of minutes since current time to compare against From 30fd90e92fb8e54c83594211d7f2aa4cc961fd7e Mon Sep 17 00:00:00 2001 From: anish-mudaraddi Date: Fri, 28 Feb 2025 13:14:13 +0000 Subject: [PATCH 3/4] bump minor version to `1.1.0` --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 1d523f4..46b5367 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ setup( name="openstackquery", - version="1.0.0", + version="1.1.0", author="STFC Cloud Team", author_email="", description=DESCRIPTION, From 28dc9d32e30d54b0d8952e41f5573f0454f25d00 Mon Sep 17 00:00:00 2001 From: anish-mudaraddi Date: Fri, 28 Feb 2025 14:24:14 +0000 Subject: [PATCH 4/4] linting fixes --- openstackquery/enums/query_presets.py | 2 -- openstackquery/query_blocks/query_builder.py | 2 +- tests/handlers/test_client_side_handler.py | 3 +++ 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/openstackquery/enums/query_presets.py b/openstackquery/enums/query_presets.py index 1a02500..be4a1fd 100644 --- a/openstackquery/enums/query_presets.py +++ b/openstackquery/enums/query_presets.py @@ -1,7 +1,5 @@ -from typing import Union from enum import auto from openstackquery.enums.enum_with_aliases import EnumWithAliases -from openstackquery.exceptions.parse_query_error import ParseQueryError # pylint: disable=too-few-public-methods diff --git a/openstackquery/query_blocks/query_builder.py b/openstackquery/query_blocks/query_builder.py index ba8fb2e..066c9b6 100644 --- a/openstackquery/query_blocks/query_builder.py +++ b/openstackquery/query_blocks/query_builder.py @@ -1,4 +1,4 @@ -from typing import Optional, Dict, Any, List, Type, Union +from typing import Optional, Dict, Any, Type, Union import logging from openstackquery.handlers.client_side_handler import ClientSideHandler diff --git a/tests/handlers/test_client_side_handler.py b/tests/handlers/test_client_side_handler.py index a995dd7..5c451dc 100644 --- a/tests/handlers/test_client_side_handler.py +++ b/tests/handlers/test_client_side_handler.py @@ -31,6 +31,9 @@ def instance_fixture(mock_filter_fn): MockQueryPresets.ITEM_3: [MockProperties.PROP_3, MockProperties.PROP_4], } ) + # pylint:disable=protected-access + # we need to mock _filter_functions mappings to test functions that use them + # but the mappings themselves are hardcoded into the class and should not be accessible client_side_handler._filter_functions = {MockQueryPresets.ITEM_1: mock_filter_fn} return client_side_handler