baldertest 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- _balder/__init__.py +12 -0
- _balder/_version.py +34 -0
- _balder/balder_plugin.py +73 -0
- _balder/balder_session.py +341 -0
- _balder/balder_settings.py +15 -0
- _balder/cnnrelations/__init__.py +7 -0
- _balder/cnnrelations/and_connection_relation.py +176 -0
- _balder/cnnrelations/base_connection_relation.py +270 -0
- _balder/cnnrelations/or_connection_relation.py +65 -0
- _balder/collector.py +874 -0
- _balder/connection.py +863 -0
- _balder/connection_metadata.py +255 -0
- _balder/console/__init__.py +0 -0
- _balder/console/balder.py +58 -0
- _balder/controllers/__init__.py +12 -0
- _balder/controllers/base_device_controller.py +72 -0
- _balder/controllers/controller.py +29 -0
- _balder/controllers/device_controller.py +446 -0
- _balder/controllers/feature_controller.py +715 -0
- _balder/controllers/normal_scenario_setup_controller.py +402 -0
- _balder/controllers/scenario_controller.py +524 -0
- _balder/controllers/setup_controller.py +134 -0
- _balder/controllers/vdevice_controller.py +95 -0
- _balder/decorator_connect.py +104 -0
- _balder/decorator_covered_by.py +74 -0
- _balder/decorator_fixture.py +29 -0
- _balder/decorator_for_vdevice.py +118 -0
- _balder/decorator_gateway.py +34 -0
- _balder/decorator_insert_into_tree.py +52 -0
- _balder/decorator_parametrize.py +31 -0
- _balder/decorator_parametrize_by_feature.py +36 -0
- _balder/device.py +18 -0
- _balder/exceptions.py +182 -0
- _balder/executor/__init__.py +0 -0
- _balder/executor/basic_executable_executor.py +133 -0
- _balder/executor/basic_executor.py +205 -0
- _balder/executor/executor_tree.py +217 -0
- _balder/executor/parametrized_testcase_executor.py +52 -0
- _balder/executor/scenario_executor.py +169 -0
- _balder/executor/setup_executor.py +163 -0
- _balder/executor/testcase_executor.py +203 -0
- _balder/executor/unresolved_parametrized_testcase_executor.py +184 -0
- _balder/executor/variation_executor.py +882 -0
- _balder/exit_code.py +19 -0
- _balder/feature.py +74 -0
- _balder/feature_replacement_mapping.py +107 -0
- _balder/feature_vdevice_mapping.py +88 -0
- _balder/fixture_definition_scope.py +19 -0
- _balder/fixture_execution_level.py +22 -0
- _balder/fixture_manager.py +483 -0
- _balder/fixture_metadata.py +26 -0
- _balder/node_gateway.py +103 -0
- _balder/objects/__init__.py +0 -0
- _balder/objects/connections/__init__.py +0 -0
- _balder/objects/connections/osi_1_physical.py +116 -0
- _balder/objects/connections/osi_2_datalink.py +35 -0
- _balder/objects/connections/osi_3_network.py +47 -0
- _balder/objects/connections/osi_4_transport.py +40 -0
- _balder/objects/connections/osi_5_session.py +13 -0
- _balder/objects/connections/osi_6_presentation.py +13 -0
- _balder/objects/connections/osi_7_application.py +83 -0
- _balder/objects/devices/__init__.py +0 -0
- _balder/objects/devices/this_device.py +12 -0
- _balder/parametrization.py +75 -0
- _balder/plugin_manager.py +138 -0
- _balder/previous_executor_mark.py +23 -0
- _balder/routing_path.py +335 -0
- _balder/scenario.py +20 -0
- _balder/setup.py +18 -0
- _balder/solver.py +246 -0
- _balder/testresult.py +163 -0
- _balder/unmapped_vdevice.py +13 -0
- _balder/utils/__init__.py +0 -0
- _balder/utils/functions.py +103 -0
- _balder/utils/inner_device_managing_metaclass.py +14 -0
- _balder/utils/mixin_can_be_covered_by_executor.py +24 -0
- _balder/utils/typings.py +4 -0
- _balder/vdevice.py +9 -0
- balder/__init__.py +56 -0
- balder/connections.py +43 -0
- balder/devices.py +9 -0
- balder/exceptions.py +44 -0
- balder/parametrization.py +8 -0
- baldertest-0.1.0.dist-info/METADATA +356 -0
- baldertest-0.1.0.dist-info/RECORD +89 -0
- baldertest-0.1.0.dist-info/WHEEL +5 -0
- baldertest-0.1.0.dist-info/entry_points.txt +2 -0
- baldertest-0.1.0.dist-info/licenses/LICENSE +21 -0
- baldertest-0.1.0.dist-info/top_level.txt +2 -0
_balder/exit_code.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ExitCode(Enum):
|
|
5
|
+
"""
|
|
6
|
+
This enum describes the balder exit codes.
|
|
7
|
+
"""
|
|
8
|
+
#: tests were collected and all tests and fixtures terminates with success
|
|
9
|
+
SUCCESS = 0
|
|
10
|
+
#: tests were collected but some tests failed
|
|
11
|
+
TESTS_FAILED = 1
|
|
12
|
+
#: test was interrupted by user
|
|
13
|
+
USER_INTERRUPT = 2
|
|
14
|
+
#: an internal unexpected error occurs
|
|
15
|
+
UNEXPECTED_ERROR = 3
|
|
16
|
+
#: Balder usage error
|
|
17
|
+
BALDER_USAGE_ERROR = 4
|
|
18
|
+
#: no tests were collected
|
|
19
|
+
NO_TESTS_COLLECTED = 5
|
_balder/feature.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Type, Dict, Tuple, Union
|
|
3
|
+
|
|
4
|
+
from _balder.device import Device
|
|
5
|
+
from _balder.vdevice import VDevice
|
|
6
|
+
from _balder.utils.inner_device_managing_metaclass import InnerDeviceManagingMetaclass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Feature(metaclass=InnerDeviceManagingMetaclass):
|
|
10
|
+
"""
|
|
11
|
+
This is the basic feature class. It represents an abstract class that should not be used directly. It is the base
|
|
12
|
+
class for all feature elements.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, **kwargs):
|
|
16
|
+
"""
|
|
17
|
+
:param kwargs: contains a dictionary that references all vDevices of the feature and a real
|
|
18
|
+
scenario :meth:`Device` as value
|
|
19
|
+
"""
|
|
20
|
+
from _balder.controllers import FeatureController # pylint: disable=import-outside-toplevel
|
|
21
|
+
|
|
22
|
+
#: this property contains the active mapping for the devices
|
|
23
|
+
self.active_vdevices: Dict[VDevice, Union[Device, str]] = {}
|
|
24
|
+
all_vdevices = FeatureController.get_for(self.__class__).get_abs_inner_vdevice_classes()
|
|
25
|
+
not_processed_kwargs = {}
|
|
26
|
+
for cur_kwargs_key, cur_kwargs_val in kwargs.items():
|
|
27
|
+
if cur_kwargs_key in [cur_vdevice.__name__ for cur_vdevice in all_vdevices]:
|
|
28
|
+
cur_vdevice = [cur_vdevice for cur_vdevice in all_vdevices if cur_vdevice.__name__ == cur_kwargs_key][0]
|
|
29
|
+
if isinstance(cur_kwargs_val, str) or issubclass(cur_kwargs_val, Device):
|
|
30
|
+
if not isinstance(cur_kwargs_val, str) and issubclass(cur_kwargs_val, VDevice):
|
|
31
|
+
raise TypeError(f"the given value of vDevice mapping for vDevice `{cur_kwargs_key}` has to be "
|
|
32
|
+
f"of the type `Device` - it is a subclass of `VDevice` - this is not allowed "
|
|
33
|
+
f"here")
|
|
34
|
+
if self.active_vdevices:
|
|
35
|
+
raise AttributeError(
|
|
36
|
+
"the constructor expects exactly none or one vDevice mapping - found more than one here")
|
|
37
|
+
|
|
38
|
+
self.active_vdevices = {cur_vdevice: cur_kwargs_val}
|
|
39
|
+
else:
|
|
40
|
+
raise TypeError(f"the given value of vDevice mapping for vDevice `{cur_kwargs_key}` has to be of "
|
|
41
|
+
f"the type `Device` or has to be a string with the name of the device class")
|
|
42
|
+
else:
|
|
43
|
+
not_processed_kwargs[cur_kwargs_key] = cur_kwargs_val
|
|
44
|
+
if len(not_processed_kwargs) != 0:
|
|
45
|
+
raise TypeError(
|
|
46
|
+
f"can not resolve the given attributes `{str(not_processed_kwargs)}` in feature "
|
|
47
|
+
f"`{self.__class__.__name__}`")
|
|
48
|
+
|
|
49
|
+
# ---------------------------------- STATIC METHODS ----------------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
# ---------------------------------- CLASS METHODS ----------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
# ---------------------------------- PROPERTIES --------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def active_vdevice_device_mapping(self) -> Tuple[Union[None, Type[VDevice]], Union[None, Type[Device]]]:
|
|
57
|
+
"""This property returns the mapped device that is active here"""
|
|
58
|
+
if len(self.active_vdevices) == 0:
|
|
59
|
+
return None, None
|
|
60
|
+
return list(self.active_vdevices.keys())[0], list(self.active_vdevices.values())[0]
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def active_vdevice(self) -> Union[None, Type[VDevice]]:
|
|
64
|
+
"""This property returns the active VDevice that is active here"""
|
|
65
|
+
return self.active_vdevice_device_mapping[0]
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def active_mapped_device(self) -> Union[None, Type[VDevice]]:
|
|
69
|
+
"""This property returns the active mapped Device"""
|
|
70
|
+
return self.active_vdevice_device_mapping[1]
|
|
71
|
+
|
|
72
|
+
# ---------------------------------- PROTECTED METHODS -------------------------------------------------------------
|
|
73
|
+
|
|
74
|
+
# ---------------------------------- METHODS -----------------------------------------------------------------------
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
from typing import Union, Type
|
|
2
|
+
import dataclasses
|
|
3
|
+
from .device import Device
|
|
4
|
+
from .feature import Feature
|
|
5
|
+
from .controllers import DeviceController
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FeatureReplacementMapping:
|
|
9
|
+
"""
|
|
10
|
+
helper object that stores mappings between scenario and setup features - is used in :class:`VariationExecutor`
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
@dataclasses.dataclass
|
|
14
|
+
class FeatureMapping:
|
|
15
|
+
"""
|
|
16
|
+
stores a single mapping
|
|
17
|
+
"""
|
|
18
|
+
#: the feature attribute name in scenario device
|
|
19
|
+
attr_name: str
|
|
20
|
+
#: the scenario feature instance or None if the current variation does not use this setup feature in scenario
|
|
21
|
+
scenario_feature: Union[Feature, None]
|
|
22
|
+
#: the setup feature that is used for the scenario feature
|
|
23
|
+
setup_feature: Feature
|
|
24
|
+
|
|
25
|
+
def __init__(self):
|
|
26
|
+
self._mappings: list[FeatureReplacementMapping.FeatureMapping] = []
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def mappings(self) -> list[FeatureMapping]:
|
|
30
|
+
"""
|
|
31
|
+
returns all existing mappings
|
|
32
|
+
"""
|
|
33
|
+
return list(self._mappings)
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def attr_names(self) -> list[str]:
|
|
37
|
+
"""
|
|
38
|
+
returns all used attribute names
|
|
39
|
+
"""
|
|
40
|
+
return [mapping.attr_name for mapping in self._mappings]
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def all_scenario_features(self) -> list[Feature]:
|
|
44
|
+
"""
|
|
45
|
+
returns all scenario features
|
|
46
|
+
"""
|
|
47
|
+
return [mapping.scenario_feature for mapping in self._mappings]
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def all_setup_features(self) -> list[Feature]:
|
|
51
|
+
"""
|
|
52
|
+
returns all setup features
|
|
53
|
+
"""
|
|
54
|
+
return [mapping.setup_feature for mapping in self._mappings]
|
|
55
|
+
|
|
56
|
+
def add(self, attr_name: str, scenario_feature: Union[Feature, None], setup_feature: Feature):
|
|
57
|
+
"""
|
|
58
|
+
adds a new mapping
|
|
59
|
+
|
|
60
|
+
:param attr_name: the feature attribute name in scenario device
|
|
61
|
+
:param scenario_feature: the scenario feature instance or None if the current variation does not use this setup
|
|
62
|
+
feature in scenario
|
|
63
|
+
:param setup_feature: the setup feature that is used for the scenario feature
|
|
64
|
+
"""
|
|
65
|
+
if attr_name in self.attr_names:
|
|
66
|
+
raise KeyError(f'entry for property name `{attr_name}` already exist - can not define it multiple times')
|
|
67
|
+
self._mappings.append(FeatureReplacementMapping.FeatureMapping(attr_name, scenario_feature, setup_feature))
|
|
68
|
+
|
|
69
|
+
def get_features_for_attr_name(self, attr_name: str) -> tuple[Feature, Feature]:
|
|
70
|
+
"""
|
|
71
|
+
returns the scenario and its mapped setup feature for a specific attribute name used in the scenario device
|
|
72
|
+
"""
|
|
73
|
+
for mapping in self._mappings:
|
|
74
|
+
if mapping.attr_name == attr_name:
|
|
75
|
+
return mapping.scenario_feature, mapping.setup_feature
|
|
76
|
+
raise KeyError(f'entry for property name `{attr_name}` does not exist')
|
|
77
|
+
|
|
78
|
+
def get_replaced_scenario_feature_for(self, setup_feature: Feature) -> Union[Feature, None]:
|
|
79
|
+
"""
|
|
80
|
+
returns the mapped scenario feature for a given setup feature
|
|
81
|
+
"""
|
|
82
|
+
for mapping in self._mappings:
|
|
83
|
+
if mapping.setup_feature == setup_feature:
|
|
84
|
+
return mapping.scenario_feature
|
|
85
|
+
raise KeyError(f'cannot find setup feature for {setup_feature}')
|
|
86
|
+
|
|
87
|
+
def add_remaining_setup_features_as_autonomous(self, cur_setup_device: Type[Device]):
|
|
88
|
+
"""
|
|
89
|
+
Adds all features that were not added as autonomous features.
|
|
90
|
+
"""
|
|
91
|
+
cur_setup_features = DeviceController.get_for(cur_setup_device).get_all_instantiated_feature_objects()
|
|
92
|
+
|
|
93
|
+
# also add all setup features that are not assigned as autonomous features
|
|
94
|
+
for cur_setup_feature in cur_setup_features.values():
|
|
95
|
+
if cur_setup_feature not in self.all_setup_features:
|
|
96
|
+
# determine free name
|
|
97
|
+
idx = 0
|
|
98
|
+
autonomous_name = None
|
|
99
|
+
while (autonomous_name is None
|
|
100
|
+
or autonomous_name in self.attr_names):
|
|
101
|
+
autonomous_name = f"_autonomous_feat_{idx}"
|
|
102
|
+
idx += 1
|
|
103
|
+
self.add(
|
|
104
|
+
attr_name=autonomous_name,
|
|
105
|
+
scenario_feature=None,
|
|
106
|
+
setup_feature=cur_setup_feature
|
|
107
|
+
)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Type
|
|
3
|
+
import dataclasses
|
|
4
|
+
|
|
5
|
+
from .controllers.feature_controller import FeatureController
|
|
6
|
+
from .device import Device
|
|
7
|
+
from .feature import Feature
|
|
8
|
+
from .vdevice import VDevice
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class FeatureVDeviceMapping:
|
|
12
|
+
"""
|
|
13
|
+
helper object that stores mappings between :class:`VDevice` and :class:`Device`
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
@dataclasses.dataclass
|
|
17
|
+
class VDeviceDeviceMapping:
|
|
18
|
+
"""describes the mapping of one VDevice to one Device"""
|
|
19
|
+
#: the vdevice class
|
|
20
|
+
vdevice: Type[VDevice]
|
|
21
|
+
#: the mapped device to this VDevice
|
|
22
|
+
device: Type[Device]
|
|
23
|
+
|
|
24
|
+
@dataclasses.dataclass
|
|
25
|
+
class VDevicesMapping:
|
|
26
|
+
"""
|
|
27
|
+
stores a single mapping
|
|
28
|
+
"""
|
|
29
|
+
#: the feature object, this mapping belongs to
|
|
30
|
+
feature: Feature
|
|
31
|
+
#: the available mapping for this feature (at the moment, we only support one)
|
|
32
|
+
mappings: list[FeatureVDeviceMapping.VDeviceDeviceMapping]
|
|
33
|
+
|
|
34
|
+
def __init__(self):
|
|
35
|
+
self._mappings: list[FeatureVDeviceMapping.VDevicesMapping] = []
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def mappings(self) -> list[VDevicesMapping]:
|
|
39
|
+
"""
|
|
40
|
+
returns all existing mappings
|
|
41
|
+
"""
|
|
42
|
+
return list(self._mappings)
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def features(self) -> list[Feature]:
|
|
46
|
+
"""
|
|
47
|
+
returns all used attribute names
|
|
48
|
+
"""
|
|
49
|
+
return [mapping.feature for mapping in self._mappings]
|
|
50
|
+
|
|
51
|
+
def items(self) -> list[tuple[Feature, list[VDeviceDeviceMapping]]]:
|
|
52
|
+
"""
|
|
53
|
+
:return: a list of Feature/vdevice mapping tuples
|
|
54
|
+
"""
|
|
55
|
+
return [(mapping.feature, mapping.mappings) for mapping in self._mappings]
|
|
56
|
+
|
|
57
|
+
def add(self, feature: Feature, mappings: dict[Type[VDevice], Type[Device]]):
|
|
58
|
+
"""
|
|
59
|
+
adds a new mapping
|
|
60
|
+
|
|
61
|
+
:param feature: the :class:`Feature` class this mapping belongs to
|
|
62
|
+
:param mappings: a dictionary that describes the mapping between the :class:`VDevice` and :class:`Device`. The
|
|
63
|
+
:class:`VDevice` needs to be part of the :class:`Feature`
|
|
64
|
+
"""
|
|
65
|
+
if feature in self.features:
|
|
66
|
+
raise KeyError(f'entry for feature `{feature}` already exist - can not define it multiple times')
|
|
67
|
+
feature_controller = FeatureController.get_for(feature.__class__)
|
|
68
|
+
vdevice_device_mappings = []
|
|
69
|
+
for cur_vdev, cur_dev in mappings.items():
|
|
70
|
+
if not (isinstance(cur_vdev, type) and issubclass(cur_vdev, VDevice)):
|
|
71
|
+
raise TypeError(f'the provided key objects in mappings needs to be a subclass of `{VDevice.__name__}`')
|
|
72
|
+
if not (isinstance(cur_dev, type) and issubclass(cur_dev, Device)):
|
|
73
|
+
raise TypeError(f'the provided value objects in mappings needs to be a subclass of `{Device.__name__}`')
|
|
74
|
+
if cur_vdev not in feature_controller.get_abs_inner_vdevice_classes():
|
|
75
|
+
raise ValueError(f'the provided VDevice `{cur_vdev}` is not part of the provided feature `{feature}`')
|
|
76
|
+
vdevice_device_mappings.append(self.VDeviceDeviceMapping(cur_vdev, cur_dev))
|
|
77
|
+
new_mapping = self.VDevicesMapping(feature=feature, mappings=vdevice_device_mappings)
|
|
78
|
+
|
|
79
|
+
self._mappings.append(new_mapping)
|
|
80
|
+
|
|
81
|
+
def get_mappings_for_feature(self, feature: Feature) -> list[VDeviceDeviceMapping]:
|
|
82
|
+
"""
|
|
83
|
+
returns the list with all mappings for the provided feature
|
|
84
|
+
"""
|
|
85
|
+
for cur_item in self._mappings:
|
|
86
|
+
if cur_item.feature == feature:
|
|
87
|
+
return cur_item.mappings
|
|
88
|
+
raise KeyError(f'entry for feature `{feature}` does not exist')
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import List
|
|
3
|
+
from enum import Enum
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class FixtureDefinitionScope(Enum):
|
|
7
|
+
"""
|
|
8
|
+
This enum describes the definition scope of a fixture. A definition scope is the position the fixture was defined.
|
|
9
|
+
If the fixture was defined within the balderglob.py file, it has the definition-scope `GLOB`. If it is defined
|
|
10
|
+
within a scenario or setup it has the equivalent SCENARIO or SETUP scope.
|
|
11
|
+
"""
|
|
12
|
+
GLOB = 'glob'
|
|
13
|
+
SETUP = 'setup'
|
|
14
|
+
SCENARIO = 'scenario'
|
|
15
|
+
|
|
16
|
+
@classmethod
|
|
17
|
+
def get_order(cls) -> List[FixtureDefinitionScope]:
|
|
18
|
+
"""returns the priority order of the fixture definition scope"""
|
|
19
|
+
return [cls.GLOB, cls.SETUP, cls.SCENARIO]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import List
|
|
3
|
+
from enum import Enum
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class FixtureExecutionLevel(Enum):
|
|
7
|
+
"""
|
|
8
|
+
This enum describes the fixture-execution-level of a fixture. It describes when the fixture should be executed. This
|
|
9
|
+
level will be set in the fixture decorator.
|
|
10
|
+
"""
|
|
11
|
+
SESSION = 'session'
|
|
12
|
+
SETUP = 'setup'
|
|
13
|
+
SCENARIO = 'scenario'
|
|
14
|
+
VARIATION = 'variation'
|
|
15
|
+
TESTCASE = 'testcase'
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
def get_order(cls) -> List[FixtureExecutionLevel]:
|
|
19
|
+
"""
|
|
20
|
+
returns the execution order of fixtures
|
|
21
|
+
"""
|
|
22
|
+
return [cls.SESSION, cls.SETUP, cls.SCENARIO, cls.VARIATION, cls.TESTCASE]
|