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
_balder/exceptions.py ADDED
@@ -0,0 +1,182 @@
1
+ from __future__ import annotations
2
+
3
+
4
+ class BalderException(Exception):
5
+ """basic balder exception"""
6
+
7
+
8
+ class BalderWarning(Warning):
9
+ """basic balder warning"""
10
+
11
+
12
+ class FixtureScopeError(BalderException):
13
+ """is thrown for fixtures that were defined in an illegal scope"""
14
+
15
+
16
+ class FixtureReferenceError(BalderException):
17
+ """
18
+ is thrown when an error is detected in the reference between fixtures
19
+ """
20
+
21
+
22
+ class UnclearSetupScopedFixtureReference(BalderException):
23
+ """
24
+ is thrown for the special UNCLEAR SETUP SCOPED FIXTURE REFERENCE error
25
+ """
26
+
27
+
28
+ class UnclearUniqueClassReference(BalderException):
29
+ """
30
+ is thrown after balder can not clearly determine the related instance reference for a :class:`Scenario` or
31
+ :class:`Setup` class
32
+ """
33
+
34
+
35
+ class LostInExecutorTreeException(BalderException):
36
+ """
37
+ is thrown if you make a wrong call when entering and leaving the fixture manager, and you got lost
38
+ """
39
+
40
+
41
+ class DeviceResolvingException(BalderException):
42
+ """
43
+ is thrown if an error occurs while resolving a device string
44
+ """
45
+
46
+
47
+ class NodeNotExistsError(BalderException):
48
+ """
49
+ is thrown if no connection node exists for a device
50
+ """
51
+
52
+
53
+ class DuplicateForVDeviceError(BalderException):
54
+ """
55
+ is thrown if some illegal `@for_vdevice` decorator exists for a feature
56
+ """
57
+
58
+
59
+ class DuplicateBalderSettingError(BalderException):
60
+ """
61
+ is thrown if balder can not determine the BalderSettings object clearly.
62
+ """
63
+
64
+
65
+ class VDeviceOverwritingError(BalderException):
66
+ """
67
+ is thrown if the device is not overwritten correctly
68
+ """
69
+
70
+
71
+ class AccessToUnmappedVDeviceException(BalderException):
72
+ """
73
+ is thrown if an unmapped vdevice is accessed
74
+ """
75
+
76
+
77
+ class DeviceOverwritingError(BalderException):
78
+ """
79
+ is thrown if the device is not overwritten correctly
80
+ """
81
+
82
+
83
+ class FeatureOverwritingError(BalderException):
84
+ """
85
+ is thrown if an inner instantiated feature is not overwritten correctly
86
+ """
87
+
88
+
89
+ class UnknownVDeviceException(BalderException):
90
+ """
91
+ is thrown if some not allowed vDevices are given in a :meth:`Feature`
92
+ """
93
+
94
+
95
+ class RoutingBrokenChainError(BalderException):
96
+ """
97
+ is thrown if the routing determines a broken pipe
98
+ """
99
+
100
+
101
+ class IllegalConnectionTypeError(BalderException):
102
+ """
103
+ is thrown if the connection is illegal
104
+ """
105
+
106
+
107
+ class ConnectionMetadataConflictError(BalderException):
108
+ """
109
+ is thrown if here is an illegal conflict between some metadata
110
+ """
111
+
112
+
113
+ class DeviceScopeError(BalderException):
114
+ """
115
+ is thrown if the device class is placed on an illegal scope
116
+ """
117
+
118
+
119
+ class ConnectionIntersectionError(BalderException):
120
+ """
121
+ is thrown if the intersection connection between two devices is reduced in a way that no intersection exists anymore
122
+ """
123
+
124
+
125
+ class UnclearAssignableFeatureConnectionError(BalderException):
126
+ """
127
+ is thrown if two devices have parallel connections and a used feature could use both or more at the same time
128
+ """
129
+
130
+
131
+ class InheritanceError(BalderException):
132
+ """
133
+ is thrown if a class inheritance is not allowed for the mentioned class
134
+ """
135
+
136
+
137
+ class MultiInheritanceError(BalderException):
138
+ """
139
+ is thrown if multi inheritance was used where it is not allowed
140
+ """
141
+
142
+
143
+ class InnerFeatureResolvingError(BalderException):
144
+ """
145
+ is thrown if an inner feature reference can not be resolved with the instantiated features of the device
146
+ """
147
+
148
+
149
+ class VDeviceResolvingError(BalderException):
150
+ """
151
+ is thrown if there is an error while resolving VDevice's.
152
+ """
153
+
154
+
155
+ class IllegalVDeviceMappingError(BalderException):
156
+ """
157
+ is thrown if there is an error while resolving vDevice mappings.
158
+ """
159
+
160
+
161
+ class MissingFeaturesOfVDeviceError(BalderException):
162
+ """
163
+ is thrown if the related device does not implement all features specified in its mapped VDevice.
164
+ """
165
+
166
+
167
+ class NotApplicableVariationException(BalderException):
168
+ """
169
+ is thrown internally after the current variation is not applicable
170
+ """
171
+
172
+
173
+ class UnclearMethodVariationError(BalderException):
174
+ """
175
+ is thrown if there are more than one possible method variations possible
176
+ """
177
+
178
+
179
+ class UnexpectedPluginMethodReturnValue(BalderException):
180
+ """
181
+ is thrown if a user plugin doesn't return something or returns wrong values in its plugin method
182
+ """
File without changes
@@ -0,0 +1,133 @@
1
+ from __future__ import annotations
2
+
3
+ import time
4
+ from typing import TYPE_CHECKING
5
+
6
+ import sys
7
+
8
+ import traceback
9
+ from abc import ABC, abstractmethod
10
+
11
+ from _balder.executor.basic_executor import BasicExecutor
12
+ from _balder.testresult import ResultState
13
+
14
+ if TYPE_CHECKING:
15
+ from _balder.fixture_execution_level import FixtureExecutionLevel
16
+ from _balder.fixture_manager import FixtureManager
17
+
18
+
19
+ class BasicExecutableExecutor(BasicExecutor, ABC):
20
+ """
21
+ The BasicExecutor class is an abstract class that represents the parent class of all executors. Together with other
22
+ executor classes, an executor forms a tree structure in which individual tests, which later on are executed, are
23
+ assigned to individual scenarios
24
+ """
25
+ fixture_execution_level: FixtureExecutionLevel = None
26
+
27
+ def __init__(self):
28
+ super().__init__()
29
+
30
+ # holds the execution time of this branch (with branch fixtures)
31
+ self.execution_time_sec = None
32
+
33
+ # ---------------------------------- STATIC METHODS ----------------------------------------------------------------
34
+
35
+ # ---------------------------------- CLASS METHODS ----------------------------------------------------------------
36
+
37
+ # ---------------------------------- PROPERTIES --------------------------------------------------------------------
38
+
39
+ @property
40
+ @abstractmethod
41
+ def fixture_manager(self) -> FixtureManager:
42
+ """returns the active fixture manager instance"""
43
+
44
+ # ---------------------------------- PROTECTED METHODS -------------------------------------------------------------
45
+
46
+ @abstractmethod
47
+ def _prepare_execution(self, show_discarded):
48
+ """
49
+ This method runs before the branch will be executed and before the fixture construction code of this branch
50
+ runs.
51
+ """
52
+
53
+ @abstractmethod
54
+ def _body_execution(self, show_discarded):
55
+ """
56
+ This method runs between the fixture construction and teardown code. It should trigger the execution of the
57
+ child branches.
58
+ """
59
+
60
+ @abstractmethod
61
+ def _cleanup_execution(self, show_discarded):
62
+ """
63
+ This method runs after the branch was executed (also after the fixture teardown code ran)
64
+ """
65
+
66
+ # ---------------------------------- METHODS -----------------------------------------------------------------------
67
+
68
+ def set_result_for_whole_branch(self, value: ResultState):
69
+ """
70
+ This method sets the executor result for all sub executors.
71
+
72
+ :param value: the new value that should be set for this branch
73
+ """
74
+ if value not in (ResultState.SKIP, ResultState.COVERED_BY, ResultState.NOT_RUN):
75
+ raise ValueError("can not set a state that is not NOT_RUN, SKIP or COVERED_BY for a whole branch")
76
+ if self.all_child_executors is None:
77
+ self.body_result.set_result(result=value, exception=None)
78
+ else:
79
+ for cur_child_executor in self.all_child_executors:
80
+ cur_child_executor.set_result_for_whole_branch(value)
81
+
82
+ @abstractmethod
83
+ def cleanup_empty_executor_branches(self, consider_discarded=False):
84
+ """
85
+ This method searches the whole tree and removes branches where an executor item has no own children. It can
86
+ remove these branches, because they have no valid matchings.
87
+
88
+ :param consider_discarded: true if this method should consider discarded branches, otherwise False
89
+ """
90
+
91
+ def filter_tree_for_user_filters(self):
92
+ """
93
+ This method calls all user defined filters that are to be applied to the executor tree.
94
+ """
95
+ if self.all_child_executors:
96
+ for cur_child_executor in self.all_child_executors:
97
+ cur_child_executor.filter_tree_for_user_filters()
98
+
99
+ def execute(self, show_discarded=False):
100
+ """
101
+ Executes the whole branch
102
+ """
103
+ start_time = time.perf_counter()
104
+ self._prepare_execution(show_discarded=show_discarded)
105
+
106
+ try:
107
+ try:
108
+ if self.has_runnable_tests():
109
+ self.fixture_manager.enter(self)
110
+ self.construct_result.set_result(ResultState.SUCCESS)
111
+ else:
112
+ self.construct_result.set_result(ResultState.NOT_RUN)
113
+
114
+ self._body_execution(show_discarded=show_discarded)
115
+ except Exception as exc: # pylint: disable=broad-exception-caught
116
+ # this has to be a construction fixture error
117
+ traceback.print_exception(*sys.exc_info())
118
+ self.construct_result.set_result(ResultState.ERROR, exc)
119
+ finally:
120
+ if self.has_runnable_tests():
121
+ if self.fixture_manager.is_allowed_to_leave(self):
122
+ self.fixture_manager.leave(self)
123
+ self.teardown_result.set_result(ResultState.SUCCESS)
124
+ else:
125
+ self.teardown_result.set_result(ResultState.NOT_RUN)
126
+ except Exception as exc: # pylint: disable=broad-exception-caught
127
+ # this has to be a teardown fixture error
128
+ traceback.print_exception(*sys.exc_info())
129
+ self.teardown_result.set_result(ResultState.ERROR, exc)
130
+
131
+ self._cleanup_execution(show_discarded=show_discarded)
132
+
133
+ self.execution_time_sec = time.perf_counter() - start_time
@@ -0,0 +1,205 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import List, Union, Type, TYPE_CHECKING
4
+
5
+ import types
6
+ from abc import ABC, abstractmethod
7
+ from _balder.previous_executor_mark import PreviousExecutorMark
8
+ from _balder.testresult import FixturePartResult, ResultState, ResultSummary, TestcaseResult
9
+
10
+ if TYPE_CHECKING:
11
+ from _balder.setup import Setup
12
+ from _balder.scenario import Scenario
13
+
14
+
15
+ class BasicExecutor(ABC):
16
+ """
17
+ The BasicExecutor class is an abstract class that represents the parent class of all executors. Together with other
18
+ executor classes, an executor forms a tree structure in which individual tests, which later on are executed, are
19
+ assigned to individual scenarios
20
+ """
21
+ # this property describes the runnable state of the executor branch before the executor is really used
22
+ # with this you can declare a whole branch as inactive, while the collecting process is active
23
+ prev_mark = PreviousExecutorMark.RUNNABLE
24
+
25
+ def __init__(self):
26
+ # contains the result object for the CONSTRUCT FIXTURE part of this branch
27
+ self.construct_result = FixturePartResult(self)
28
+ # contains the result object for the BODY part of this branch (will be defined in subclasses)
29
+ self.body_result = None
30
+ # contains the result object for the TEARDOWN FIXTURE part of this branch
31
+ self.teardown_result = FixturePartResult(self)
32
+
33
+ # ---------------------------------- STATIC METHODS ----------------------------------------------------------------
34
+
35
+ # ---------------------------------- CLASS METHODS ----------------------------------------------------------------
36
+
37
+ # ---------------------------------- PROPERTIES --------------------------------------------------------------------
38
+
39
+ @property
40
+ @abstractmethod
41
+ def all_child_executors(self) -> list[BasicExecutor] | None:
42
+ """
43
+ returns all child executors of this object or None if no child executors can exist (this element is a leaf)
44
+ """
45
+
46
+ @property
47
+ @abstractmethod
48
+ def parent_executor(self) -> BasicExecutor:
49
+ """returns the parent executor of this element"""
50
+
51
+ @property
52
+ @abstractmethod
53
+ def base_instance(self) -> object:
54
+ """returns the base class instance to which this executor instance belongs or None if this element is a
55
+ ExecutorTree"""
56
+
57
+ @property
58
+ def executor_result(self) -> ResultState:
59
+ """
60
+ This property returns the combined state of this executor object. This is determined by its properties
61
+ ``construct_result``, ``body_result`` and ``teardown_result``.
62
+ """
63
+ relative_result = ResultState.NOT_RUN
64
+ priority_order = ResultState.priority_order()
65
+
66
+ if priority_order.index(self.construct_result.result) < priority_order.index(relative_result):
67
+ relative_result = self.construct_result.result
68
+ if priority_order.index(self.body_result.result) < priority_order.index(relative_result):
69
+ relative_result = self.body_result.result
70
+ if priority_order.index(self.teardown_result.result) < priority_order.index(relative_result):
71
+ relative_result = self.teardown_result.result
72
+ return relative_result
73
+
74
+ # ---------------------------------- PROTECTED METHODS -------------------------------------------------------------
75
+
76
+ # ---------------------------------- METHODS -----------------------------------------------------------------------
77
+
78
+ def get_all_recognized_exception(self) -> List[Exception]:
79
+ """
80
+ This method returns all occurred Exception of this branch.
81
+
82
+ :return: a list with all occurred and recorded exceptions
83
+ """
84
+ all_own = [self.construct_result.exception, self.body_result.exception, self.teardown_result.exception]
85
+ if self.all_child_executors:
86
+ for cur_child_executor in self.all_child_executors:
87
+ all_own += cur_child_executor.get_all_recognized_exception()
88
+
89
+ # filter all duplicated entries
90
+ all_own = list(set(all_own))
91
+ if None in all_own:
92
+ all_own.remove(None)
93
+ return all_own
94
+
95
+ def has_runnable_tests(self, consider_discarded_too=False) -> bool:
96
+ """
97
+ This method returns true if this executor element is runnable. The method returns true if this element has
98
+ `prev_mark=RUNNABLE` and minimum one of its children has `prev_mark=RUNNABLE` too.
99
+
100
+ :param consider_discarded_too: True if the method allows DISCARDED elements too
101
+ """
102
+ allowed_prev_marks = [PreviousExecutorMark.RUNNABLE]
103
+
104
+ if consider_discarded_too:
105
+ allowed_prev_marks.append(PreviousExecutorMark.DISCARDED)
106
+
107
+ if self.prev_mark not in allowed_prev_marks:
108
+ return False
109
+
110
+ if self.all_child_executors is not None:
111
+ # the executor has child executors -> check them
112
+ for cur_child in self.all_child_executors:
113
+ if cur_child.has_runnable_tests(consider_discarded_too):
114
+ return True
115
+ return False
116
+ return True
117
+
118
+ def has_skipped_tests(self) -> bool:
119
+ """
120
+ This method returns true if this executor element has at least one test that is marked to be skipped. The method
121
+ returns true if minimum one of its children has `prev_mark=SKIP`.
122
+ """
123
+ if self.all_child_executors is not None:
124
+ # the executor has child executors -> check them
125
+ for cur_child in self.all_child_executors:
126
+ if cur_child.has_skipped_tests():
127
+ return True
128
+ return False
129
+ return False
130
+
131
+ def has_covered_by_tests(self) -> bool:
132
+ """
133
+ This method returns true if this executor element has at least one test that is marked as covered-by. The method
134
+ returns true if minimum one of its children has `prev_mark=COVERED_BY`.
135
+ """
136
+ if self.all_child_executors is not None:
137
+ # the executor has child executors -> check them
138
+ for cur_child in self.all_child_executors:
139
+ if cur_child.has_covered_by_tests():
140
+ return True
141
+ return False
142
+ return False
143
+
144
+ def get_all_base_instances_of_this_branch(
145
+ self, with_type: Union[Type[Setup], Type[Scenario], Type[types.FunctionType]],
146
+ only_runnable_elements: bool = True) -> List[Union[Setup, Scenario, object]]:
147
+ """
148
+ This method returns a list of all base instance elements that are from given type `with_type`. If `with_type`
149
+ is a base type of this branch element, the method always returns a list with one element. If the base instance
150
+ element is a child of the current branch, it could be a list with zero to infinite elements.
151
+
152
+ .. note::
153
+ The method only returns unique objects.
154
+ """
155
+ # search all higher classes and this one (if there is a match, return value is a list with exactly one element)
156
+ cur_executor = self
157
+ # only go through cur_executor == ExecutorTree (do not iterate with this object)
158
+ while cur_executor.parent_executor is not None:
159
+ if isinstance(cur_executor.base_instance, with_type):
160
+ if not only_runnable_elements or cur_executor.has_runnable_tests():
161
+ return [cur_executor.base_instance]
162
+ cur_executor = cur_executor.parent_executor
163
+
164
+ # go in the branch and search in all children (recursively)
165
+ result = []
166
+ # if there are no child executors -> we do not need to search in children because there are no children
167
+ if self.all_child_executors is not None:
168
+ for cur_child_executor in self.all_child_executors:
169
+ child_result = cur_child_executor.get_all_base_instances_of_this_branch(
170
+ with_type=with_type, only_runnable_elements=only_runnable_elements)
171
+ result += child_result
172
+ # remove duplicate items
173
+ return list(set(result))
174
+
175
+ @abstractmethod
176
+ def cleanup_empty_executor_branches(self, consider_discarded=False):
177
+ """
178
+ This method searches the whole tree and removes branches where an executor item has no own children. It can
179
+ remove these branches, because they have no valid matchings.
180
+
181
+ :param consider_discarded: true if this method should consider discarded branches, otherwise False
182
+ """
183
+
184
+ def filter_tree_for_user_filters(self):
185
+ """
186
+ This method calls all user defined filters that are to be applied to the executor tree.
187
+ """
188
+ if self.all_child_executors:
189
+ for cur_child_executor in self.all_child_executors:
190
+ cur_child_executor.filter_tree_for_user_filters()
191
+
192
+ def testsummary(self) -> ResultSummary:
193
+ """
194
+ returns a dictionary with all possible :class:`ResultState` as keys and the number of times they have occurred
195
+ in this branch as values
196
+ """
197
+
198
+ summary = ResultSummary()
199
+
200
+ if isinstance(self.body_result, TestcaseResult):
201
+ setattr(summary, self.executor_result.value, 1)
202
+ elif self.all_child_executors:
203
+ for cur_child_exec in self.all_child_executors:
204
+ summary += cur_child_exec.testsummary()
205
+ return summary