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/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
|