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.
Files changed (89) hide show
  1. _balder/__init__.py +12 -0
  2. _balder/_version.py +34 -0
  3. _balder/balder_plugin.py +73 -0
  4. _balder/balder_session.py +341 -0
  5. _balder/balder_settings.py +15 -0
  6. _balder/cnnrelations/__init__.py +7 -0
  7. _balder/cnnrelations/and_connection_relation.py +176 -0
  8. _balder/cnnrelations/base_connection_relation.py +270 -0
  9. _balder/cnnrelations/or_connection_relation.py +65 -0
  10. _balder/collector.py +874 -0
  11. _balder/connection.py +863 -0
  12. _balder/connection_metadata.py +255 -0
  13. _balder/console/__init__.py +0 -0
  14. _balder/console/balder.py +58 -0
  15. _balder/controllers/__init__.py +12 -0
  16. _balder/controllers/base_device_controller.py +72 -0
  17. _balder/controllers/controller.py +29 -0
  18. _balder/controllers/device_controller.py +446 -0
  19. _balder/controllers/feature_controller.py +715 -0
  20. _balder/controllers/normal_scenario_setup_controller.py +402 -0
  21. _balder/controllers/scenario_controller.py +524 -0
  22. _balder/controllers/setup_controller.py +134 -0
  23. _balder/controllers/vdevice_controller.py +95 -0
  24. _balder/decorator_connect.py +104 -0
  25. _balder/decorator_covered_by.py +74 -0
  26. _balder/decorator_fixture.py +29 -0
  27. _balder/decorator_for_vdevice.py +118 -0
  28. _balder/decorator_gateway.py +34 -0
  29. _balder/decorator_insert_into_tree.py +52 -0
  30. _balder/decorator_parametrize.py +31 -0
  31. _balder/decorator_parametrize_by_feature.py +36 -0
  32. _balder/device.py +18 -0
  33. _balder/exceptions.py +182 -0
  34. _balder/executor/__init__.py +0 -0
  35. _balder/executor/basic_executable_executor.py +133 -0
  36. _balder/executor/basic_executor.py +205 -0
  37. _balder/executor/executor_tree.py +217 -0
  38. _balder/executor/parametrized_testcase_executor.py +52 -0
  39. _balder/executor/scenario_executor.py +169 -0
  40. _balder/executor/setup_executor.py +163 -0
  41. _balder/executor/testcase_executor.py +203 -0
  42. _balder/executor/unresolved_parametrized_testcase_executor.py +184 -0
  43. _balder/executor/variation_executor.py +882 -0
  44. _balder/exit_code.py +19 -0
  45. _balder/feature.py +74 -0
  46. _balder/feature_replacement_mapping.py +107 -0
  47. _balder/feature_vdevice_mapping.py +88 -0
  48. _balder/fixture_definition_scope.py +19 -0
  49. _balder/fixture_execution_level.py +22 -0
  50. _balder/fixture_manager.py +483 -0
  51. _balder/fixture_metadata.py +26 -0
  52. _balder/node_gateway.py +103 -0
  53. _balder/objects/__init__.py +0 -0
  54. _balder/objects/connections/__init__.py +0 -0
  55. _balder/objects/connections/osi_1_physical.py +116 -0
  56. _balder/objects/connections/osi_2_datalink.py +35 -0
  57. _balder/objects/connections/osi_3_network.py +47 -0
  58. _balder/objects/connections/osi_4_transport.py +40 -0
  59. _balder/objects/connections/osi_5_session.py +13 -0
  60. _balder/objects/connections/osi_6_presentation.py +13 -0
  61. _balder/objects/connections/osi_7_application.py +83 -0
  62. _balder/objects/devices/__init__.py +0 -0
  63. _balder/objects/devices/this_device.py +12 -0
  64. _balder/parametrization.py +75 -0
  65. _balder/plugin_manager.py +138 -0
  66. _balder/previous_executor_mark.py +23 -0
  67. _balder/routing_path.py +335 -0
  68. _balder/scenario.py +20 -0
  69. _balder/setup.py +18 -0
  70. _balder/solver.py +246 -0
  71. _balder/testresult.py +163 -0
  72. _balder/unmapped_vdevice.py +13 -0
  73. _balder/utils/__init__.py +0 -0
  74. _balder/utils/functions.py +103 -0
  75. _balder/utils/inner_device_managing_metaclass.py +14 -0
  76. _balder/utils/mixin_can_be_covered_by_executor.py +24 -0
  77. _balder/utils/typings.py +4 -0
  78. _balder/vdevice.py +9 -0
  79. balder/__init__.py +56 -0
  80. balder/connections.py +43 -0
  81. balder/devices.py +9 -0
  82. balder/exceptions.py +44 -0
  83. balder/parametrization.py +8 -0
  84. baldertest-0.1.0.dist-info/METADATA +356 -0
  85. baldertest-0.1.0.dist-info/RECORD +89 -0
  86. baldertest-0.1.0.dist-info/WHEEL +5 -0
  87. baldertest-0.1.0.dist-info/entry_points.txt +2 -0
  88. baldertest-0.1.0.dist-info/licenses/LICENSE +21 -0
  89. baldertest-0.1.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,255 @@
