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
):