baldertest 0.1.0b9__py3-none-any.whl → 0.1.0b11__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/_version.py +1 -1
- _balder/balder_session.py +4 -2
- _balder/cnnrelations/__init__.py +7 -0
- _balder/cnnrelations/and_connection_relation.py +149 -0
- _balder/cnnrelations/base_connection_relation.py +270 -0
- _balder/cnnrelations/or_connection_relation.py +65 -0
- _balder/collector.py +116 -14
- _balder/connection.py +400 -881
- _balder/connection_metadata.py +255 -0
- _balder/console/balder.py +1 -1
- _balder/controllers/device_controller.py +26 -12
- _balder/controllers/feature_controller.py +63 -99
- _balder/controllers/normal_scenario_setup_controller.py +7 -7
- _balder/controllers/scenario_controller.py +97 -7
- _balder/controllers/setup_controller.py +2 -3
- _balder/decorator_connect.py +12 -10
- _balder/decorator_fixture.py +4 -7
- _balder/decorator_for_vdevice.py +21 -31
- _balder/decorator_gateway.py +3 -3
- _balder/decorator_parametrize.py +31 -0
- _balder/decorator_parametrize_by_feature.py +36 -0
- _balder/exceptions.py +6 -0
- _balder/executor/basic_executable_executor.py +126 -0
- _balder/executor/basic_executor.py +1 -78
- _balder/executor/executor_tree.py +7 -5
- _balder/executor/parametrized_testcase_executor.py +52 -0
- _balder/executor/scenario_executor.py +5 -2
- _balder/executor/setup_executor.py +5 -2
- _balder/executor/testcase_executor.py +41 -9
- _balder/executor/unresolved_parametrized_testcase_executor.py +209 -0
- _balder/executor/variation_executor.py +148 -123
- _balder/feature.py +1 -1
- _balder/fixture_definition_scope.py +19 -0
- _balder/fixture_execution_level.py +22 -0
- _balder/fixture_manager.py +170 -182
- _balder/fixture_metadata.py +26 -0
- _balder/objects/connections/osi_3_network.py +2 -2
- _balder/objects/connections/osi_4_transport.py +2 -2
- _balder/parametrization.py +75 -0
- _balder/routing_path.py +18 -25
- _balder/solver.py +52 -32
- _balder/testresult.py +1 -1
- _balder/utils.py +27 -1
- balder/__init__.py +6 -0
- balder/exceptions.py +4 -3
- balder/parametrization.py +8 -0
- {baldertest-0.1.0b9.dist-info → baldertest-0.1.0b11.dist-info}/METADATA +2 -2
- baldertest-0.1.0b11.dist-info/RECORD +83 -0
- {baldertest-0.1.0b9.dist-info → baldertest-0.1.0b11.dist-info}/WHEEL +1 -1
- baldertest-0.1.0b9.dist-info/RECORD +0 -68
- {baldertest-0.1.0b9.dist-info → baldertest-0.1.0b11.dist-info}/LICENSE +0 -0
- {baldertest-0.1.0b9.dist-info → baldertest-0.1.0b11.dist-info}/entry_points.txt +0 -0
- {baldertest-0.1.0b9.dist-info → baldertest-0.1.0b11.dist-info}/top_level.txt +0 -0
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import itertools
|
|
2
4
|
from typing import Type, Union, List, Dict, Tuple, TYPE_CHECKING
|
|
3
5
|
|
|
4
6
|
import inspect
|
|
5
7
|
import logging
|
|
8
|
+
from _balder.cnnrelations import OrConnectionRelation
|
|
6
9
|
from _balder.device import Device
|
|
7
10
|
from _balder.connection import Connection
|
|
11
|
+
from _balder.fixture_execution_level import FixtureExecutionLevel
|
|
8
12
|
from _balder.testresult import ResultState, BranchBodyResult, ResultSummary
|
|
9
|
-
from _balder.executor.
|
|
13
|
+
from _balder.executor.basic_executable_executor import BasicExecutableExecutor
|
|
10
14
|
from _balder.executor.testcase_executor import TestcaseExecutor
|
|
15
|
+
from _balder.executor.unresolved_parametrized_testcase_executor import UnresolvedParametrizedTestcaseExecutor
|
|
11
16
|
from _balder.previous_executor_mark import PreviousExecutorMark
|
|
12
17
|
from _balder.routing_path import RoutingPath
|
|
13
18
|
from _balder.unmapped_vdevice import UnmappedVDevice
|
|
@@ -19,6 +24,8 @@ if TYPE_CHECKING:
|
|
|
19
24
|
from _balder.feature import Feature
|
|
20
25
|
from _balder.scenario import Scenario
|
|
21
26
|
from _balder.vdevice import VDevice
|
|
27
|
+
from _balder.controllers.scenario_controller import ScenarioController
|
|
28
|
+
from _balder.controllers.setup_controller import SetupController
|
|
22
29
|
from _balder.executor.scenario_executor import ScenarioExecutor
|
|
23
30
|
from _balder.fixture_manager import FixtureManager
|
|
24
31
|
|
|
@@ -26,10 +33,11 @@ if TYPE_CHECKING:
|
|
|
26
33
|
logger = logging.getLogger(__file__)
|
|
27
34
|
|
|
28
35
|
|
|
29
|
-
class VariationExecutor(
|
|
36
|
+
class VariationExecutor(BasicExecutableExecutor):
|
|
30
37
|
"""
|
|
31
38
|
A VariationExecutor only contains :meth:`TestcaseExecutor` children.
|
|
32
39
|
"""
|
|
40
|
+
fixture_execution_level = FixtureExecutionLevel.VARIATION
|
|
33
41
|
|
|
34
42
|
def __init__(self, device_mapping: Dict[Type[Device], Type[Device]], parent: ScenarioExecutor):
|
|
35
43
|
super().__init__()
|
|
@@ -93,11 +101,25 @@ class VariationExecutor(BasicExecutor):
|
|
|
93
101
|
"""property returns the current :class:`Scenario` for this variation"""
|
|
94
102
|
return self._parent_executor.base_scenario_class
|
|
95
103
|
|
|
104
|
+
@property
|
|
105
|
+
def cur_scenario_controller(self) -> ScenarioController:
|
|
106
|
+
"""
|
|
107
|
+
returns the current :class:`ScenarioController` for this variation
|
|
108
|
+
"""
|
|
109
|
+
return self._parent_executor.base_scenario_controller
|
|
110
|
+
|
|
96
111
|
@property
|
|
97
112
|
def cur_setup_class(self) -> Setup:
|
|
98
113
|
"""property returns the current :class:`Setup` for this variation"""
|
|
99
114
|
return self._parent_executor.parent_executor.base_setup_class
|
|
100
115
|
|
|
116
|
+
@property
|
|
117
|
+
def cur_setup_controller(self) -> SetupController:
|
|
118
|
+
"""
|
|
119
|
+
returns the current :class:`SetupController` for this variation
|
|
120
|
+
"""
|
|
121
|
+
return self._parent_executor.parent_executor.base_setup_controller
|
|
122
|
+
|
|
101
123
|
@property
|
|
102
124
|
def base_device_mapping(self) -> Dict[Type[Device], Type[Device]]:
|
|
103
125
|
"""
|
|
@@ -107,7 +129,7 @@ class VariationExecutor(BasicExecutor):
|
|
|
107
129
|
return self._base_device_mapping
|
|
108
130
|
|
|
109
131
|
@property
|
|
110
|
-
def all_child_executors(self) -> List[TestcaseExecutor]:
|
|
132
|
+
def all_child_executors(self) -> List[TestcaseExecutor | UnresolvedParametrizedTestcaseExecutor]:
|
|
111
133
|
return self._testcase_executors
|
|
112
134
|
|
|
113
135
|
@property
|
|
@@ -153,6 +175,7 @@ class VariationExecutor(BasicExecutor):
|
|
|
153
175
|
self.exchange_unmapped_vdevice_references()
|
|
154
176
|
self.update_vdevice_referenced_feature_instances()
|
|
155
177
|
self.set_conn_dependent_methods()
|
|
178
|
+
self.resolve_possible_parametrization()
|
|
156
179
|
|
|
157
180
|
def _body_execution(self, show_discarded):
|
|
158
181
|
if show_discarded and not self.can_be_applied():
|
|
@@ -280,6 +303,39 @@ class VariationExecutor(BasicExecutor):
|
|
|
280
303
|
f'can not find a valid routing on setup level for the connection `{scenario_cnn.get_tree_str()}` '
|
|
281
304
|
f'between scenario devices `{scenario_cnn.from_device}` and `{scenario_cnn.to_device}`')
|
|
282
305
|
|
|
306
|
+
def _get_matching_setup_features_for(
|
|
307
|
+
self,
|
|
308
|
+
scenario_feature_obj: Feature,
|
|
309
|
+
in_setup_device: Type[Device]
|
|
310
|
+
) -> List[Feature]:
|
|
311
|
+
"""
|
|
312
|
+
Helper method that returns all matching setup features for the provided scenario feature in the provided setup
|
|
313
|
+
device.
|
|
314
|
+
"""
|
|
315
|
+
cur_setup_features = DeviceController.get_for(in_setup_device).get_all_instantiated_feature_objects()
|
|
316
|
+
|
|
317
|
+
replacing_feature_candidates = [
|
|
318
|
+
cur_setup_feature for cur_setup_feature in cur_setup_features.values()
|
|
319
|
+
if isinstance(cur_setup_feature, scenario_feature_obj.__class__)
|
|
320
|
+
]
|
|
321
|
+
active_scenario_vdev, mapped_scenario_dev = scenario_feature_obj.active_vdevice_device_mapping
|
|
322
|
+
|
|
323
|
+
replacing_features = replacing_feature_candidates.copy()
|
|
324
|
+
if mapped_scenario_dev is not None:
|
|
325
|
+
# get the related setup device for the mapped scenario device (on scenario level)
|
|
326
|
+
setup_dev_of_mapped_scenario_dev = self.get_setup_device_for(mapped_scenario_dev)
|
|
327
|
+
|
|
328
|
+
# now check if there is a mapping on setup level too
|
|
329
|
+
for cur_replacing_feature in replacing_feature_candidates:
|
|
330
|
+
mapped_setup_vdev, mapped_setup_dev = cur_replacing_feature.active_vdevice_device_mapping
|
|
331
|
+
if mapped_setup_vdev is not None and not issubclass(mapped_setup_vdev, active_scenario_vdev):
|
|
332
|
+
# drop this feature matching, because we have different vdevice mapped
|
|
333
|
+
replacing_features.remove(cur_replacing_feature)
|
|
334
|
+
elif mapped_setup_dev is not None and mapped_setup_dev != setup_dev_of_mapped_scenario_dev:
|
|
335
|
+
# drop this feature matching, because it is not applicable here
|
|
336
|
+
replacing_features.remove(cur_replacing_feature)
|
|
337
|
+
return replacing_features
|
|
338
|
+
|
|
283
339
|
# ---------------------------------- METHODS -----------------------------------------------------------------------
|
|
284
340
|
|
|
285
341
|
def testsummary(self) -> ResultSummary:
|
|
@@ -289,14 +345,22 @@ class VariationExecutor(BasicExecutor):
|
|
|
289
345
|
|
|
290
346
|
def get_testcase_executors(self) -> List[TestcaseExecutor]:
|
|
291
347
|
"""returns all sub testcase executors that belongs to this variation-executor"""
|
|
292
|
-
|
|
348
|
+
result = []
|
|
349
|
+
for cur_executor in self._testcase_executors:
|
|
350
|
+
if (isinstance(cur_executor, UnresolvedParametrizedTestcaseExecutor) and
|
|
351
|
+
cur_executor.parametrization_has_been_resolved):
|
|
352
|
+
result += cur_executor.get_testcase_executors()
|
|
353
|
+
else:
|
|
354
|
+
result.append(cur_executor)
|
|
355
|
+
return result
|
|
293
356
|
|
|
294
|
-
def add_testcase_executor(self, testcase_executor: TestcaseExecutor):
|
|
357
|
+
def add_testcase_executor(self, testcase_executor: TestcaseExecutor | UnresolvedParametrizedTestcaseExecutor):
|
|
295
358
|
"""
|
|
296
359
|
This method adds a new TestcaseExecutor to the child element list of this object branch
|
|
297
360
|
"""
|
|
298
|
-
if not isinstance(testcase_executor, TestcaseExecutor):
|
|
299
|
-
raise TypeError("the given object `testcase_executor` must be of type type `TestcaseExecutor`"
|
|
361
|
+
if not isinstance(testcase_executor, (TestcaseExecutor, UnresolvedParametrizedTestcaseExecutor)):
|
|
362
|
+
raise TypeError("the given object `testcase_executor` must be of type type `TestcaseExecutor` or "
|
|
363
|
+
"`UnresolvedParametrizedTestcaseExecutor`")
|
|
300
364
|
if testcase_executor in self._testcase_executors:
|
|
301
365
|
raise ValueError("the given object `testcase_executor` already exists in child list")
|
|
302
366
|
self._testcase_executors.append(testcase_executor)
|
|
@@ -324,75 +388,53 @@ class VariationExecutor(BasicExecutor):
|
|
|
324
388
|
:raises NotApplicableVariationError: will be thrown if this variation cannot be applied, because the setup-/
|
|
325
389
|
scenario-device-features can not be resolved
|
|
326
390
|
"""
|
|
327
|
-
feature_replacement = {}
|
|
328
|
-
abs_setup_vdevice_mappings = {}
|
|
391
|
+
feature_replacement = {scenario_dev: {} for scenario_dev in self.base_device_mapping.keys()}
|
|
392
|
+
abs_setup_vdevice_mappings = {setup_dev: {} for setup_dev in self.base_device_mapping.values()}
|
|
329
393
|
for cur_scenario_device, cur_setup_device in self.base_device_mapping.items():
|
|
330
394
|
cur_setup_features = DeviceController.get_for(cur_setup_device).get_all_instantiated_feature_objects()
|
|
331
395
|
|
|
332
|
-
if cur_scenario_device not in feature_replacement.keys():
|
|
333
|
-
feature_replacement[cur_scenario_device] = {}
|
|
334
|
-
|
|
335
|
-
if cur_setup_device not in abs_setup_vdevice_mappings.keys():
|
|
336
|
-
abs_setup_vdevice_mappings[cur_setup_device] = {}
|
|
337
|
-
|
|
338
396
|
all_assigned_setup_features = []
|
|
339
397
|
cur_scenario_device_orig_features = \
|
|
340
398
|
DeviceController.get_for(cur_scenario_device).get_original_instanced_feature_objects()
|
|
341
|
-
for cur_attr_name,
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
if
|
|
349
|
-
# get the related setup device for the mapped scenario device (on scenario level)
|
|
350
|
-
to_scenarios_vdevice_mapped_setup_device = self.get_setup_device_for(mapped_scenario_device)
|
|
351
|
-
|
|
352
|
-
# now check if there is a mapping on setup level too
|
|
353
|
-
for cur_replacing_feature in replacing_features:
|
|
354
|
-
mapped_setup_vdevice, mapped_setup_device = cur_replacing_feature.active_vdevice_device_mapping
|
|
355
|
-
if mapped_setup_vdevice is not None and \
|
|
356
|
-
not issubclass(mapped_setup_vdevice, used_scenario_vdevice):
|
|
357
|
-
# drop this feature matching, because we have different vdevice mapped
|
|
358
|
-
cleanup_replacing_features.remove(cur_replacing_feature)
|
|
359
|
-
elif mapped_setup_device is not None and \
|
|
360
|
-
mapped_setup_device != to_scenarios_vdevice_mapped_setup_device:
|
|
361
|
-
# drop this feature matching, because it is not applicable here
|
|
362
|
-
cleanup_replacing_features.remove(cur_replacing_feature)
|
|
363
|
-
|
|
364
|
-
if len(cleanup_replacing_features) != 1:
|
|
399
|
+
for cur_attr_name, cur_scenario_feature_obj in cur_scenario_device_orig_features.items():
|
|
400
|
+
active_scenario_vdevice, mapped_scenario_device = cur_scenario_feature_obj.active_vdevice_device_mapping
|
|
401
|
+
|
|
402
|
+
cur_setup_feature_objs = self._get_matching_setup_features_for(
|
|
403
|
+
scenario_feature_obj=cur_scenario_feature_obj, in_setup_device=cur_setup_device
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
if len(cur_setup_feature_objs) != 1:
|
|
365
407
|
raise NotApplicableVariationException(
|
|
366
408
|
f'this variation can not be applicable because there was no setup feature implementation of '
|
|
367
|
-
f'`{
|
|
409
|
+
f'`{cur_scenario_feature_obj.__class__.__name__}` (used by scenario device '
|
|
368
410
|
f'`{cur_scenario_device.__name__}`) in setup device `{cur_setup_device.__name__}`')
|
|
411
|
+
cur_setup_feature_obj = cur_setup_feature_objs[0]
|
|
369
412
|
|
|
370
413
|
if mapped_scenario_device is None:
|
|
371
414
|
# we have exactly one matching candidate, but also no vDevice mapping
|
|
372
415
|
# check if the matching candidate has a vDevice mapping
|
|
373
|
-
_, mapped_setup_device =
|
|
374
|
-
cleanup_feature_controller = FeatureController.get_for(
|
|
416
|
+
_, mapped_setup_device = cur_setup_feature_obj.active_vdevice_device_mapping
|
|
417
|
+
cleanup_feature_controller = FeatureController.get_for(cur_setup_feature_obj.__class__)
|
|
375
418
|
if mapped_setup_device is None \
|
|
376
419
|
and len(cleanup_feature_controller.get_abs_inner_vdevice_classes()) > 0:
|
|
377
420
|
# there is no vDevice mapping on scenario and no vDevice mapping on setup level, but the
|
|
378
421
|
# feature defined vDevices -> NOT APPLICABLE
|
|
379
422
|
logger.warning(
|
|
380
423
|
f"missing vDevice mapping for feature "
|
|
381
|
-
f"`{
|
|
424
|
+
f"`{cur_scenario_feature_obj.__class__.__name__}` (used in scenario device "
|
|
382
425
|
f"`{cur_scenario_device.__name__}` and in setup device `{cur_setup_device.__name__}`) - "
|
|
383
426
|
f"VARIATION CAN NOT BE APPLIED")
|
|
384
427
|
raise NotApplicableVariationException(
|
|
385
|
-
f'this variation can not be
|
|
428
|
+
f'this variation can not be applied because there was no vDevice mapping given on '
|
|
386
429
|
f'scenario or on setup level for the feature '
|
|
387
|
-
f'`{
|
|
430
|
+
f'`{cur_scenario_feature_obj.__class__.__name__}` (used by scenario device '
|
|
388
431
|
f'`{cur_scenario_device.__name__}`) in setup device `{cur_setup_device.__name__}`')
|
|
389
432
|
|
|
390
|
-
all_assigned_setup_features.append(
|
|
433
|
+
all_assigned_setup_features.append(cur_setup_feature_obj)
|
|
391
434
|
if cur_attr_name not in feature_replacement[cur_scenario_device].keys():
|
|
392
|
-
|
|
393
|
-
cleanup_feature_controller = FeatureController.get_for(cleanup_feature.__class__)
|
|
435
|
+
cleanup_feature_controller = FeatureController.get_for(cur_setup_feature_obj.__class__)
|
|
394
436
|
|
|
395
|
-
used_setup_vdevice, mapped_setup_device =
|
|
437
|
+
used_setup_vdevice, mapped_setup_device = cur_setup_feature_obj.active_vdevice_device_mapping
|
|
396
438
|
|
|
397
439
|
# if there is a vDevice mapping on scenario level, but not on setup level, so update the
|
|
398
440
|
# VDevice-Device-Mapping there
|
|
@@ -401,21 +443,21 @@ class VariationExecutor(BasicExecutor):
|
|
|
401
443
|
# because check was already done in collector-stage)
|
|
402
444
|
setup_vdevices = [cur_vdevice for cur_vdevice
|
|
403
445
|
in cleanup_feature_controller.get_abs_inner_vdevice_classes()
|
|
404
|
-
if cur_vdevice.__name__ ==
|
|
446
|
+
if cur_vdevice.__name__ == active_scenario_vdevice.__name__]
|
|
405
447
|
used_setup_vdevice = setup_vdevices[0]
|
|
406
448
|
# set the mapping
|
|
407
|
-
abs_setup_vdevice_mappings[cur_setup_device][
|
|
449
|
+
abs_setup_vdevice_mappings[cur_setup_device][cur_setup_feature_obj] = {
|
|
408
450
|
used_setup_vdevice: self.get_setup_device_for(mapped_scenario_device)}
|
|
409
451
|
# if there is a vDevice mapping on setup level, but not on scenario level, so directly update the
|
|
410
452
|
# VDevice-Device-Mapping there
|
|
411
453
|
elif mapped_scenario_device is None and mapped_setup_device is not None:
|
|
412
|
-
abs_setup_vdevice_mappings[cur_setup_device][
|
|
454
|
+
abs_setup_vdevice_mappings[cur_setup_device][cur_setup_feature_obj] = {
|
|
413
455
|
used_setup_vdevice: mapped_setup_device}
|
|
414
456
|
|
|
415
457
|
feature_replacement[cur_scenario_device][cur_attr_name] = \
|
|
416
|
-
(
|
|
458
|
+
(cur_scenario_feature_obj, cur_setup_feature_obj)
|
|
417
459
|
# also add all setup features that are not assigned as autonomous features
|
|
418
|
-
for
|
|
460
|
+
for cur_setup_feature in cur_setup_features.values():
|
|
419
461
|
if cur_setup_feature not in all_assigned_setup_features:
|
|
420
462
|
# determine free name
|
|
421
463
|
idx = 0
|
|
@@ -461,7 +503,7 @@ class VariationExecutor(BasicExecutor):
|
|
|
461
503
|
raise KeyError("the requested setup device exists more than one time in `base_device_mapping`")
|
|
462
504
|
return [cur_key for cur_key, cur_value in self.base_device_mapping.items() if cur_value == setup_device][0]
|
|
463
505
|
|
|
464
|
-
def get_executor_for_testcase(self, testcase: callable) ->
|
|
506
|
+
def get_executor_for_testcase(self, testcase: callable) -> TestcaseExecutor | None:
|
|
465
507
|
"""
|
|
466
508
|
This method searches for a TestcaseExecutor in the internal list for which the given testcase method is
|
|
467
509
|
contained in
|
|
@@ -667,31 +709,16 @@ class VariationExecutor(BasicExecutor):
|
|
|
667
709
|
|
|
668
710
|
def determine_absolute_scenario_device_connections(self):
|
|
669
711
|
"""
|
|
670
|
-
This method determines the
|
|
671
|
-
|
|
712
|
+
This method determines the absolute connections for this variation and sets the internal properties
|
|
713
|
+
`_abs_variation_*_device_connections` with them. This will be used to determine the real connection-subtree
|
|
672
714
|
(that can be used for this variation) by the method `create_all_valid_routings()`.
|
|
673
715
|
|
|
674
716
|
The method re-executes the algorithm to determine the absolute connections for a scenario/setup (see the method
|
|
675
717
|
:meth:`Collector.determine_absolute_device_connections_for`), but it considers the real applied vDevice and
|
|
676
718
|
their feature restrictions too.
|
|
677
719
|
"""
|
|
678
|
-
abs_var_scenario_device_cnns = {}
|
|
679
|
-
|
|
680
720
|
# first determine all relevant absolute connection depending on the current scenario
|
|
681
|
-
|
|
682
|
-
cur_scenario_device_abs_cnns = \
|
|
683
|
-
DeviceController.get_for(cur_scenario_device).get_all_absolute_connections()
|
|
684
|
-
for _, cur_cnn_list in cur_scenario_device_abs_cnns.items():
|
|
685
|
-
for cur_cnn in cur_cnn_list:
|
|
686
|
-
if cur_scenario_device not in abs_var_scenario_device_cnns.keys():
|
|
687
|
-
abs_var_scenario_device_cnns[cur_scenario_device] = {}
|
|
688
|
-
|
|
689
|
-
cur_to_device, _ = cur_cnn.get_conn_partner_of(cur_scenario_device)
|
|
690
|
-
|
|
691
|
-
if cur_to_device not in abs_var_scenario_device_cnns[cur_scenario_device].keys():
|
|
692
|
-
abs_var_scenario_device_cnns[cur_scenario_device][cur_to_device] = []
|
|
693
|
-
|
|
694
|
-
abs_var_scenario_device_cnns[cur_scenario_device][cur_to_device].append(cur_cnn)
|
|
721
|
+
abs_var_scenario_device_cnns = self.cur_scenario_controller.get_all_abs_connections()
|
|
695
722
|
|
|
696
723
|
# now iterate over every feature, that is used by the scenario and determine the class-based feature connections
|
|
697
724
|
# of the mapped scenario feature (and its vDevice)
|
|
@@ -714,31 +741,34 @@ class VariationExecutor(BasicExecutor):
|
|
|
714
741
|
|
|
715
742
|
# get relevant class based connections for the current feature on setup level (this is really be used
|
|
716
743
|
# here)
|
|
717
|
-
|
|
744
|
+
feature_cnn = \
|
|
718
745
|
FeatureController.get_for(
|
|
719
746
|
cur_setup_feature.__class__).get_abs_class_based_for_vdevice()[cur_setup_feature_vdevice]
|
|
720
747
|
# connection that are relevant for this feature
|
|
721
|
-
relevant_cnns =
|
|
748
|
+
relevant_cnns = [
|
|
749
|
+
cnn for cnn in abs_var_scenario_device_cnns
|
|
750
|
+
if cnn.has_connection_from_to(cur_scenario_device, end_device=cur_mapped_scenario_device)
|
|
751
|
+
]
|
|
722
752
|
|
|
723
753
|
relevant_device_cnn = None
|
|
724
754
|
|
|
725
755
|
if len(relevant_cnns) > 1:
|
|
726
756
|
# we have parallel possibilities -> determine the selected one (only one is allowed to fit)
|
|
727
757
|
for cur_relevant_cnn in relevant_cnns:
|
|
728
|
-
for cur_relevant_single_cnn in
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
758
|
+
for cur_relevant_single_cnn, cur_feature_single_cnn in (
|
|
759
|
+
itertools.product(cur_relevant_cnn.get_singles(), feature_cnn.get_singles())):
|
|
760
|
+
if not cur_feature_single_cnn.contained_in(cur_relevant_single_cnn, ignore_metadata=True):
|
|
761
|
+
continue
|
|
762
|
+
if relevant_device_cnn is not None:
|
|
763
|
+
raise UnclearAssignableFeatureConnectionError(
|
|
764
|
+
f"the devices {cur_scenario_device.__name__} and "
|
|
765
|
+
f"{cur_mapped_scenario_device.__name__} have multiple parallel connections - the "
|
|
766
|
+
f"device `{cur_scenario_device.__name__}` uses a feature "
|
|
767
|
+
f"`{cur_scenario_feature.__class__.__name__}` that matches with the device "
|
|
768
|
+
f"`{cur_mapped_scenario_device.__name__}`, but it is not clear which of the "
|
|
769
|
+
f"parallel connection could be used"
|
|
770
|
+
)
|
|
771
|
+
relevant_device_cnn = cur_relevant_cnn
|
|
742
772
|
elif len(relevant_cnns) == 1:
|
|
743
773
|
relevant_device_cnn = relevant_cnns[0]
|
|
744
774
|
if relevant_device_cnn is None:
|
|
@@ -747,36 +777,19 @@ class VariationExecutor(BasicExecutor):
|
|
|
747
777
|
|
|
748
778
|
# now cleanup the scenario-device connection `relevant_device_cnn` according to the class-based feature
|
|
749
779
|
# connection
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
relevant_device_cnn)
|
|
761
|
-
abs_var_scenario_device_cnns[cur_scenario_device][cur_mapped_scenario_device].append(new_cnn_to_replace)
|
|
762
|
-
|
|
763
|
-
# also search the connection in the other direction
|
|
764
|
-
other_dir_relevant_device_cnn = None
|
|
765
|
-
for cur_cnn in abs_var_scenario_device_cnns[cur_mapped_scenario_device][cur_scenario_device]:
|
|
766
|
-
if cur_cnn.equal_with(relevant_device_cnn):
|
|
767
|
-
other_dir_relevant_device_cnn = cur_cnn
|
|
768
|
-
break
|
|
769
|
-
# and also replace it
|
|
770
|
-
abs_var_scenario_device_cnns[cur_mapped_scenario_device][cur_scenario_device].remove(
|
|
771
|
-
other_dir_relevant_device_cnn)
|
|
772
|
-
abs_var_scenario_device_cnns[cur_mapped_scenario_device][cur_scenario_device].append(new_cnn_to_replace)
|
|
780
|
+
new_cnn_to_replace = Connection.based_on(OrConnectionRelation(*[
|
|
781
|
+
cur_old_cnn_single for cur_old_cnn_single in relevant_device_cnn.get_singles()
|
|
782
|
+
if feature_cnn.contained_in(cur_old_cnn_single, ignore_metadata=True)
|
|
783
|
+
]))
|
|
784
|
+
new_cnn_to_replace.set_metadata_for_all_subitems(relevant_device_cnn.metadata)
|
|
785
|
+
|
|
786
|
+
abs_var_scenario_device_cnns.remove(relevant_device_cnn)
|
|
787
|
+
abs_var_scenario_device_cnns.append(new_cnn_to_replace)
|
|
788
|
+
|
|
789
|
+
# we do not need to check other direction because `has_connection_from_to()` returns both possibilities
|
|
773
790
|
|
|
774
791
|
# set the determined values in variation object
|
|
775
|
-
self._abs_variation_scenario_device_connections =
|
|
776
|
-
for _, from_device_dict in abs_var_scenario_device_cnns.items():
|
|
777
|
-
for _, cur_cnn_list in from_device_dict.items():
|
|
778
|
-
for cur_cnn in cur_cnn_list:
|
|
779
|
-
self._abs_variation_scenario_device_connections.append(cur_cnn)
|
|
792
|
+
self._abs_variation_scenario_device_connections = abs_var_scenario_device_cnns
|
|
780
793
|
|
|
781
794
|
def create_all_valid_routings(self):
|
|
782
795
|
"""
|
|
@@ -816,16 +829,18 @@ class VariationExecutor(BasicExecutor):
|
|
|
816
829
|
if virtual_routing_cnns[cur_cnn] is None:
|
|
817
830
|
virtual_routing_cnns[cur_cnn] = Connection.based_on(virtual_cnn)
|
|
818
831
|
else:
|
|
819
|
-
virtual_routing_cnns[cur_cnn] = Connection.based_on(
|
|
832
|
+
virtual_routing_cnns[cur_cnn] = Connection.based_on(
|
|
833
|
+
OrConnectionRelation(virtual_routing_cnns[cur_cnn], virtual_cnn))
|
|
820
834
|
virtual_routing_cnns[cur_cnn].set_metadata_for_all_subitems(virtual_cnn.metadata)
|
|
821
835
|
|
|
822
836
|
self._abs_variation_connections = []
|
|
823
837
|
for cur_cnn in self._abs_variation_scenario_device_connections:
|
|
824
838
|
cur_virtual_cnn = virtual_routing_cnns[cur_cnn]
|
|
825
839
|
new_intersection = cur_cnn.intersection_with(cur_virtual_cnn)
|
|
826
|
-
new_intersection
|
|
827
|
-
|
|
828
|
-
|
|
840
|
+
if new_intersection:
|
|
841
|
+
new_intersection.set_metadata_for_all_subitems(None)
|
|
842
|
+
# always set the metadata for setup devices
|
|
843
|
+
new_intersection.set_metadata_for_all_subitems(cur_virtual_cnn.metadata)
|
|
829
844
|
self._abs_variation_connections.append(new_intersection)
|
|
830
845
|
|
|
831
846
|
def set_conn_dependent_methods(self):
|
|
@@ -861,11 +876,15 @@ class VariationExecutor(BasicExecutor):
|
|
|
861
876
|
relevant_abs_conn = []
|
|
862
877
|
for cur_cnn in self._abs_variation_connections:
|
|
863
878
|
if cur_cnn.has_connection_from_to(start_device=setup_device, end_device=mapped_setup_device):
|
|
864
|
-
|
|
879
|
+
# add the children
|
|
880
|
+
relevant_abs_conn.extend(
|
|
881
|
+
cur_cnn.based_on_elements.connections if cur_cnn.__class__ == Connection else [cur_cnn]
|
|
882
|
+
)
|
|
883
|
+
|
|
865
884
|
if len(relevant_abs_conn) is None:
|
|
866
885
|
raise RuntimeError(f"detect empty absolute connection between device `{setup_device.__name__}` "
|
|
867
886
|
f"and device `{mapped_setup_device.__name__}`")
|
|
868
|
-
absolute_feature_method_var_cnn = Connection.based_on(*relevant_abs_conn)
|
|
887
|
+
absolute_feature_method_var_cnn = Connection.based_on(OrConnectionRelation(*relevant_abs_conn))
|
|
869
888
|
cur_method_variation = cur_setup_feature_controller.get_method_variation(
|
|
870
889
|
of_method_name=cur_method_name, for_vdevice=mapped_vdevice,
|
|
871
890
|
with_connection=absolute_feature_method_var_cnn)
|
|
@@ -876,3 +895,9 @@ class VariationExecutor(BasicExecutor):
|
|
|
876
895
|
(mapped_vdevice, absolute_feature_method_var_cnn, cur_method_variation)
|
|
877
896
|
|
|
878
897
|
cur_setup_feature_controller.set_active_method_variation(method_selection=method_var_selection)
|
|
898
|
+
|
|
899
|
+
def resolve_possible_parametrization(self):
|
|
900
|
+
"""resolves the parametrization if there are any :class:`UnresolvedParametrizedTestcaseExecutor` in the tree"""
|
|
901
|
+
for cur_child in self._testcase_executors:
|
|
902
|
+
if isinstance(cur_child, UnresolvedParametrizedTestcaseExecutor):
|
|
903
|
+
cur_child.resolve_dynamic_parametrization()
|
_balder/feature.py
CHANGED
|
@@ -16,7 +16,7 @@ class Feature:
|
|
|
16
16
|
:param kwargs: contains a dictionary that references all vDevices of the feature and a real
|
|
17
17
|
scenario :meth:`Device` as value
|
|
18
18
|
"""
|
|
19
|
-
from _balder.controllers import FeatureController
|
|
19
|
+
from _balder.controllers import FeatureController # pylint: disable=import-outside-toplevel
|
|
20
20
|
|
|
21
21
|
#: this property contains the active mapping for the devices
|
|
22
22
|
self.active_vdevices: Dict[VDevice, Union[Device, str]] = {}
|
|
@@ -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]
|