1
+ from __future__ import annotations
2
+ from typing import Union, Type, Tuple
3
+ from .device import Device
4
+
5
+
6
+ class ConnectionMetadata:
7
+ """
8
+ Describes the metadata of a connection.
9
+ """
10
+
11
+ def __init__(
12
+ self,
13
+ from_device: Union[Type[Device], None] = None,
14
+ to_device: Union[Type[Device], None] = None,
15
+ from_device_node_name: Union[str, None] = None,
16
+ to_device_node_name: Union[str, None] = None,
17
+ bidirectional: bool = True,
18
+ ):
19
+
20
+ self._from_device = None
21
+ self._from_device_node_name = None
22
+ self.set_from(from_device, from_device_node_name)
23
+
24
+ self._to_device = None
25
+ self._to_device_node_name = None
26
+ self.set_to(to_device, to_device_node_name)
27
+
28
+ if not ((from_device is None and to_device is None and from_device_node_name is None
29
+ and to_device_node_name is None) or (
30
+ from_device is not None and to_device is not None and from_device_node_name is not None and
31
+ to_device_node_name is not None)):
32
+ raise ValueError(
33
+ "you have to provide all or none of the following items: `from_device`, `from_device_node_name`, "
34
+ "`to_device` or `to_device_node_name`")
35
+
36
+ # describes if the connection is uni or bidirectional
37
+ self._bidirectional = bidirectional
38
+
39
+ def __eq__(self, other: ConnectionMetadata):
40
+ return self.equal_with(other)
41
+
42
+ def __hash__(self):
43
+ all_hashes = hash(self._from_device) + hash(self._to_device) + hash(self._from_device_node_name) + \
44
+ hash(self._to_device_node_name) + hash(self._bidirectional)
45
+ return hash(all_hashes)
46
+
47
+ def __compare_with(self, other: ConnectionMetadata, allow_single_unidirectional_for_both_directions: bool) -> bool:
48
+ """
49
+ This method checks, if the metadata of this object is the metadata of the other object.
50
+
51
+ The method returns true in the following situations:
52
+ * both connections are bidirectional / the FROM and TO elements (device and node name) are the same
53
+ * both connections are bidirectional / the FROM is the TO and the TO is the FROM
54
+ * both connections are unidirectional and have the same from and to elements
55
+
56
+ If the parameter `allow_single_unidirectional_for_both_directions` is True, it additionally checks the following
57
+ situations:
58
+ * one is unidirectional / the other is bidirectional / the FROM and TO elements are the same
59
+ * one is unidirectional / the other is bidirectional / the FROM is the TO and the TO is the FROM
60
+ """
61
+ def check_same() -> bool:
62
+ return (self.from_device == other.from_device and self.from_node_name == other.from_node_name and
63
+ self.to_device == other.to_device and self.to_node_name == other.to_node_name)
64
+
65
+ def check_twisted() -> bool:
66
+ return (self.from_device == other.to_device and self.from_node_name == other.to_node_name and
67
+ self.to_device == other.from_device and self.to_node_name == other.from_node_name)
68
+
69
+ # CHECK: both connections are bidirectional / the FROM and TO elements (device and node name) are the same
70
+ # CHECK: both connections are bidirectional / the FROM is the TO and the TO is the FROM
71
+ if self.bidirectional and other.bidirectional:
72
+ return check_same() or check_twisted()
73
+ # CHECK: both connections are unidirectional and have the same from and to elements
74
+ if not self.bidirectional and not other.bidirectional:
75
+ return check_same()
76
+
77
+ if allow_single_unidirectional_for_both_directions:
78
+ # CHECK: one is unidirectional / the other is bidirectional / the FROM and TO elements are the same
79
+ # CHECK: one is unidirectional / the other is bidirectional / the FROM is the TO and the TO is the FROM
80
+ if self.bidirectional and not other.bidirectional or not self.bidirectional and other.bidirectional:
81
+ return check_same() or check_twisted()
82
+ return False
83
+
84
+ def set_from(self, from_device: Union[Type[Device], None], from_device_node_name: Union[str, None] = None):
85
+ """
86
+ This method sets the FROM device and node for this connection.
87
+
88
+ :param from_device: The FROM device of this connection.
89
+ :param from_device_node_name: The FROM node of this connection (if it should be set, otherwise None).
90
+ """
91
+ if from_device is not None and isinstance(from_device, type) and not issubclass(from_device, Device):
92
+ raise TypeError(f"detect illegal argument element {str(from_device)} for given attribute "
93
+ f"`from_device` - should be a subclasses of `balder.Device`")
94
+ self._from_device = from_device
95
+
96
+ if from_device_node_name is not None and not isinstance(from_device_node_name, str):
97
+ raise TypeError(f"detect illegal argument type {type(from_device_node_name)} for given attribute "
98
+ f"`from_device_node_name` - should be a string value")
99
+ self._from_device_node_name = from_device_node_name
100
+
101
+ def set_to(self, to_device: Union[Type[Device], None], to_device_node_name: Union[str, None] = None):
102
+ """
103
+ This method sets the TO device and node of this connection.
104
+
105
+ :param to_device: The TO device of this connection.
106
+ :param to_device_node_name: The TO node of this connection (if it should be set, otherwise None).
107
+ """
108
+ if to_device is not None and isinstance(to_device, type) and not issubclass(to_device, Device):
109
+ raise TypeError(f"detect illegal argument element {str(to_device)} for given attribute "
110
+ f"`to_device` - should be a subclasses of `balder.Device`")
111
+ self._to_device = to_device
112
+
113
+ if to_device_node_name is not None and not isinstance(to_device_node_name, str):
114
+ raise TypeError(f"detect illegal argument type {type(to_device_node_name)} for given attribute "
115
+ f"`to_device_node_name` - should be a string value")
116
+ self._to_device_node_name = to_device_node_name
117
+
118
+ def get_conn_partner_of(self, device: Type[Device], node: Union[str, None] = None) -> Tuple[Type[Device], str]:
119
+ """
120
+ This method returns the connection partner of this connection - it always returns the other not given side
121
+
122
+ :param device: the device itself - the other will be returned
123
+
124
+ :param node: the node name of the device itself (only required if the connection starts and ends with the same
125
+ device)
126
+ """
127
+ if device not in (self.from_device, self.to_device):
128
+ raise ValueError(f"the given device `{device.__qualname__}` is no component of this connection")
129
+ if node is None:
130
+ # check that the from_device and to_device are not the same
131
+ if self.from_device == self.to_device:
132
+ raise ValueError("the connection is a inner-device connection (start and end is the same device) - you "
133
+ "have to provide the `node` string too")
134
+ if device == self.from_device:
135
+ return self.to_device, self.to_node_name
136
+
137
+ return self.from_device, self.from_node_name
138
+
139
+ if node not in (self.from_node_name, self.to_node_name):
140
+ raise ValueError(f"the given node `{node}` is no component of this connection")
141
+
142
+ if device == self.from_device and node == self.from_node_name:
143
+ return self.to_device, self.to_node_name
144
+
145
+ if device == self.to_device and node == self.to_node_name:
146
+ return self.from_device, self.from_node_name
147
+
148
+ raise ValueError(f"the given node `{node}` is no component of the given device `{device.__qualname__}`")
149
+
150
+ def has_connection_from_to(
151
+ self,
152
+ start_device: Type[Device],
153
+ start_device_node_name: Union[str, None] = None,
154
+ end_device: Union[Type[Device], None] = None,
155
+ end_device_node_name: Union[str, None] = None,
156
+ ) -> bool:
157
+ """
158
+ This method checks if there is a connection from ``start_device`` to ``end_device``. This will return
159
+ true if the ``start_device`` and ``end_device`` given in this method are also the ``start_device`` and
160
+ ``end_device`` mentioned in this connection object. If this is a bidirectional connection, ``start_device`` and
161
+ ``end_device`` can switch places.
162
+
163
+
164
+ :param start_device: the device for which the method should check whether it is a communication partner (for
165
+ non-bidirectional connection, this has to be the start device)
166
+ :param start_device_node_name: the node name that start device should have or None if it should be ignored
167
+ :param end_device: the other device for which the method should check whether it is a communication partner (for
168
+ non-bidirectional connection, this has to be the end device - this is optional if only the
169
+ start device should be checked)
170
+ :param end_device_node_name: the node name that start device should have or None if it should be ignored
171
+
172
+ :return: returns true if the given direction is possible
173
+ """
174
+ if not (isinstance(start_device, type) and issubclass(start_device, Device)):
175
+ raise TypeError("argument `start_device` needs to be a device")
176
+ if not (start_device_node_name is None or isinstance(start_device_node_name, str)):
177
+ raise TypeError("argument `start_device_node_name` needs to be a string or None if it should be ignored")
178
+ if not (end_device is None or isinstance(end_device, type) and issubclass(end_device, Device)):
179
+ raise TypeError("argument `end_device` needs to be a device or None if it should be ignored")
180
+ if not (end_device_node_name is None or isinstance(end_device_node_name, str)):
181
+ raise TypeError("argument `end_device_node_name` needs to be a string or None if it should be ignored")
182
+
183
+ def check(start_dev, start_node_name, end_dev, end_node_name):
184
+ if start_device != start_dev:
185
+ return False
186
+ if start_device_node_name is not None and start_device_node_name != start_node_name:
187
+ return False
188
+ if end_device is not None and end_device != end_dev:
189
+ return False
190
+ if end_device_node_name is not None and end_device_node_name != end_node_name:
191
+ return False
192
+ return True
193
+
194
+ if self.bidirectional:
195
+ if check(start_dev=self.to_device, start_node_name=self.to_node_name,
196
+ end_dev=self.from_device, end_node_name=self.from_node_name):
197
+ return True
198
+ return check(start_dev=self.from_device, start_node_name=self.from_node_name,
199
+ end_dev=self.to_device, end_node_name=self.to_node_name)
200
+
201
+ def equal_with(self, other: ConnectionMetadata) -> bool:
202
+ """
203
+ This method returns true if the metadata of the current connection is equal with the metadata of the given
204
+ connection.
205
+
206
+ The method returns true in the following situations:
207
+ * both connections are bidirectional and the from and to elements (device and node name) are the same
208
+ * both connections are unidirectional and have the same from and to elements
209
+ * both connections are bidirectional and the from is the to and the to is the from
210
+
211
+ :return: true if the metadata of the current connection is contained in the metadata of the given one
212
+ """
213
+ return self.__compare_with(other, allow_single_unidirectional_for_both_directions=False)
214
+
215
+ def contained_in(self, other: ConnectionMetadata) -> bool:
216
+ """
217
+ This method returns true if the metadata of the current connection is contained in the given one.
218
+
219
+ The method returns true in the following situations:
220
+ * both connections are bidirectional and the from and to elements (device and node name) are the same
221
+ * both connections are unidirectional and have the same from and to elements
222
+ * both connections are bidirectional and the from is the to and the to is the from
223
+ * one connection is unidirectional and the other is bidirectional and the from and to elements are the same
224
+ * one connection is unidirectional and the other is bidirectional and the from is the to and the to is the from
225
+
226
+ :return: true if the metadata of the current connection is contained in the metadata of the given one
227
+ """
228
+ return self.__compare_with(other, allow_single_unidirectional_for_both_directions=True)
229
+
230
+ @property
231
+ def from_device(self):
232
+ """device from which the connection starts"""
233
+ return self._from_device
234
+
235
+ @property
236
+ def to_device(self):
237
+ """device at which the connection ends"""
238
+ return self._to_device
239
+
240
+ @property
241
+ def from_node_name(self):
242
+ """the name of the node in the `Device` from which the connection starts"""
243
+ return self._from_device_node_name
244
+
245
+ @property
246
+ def to_node_name(self):
247
+ """the name of the node in the `Device` at which the connection ends"""
248
+ return self._to_device_node_name
249
+
250
+ @property
251
+ def bidirectional(self) -> bool:
252
+ """
253
+ returns true if the connection is bidirectional (can go in both directions) otherwise false
254
+ """
255
+ return self._bidirectional
File without changes
@@ -0,0 +1,58 @@
1
+ from __future__ import annotations
2
+
3
+ import pathlib
4
+ import sys
5
+ import traceback
6
+ from typing import Callable, Optional, Union, List
7
+ from _balder.exit_code import ExitCode
8
+ from _balder.testresult import ResultState
9
+ from _balder.exceptions import BalderException
10
+ from _balder.balder_session import BalderSession
11
+
12
+
13
+ def console_balder(cmd_args: Optional[List[str]] = None, working_dir: Union[str, pathlib.Path, None] = None):
14
+ """script that executes a balder session"""
15
+ _console_balder_debug(cmd_args=cmd_args, working_dir=working_dir)
16
+
17
+
18
+ # pylint: disable-next=too-many-arguments
19
+ def _console_balder_debug(cmd_args: Optional[List[str]] = None, working_dir: Union[str, pathlib.Path, None] = None,
20
+ cb_session_created: Optional[Callable] = None, cb_run_finished: Optional[Callable] = None,
21
+ cb_balder_exc: Optional[Callable] = None, cb_unexpected_exc: Optional[Callable] = None):
22
+ """helper balder execution that allows more debug access"""
23
+ try:
24
+ balder_session = BalderSession(cmd_args=cmd_args, working_dir=working_dir)
25
+
26
+ if cb_session_created:
27
+ cb_session_created(balder_session)
28
+
29
+ balder_session.run()
30
+
31
+ if cb_run_finished:
32
+ cb_run_finished(balder_session)
33
+
34
+ if balder_session.executor_tree is None:
35
+ sys.exit(ExitCode.SUCCESS.value)
36
+ elif balder_session.executor_tree.executor_result == ResultState.SUCCESS:
37
+ sys.exit(ExitCode.SUCCESS.value)
38
+ elif balder_session.executor_tree.executor_result in [ResultState.ERROR, ResultState.FAILURE]:
39
+ # check if a BalderException was thrown too -> would be a balder environment error -> special exit code
40
+ balder_exceptions = [cur_exc for cur_exc in balder_session.executor_tree.get_all_recognized_exception()
41
+ if isinstance(cur_exc, BalderException)]
42
+ if len(balder_exceptions) > 0:
43
+ sys.exit(ExitCode.BALDER_USAGE_ERROR.value)
44
+ else:
45
+ sys.exit(ExitCode.TESTS_FAILED.value)
46
+
47
+ except BalderException as exc:
48
+ # a balder usage error occurs
49
+ if cb_balder_exc:
50
+ cb_balder_exc(exc)
51
+ traceback.print_exception(*sys.exc_info())
52
+ sys.exit(ExitCode.BALDER_USAGE_ERROR.value)
53
+ except Exception as exc: # pylint: disable=broad-exception-caught
54
+ # a unexpected error occurs
55
+ if cb_unexpected_exc:
56
+ cb_unexpected_exc(exc)
57
+ traceback.print_exception(*sys.exc_info())
58
+ sys.exit(ExitCode.UNEXPECTED_ERROR.value)
@@ -0,0 +1,12 @@
1
+ from _balder.controllers.controller import Controller
2
+
3
+ from _balder.controllers.base_device_controller import BaseDeviceController
4
+ from _balder.controllers.device_controller import DeviceController
5
+
6
+ from _balder.controllers.vdevice_controller import VDeviceController
7
+
8
+ from _balder.controllers.normal_scenario_setup_controller import NormalScenarioSetupController
9
+ from _balder.controllers.scenario_controller import ScenarioController
10
+ from _balder.controllers.setup_controller import SetupController
11
+
12
+ from _balder.controllers.feature_controller import FeatureController
@@ -0,0 +1,72 @@
1
+ from __future__ import annotations
2
+ from typing import Dict, Type, Union, TYPE_CHECKING
3
+
4
+ import logging
5
+ import inspect
6
+ from abc import ABC, abstractmethod
7
+ from _balder.controllers.controller import Controller
8
+ from _balder.feature import Feature
9
+
10
+ if TYPE_CHECKING:
11
+ from _balder.scenario import Scenario
12
+ from _balder.setup import Setup
13
+
14
+ logger = logging.getLogger(__file__)
15
+
16
+
17
+ class BaseDeviceController(Controller, ABC):
18
+ """
19
+ This is the abstract controller class for :class:`Device` items.
20
+ """
21
+ def __init__(self):
22
+
23
+ #: contains the original instantiated objects for the related device class (will be automatically set by
24
+ #: :class:`Collector`)
25
+ self._original_instanced_features: Union[Dict[str, Feature], None] = {}
26
+
27
+ # ---------------------------------- STATIC METHODS ----------------------------------------------------------------
28
+
29
+ # ---------------------------------- CLASS METHODS -----------------------------------------------------------------
30
+
31
+ # ---------------------------------- PROPERTIES --------------------------------------------------------------------
32
+
33
+ # ---------------------------------- PROTECTED METHODS -------------------------------------------------------------
34
+
35
+ # ---------------------------------- METHODS -----------------------------------------------------------------------
36
+
37
+ @abstractmethod
38
+ def get_outer_class(self) -> Union[Type[Scenario], Type[Setup], None]:
39
+ """
40
+ This method delivers the outer class of this device. This has to be a :meth:`Setup` or a :meth:`Scenario`.
41
+ """
42
+
43
+ def get_all_instantiated_feature_objects(self) -> Dict[str, Feature]:
44
+ """
45
+ This method returns all instantiated :meth:`Feature` classes that were defined as static attributes within the
46
+ related device.
47
+
48
+ :return: supplies a dictionary with the name of the attribute as key and the current feature class as value
49
+ """
50
+
51
+ results = {}
52
+ for cur_attr_name, cur_elem in inspect.getmembers(self.related_cls, lambda elem: isinstance(elem, Feature)):
53
+ results[cur_attr_name] = cur_elem
54
+ return results
55
+
56
+ def get_original_instanced_feature_objects(self) -> Dict[str, Feature]:
57
+ """
58
+ This method returns the original instanced feature objects of the related device
59
+ """
60
+ if self._original_instanced_features is None:
61
+ raise RuntimeError('can not access the original instantiated features before they were set with '
62
+ '`save_all_original_instanced_features`')
63
+ return self._original_instanced_features
64
+
65
+ def save_all_original_instanced_features(self):
66
+ """
67
+ This property sets the internal dictionary about the original instantiated features of this
68
+ :class:`Device`/:class:`VDevice`. This is done, to ensure that balder has saved an original copy of the original
69
+ instantiated abstract features. The real features will be overwritten for each new variation by the
70
+ :class:`ExecutorTree`!
71
+ """
72
+ self._original_instanced_features = self.get_all_instantiated_feature_objects()
@@ -0,0 +1,29 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from abc import ABC, abstractmethod
5
+
6
+ logger = logging.getLogger(__file__)
7
+
8
+
9
+ class Controller(ABC):
10
+ """
11
+ This is the base controller class. It serves as a base class for all other specialized controllers.
12
+
13
+ A controller is used to manage the behavior internally.
14
+ """
15
+
16
+ @staticmethod
17
+ @abstractmethod
18
+ def get_for(related_cls):
19
+ """
20
+ This class returns the current existing controller instance for the given item. If the instance does not exist
21
+ yet, it will automatically create it and saves the instance in an internal dictionary.
22
+ """
23
+
24
+ @property
25
+ @abstractmethod
26
+ def related_cls(self):
27
+ """
28
+ This method returns the related class that belongs to that controller.
29
+ """