diff --git a/CHANGELOG.md b/CHANGELOG.md index ae7362404..c5291e842 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ and this project adheres to [Calendar Versioning](https://calver.org)html). * Introduced new explicit API calls for SecInfo: `get_nvt()`, `get_nvt_list()`, `get_cpe()`, `get_cpe_list()`, `get_cve()`, `get_cve_list()`, `get_cert_bund_advisory()`, `get_cert_bund_advisory_list()`, `get_dnf_cert_advisory()`, `get_dnf_cert_advisory_list()`, `get_oval_definition()`, `get_oval_definition_list()`. [#456](https://github.com/greenbone/python-gvm/pull/456) ### Changed +* Detached the Tags API calls from the GMP class into a new `TagsMixin`. [#468](https://github.com/greenbone/python-gvm/pull/468) +* Detached the Feeds API calls from the GMP class into a new `FeedsMixin`. [#468](https://github.com/greenbone/python-gvm/pull/468) +* Detached the Aggregates API calls from the GMP class into a new `AggregatesMixin`. [#468](https://github.com/greenbone/python-gvm/pull/468) * Detached the EntityType from the GMP types class into a new `entites` file. [#467](https://github.com/greenbone/python-gvm/pull/467) * Detached the Users API calls from the GMP class into a new `UsersMixin`. [#467](https://github.com/greenbone/python-gvm/pull/467) * Detached the Permissions API calls from the GMP class into a new `PermissionsMixin`. [#467](https://github.com/greenbone/python-gvm/pull/467) diff --git a/gvm/protocols/gmpv208/__init__.py b/gvm/protocols/gmpv208/__init__.py index 7415977dc..31d96c356 100644 --- a/gvm/protocols/gmpv208/__init__.py +++ b/gvm/protocols/gmpv208/__init__.py @@ -28,6 +28,13 @@ from typing import Any, Callable, Optional from gvm.protocols.gmpv208.gmpv208 import GmpV208Mixin +from gvm.protocols.gmpv208.entities.aggregates import ( + AggregatesMixin, + AggregateStatistic, + get_aggregate_statistic_from_string, + SortOrder, + get_sort_order_from_string, +) from gvm.protocols.gmpv208.entities.alerts import ( AlertCondition, AlertEvent, @@ -53,6 +60,11 @@ EntityType, get_entity_type_from_string, ) +from gvm.protocols.gmpv208.entities.feeds import ( + FeedType, + FeedsMixin, + get_feed_type_from_string, +) from gvm.protocols.gmpv208.entities.hosts import ( HostsMixin, ) @@ -93,6 +105,7 @@ SeverityLevel, get_severity_level_from_string, ) +from gvm.protocols.gmpv208.entities.tags import TagsMixin from gvm.protocols.gmpv208.entities.targets import ( AliveTest, get_alive_test_from_string, @@ -116,9 +129,11 @@ class Gmp( GmpV208Mixin, + AggregatesMixin, AlertsMixin, AuditsMixin, CredentialsMixin, + FeedsMixin, HostsMixin, NotesMixin, OperatingSystemsMixin, @@ -128,6 +143,7 @@ class Gmp( PortListMixin, ReportsMixin, ResultsMixin, + TagsMixin, TargetsMixin, TasksMixin, TLSCertificateMixin, diff --git a/gvm/protocols/gmpv208/entities/aggregates.py b/gvm/protocols/gmpv208/entities/aggregates.py new file mode 100644 index 000000000..e55104d41 --- /dev/null +++ b/gvm/protocols/gmpv208/entities/aggregates.py @@ -0,0 +1,259 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2021 Greenbone Networks GmbH +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# pylint: disable=redefined-builtin +# MAYBE we should change filter to filter_string (everywhere) + +from enum import Enum +from typing import Any, Optional + +from gvm.protocols.gmpv208.entities.entities import ( + EntityType, +) # if I use latest, I get circular import :/ +from gvm.errors import RequiredArgument, InvalidArgument, InvalidArgumentType +from gvm.utils import add_filter +from gvm.xml import XmlCommand + + +class AggregateStatistic(Enum): + """Enum for aggregate statistic types""" + + COUNT = "count" # Number of items + C_COUNT = "c_count" # Cumulative number of items + C_SUM = "c_sum" # Cumulative sum of values + MAX = "max" # Maximum value + MEAN = "mean" # Arithmetic mean of values + MIN = "min" # Minimum value + SUM = "sum" # Sum of values + TEXT = "text" # Text column value + VALUE = "value" # Group or subgroup column value + + +def get_aggregate_statistic_from_string( + aggregate_statistic: Optional[str], +) -> Optional[AggregateStatistic]: + """ + Convert a aggregate statistic string to an actual AggregateStatistic + instance. + + Arguments: + aggregate_statistic: Aggregate statistic string to convert to a + AggregateStatistic + """ + if not aggregate_statistic: + return None + + try: + return AggregateStatistic[aggregate_statistic.upper()] + except KeyError: + raise InvalidArgument( + argument='aggregate_statistic', + function=get_aggregate_statistic_from_string.__name__, + ) from None + + +class SortOrder(Enum): + """Enum for sort order""" + + ASCENDING = "ascending" + DESCENDING = "descending" + + +def get_sort_order_from_string( + sort_order: Optional[str], +) -> Optional[SortOrder]: + """ + Convert a sort order string to an actual SortOrder instance. + + Arguments: + sort_order: Sort order string to convert to a SortOrder + """ + if not sort_order: + return None + + try: + return SortOrder[sort_order.upper()] + except KeyError: + raise InvalidArgument( + argument='sort_order', function=get_sort_order_from_string.__name__ + ) from None + + +class AggregatesMixin: + def get_aggregates( + self, + resource_type: EntityType, + *, + filter: Optional[str] = None, + filter_id: Optional[str] = None, + sort_criteria: Optional[list] = None, + data_columns: Optional[list] = None, + group_column: Optional[str] = None, + subgroup_column: Optional[str] = None, + text_columns: Optional[list] = None, + first_group: Optional[int] = None, + max_groups: Optional[int] = None, + mode: Optional[int] = None, + **kwargs, + ) -> Any: + """Request aggregated information on a resource / entity type + + Additional arguments can be set via the kwargs parameter for backward + compatibility with older versions of python-gvm, but are not validated. + + Arguments: + resource_type: The entity type to gather data from + filter: Filter term to use for the query + filter_id: UUID of an existing filter to use for the query + sort_criteria: List of sort criteria (dicts that can contain + a field, stat and order) + data_columns: List of fields to aggregate data from + group_column: The field to group the entities by + subgroup_column: The field to further group the entities + inside groups by + text_columns: List of simple text columns which no statistics + are calculated for + first_group: The index of the first aggregate group to return + max_groups: The maximum number of aggregate groups to return, + -1 for all + mode: Special mode for aggregation + + Returns: + The response. See :py:meth:`send_command` for details. + """ + if not resource_type: + raise RequiredArgument( + function=self.get_aggregates.__name__, argument='resource_type' + ) + + if not isinstance(resource_type, EntityType): + raise InvalidArgumentType( + function=self.get_aggregates.__name__, + argument='resource_type', + arg_type=EntityType.__name__, + ) + + cmd = XmlCommand('get_aggregates') + + _actual_resource_type = resource_type + if resource_type.value == EntityType.AUDIT.value: + _actual_resource_type = EntityType.TASK + cmd.set_attribute('usage_type', 'audit') + elif resource_type.value == EntityType.POLICY.value: + _actual_resource_type = EntityType.SCAN_CONFIG + cmd.set_attribute('usage_type', 'policy') + elif resource_type.value == EntityType.SCAN_CONFIG.value: + cmd.set_attribute('usage_type', 'scan') + elif resource_type.value == EntityType.TASK.value: + cmd.set_attribute('usage_type', 'scan') + cmd.set_attribute('type', _actual_resource_type.value) + + add_filter(cmd, filter, filter_id) + + if first_group is not None: + if not isinstance(first_group, int): + raise InvalidArgumentType( + function=self.get_aggregates.__name__, + argument='first_group', + arg_type=int.__name__, + ) + cmd.set_attribute('first_group', str(first_group)) + + if max_groups is not None: + if not isinstance(max_groups, int): + raise InvalidArgumentType( + function=self.get_aggregates.__name__, + argument='max_groups', + arg_type=int.__name__, + ) + cmd.set_attribute('max_groups', str(max_groups)) + + if sort_criteria is not None: + if not isinstance(sort_criteria, list): + raise InvalidArgumentType( + function=self.get_aggregates.__name__, + argument='sort_criteria', + arg_type=list.__name__, + ) + for sort in sort_criteria: + if not isinstance(sort, dict): + raise InvalidArgumentType( + function=self.get_aggregates.__name__, + argument='sort_criteria', + ) + + sort_elem = cmd.add_element('sort') + if sort.get('field'): + sort_elem.set_attribute('field', sort.get('field')) + + if sort.get('stat'): + if isinstance(sort['stat'], AggregateStatistic): + sort_elem.set_attribute('stat', sort['stat'].value) + else: + stat = get_aggregate_statistic_from_string(sort['stat']) + sort_elem.set_attribute('stat', stat.value) + + if sort.get('order'): + if isinstance(sort['order'], SortOrder): + sort_elem.set_attribute('order', sort['order'].value) + else: + so = get_sort_order_from_string(sort['order']) + sort_elem.set_attribute('order', so.value) + + if data_columns is not None: + if not isinstance(data_columns, list): + raise InvalidArgumentType( + function=self.get_aggregates.__name__, + argument='data_columns', + arg_type=list.__name__, + ) + for column in data_columns: + cmd.add_element('data_column', column) + + if group_column is not None: + cmd.set_attribute('group_column', group_column) + + if subgroup_column is not None: + if not group_column: + raise RequiredArgument( + '{} requires a group_column argument' + ' if subgroup_column is given'.format( + self.get_aggregates.__name__ + ), + function=self.get_aggregates.__name__, + argument='subgroup_column', + ) + cmd.set_attribute('subgroup_column', subgroup_column) + + if text_columns is not None: + if not isinstance(text_columns, list): + raise InvalidArgumentType( + function=self.get_aggregates.__name__, + argument='text_columns', + arg_type=list.__name__, + ) + for column in text_columns: + cmd.add_element('text_column', column) + + if mode is not None: + cmd.set_attribute('mode', mode) + + # Add additional keyword args as attributes for backward compatibility. + cmd.set_attributes(kwargs) + + return self._send_xml_command(cmd) diff --git a/gvm/protocols/gmpv208/entities/feeds.py b/gvm/protocols/gmpv208/entities/feeds.py new file mode 100644 index 000000000..390afdc07 --- /dev/null +++ b/gvm/protocols/gmpv208/entities/feeds.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2021 Greenbone Networks GmbH +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# pylint: disable=redefined-builtin +# MAYBE we should change filter to filter_string (everywhere) + +from enum import Enum +from typing import Any, Optional + +from gvm.errors import InvalidArgument, InvalidArgumentType, RequiredArgument +from gvm.xml import XmlCommand + + +class FeedType(Enum): + """Enum for feed types""" + + NVT = "NVT" + CERT = "CERT" + SCAP = "SCAP" + GVMD_DATA = "GVMD_DATA" + + +def get_feed_type_from_string(feed_type: Optional[str]) -> Optional[FeedType]: + """Convert a feed type string into a FeedType instance""" + if not feed_type: + return None + + try: + return FeedType[feed_type.upper()] + except KeyError: + raise InvalidArgument( + argument='feed_type', function=get_feed_type_from_string.__name__ + ) from None + + +class FeedsMixin: + def get_feeds(self) -> Any: + """Request the list of feeds + + Returns: + The response. See :py:meth:`send_command` for details. + """ + return self._send_xml_command(XmlCommand("get_feeds")) + + def get_feed(self, feed_type: Optional[FeedType]) -> Any: + """Request a single feed + + Arguments: + feed_type: Type of single feed to get: NVT, CERT or SCAP + + Returns: + The response. See :py:meth:`send_command` for details. + """ + if not feed_type: + raise RequiredArgument( + function=self.get_feed.__name__, argument='feed_type' + ) + + if not isinstance(feed_type, FeedType): + raise InvalidArgumentType( + function=self.get_feed.__name__, + argument='feed_type', + arg_type=FeedType.__name__, + ) + + cmd = XmlCommand("get_feeds") + cmd.set_attribute("type", feed_type.value) + + return self._send_xml_command(cmd) + + def sync_feed(self) -> Any: + """Request a synchronization with the NVT feed service + + Returns: + The response. See :py:meth:`send_command` for details. + """ + return self._send_xml_command(XmlCommand("sync_feed")) diff --git a/gvm/protocols/gmpv208/entities/tags.py b/gvm/protocols/gmpv208/entities/tags.py new file mode 100644 index 000000000..a6d0f8e32 --- /dev/null +++ b/gvm/protocols/gmpv208/entities/tags.py @@ -0,0 +1,288 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2021 Greenbone Networks GmbH +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# pylint: disable=redefined-builtin + +from typing import Any, List, Optional + +from gvm.errors import RequiredArgument, InvalidArgument, InvalidArgumentType +from gvm.protocols.gmpv208.entities.entities import EntityType +from gvm.utils import add_filter, to_bool +from gvm.xml import XmlCommand + + +class TagsMixin: + def clone_tag(self, tag_id: str) -> Any: + """Clone an existing tag + + Arguments: + tag_id: UUID of an existing tag to clone from + + Returns: + The response. See :py:meth:`send_command` for details. + """ + if not tag_id: + raise RequiredArgument( + function=self.clone_tag.__name__, argument='tag_id' + ) + + cmd = XmlCommand("create_tag") + cmd.add_element("copy", tag_id) + return self._send_xml_command(cmd) + + def create_tag( + self, + name: str, + resource_type: EntityType, + *, + resource_filter: Optional[str] = None, + resource_ids: Optional[List[str]] = None, + value: Optional[str] = None, + comment: Optional[str] = None, + active: Optional[bool] = None, + ) -> Any: + """Create a tag. + + Arguments: + name: Name of the tag. A full tag name consisting of namespace and + predicate e.g. `foo:bar`. + resource_type: Entity type the tag is to be attached to. + resource_filter: Filter term to select resources the tag is to be + attached to. Only one of resource_filter or resource_ids can be + provided. + resource_ids: IDs of the resources the tag is to be attached to. + Only one of resource_filter or resource_ids can be provided. + value: Value associated with the tag. + comment: Comment for the tag. + active: Whether the tag should be active. + + Returns: + The response. See :py:meth:`send_command` for details. + """ + if not name: + raise RequiredArgument( + function=self.create_tag.__name__, argument='name' + ) + + if resource_filter and resource_ids: + raise InvalidArgument( + "create_tag accepts either resource_filter or resource_ids " + "argument", + function=self.create_tag.__name__, + ) + + if not resource_type: + raise RequiredArgument( + function=self.create_tag.__name__, argument='resource_type' + ) + + if not isinstance(resource_type, EntityType): + raise InvalidArgumentType( + function=self.create_tag.__name__, + argument='resource_type', + arg_type=EntityType.__name__, + ) + + cmd = XmlCommand('create_tag') + cmd.add_element('name', name) + + _xmlresources = cmd.add_element("resources") + if resource_filter is not None: + _xmlresources.set_attribute("filter", resource_filter) + + for resource_id in resource_ids or []: + _xmlresources.add_element( + "resource", attrs={"id": str(resource_id)} + ) + + _actual_resource_type = resource_type + if resource_type.value == EntityType.AUDIT.value: + _actual_resource_type = EntityType.TASK + elif resource_type.value == EntityType.POLICY.value: + _actual_resource_type = EntityType.SCAN_CONFIG + _xmlresources.add_element("type", _actual_resource_type.value) + + if comment: + cmd.add_element("comment", comment) + + if value: + cmd.add_element("value", value) + + if active is not None: + if active: + cmd.add_element("active", "1") + else: + cmd.add_element("active", "0") + + return self._send_xml_command(cmd) + + def delete_tag( + self, tag_id: str, *, ultimate: Optional[bool] = False + ) -> Any: + """Deletes an existing tag + + Arguments: + tag_id: UUID of the tag to be deleted. + ultimate: Whether to remove entirely, or to the trashcan. + """ + if not tag_id: + raise RequiredArgument( + function=self.delete_tag.__name__, argument='tag_id' + ) + + cmd = XmlCommand("delete_tag") + cmd.set_attribute("tag_id", tag_id) + cmd.set_attribute("ultimate", to_bool(ultimate)) + + return self._send_xml_command(cmd) + + def get_tags( + self, + *, + filter: Optional[str] = None, + filter_id: Optional[str] = None, + trash: Optional[bool] = None, + names_only: Optional[bool] = None, + ) -> Any: + """Request a list of tags + + Arguments: + filter: Filter term to use for the query + filter_id: UUID of an existing filter to use for the query + trash: Whether to get tags from the trashcan instead + names_only: Whether to get only distinct tag names + + Returns: + The response. See :py:meth:`send_command` for details. + """ + cmd = XmlCommand("get_tags") + + add_filter(cmd, filter, filter_id) + + if trash is not None: + cmd.set_attribute("trash", to_bool(trash)) + + if names_only is not None: + cmd.set_attribute("names_only", to_bool(names_only)) + + return self._send_xml_command(cmd) + + def get_tag(self, tag_id: str) -> Any: + """Request a single tag + + Arguments: + tag_id: UUID of an existing tag + + Returns: + The response. See :py:meth:`send_command` for details. + """ + cmd = XmlCommand("get_tags") + + if not tag_id: + raise RequiredArgument( + function=self.get_tag.__name__, argument='tag_id' + ) + + cmd.set_attribute("tag_id", tag_id) + return self._send_xml_command(cmd) + + def modify_tag( + self, + tag_id: str, + *, + comment: Optional[str] = None, + name: Optional[str] = None, + value=None, + active=None, + resource_action: Optional[str] = None, + resource_type: Optional[EntityType] = None, + resource_filter: Optional[str] = None, + resource_ids: Optional[List[str]] = None, + ) -> Any: + """Modifies an existing tag. + + Arguments: + tag_id: UUID of the tag. + comment: Comment to add to the tag. + name: Name of the tag. + value: Value of the tag. + active: Whether the tag is active. + resource_action: Whether to add or remove resources instead of + overwriting. One of '', 'add', 'set' or 'remove'. + resource_type: Type of the resources to which to attach the tag. + Required if resource_filter is set. + resource_filter: Filter term to select resources the tag is to be + attached to. + resource_ids: IDs of the resources to which to attach the tag. + + Returns: + The response. See :py:meth:`send_command` for details. + """ + if not tag_id: + raise RequiredArgument( + function=self.modify_tag.__name__, argument='tag_id' + ) + + cmd = XmlCommand("modify_tag") + cmd.set_attribute("tag_id", str(tag_id)) + + if comment: + cmd.add_element("comment", comment) + + if name: + cmd.add_element("name", name) + + if value: + cmd.add_element("value", value) + + if active is not None: + cmd.add_element("active", to_bool(active)) + + if resource_action or resource_filter or resource_ids or resource_type: + if resource_filter and not resource_type: + raise RequiredArgument( + function=self.modify_tag.__name__, argument='resource_type' + ) + + _xmlresources = cmd.add_element("resources") + if resource_action is not None: + _xmlresources.set_attribute("action", resource_action) + + if resource_filter is not None: + _xmlresources.set_attribute("filter", resource_filter) + + for resource_id in resource_ids or []: + _xmlresources.add_element( + "resource", attrs={"id": str(resource_id)} + ) + + if resource_type is not None: + if not isinstance(resource_type, EntityType): + raise InvalidArgumentType( + function=self.modify_tag.__name__, + argument="resource_type", + arg_type=EntityType.__name__, + ) + _actual_resource_type = resource_type + if resource_type.value == EntityType.AUDIT.value: + _actual_resource_type = EntityType.TASK + elif resource_type.value == EntityType.POLICY.value: + _actual_resource_type = EntityType.SCAN_CONFIG + _xmlresources.add_element("type", _actual_resource_type.value) + + return self._send_xml_command(cmd) diff --git a/gvm/protocols/gmpv208/gmpv208.py b/gvm/protocols/gmpv208/gmpv208.py index 1562a67ae..cec7a5c61 100644 --- a/gvm/protocols/gmpv208/gmpv208.py +++ b/gvm/protocols/gmpv208/gmpv208.py @@ -37,7 +37,6 @@ from gvm.protocols.gmpv208.entities.report_formats import ( ReportFormatType, ) -from gvm.protocols.gmpv208.entities.entities import EntityType from gvm.utils import ( check_command_status, @@ -141,341 +140,6 @@ def authenticate(self, username: str, password: str) -> Any: return self._transform(response) - def create_tag( - self, - name: str, - resource_type: EntityType, - *, - resource_filter: Optional[str] = None, - resource_ids: Optional[List[str]] = None, - value: Optional[str] = None, - comment: Optional[str] = None, - active: Optional[bool] = None, - ) -> Any: - """Create a tag. - - Arguments: - name: Name of the tag. A full tag name consisting of namespace and - predicate e.g. `foo:bar`. - resource_type: Entity type the tag is to be attached to. - resource_filter: Filter term to select resources the tag is to be - attached to. Only one of resource_filter or resource_ids can be - provided. - resource_ids: IDs of the resources the tag is to be attached to. - Only one of resource_filter or resource_ids can be provided. - value: Value associated with the tag. - comment: Comment for the tag. - active: Whether the tag should be active. - - Returns: - The response. See :py:meth:`send_command` for details. - """ - if not name: - raise RequiredArgument( - function=self.create_tag.__name__, argument='name' - ) - - if resource_filter and resource_ids: - raise InvalidArgument( - "create_tag accepts either resource_filter or resource_ids " - "argument", - function=self.create_tag.__name__, - ) - - if not resource_type: - raise RequiredArgument( - function=self.create_tag.__name__, argument='resource_type' - ) - - if not isinstance(resource_type, EntityType): - raise InvalidArgumentType( - function=self.create_tag.__name__, - argument='resource_type', - arg_type=EntityType.__name__, - ) - - cmd = XmlCommand('create_tag') - cmd.add_element('name', name) - - _xmlresources = cmd.add_element("resources") - if resource_filter is not None: - _xmlresources.set_attribute("filter", resource_filter) - - for resource_id in resource_ids or []: - _xmlresources.add_element( - "resource", attrs={"id": str(resource_id)} - ) - - _actual_resource_type = resource_type - if resource_type.value == EntityType.AUDIT.value: - _actual_resource_type = EntityType.TASK - elif resource_type.value == EntityType.POLICY.value: - _actual_resource_type = EntityType.SCAN_CONFIG - _xmlresources.add_element("type", _actual_resource_type.value) - - if comment: - cmd.add_element("comment", comment) - - if value: - cmd.add_element("value", value) - - if active is not None: - if active: - cmd.add_element("active", "1") - else: - cmd.add_element("active", "0") - - return self._send_xml_command(cmd) - - def get_aggregates( - self, - resource_type: EntityType, - *, - filter: Optional[str] = None, - filter_id: Optional[str] = None, - sort_criteria: Optional[list] = None, - data_columns: Optional[list] = None, - group_column: Optional[str] = None, - subgroup_column: Optional[str] = None, - text_columns: Optional[list] = None, - first_group: Optional[int] = None, - max_groups: Optional[int] = None, - mode: Optional[int] = None, - **kwargs, - ) -> Any: - """Request aggregated information on a resource / entity type - - Additional arguments can be set via the kwargs parameter for backward - compatibility with older versions of python-gvm, but are not validated. - - Arguments: - resource_type: The entity type to gather data from - filter: Filter term to use for the query - filter_id: UUID of an existing filter to use for the query - sort_criteria: List of sort criteria (dicts that can contain - a field, stat and order) - data_columns: List of fields to aggregate data from - group_column: The field to group the entities by - subgroup_column: The field to further group the entities - inside groups by - text_columns: List of simple text columns which no statistics - are calculated for - first_group: The index of the first aggregate group to return - max_groups: The maximum number of aggregate groups to return, - -1 for all - mode: Special mode for aggregation - - Returns: - The response. See :py:meth:`send_command` for details. - """ - if not resource_type: - raise RequiredArgument( - function=self.get_aggregates.__name__, argument='resource_type' - ) - - if not isinstance(resource_type, EntityType): - raise InvalidArgumentType( - function=self.get_aggregates.__name__, - argument='resource_type', - arg_type=EntityType.__name__, - ) - - cmd = XmlCommand('get_aggregates') - - _actual_resource_type = resource_type - if resource_type.value == EntityType.AUDIT.value: - _actual_resource_type = EntityType.TASK - cmd.set_attribute('usage_type', 'audit') - elif resource_type.value == EntityType.POLICY.value: - _actual_resource_type = EntityType.SCAN_CONFIG - cmd.set_attribute('usage_type', 'policy') - elif resource_type.value == EntityType.SCAN_CONFIG.value: - cmd.set_attribute('usage_type', 'scan') - elif resource_type.value == EntityType.TASK.value: - cmd.set_attribute('usage_type', 'scan') - cmd.set_attribute('type', _actual_resource_type.value) - - add_filter(cmd, filter, filter_id) - - if first_group is not None: - if not isinstance(first_group, int): - raise InvalidArgumentType( - function=self.get_aggregates.__name__, - argument='first_group', - arg_type=int.__name__, - ) - cmd.set_attribute('first_group', str(first_group)) - - if max_groups is not None: - if not isinstance(max_groups, int): - raise InvalidArgumentType( - function=self.get_aggregates.__name__, - argument='max_groups', - arg_type=int.__name__, - ) - cmd.set_attribute('max_groups', str(max_groups)) - - if sort_criteria is not None: - if not isinstance(sort_criteria, list): - raise InvalidArgumentType( - function=self.get_aggregates.__name__, - argument='sort_criteria', - arg_type=list.__name__, - ) - for sort in sort_criteria: - if not isinstance(sort, dict): - raise InvalidArgumentType( - function=self.get_aggregates.__name__, - argument='sort_criteria', - ) - - sort_elem = cmd.add_element('sort') - if sort.get('field'): - sort_elem.set_attribute('field', sort.get('field')) - - if sort.get('stat'): - if isinstance(sort['stat'], AggregateStatistic): - sort_elem.set_attribute('stat', sort['stat'].value) - else: - stat = get_aggregate_statistic_from_string(sort['stat']) - sort_elem.set_attribute('stat', stat.value) - - if sort.get('order'): - if isinstance(sort['order'], SortOrder): - sort_elem.set_attribute('order', sort['order'].value) - else: - so = get_sort_order_from_string(sort['order']) - sort_elem.set_attribute('order', so.value) - - if data_columns is not None: - if not isinstance(data_columns, list): - raise InvalidArgumentType( - function=self.get_aggregates.__name__, - argument='data_columns', - arg_type=list.__name__, - ) - for column in data_columns: - cmd.add_element('data_column', column) - - if group_column is not None: - cmd.set_attribute('group_column', group_column) - - if subgroup_column is not None: - if not group_column: - raise RequiredArgument( - '{} requires a group_column argument' - ' if subgroup_column is given'.format( - self.get_aggregates.__name__ - ), - function=self.get_aggregates.__name__, - argument='subgroup_column', - ) - cmd.set_attribute('subgroup_column', subgroup_column) - - if text_columns is not None: - if not isinstance(text_columns, list): - raise InvalidArgumentType( - function=self.get_aggregates.__name__, - argument='text_columns', - arg_type=list.__name__, - ) - for column in text_columns: - cmd.add_element('text_column', column) - - if mode is not None: - cmd.set_attribute('mode', mode) - - # Add additional keyword args as attributes for backward compatibility. - cmd.set_attributes(kwargs) - - return self._send_xml_command(cmd) - - def modify_tag( - self, - tag_id: str, - *, - comment: Optional[str] = None, - name: Optional[str] = None, - value=None, - active=None, - resource_action: Optional[str] = None, - resource_type: Optional[EntityType] = None, - resource_filter: Optional[str] = None, - resource_ids: Optional[List[str]] = None, - ) -> Any: - """Modifies an existing tag. - - Arguments: - tag_id: UUID of the tag. - comment: Comment to add to the tag. - name: Name of the tag. - value: Value of the tag. - active: Whether the tag is active. - resource_action: Whether to add or remove resources instead of - overwriting. One of '', 'add', 'set' or 'remove'. - resource_type: Type of the resources to which to attach the tag. - Required if resource_filter is set. - resource_filter: Filter term to select resources the tag is to be - attached to. - resource_ids: IDs of the resources to which to attach the tag. - - Returns: - The response. See :py:meth:`send_command` for details. - """ - if not tag_id: - raise RequiredArgument( - function=self.modify_tag.__name__, argument='tag_id' - ) - - cmd = XmlCommand("modify_tag") - cmd.set_attribute("tag_id", str(tag_id)) - - if comment: - cmd.add_element("comment", comment) - - if name: - cmd.add_element("name", name) - - if value: - cmd.add_element("value", value) - - if active is not None: - cmd.add_element("active", to_bool(active)) - - if resource_action or resource_filter or resource_ids or resource_type: - if resource_filter and not resource_type: - raise RequiredArgument( - function=self.modify_tag.__name__, argument='resource_type' - ) - - _xmlresources = cmd.add_element("resources") - if resource_action is not None: - _xmlresources.set_attribute("action", resource_action) - - if resource_filter is not None: - _xmlresources.set_attribute("filter", resource_filter) - - for resource_id in resource_ids or []: - _xmlresources.add_element( - "resource", attrs={"id": str(resource_id)} - ) - - if resource_type is not None: - if not isinstance(resource_type, EntityType): - raise InvalidArgumentType( - function=self.modify_tag.__name__, - argument="resource_type", - arg_type=EntityType.__name__, - ) - _actual_resource_type = resource_type - if resource_type.value == EntityType.AUDIT.value: - _actual_resource_type = EntityType.TASK - elif resource_type.value == EntityType.POLICY.value: - _actual_resource_type = EntityType.SCAN_CONFIG - _xmlresources.add_element("type", _actual_resource_type.value) - - return self._send_xml_command(cmd) - def clone_ticket(self, ticket_id: str) -> Any: """Clone an existing ticket @@ -496,32 +160,6 @@ def clone_ticket(self, ticket_id: str) -> Any: return self._send_xml_command(cmd) - def get_feed(self, feed_type: Optional[FeedType]) -> Any: - """Request a single feed - - Arguments: - feed_type: Type of single feed to get: NVT, CERT or SCAP - - Returns: - The response. See :py:meth:`send_command` for details. - """ - if not feed_type: - raise RequiredArgument( - function=self.get_feed.__name__, argument='feed_type' - ) - - if not isinstance(feed_type, FeedType): - raise InvalidArgumentType( - function=self.get_feed.__name__, - argument='feed_type', - arg_type=FeedType.__name__, - ) - - cmd = XmlCommand("get_feeds") - cmd.set_attribute("type", feed_type.value) - - return self._send_xml_command(cmd) - def create_ticket( self, *, @@ -1155,24 +793,6 @@ def clone_schedule(self, schedule_id: str) -> Any: cmd.add_element("copy", schedule_id) return self._send_xml_command(cmd) - def clone_tag(self, tag_id: str) -> Any: - """Clone an existing tag - - Arguments: - tag_id: UUID of an existing tag to clone from - - Returns: - The response. See :py:meth:`send_command` for details. - """ - if not tag_id: - raise RequiredArgument( - function=self.clone_tag.__name__, argument='tag_id' - ) - - cmd = XmlCommand("create_tag") - cmd.add_element("copy", tag_id) - return self._send_xml_command(cmd) - def delete_filter( self, filter_id: str, *, ultimate: Optional[bool] = False ) -> Any: @@ -1283,26 +903,6 @@ def delete_schedule( return self._send_xml_command(cmd) - def delete_tag( - self, tag_id: str, *, ultimate: Optional[bool] = False - ) -> Any: - """Deletes an existing tag - - Arguments: - tag_id: UUID of the tag to be deleted. - ultimate: Whether to remove entirely, or to the trashcan. - """ - if not tag_id: - raise RequiredArgument( - function=self.delete_tag.__name__, argument='tag_id' - ) - - cmd = XmlCommand("delete_tag") - cmd.set_attribute("tag_id", tag_id) - cmd.set_attribute("ultimate", to_bool(ultimate)) - - return self._send_xml_command(cmd) - def describe_auth(self) -> Any: """Describe authentication methods @@ -1325,14 +925,6 @@ def empty_trashcan(self) -> Any: """ return self._send_xml_command(XmlCommand("empty_trashcan")) - def get_feeds(self) -> Any: - """Request the list of feeds - - Returns: - The response. See :py:meth:`send_command` for details. - """ - return self._send_xml_command(XmlCommand("get_feeds")) - def get_filters( self, *, @@ -1751,56 +1343,6 @@ def get_system_reports( return self._send_xml_command(cmd) - def get_tags( - self, - *, - filter: Optional[str] = None, - filter_id: Optional[str] = None, - trash: Optional[bool] = None, - names_only: Optional[bool] = None, - ) -> Any: - """Request a list of tags - - Arguments: - filter: Filter term to use for the query - filter_id: UUID of an existing filter to use for the query - trash: Whether to get tags from the trashcan instead - names_only: Whether to get only distinct tag names - - Returns: - The response. See :py:meth:`send_command` for details. - """ - cmd = XmlCommand("get_tags") - - add_filter(cmd, filter, filter_id) - - if trash is not None: - cmd.set_attribute("trash", to_bool(trash)) - - if names_only is not None: - cmd.set_attribute("names_only", to_bool(names_only)) - - return self._send_xml_command(cmd) - - def get_tag(self, tag_id: str) -> Any: - """Request a single tag - - Arguments: - tag_id: UUID of an existing tag - - Returns: - The response. See :py:meth:`send_command` for details. - """ - cmd = XmlCommand("get_tags") - - if not tag_id: - raise RequiredArgument( - function=self.get_tag.__name__, argument='tag_id' - ) - - cmd.set_attribute("tag_id", tag_id) - return self._send_xml_command(cmd) - def get_version(self) -> Any: """Get the Greenbone Manager Protocol version used by the remote gvmd Returns: @@ -2069,14 +1611,6 @@ def sync_cert(self) -> Any: """ return self._send_xml_command(XmlCommand("sync_cert")) - def sync_feed(self) -> Any: - """Request a synchronization with the NVT feed service - - Returns: - The response. See :py:meth:`send_command` for details. - """ - return self._send_xml_command(XmlCommand("sync_feed")) - def sync_scap(self) -> Any: """Request a synchronization with the SCAP feed service diff --git a/gvm/protocols/gmpv208/types.py b/gvm/protocols/gmpv208/types.py index b656834b6..92749be57 100644 --- a/gvm/protocols/gmpv208/types.py +++ b/gvm/protocols/gmpv208/types.py @@ -25,45 +25,17 @@ from gvm.errors import InvalidArgument __all__ = [ - "AggregateStatistic", - "FeedType", "FilterType", "HostsOrdering", - "SortOrder", "TicketStatus", "TimeUnit", - "get_aggregate_statistic_from_string", - "get_feed_type_from_string", "get_filter_type_from_string", "get_hosts_ordering_from_string", - "get_sort_order_from_string", "get_ticket_status_from_string", "get_time_unit_from_string", ] -class FeedType(Enum): - """Enum for feed types""" - - NVT = "NVT" - CERT = "CERT" - SCAP = "SCAP" - GVMD_DATA = "GVMD_DATA" - - -def get_feed_type_from_string(feed_type: Optional[str]) -> Optional[FeedType]: - """Convert a feed type string into a FeedType instance""" - if not feed_type: - return None - - try: - return FeedType[feed_type.upper()] - except KeyError: - raise InvalidArgument( - argument='feed_type', function=get_feed_type_from_string.__name__ - ) from None - - class FilterType(Enum): """Enum for filter types""" @@ -129,70 +101,6 @@ def get_filter_type_from_string( ) from None -class AggregateStatistic(Enum): - """Enum for aggregate statistic types""" - - COUNT = "count" # Number of items - C_COUNT = "c_count" # Cumulative number of items - C_SUM = "c_sum" # Cumulative sum of values - MAX = "max" # Maximum value - MEAN = "mean" # Arithmetic mean of values - MIN = "min" # Minimum value - SUM = "sum" # Sum of values - TEXT = "text" # Text column value - VALUE = "value" # Group or subgroup column value - - -def get_aggregate_statistic_from_string( - aggregate_statistic: Optional[str], -) -> Optional[AggregateStatistic]: - """ - Convert a aggregate statistic string to an actual AggregateStatistic - instance. - - Arguments: - aggregate_statistic: Aggregate statistic string to convert to a - AggregateStatistic - """ - if not aggregate_statistic: - return None - - try: - return AggregateStatistic[aggregate_statistic.upper()] - except KeyError: - raise InvalidArgument( - argument='aggregate_statistic', - function=get_aggregate_statistic_from_string.__name__, - ) from None - - -class SortOrder(Enum): - """Enum for sort order""" - - ASCENDING = "ascending" - DESCENDING = "descending" - - -def get_sort_order_from_string( - sort_order: Optional[str], -) -> Optional[SortOrder]: - """ - Convert a sort order string to an actual SortOrder instance. - - Arguments: - sort_order: Sort order string to convert to a SortOrder - """ - if not sort_order: - return None - - try: - return SortOrder[sort_order.upper()] - except KeyError: - raise InvalidArgument( - argument='sort_order', function=get_sort_order_from_string.__name__ - ) from None - - class TicketStatus(Enum): """Enum for ticket status""" diff --git a/gvm/protocols/gmpv214/__init__.py b/gvm/protocols/gmpv214/__init__.py index 4f4f9824f..209a4d4a2 100644 --- a/gvm/protocols/gmpv214/__init__.py +++ b/gvm/protocols/gmpv214/__init__.py @@ -28,6 +28,13 @@ from typing import Any, Callable, Optional +from gvm.protocols.gmpv208.entities.aggregates import ( + AggregatesMixin, + AggregateStatistic, + get_aggregate_statistic_from_string, + SortOrder, + get_sort_order_from_string, +) from gvm.protocols.gmpv208.entities.alerts import ( AlertCondition, AlertEvent, @@ -53,6 +60,11 @@ EntityType, get_entity_type_from_string, ) +from gvm.protocols.gmpv208.entities.feeds import ( + FeedType, + FeedsMixin, + get_feed_type_from_string, +) from gvm.protocols.gmpv208.entities.hosts import HostsMixin from gvm.protocols.gmpv208.entities.operating_systems import ( OperatingSystemsMixin, @@ -84,7 +96,7 @@ SeverityLevel, get_severity_level_from_string, ) - +from gvm.protocols.gmpv208.entities.tags import TagsMixin from gvm.protocols.gmpv208.entities.tasks import TasksMixin from gvm.protocols.gmpv208.entities.tls_certificates import TLSCertificateMixin from gvm.protocols.gmpv208.entities.users import ( @@ -120,9 +132,11 @@ class Gmp( GmpV208Mixin, + AggregatesMixin, AlertsMixin, AuditsMixin, CredentialsMixin, + FeedsMixin, HostsMixin, NotesMixin, OperatingSystemsMixin, @@ -132,6 +146,7 @@ class Gmp( PortListMixin, ReportsMixin, ResultsMixin, + TagsMixin, TargetsMixin, TasksMixin, TLSCertificateMixin, diff --git a/gvm/protocols/gmpv214/types.py b/gvm/protocols/gmpv214/types.py index 9b73f5bc4..0b12646f5 100644 --- a/gvm/protocols/gmpv214/types.py +++ b/gvm/protocols/gmpv214/types.py @@ -15,71 +15,26 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from enum import Enum - -from typing import Optional - -from gvm.errors import InvalidArgument from gvm.protocols.gmpv208.types import ( - AggregateStatistic, - FeedType, FilterType, HostsOrdering, - SortOrder, TicketStatus, TimeUnit, - get_aggregate_statistic_from_string, - get_feed_type_from_string, get_filter_type_from_string, get_hosts_ordering_from_string, - get_sort_order_from_string, get_ticket_status_from_string, get_time_unit_from_string, ) __all__ = [ - "AggregateStatistic", - "FeedType", "FilterType", "HostsOrdering", - "SeverityLevel", - "SortOrder", "TicketStatus", "TimeUnit", - "get_aggregate_statistic_from_string", - "get_feed_type_from_string", "get_filter_type_from_string", "get_hosts_ordering_from_string", - "get_severity_level_from_string", - "get_sort_order_from_string", "get_ticket_status_from_string", "get_time_unit_from_string", ] - -# move this: Severity Level !!! -class SeverityLevel(Enum): - """Enum for severity levels""" - - HIGH = "High" - MEDIUM = "Medium" - LOW = "Low" - LOG = "Log" - ALARM = "Alarm" - - -def get_severity_level_from_string( - severity_level: Optional[str], -) -> Optional[SeverityLevel]: - """Convert a severity level string into a SeverityLevel instance""" - if not severity_level: - return None - - try: - return SeverityLevel[severity_level.upper()] - except KeyError: - raise InvalidArgument( - argument='severity_level', - function=get_severity_level_from_string.__name__, - ) from None diff --git a/tests/protocols/gmpv208/entities/aggregates/__init__.py b/tests/protocols/gmpv208/entities/aggregates/__init__.py new file mode 100644 index 000000000..ab8cf0728 --- /dev/null +++ b/tests/protocols/gmpv208/entities/aggregates/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2021 Greenbone Networks GmbH +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from .test_get_aggregates import GmpGetAggregatesTestMixin diff --git a/tests/protocols/gmpv208/testcmds/test_get_aggregates.py b/tests/protocols/gmpv208/entities/aggregates/test_get_aggregates.py similarity index 99% rename from tests/protocols/gmpv208/testcmds/test_get_aggregates.py rename to tests/protocols/gmpv208/entities/aggregates/test_get_aggregates.py index 5432904a6..8deec06f4 100644 --- a/tests/protocols/gmpv208/testcmds/test_get_aggregates.py +++ b/tests/protocols/gmpv208/entities/aggregates/test_get_aggregates.py @@ -21,7 +21,7 @@ from gvm.protocols.gmpv208 import EntityType, AggregateStatistic, SortOrder -class GmpGetAggregatesTestCase: +class GmpGetAggregatesTestMixin: def test_get_aggregates(self): """ Test basic get_aggregates calls with only resource_type except special diff --git a/tests/protocols/gmpv208/entities/feeds/__init__.py b/tests/protocols/gmpv208/entities/feeds/__init__.py new file mode 100644 index 000000000..4f27dca09 --- /dev/null +++ b/tests/protocols/gmpv208/entities/feeds/__init__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2021 Greenbone Networks GmbH +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from .test_get_feed import GmpGetFeedTestMixin +from .test_get_feeds import GmpGetFeedsTestMixin +from .test_sync_feed import GmpSyncFeedTestMixin diff --git a/tests/protocols/gmpv208/testcmds/test_get_feed.py b/tests/protocols/gmpv208/entities/feeds/test_get_feed.py similarity index 98% rename from tests/protocols/gmpv208/testcmds/test_get_feed.py rename to tests/protocols/gmpv208/entities/feeds/test_get_feed.py index 7f1da9fd9..b0b1c0c5e 100644 --- a/tests/protocols/gmpv208/testcmds/test_get_feed.py +++ b/tests/protocols/gmpv208/entities/feeds/test_get_feed.py @@ -21,7 +21,7 @@ from gvm.protocols.gmpv208 import FeedType -class GmpGetFeedTestCase: +class GmpGetFeedTestMixin: def test_get_feed(self): """ Test basic get_feed calls with only resource_type except special diff --git a/tests/protocols/gmpv208/testcmds/test_get_feeds.py b/tests/protocols/gmpv208/entities/feeds/test_get_feeds.py similarity index 96% rename from tests/protocols/gmpv208/testcmds/test_get_feeds.py rename to tests/protocols/gmpv208/entities/feeds/test_get_feeds.py index 83b963138..9f0eaeb47 100644 --- a/tests/protocols/gmpv208/testcmds/test_get_feeds.py +++ b/tests/protocols/gmpv208/entities/feeds/test_get_feeds.py @@ -17,7 +17,7 @@ # along with this program. If not, see . -class GmpGetFeedsTestCase: +class GmpGetFeedsTestMixin: def test_get_feeds(self): self.gmp.get_feeds() diff --git a/tests/protocols/gmpv208/testcmds/test_sync_feed.py b/tests/protocols/gmpv208/entities/feeds/test_sync_feed.py similarity index 96% rename from tests/protocols/gmpv208/testcmds/test_sync_feed.py rename to tests/protocols/gmpv208/entities/feeds/test_sync_feed.py index 525da8205..f002fe71c 100644 --- a/tests/protocols/gmpv208/testcmds/test_sync_feed.py +++ b/tests/protocols/gmpv208/entities/feeds/test_sync_feed.py @@ -17,7 +17,7 @@ # along with this program. If not, see . -class GmpSyncFeedCommandTestCase: +class GmpSyncFeedTestMixin: def test_sync_feed(self): self.gmp.sync_feed() diff --git a/tests/protocols/gmpv208/entities/tags/__init__.py b/tests/protocols/gmpv208/entities/tags/__init__.py new file mode 100644 index 000000000..85d5ffa1c --- /dev/null +++ b/tests/protocols/gmpv208/entities/tags/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2021 Greenbone Networks GmbH +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from .test_clone_tag import GmpCloneTagTestMixin +from .test_create_tag import GmpCreateTagTestMixin +from .test_delete_tag import GmpDeleteTagTestMixin +from .test_get_tag import GmpGetTagTestMixin +from .test_get_tags import GmpGetTagsTestMixin +from .test_modify_tag import GmpModifyTagTestMixin diff --git a/tests/protocols/gmpv208/testcmds/test_clone_tag.py b/tests/protocols/gmpv208/entities/tags/test_clone_tag.py similarity index 97% rename from tests/protocols/gmpv208/testcmds/test_clone_tag.py rename to tests/protocols/gmpv208/entities/tags/test_clone_tag.py index a7536c578..8ef0d1122 100644 --- a/tests/protocols/gmpv208/testcmds/test_clone_tag.py +++ b/tests/protocols/gmpv208/entities/tags/test_clone_tag.py @@ -19,7 +19,7 @@ from gvm.errors import RequiredArgument -class GmpCloneTagTestCase: +class GmpCloneTagTestMixin: def test_clone(self): self.gmp.clone_tag('a1') diff --git a/tests/protocols/gmpv208/testcmds/test_create_tag.py b/tests/protocols/gmpv208/entities/tags/test_create_tag.py similarity index 83% rename from tests/protocols/gmpv208/testcmds/test_create_tag.py rename to tests/protocols/gmpv208/entities/tags/test_create_tag.py index d35ec6dbf..ebff0720f 100644 --- a/tests/protocols/gmpv208/testcmds/test_create_tag.py +++ b/tests/protocols/gmpv208/entities/tags/test_create_tag.py @@ -16,11 +16,11 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from gvm.errors import InvalidArgument, RequiredArgument +from gvm.errors import InvalidArgument, RequiredArgument, InvalidArgumentType from gvm.protocols.gmpv208 import EntityType -class GmpCreateTagTestCase: +class GmpCreateTagTestMixin: def test_create_tag_missing_name(self): with self.assertRaises(RequiredArgument): self.gmp.create_tag( @@ -85,6 +85,15 @@ def test_create_tag_both_resource_filter_and_ids(self): resource_type=EntityType.TASK, ) + def test_create_tag_invalid_resource_type(self): + with self.assertRaises(InvalidArgumentType): + self.gmp.create_tag( + name='foo', + resource_type="Foo", + resource_filter=None, + resource_ids=['foo'], + ) + def test_create_tag_missing_resource_type(self): with self.assertRaises(RequiredArgument): self.gmp.create_tag( @@ -123,6 +132,38 @@ def test_create_tag_with_resource_filter(self): '' ) + def test_create_tag_with_resource_filter_audit(self): + self.gmp.create_tag( + name='foo', + resource_filter='name=foo', + resource_type=EntityType.AUDIT, + ) + + self.connection.send.has_been_called_with( + '' + 'foo' + '' + 'task' + '' + '' + ) + + def test_create_tag_with_resource_filter_policy(self): + self.gmp.create_tag( + name='foo', + resource_filter='name=foo', + resource_type=EntityType.POLICY, + ) + + self.connection.send.has_been_called_with( + '' + 'foo' + '' + 'config' + '' + '' + ) + def test_create_tag_with_resource_ids(self): self.gmp.create_tag( name='foo', resource_ids=['foo'], resource_type=EntityType.TASK diff --git a/tests/protocols/gmpv208/testcmds/test_delete_tag.py b/tests/protocols/gmpv208/entities/tags/test_delete_tag.py similarity index 97% rename from tests/protocols/gmpv208/testcmds/test_delete_tag.py rename to tests/protocols/gmpv208/entities/tags/test_delete_tag.py index a4341728c..39fe8007a 100644 --- a/tests/protocols/gmpv208/testcmds/test_delete_tag.py +++ b/tests/protocols/gmpv208/entities/tags/test_delete_tag.py @@ -19,7 +19,7 @@ from gvm.errors import GvmError -class GmpDeleteTagTestCase: +class GmpDeleteTagTestMixin: def test_delete(self): self.gmp.delete_tag('a1') diff --git a/tests/protocols/gmpv208/testcmds/test_get_tag.py b/tests/protocols/gmpv208/entities/tags/test_get_tag.py similarity index 97% rename from tests/protocols/gmpv208/testcmds/test_get_tag.py rename to tests/protocols/gmpv208/entities/tags/test_get_tag.py index 13c806d21..2a90898a7 100644 --- a/tests/protocols/gmpv208/testcmds/test_get_tag.py +++ b/tests/protocols/gmpv208/entities/tags/test_get_tag.py @@ -19,7 +19,7 @@ from gvm.errors import RequiredArgument -class GmpGetTagTestCase: +class GmpGetTagTestMixin: def test_get_tag(self): self.gmp.get_tag('t1') diff --git a/tests/protocols/gmpv208/testcmds/test_get_tags.py b/tests/protocols/gmpv208/entities/tags/test_get_tags.py similarity index 98% rename from tests/protocols/gmpv208/testcmds/test_get_tags.py rename to tests/protocols/gmpv208/entities/tags/test_get_tags.py index ac8ec0e54..b966a65e3 100644 --- a/tests/protocols/gmpv208/testcmds/test_get_tags.py +++ b/tests/protocols/gmpv208/entities/tags/test_get_tags.py @@ -17,7 +17,7 @@ # along with this program. If not, see . -class GmpGetTagsTestCase: +class GmpGetTagsTestMixin: def test_get_tags(self): self.gmp.get_tags() diff --git a/tests/protocols/gmpv208/testcmds/test_modify_tag.py b/tests/protocols/gmpv208/entities/tags/test_modify_tag.py similarity index 81% rename from tests/protocols/gmpv208/testcmds/test_modify_tag.py rename to tests/protocols/gmpv208/entities/tags/test_modify_tag.py index 211797ace..b2a3d22b5 100644 --- a/tests/protocols/gmpv208/testcmds/test_modify_tag.py +++ b/tests/protocols/gmpv208/entities/tags/test_modify_tag.py @@ -16,11 +16,11 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from gvm.errors import RequiredArgument +from gvm.errors import RequiredArgument, InvalidArgumentType from gvm.protocols.gmpv208 import EntityType -class GmpModifyTagTestCase: +class GmpModifyTagTestMixin: def test_modify_tag(self): self.gmp.modify_tag(tag_id='t1') @@ -82,6 +82,36 @@ def test_modify_tag_with_resource_filter_and_type(self): '' ) + def test_modify_tag_with_resource_filter_and_type_audit(self): + self.gmp.modify_tag( + tag_id='t1', + resource_filter='name=foo', + resource_type=EntityType.AUDIT, + ) + + self.connection.send.has_been_called_with( + '' + '' + 'task' + '' + '' + ) + + def test_modify_tag_with_resource_filter_and_type_policy(self): + self.gmp.modify_tag( + tag_id='t1', + resource_filter='name=foo', + resource_type=EntityType.POLICY, + ) + + self.connection.send.has_been_called_with( + '' + '' + 'config' + '' + '' + ) + def test_modify_tag_with_resource_action_filter_and_type(self): self.gmp.modify_tag( tag_id='t1', @@ -152,6 +182,12 @@ def test_modify_tag_with_missing_resource_type(self): with self.assertRaises(RequiredArgument): self.gmp.modify_tag(tag_id='t1', resource_filter='name=foo') + def test_modify_tag_with_invalid_resource_type(self): + with self.assertRaises(InvalidArgumentType): + self.gmp.modify_tag( + tag_id='t1', resource_type="foo", resource_filter='name=foo' + ) + def test_modify_tag_with_missing_resource_filter_and_ids(self): self.gmp.modify_tag(tag_id='t1', resource_type=EntityType.TASK) diff --git a/tests/protocols/gmpv208/entities/test_aggregates.py b/tests/protocols/gmpv208/entities/test_aggregates.py new file mode 100644 index 000000000..be8a3384c --- /dev/null +++ b/tests/protocols/gmpv208/entities/test_aggregates.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2021 Greenbone Networks GmbH +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from ...gmpv208 import Gmpv208TestCase +from .aggregates import ( + GmpGetAggregatesTestMixin, +) + + +class Gmpv208GetAggregatesTestCase(GmpGetAggregatesTestMixin, Gmpv208TestCase): + pass diff --git a/tests/protocols/gmpv208/entities/test_feeds.py b/tests/protocols/gmpv208/entities/test_feeds.py new file mode 100644 index 000000000..4a10a4576 --- /dev/null +++ b/tests/protocols/gmpv208/entities/test_feeds.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2021 Greenbone Networks GmbH +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from ...gmpv208 import Gmpv208TestCase +from .feeds import ( + GmpGetFeedsTestMixin, + GmpGetFeedTestMixin, + GmpSyncFeedTestMixin, +) + + +class Gmpv208GetFeedTestCase(GmpGetFeedTestMixin, Gmpv208TestCase): + pass + + +class Gmpv208GetFeedsTestCase(GmpGetFeedsTestMixin, Gmpv208TestCase): + pass + + +class Gmpv208SyncFeedTestMixin(GmpSyncFeedTestMixin, Gmpv208TestCase): + pass diff --git a/tests/protocols/gmpv208/entities/test_tags.py b/tests/protocols/gmpv208/entities/test_tags.py new file mode 100644 index 000000000..8f0e9ec18 --- /dev/null +++ b/tests/protocols/gmpv208/entities/test_tags.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2021 Greenbone Networks GmbH +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from ...gmpv208 import Gmpv208TestCase +from .tags import ( + GmpCloneTagTestMixin, + GmpCreateTagTestMixin, + GmpDeleteTagTestMixin, + GmpGetTagTestMixin, + GmpGetTagsTestMixin, + GmpModifyTagTestMixin, +) + + +class Gmpv208DeleteTagTestCase(GmpDeleteTagTestMixin, Gmpv208TestCase): + pass + + +class Gmpv208GetTagTestCase(GmpGetTagTestMixin, Gmpv208TestCase): + pass + + +class Gmpv208GetTagsTestCase(GmpGetTagsTestMixin, Gmpv208TestCase): + pass + + +class Gmpv208CloneTagTestCase(GmpCloneTagTestMixin, Gmpv208TestCase): + pass + + +class Gmpv208CreateTagTestCase(GmpCreateTagTestMixin, Gmpv208TestCase): + pass + + +class Gmpv208ModifyTagTestCase(GmpModifyTagTestMixin, Gmpv208TestCase): + pass diff --git a/tests/protocols/gmpv208/test_new_gmpv208.py b/tests/protocols/gmpv208/test_new_gmpv208.py index 117a9bbad..eeb30bd18 100644 --- a/tests/protocols/gmpv208/test_new_gmpv208.py +++ b/tests/protocols/gmpv208/test_new_gmpv208.py @@ -24,14 +24,6 @@ class Gmpv208CreateFilterTestCase(GmpCreateFilterTestCase, Gmpv208TestCase): pass -class Gmpv208CreateTagTestCase(GmpCreateTagTestCase, Gmpv208TestCase): - pass - - -class Gmpv208GetAggregatesTestCase(GmpGetAggregatesTestCase, Gmpv208TestCase): - pass - - class Gmpv208ModifyFilterTestCase(GmpModifyFilterTestCase, Gmpv208TestCase): pass @@ -42,14 +34,6 @@ class Gmpv208ModifyReportFormatTestCase( pass -class Gmpv208ModifyTagTestCase(GmpModifyTagTestCase, Gmpv208TestCase): - pass - - -class Gmpv208GetFeedTestCase(GmpGetFeedTestCase, Gmpv208TestCase): - pass - - class Gmpv208ModifyTicketTestCase(GmpModifyTicketTestCase, Gmpv208TestCase): pass @@ -122,10 +106,6 @@ class Gmpv208CloneScheduleTestCase(GmpCloneScheduleTestCase, Gmpv208TestCase): pass -class Gmpv208CloneTagTestCase(GmpCloneTagTestCase, Gmpv208TestCase): - pass - - class Gmpv208CreateGroupTestCase(GmpCreateGroupTestCase, Gmpv208TestCase): pass @@ -156,10 +136,6 @@ class Gmpv208DeleteScheduleTestCase(GmpDeleteScheduleTestCase, Gmpv208TestCase): pass -class Gmpv208DeleteTagTestCase(GmpDeleteTagTestCase, Gmpv208TestCase): - pass - - class Gmpv208DescribeAuthCommandTestCase( GmpDescribeAuthCommandTestCase, Gmpv208TestCase ): @@ -172,10 +148,6 @@ class Gmpv208EmptyTrashcanCommandTestCase( pass -class Gmpv208GetFeedsTestCase(GmpGetFeedsTestCase, Gmpv208TestCase): - pass - - class Gmpv208GetFilterTestCase(GmpGetFilterTestCase, Gmpv208TestCase): pass @@ -242,14 +214,6 @@ class Gmpv208GetSystemReportsTestCase( pass -class Gmpv208GetTagTestCase(GmpGetTagTestCase, Gmpv208TestCase): - pass - - -class Gmpv208GetTagsTestCase(GmpGetTagsTestCase, Gmpv208TestCase): - pass - - class Gmpv208GetVersionCommandTestCase( GmpGetVersionCommandTestCase, Gmpv208TestCase ): @@ -288,12 +252,6 @@ class Gmpv208SyncCertCommandTestCase( pass -class Gmpv208SyncFeedCommandTestCase( - GmpSyncFeedCommandTestCase, Gmpv208TestCase -): - pass - - class Gmpv208SyncScapCommandTestCase( GmpSyncScapCommandTestCase, Gmpv208TestCase ): diff --git a/tests/protocols/gmpv208/testcmds/__init__.py b/tests/protocols/gmpv208/testcmds/__init__.py index 79afe653e..6b8c3757d 100644 --- a/tests/protocols/gmpv208/testcmds/__init__.py +++ b/tests/protocols/gmpv208/testcmds/__init__.py @@ -19,12 +19,8 @@ # pylint: disable=no-member from .test_create_filter import GmpCreateFilterTestCase -from .test_create_tag import GmpCreateTagTestCase -from .test_get_aggregates import GmpGetAggregatesTestCase from .test_modify_filter import GmpModifyFilterTestCase from .test_modify_report_format import GmpModifyReportFormatTestCase -from .test_modify_tag import GmpModifyTagTestCase -from .test_get_feed import GmpGetFeedTestCase from .test_modify_ticket import GmpModifyTicketTestCase from .test_clone_ticket import GmpCloneTicketTestCase from .test_create_schedule import GmpCreateScheduleTestCase @@ -42,7 +38,6 @@ from .test_clone_group import GmpCloneGroupTestCase from .test_clone_role import GmpCloneRoleTestCase from .test_clone_schedule import GmpCloneScheduleTestCase -from .test_clone_tag import GmpCloneTagTestCase from .test_create_group import GmpCreateGroupTestCase from .test_create_role import GmpCreateRoleTestCase from .test_delete_filter import GmpDeleteFilterTestCase @@ -50,10 +45,8 @@ from .test_delete_report_format import GmpDeleteReportFormatTestCase from .test_delete_role import GmpDeleteRoleTestCase from .test_delete_schedule import GmpDeleteScheduleTestCase -from .test_delete_tag import GmpDeleteTagTestCase from .test_describe_auth import GmpDescribeAuthCommandTestCase from .test_empty_trashcan import GmpEmptyTrashcanCommandTestCase -from .test_get_feeds import GmpGetFeedsTestCase from .test_get_filter import GmpGetFilterTestCase from .test_get_filters import GmpGetFiltersTestCase from .test_get_group import GmpGetGroupTestCase @@ -69,8 +62,6 @@ from .test_get_setting import GmpGetSettingTestCase from .test_get_settings import GmpGetSettingsTestCase from .test_get_system_reports import GmpGetSystemReportsTestCase -from .test_get_tag import GmpGetTagTestCase -from .test_get_tags import GmpGetTagsTestCase from .test_get_version import GmpGetVersionCommandTestCase from .test_help import GmpHelpTestCase from .test_import_report_format import GmpImportReportFormatTestCase @@ -80,7 +71,6 @@ from .test_modify_setting import GmpModifySettingTestCase from .test_restore import GmpRestoreTestCase from .test_sync_cert import GmpSyncCertCommandTestCase -from .test_sync_feed import GmpSyncFeedCommandTestCase from .test_sync_scap import GmpSyncScapCommandTestCase from .test_verify_report_format import GmpVerifyReportFormatTestCase from .test_with_statement import GmpWithStatementTestCase diff --git a/tests/protocols/gmpv214/entities/test_aggregates.py b/tests/protocols/gmpv214/entities/test_aggregates.py new file mode 100644 index 000000000..c1bb1f483 --- /dev/null +++ b/tests/protocols/gmpv214/entities/test_aggregates.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2021 Greenbone Networks GmbH +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from ...gmpv208 import Gmpv208TestCase +from ...gmpv208.entities.aggregates import ( + GmpGetAggregatesTestMixin, +) + + +class Gmpv208GetAggregatesTestCase(GmpGetAggregatesTestMixin, Gmpv208TestCase): + pass diff --git a/tests/protocols/gmpv214/entities/test_feeds.py b/tests/protocols/gmpv214/entities/test_feeds.py new file mode 100644 index 000000000..498bbcb90 --- /dev/null +++ b/tests/protocols/gmpv214/entities/test_feeds.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2021 Greenbone Networks GmbH +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from ...gmpv208 import Gmpv208TestCase +from ...gmpv208.entities.feeds import ( + GmpGetFeedsTestMixin, + GmpGetFeedTestMixin, + GmpSyncFeedTestMixin, +) + + +class Gmpv208GetFeedTestCase(GmpGetFeedTestMixin, Gmpv208TestCase): + pass + + +class Gmpv208GetFeedsTestCase(GmpGetFeedsTestMixin, Gmpv208TestCase): + pass + + +class Gmpv208SyncFeedTestMixin(GmpSyncFeedTestMixin, Gmpv208TestCase): + pass diff --git a/tests/protocols/gmpv214/entities/test_tags.py b/tests/protocols/gmpv214/entities/test_tags.py new file mode 100644 index 000000000..8b3a9d8a5 --- /dev/null +++ b/tests/protocols/gmpv214/entities/test_tags.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2021 Greenbone Networks GmbH +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from ...gmpv208 import Gmpv208TestCase +from ...gmpv208.entities.tags import ( + GmpCloneTagTestMixin, + GmpCreateTagTestMixin, + GmpDeleteTagTestMixin, + GmpGetTagTestMixin, + GmpGetTagsTestMixin, + GmpModifyTagTestMixin, +) + + +class Gmpv208DeleteTagTestCase(GmpDeleteTagTestMixin, Gmpv208TestCase): + pass + + +class Gmpv208GetTagTestCase(GmpGetTagTestMixin, Gmpv208TestCase): + pass + + +class Gmpv208GetTagsTestCase(GmpGetTagsTestMixin, Gmpv208TestCase): + pass + + +class Gmpv208CloneTagTestCase(GmpCloneTagTestMixin, Gmpv208TestCase): + pass + + +class Gmpv208CreateTagTestCase(GmpCreateTagTestMixin, Gmpv208TestCase): + pass + + +class Gmpv208ModifyTagTestCase(GmpModifyTagTestMixin, Gmpv208TestCase): + pass diff --git a/tests/protocols/gmpv214/test_v208_from_gmpv214.py b/tests/protocols/gmpv214/test_v208_from_gmpv214.py index 68b6d40f5..f6a184873 100644 --- a/tests/protocols/gmpv214/test_v208_from_gmpv214.py +++ b/tests/protocols/gmpv214/test_v208_from_gmpv214.py @@ -24,14 +24,6 @@ class Gmpv214CreateFilterTestCase(GmpCreateFilterTestCase, Gmpv214TestCase): pass -class Gmpv214CreateTagTestCase(GmpCreateTagTestCase, Gmpv214TestCase): - pass - - -class Gmpv214GetAggregatesTestCase(GmpGetAggregatesTestCase, Gmpv214TestCase): - pass - - class Gmpv214ModifyFilterTestCase(GmpModifyFilterTestCase, Gmpv214TestCase): pass @@ -42,14 +34,6 @@ class Gmpv214ModifyReportFormatTestCase( pass -class Gmpv214ModifyTagTestCase(GmpModifyTagTestCase, Gmpv214TestCase): - pass - - -class Gmpv214GetFeedTestCase(GmpGetFeedTestCase, Gmpv214TestCase): - pass - - class Gmpv214ModifyTicketTestCase(GmpModifyTicketTestCase, Gmpv214TestCase): pass @@ -122,10 +106,6 @@ class Gmpv214CloneScheduleTestCase(GmpCloneScheduleTestCase, Gmpv214TestCase): pass -class Gmpv214CloneTagTestCase(GmpCloneTagTestCase, Gmpv214TestCase): - pass - - class Gmpv214CreateGroupTestCase(GmpCreateGroupTestCase, Gmpv214TestCase): pass @@ -156,10 +136,6 @@ class Gmpv214DeleteScheduleTestCase(GmpDeleteScheduleTestCase, Gmpv214TestCase): pass -class Gmpv214DeleteTagTestCase(GmpDeleteTagTestCase, Gmpv214TestCase): - pass - - class Gmpv214DescribeAuthCommandTestCase( GmpDescribeAuthCommandTestCase, Gmpv214TestCase ): @@ -172,10 +148,6 @@ class Gmpv214EmptyTrashcanCommandTestCase( pass -class Gmpv214GetFeedsTestCase(GmpGetFeedsTestCase, Gmpv214TestCase): - pass - - class Gmpv214GetFilterTestCase(GmpGetFilterTestCase, Gmpv214TestCase): pass @@ -242,14 +214,6 @@ class Gmpv214GetSystemReportsTestCase( pass -class Gmpv214GetTagTestCase(GmpGetTagTestCase, Gmpv214TestCase): - pass - - -class Gmpv214GetTagsTestCase(GmpGetTagsTestCase, Gmpv214TestCase): - pass - - class Gmpv214GetVersionCommandTestCase( GmpGetVersionCommandTestCase, Gmpv214TestCase ): @@ -288,12 +252,6 @@ class Gmpv214SyncCertCommandTestCase( pass -class Gmpv214SyncFeedCommandTestCase( - GmpSyncFeedCommandTestCase, Gmpv214TestCase -): - pass - - class Gmpv214SyncScapCommandTestCase( GmpSyncScapCommandTestCase, Gmpv214TestCase ):