baldertest 0.1.0b11__py3-none-any.whl → 0.1.0b13__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 +8 -3
- _balder/cnnrelations/and_connection_relation.py +28 -1
- _balder/cnnrelations/base_connection_relation.py +1 -1
- _balder/collector.py +101 -113
- _balder/connection.py +76 -80
- _balder/controllers/device_controller.py +17 -29
- _balder/controllers/feature_controller.py +2 -2
- _balder/controllers/normal_scenario_setup_controller.py +1 -2
- _balder/controllers/scenario_controller.py +121 -0
- _balder/controllers/vdevice_controller.py +2 -23
- _balder/decorator_connect.py +3 -3
- _balder/decorator_covered_by.py +28 -36
- _balder/executor/basic_executable_executor.py +13 -6
- _balder/executor/basic_executor.py +31 -4
- _balder/executor/executor_tree.py +5 -4
- _balder/executor/parametrized_testcase_executor.py +2 -2
- _balder/executor/scenario_executor.py +12 -71
- _balder/executor/setup_executor.py +4 -3
- _balder/executor/testcase_executor.py +35 -19
- _balder/executor/unresolved_parametrized_testcase_executor.py +32 -57
- _balder/executor/variation_executor.py +127 -148
- _balder/feature.py +2 -1
- _balder/feature_replacement_mapping.py +107 -0
- _balder/feature_vdevice_mapping.py +88 -0
- _balder/fixture_manager.py +1 -1
- _balder/fixture_metadata.py +1 -1
- _balder/routing_path.py +27 -16
- _balder/scenario.py +2 -2
- _balder/setup.py +2 -1
- _balder/testresult.py +4 -3
- _balder/utils/__init__.py +0 -0
- _balder/{utils.py → utils/functions.py} +29 -31
- _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
- {baldertest-0.1.0b11.dist-info → baldertest-0.1.0b13.dist-info}/METADATA +3 -2
- {baldertest-0.1.0b11.dist-info → baldertest-0.1.0b13.dist-info}/RECORD +41 -35
- {baldertest-0.1.0b11.dist-info → baldertest-0.1.0b13.dist-info}/WHEEL +1 -1
- {baldertest-0.1.0b11.dist-info → baldertest-0.1.0b13.dist-info}/entry_points.txt +0 -0
- {baldertest-0.1.0b11.dist-info → baldertest-0.1.0b13.dist-info/licenses}/LICENSE +0 -0
- {baldertest-0.1.0b11.dist-info → baldertest-0.1.0b13.dist-info}/top_level.txt +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
from typing import Type, Union, List, Dict, Tuple, TYPE_CHECKING
|
|
3
|
+
from typing import Type, Union, List, Dict, TYPE_CHECKING
|
|
5
4
|
|
|
6
5
|
import inspect
|
|
7
6
|
import logging
|
|
8
7
|
from _balder.cnnrelations import OrConnectionRelation
|
|
9
8
|
from _balder.device import Device
|
|
10
9
|
from _balder.connection import Connection
|
|
10
|
+
from _balder.feature_replacement_mapping import FeatureReplacementMapping
|
|
11
11
|
from _balder.fixture_execution_level import FixtureExecutionLevel
|
|
12
12
|
from _balder.testresult import ResultState, BranchBodyResult, ResultSummary
|
|
13
13
|
from _balder.executor.basic_executable_executor import BasicExecutableExecutor
|
|
@@ -16,6 +16,7 @@ from _balder.executor.unresolved_parametrized_testcase_executor import Unresolve
|
|
|
16
16
|
from _balder.previous_executor_mark import PreviousExecutorMark
|
|
17
17
|
from _balder.routing_path import RoutingPath
|
|
18
18
|
from _balder.unmapped_vdevice import UnmappedVDevice
|
|
19
|
+
from _balder.feature_vdevice_mapping import FeatureVDeviceMapping
|
|
19
20
|
from _balder.controllers import DeviceController, VDeviceController, FeatureController, NormalScenarioSetupController
|
|
20
21
|
from _balder.exceptions import NotApplicableVariationException, UnclearAssignableFeatureConnectionError
|
|
21
22
|
|
|
@@ -23,7 +24,6 @@ if TYPE_CHECKING:
|
|
|
23
24
|
from _balder.setup import Setup
|
|
24
25
|
from _balder.feature import Feature
|
|
25
26
|
from _balder.scenario import Scenario
|
|
26
|
-
from _balder.vdevice import VDevice
|
|
27
27
|
from _balder.controllers.scenario_controller import ScenarioController
|
|
28
28
|
from _balder.controllers.setup_controller import SetupController
|
|
29
29
|
from _balder.executor.scenario_executor import ScenarioExecutor
|
|
@@ -50,12 +50,10 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
50
50
|
self._routings: Dict[Connection, List[RoutingPath]] = {}
|
|
51
51
|
# buffer variable to save the feature replacement after it was determined with
|
|
52
52
|
# `determine_feature_replacement_and_vdevice_mappings()`
|
|
53
|
-
self._feature_replacement:
|
|
54
|
-
Union[None, Dict[Type[Device], Dict[str, Tuple[Union[Feature, None], Feature]]]] = None
|
|
53
|
+
self._feature_replacement: Union[None, Dict[Type[Device], FeatureReplacementMapping]] = None
|
|
55
54
|
# buffer variable to save the feature replacement after it was determined with
|
|
56
55
|
# `determine_feature_replacement_and_vdevice_mappings()`
|
|
57
|
-
self._abs_setup_feature_vdevice_mappings:
|
|
58
|
-
Union[None, Dict[Type[Device], Dict[Feature, Dict[Type[VDevice], Type[Device]]]]] = None
|
|
56
|
+
self._abs_setup_feature_vdevice_mappings: Union[None, Dict[Type[Device], FeatureVDeviceMapping]] = None
|
|
59
57
|
|
|
60
58
|
# contains the absolute scenario device connections for the current variation
|
|
61
59
|
self._abs_variation_scenario_device_connections: Union[List[Connection], None] = None
|
|
@@ -67,8 +65,7 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
67
65
|
# contains the original active vdevice mappings for all scenario and setup devices (will be managed by
|
|
68
66
|
# `update_active_vdevice_device_mappings_in_scenario_and_setup_devices()` and
|
|
69
67
|
# `revert_active_vdevice_device_mappings_in_scenario_and_setup_devices()`)
|
|
70
|
-
self._original_active_vdevice_mappings:
|
|
71
|
-
Dict[Type[Device], Dict[Feature, Dict[Type[VDevice], Type[Device]]]] = {}
|
|
68
|
+
self._original_active_vdevice_mappings: Dict[Type[Device], FeatureVDeviceMapping] = {}
|
|
72
69
|
|
|
73
70
|
# is True if the applicability check was done
|
|
74
71
|
self._applicability_check_done = False
|
|
@@ -138,18 +135,17 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
138
135
|
return self._fixture_manager
|
|
139
136
|
|
|
140
137
|
@property
|
|
141
|
-
def feature_replacement(self) -> Dict[Type[Device],
|
|
138
|
+
def feature_replacement(self) -> Dict[Type[Device], FeatureReplacementMapping]:
|
|
142
139
|
"""
|
|
143
|
-
this property is a dictionary with every scenario device as key and
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
140
|
+
this property is a dictionary with every scenario device as key and feature-replacement-mapping as value - the
|
|
141
|
+
mappings hold at least information about the attribute name of the feature in scenario device, the old
|
|
142
|
+
scenario-feature the instantiated feature from the scenario if it exists, otherwise this is None) and the
|
|
143
|
+
new feature as second item (the feature of the related Setup-Device)
|
|
147
144
|
"""
|
|
148
145
|
return self._feature_replacement
|
|
149
146
|
|
|
150
147
|
@property
|
|
151
|
-
def abs_setup_feature_vdevice_mappings(self)
|
|
152
|
-
-> Dict[Type[Device], Dict[Feature, Dict[Type[VDevice], Type[Device]]]]:
|
|
148
|
+
def abs_setup_feature_vdevice_mappings(self) -> Dict[Type[Device], FeatureVDeviceMapping]:
|
|
153
149
|
"""returns the feature replacement that was determined with
|
|
154
150
|
`determine_feature_replacement_and_vdevice_mappings()`"""
|
|
155
151
|
return self._abs_setup_feature_vdevice_mappings
|
|
@@ -175,7 +171,7 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
175
171
|
self.exchange_unmapped_vdevice_references()
|
|
176
172
|
self.update_vdevice_referenced_feature_instances()
|
|
177
173
|
self.set_conn_dependent_methods()
|
|
178
|
-
self.
|
|
174
|
+
self.resolve_and_exchange_unresolved_parametrization()
|
|
179
175
|
|
|
180
176
|
def _body_execution(self, show_discarded):
|
|
181
177
|
if show_discarded and not self.can_be_applied():
|
|
@@ -183,13 +179,10 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
183
179
|
return
|
|
184
180
|
|
|
185
181
|
for cur_testcase_executor in self.get_testcase_executors():
|
|
186
|
-
if cur_testcase_executor.has_runnable_tests()
|
|
187
|
-
|
|
182
|
+
if (cur_testcase_executor.has_runnable_tests()
|
|
183
|
+
or cur_testcase_executor.has_skipped_tests()
|
|
184
|
+
or cur_testcase_executor.has_covered_by_tests()):
|
|
188
185
|
cur_testcase_executor.execute()
|
|
189
|
-
elif cur_testcase_executor.prev_mark == PreviousExecutorMark.SKIP:
|
|
190
|
-
cur_testcase_executor.set_result_for_whole_branch(ResultState.SKIP)
|
|
191
|
-
elif cur_testcase_executor.prev_mark == PreviousExecutorMark.COVERED_BY:
|
|
192
|
-
cur_testcase_executor.set_result_for_whole_branch(ResultState.COVERED_BY)
|
|
193
186
|
else:
|
|
194
187
|
cur_testcase_executor.set_result_for_whole_branch(ResultState.NOT_RUN)
|
|
195
188
|
|
|
@@ -230,26 +223,22 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
230
223
|
vDevices-Mappings (so the mapped setup-devices) implements all features that are defined in the vDevices
|
|
231
224
|
"""
|
|
232
225
|
|
|
233
|
-
for cur_scenario_device,
|
|
226
|
+
for cur_scenario_device, cur_replacement_mapping in self.feature_replacement.items():
|
|
234
227
|
cur_setup_device = self.get_setup_device_for(scenario_device=cur_scenario_device)
|
|
235
228
|
all_inner_setup_features = \
|
|
236
229
|
DeviceController.get_for(cur_setup_device).get_all_instantiated_feature_objects()
|
|
237
230
|
|
|
238
|
-
# describes the mapping from the new setup feature (key) to the instantiated scenario feature (value)
|
|
239
|
-
# note that this dictionary only contains the required one
|
|
240
|
-
setup_to_scenario_feature_mapping: Dict[Type[Feature], Feature] = {
|
|
241
|
-
cur_replacement_tuple[1]: cur_replacement_tuple[0]
|
|
242
|
-
for cur_attr_name, cur_replacement_tuple in cur_replacement_dict.items()
|
|
243
|
-
if cur_replacement_tuple[0] is not None}
|
|
244
|
-
|
|
245
231
|
# now secure that all features are available in the corresponding setup device, that are defined in the
|
|
246
232
|
# mapped vDevice
|
|
247
233
|
for _, cur_setup_feature_obj in all_inner_setup_features.items():
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
234
|
+
related_scenario_feature_obj = \
|
|
235
|
+
cur_replacement_mapping.get_replaced_scenario_feature_for(cur_setup_feature_obj)
|
|
236
|
+
|
|
237
|
+
# only check if this feature is required by the scenario
|
|
238
|
+
if related_scenario_feature_obj is None:
|
|
239
|
+
# ignore this, because this feature is not used in the scenario
|
|
251
240
|
continue
|
|
252
|
-
|
|
241
|
+
|
|
253
242
|
# get vDevice and device mapping
|
|
254
243
|
partner_scenario_vdevice, partner_scenario_device = \
|
|
255
244
|
related_scenario_feature_obj.active_vdevice_device_mapping
|
|
@@ -258,7 +247,7 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
258
247
|
# ignore because no mapping exist here
|
|
259
248
|
continue
|
|
260
249
|
|
|
261
|
-
partner_setup_device = self.get_setup_device_for(scenario_device=
|
|
250
|
+
partner_setup_device = self.get_setup_device_for(scenario_device=partner_scenario_device)
|
|
262
251
|
# get the related vDevice on setup view that is currently active
|
|
263
252
|
mapped_setup_vdevices = [
|
|
264
253
|
cur_vdevice for cur_vdevice
|
|
@@ -343,16 +332,9 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
343
332
|
return super().testsummary()
|
|
344
333
|
return ResultSummary()
|
|
345
334
|
|
|
346
|
-
def get_testcase_executors(self) -> List[TestcaseExecutor]:
|
|
335
|
+
def get_testcase_executors(self) -> List[TestcaseExecutor | UnresolvedParametrizedTestcaseExecutor]:
|
|
347
336
|
"""returns all sub testcase executors that belongs to this variation-executor"""
|
|
348
|
-
|
|
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
|
|
337
|
+
return self._testcase_executors.copy()
|
|
356
338
|
|
|
357
339
|
def add_testcase_executor(self, testcase_executor: TestcaseExecutor | UnresolvedParametrizedTestcaseExecutor):
|
|
358
340
|
"""
|
|
@@ -388,15 +370,17 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
388
370
|
:raises NotApplicableVariationError: will be thrown if this variation cannot be applied, because the setup-/
|
|
389
371
|
scenario-device-features can not be resolved
|
|
390
372
|
"""
|
|
391
|
-
feature_replacement = {
|
|
392
|
-
|
|
373
|
+
feature_replacement = {
|
|
374
|
+
scenario_dev: FeatureReplacementMapping() for scenario_dev in self.base_device_mapping.keys()
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
abs_setup_vdevice_mappings = {
|
|
378
|
+
setup_dev: FeatureVDeviceMapping() for setup_dev in self.base_device_mapping.values()
|
|
379
|
+
}
|
|
393
380
|
for cur_scenario_device, cur_setup_device in self.base_device_mapping.items():
|
|
394
|
-
cur_setup_features = DeviceController.get_for(cur_setup_device).get_all_instantiated_feature_objects()
|
|
395
381
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
DeviceController.get_for(cur_scenario_device).get_original_instanced_feature_objects()
|
|
399
|
-
for cur_attr_name, cur_scenario_feature_obj in cur_scenario_device_orig_features.items():
|
|
382
|
+
for cur_attr_name, cur_scenario_feature_obj in \
|
|
383
|
+
DeviceController.get_for(cur_scenario_device).get_all_instantiated_feature_objects().items():
|
|
400
384
|
active_scenario_vdevice, mapped_scenario_device = cur_scenario_feature_obj.active_vdevice_device_mapping
|
|
401
385
|
|
|
402
386
|
cur_setup_feature_objs = self._get_matching_setup_features_for(
|
|
@@ -410,13 +394,14 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
410
394
|
f'`{cur_scenario_device.__name__}`) in setup device `{cur_setup_device.__name__}`')
|
|
411
395
|
cur_setup_feature_obj = cur_setup_feature_objs[0]
|
|
412
396
|
|
|
397
|
+
all_abs_inner_vdevs_of_setup = \
|
|
398
|
+
FeatureController.get_for(cur_setup_feature_obj.__class__).get_abs_inner_vdevice_classes()
|
|
399
|
+
used_setup_vdevice, mapped_setup_device = cur_setup_feature_obj.active_vdevice_device_mapping
|
|
400
|
+
|
|
413
401
|
if mapped_scenario_device is None:
|
|
414
402
|
# we have exactly one matching candidate, but also no vDevice mapping
|
|
415
403
|
# check if the matching candidate has a vDevice mapping
|
|
416
|
-
|
|
417
|
-
cleanup_feature_controller = FeatureController.get_for(cur_setup_feature_obj.__class__)
|
|
418
|
-
if mapped_setup_device is None \
|
|
419
|
-
and len(cleanup_feature_controller.get_abs_inner_vdevice_classes()) > 0:
|
|
404
|
+
if mapped_setup_device is None and len(all_abs_inner_vdevs_of_setup) > 0:
|
|
420
405
|
# there is no vDevice mapping on scenario and no vDevice mapping on setup level, but the
|
|
421
406
|
# feature defined vDevices -> NOT APPLICABLE
|
|
422
407
|
logger.warning(
|
|
@@ -430,42 +415,38 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
430
415
|
f'`{cur_scenario_feature_obj.__class__.__name__}` (used by scenario device '
|
|
431
416
|
f'`{cur_scenario_device.__name__}`) in setup device `{cur_setup_device.__name__}`')
|
|
432
417
|
|
|
433
|
-
|
|
434
|
-
if cur_attr_name not in feature_replacement[cur_scenario_device].keys():
|
|
435
|
-
cleanup_feature_controller = FeatureController.get_for(cur_setup_feature_obj.__class__)
|
|
436
|
-
|
|
437
|
-
used_setup_vdevice, mapped_setup_device = cur_setup_feature_obj.active_vdevice_device_mapping
|
|
418
|
+
if cur_attr_name not in feature_replacement[cur_scenario_device].attr_names:
|
|
438
419
|
|
|
439
420
|
# if there is a vDevice mapping on scenario level, but not on setup level, so update the
|
|
440
421
|
# VDevice-Device-Mapping there
|
|
441
422
|
if mapped_scenario_device is not None and mapped_setup_device is None:
|
|
442
423
|
# search the equivalent vDevice on setup level and use this one (we had not to check it,
|
|
443
424
|
# because check was already done in collector-stage)
|
|
444
|
-
setup_vdevices = [cur_vdevice for cur_vdevice
|
|
445
|
-
in cleanup_feature_controller.get_abs_inner_vdevice_classes()
|
|
425
|
+
setup_vdevices = [cur_vdevice for cur_vdevice in all_abs_inner_vdevs_of_setup
|
|
446
426
|
if cur_vdevice.__name__ == active_scenario_vdevice.__name__]
|
|
447
427
|
used_setup_vdevice = setup_vdevices[0]
|
|
448
428
|
# set the mapping
|
|
449
|
-
abs_setup_vdevice_mappings[cur_setup_device]
|
|
450
|
-
|
|
429
|
+
abs_setup_vdevice_mappings[cur_setup_device].add(
|
|
430
|
+
feature=cur_setup_feature_obj,
|
|
431
|
+
mappings={
|
|
432
|
+
used_setup_vdevice: self.get_setup_device_for(mapped_scenario_device)
|
|
433
|
+
}
|
|
434
|
+
)
|
|
451
435
|
# if there is a vDevice mapping on setup level, but not on scenario level, so directly update the
|
|
452
436
|
# VDevice-Device-Mapping there
|
|
453
437
|
elif mapped_scenario_device is None and mapped_setup_device is not None:
|
|
454
|
-
abs_setup_vdevice_mappings[cur_setup_device]
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
autonomous_name = f"_autonomous_feat_{idx}"
|
|
467
|
-
idx += 1
|
|
468
|
-
feature_replacement[cur_scenario_device][autonomous_name] = (None, cur_setup_feature)
|
|
438
|
+
abs_setup_vdevice_mappings[cur_setup_device].add(
|
|
439
|
+
feature=cur_setup_feature_obj,
|
|
440
|
+
mappings={
|
|
441
|
+
used_setup_vdevice: mapped_setup_device
|
|
442
|
+
}
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
feature_replacement[cur_scenario_device].add(attr_name=cur_attr_name,
|
|
446
|
+
scenario_feature=cur_scenario_feature_obj,
|
|
447
|
+
setup_feature=cur_setup_feature_obj)
|
|
448
|
+
|
|
449
|
+
feature_replacement[cur_scenario_device].add_remaining_setup_features_as_autonomous(cur_setup_device)
|
|
469
450
|
|
|
470
451
|
# set the result to internal properties
|
|
471
452
|
self._feature_replacement = feature_replacement
|
|
@@ -531,20 +512,18 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
531
512
|
This method ensures that the (mostly abstract) feature instances of a scenario are exchanged with the
|
|
532
513
|
feature instances of the assigned setup devices
|
|
533
514
|
"""
|
|
534
|
-
for cur_scenario_device,
|
|
535
|
-
for
|
|
536
|
-
|
|
537
|
-
setattr(cur_scenario_device, cur_attr_name, new_feature_obj)
|
|
515
|
+
for cur_scenario_device, cur_replacement_mapping in self.feature_replacement.items():
|
|
516
|
+
for cur_feature_mapping in cur_replacement_mapping.mappings:
|
|
517
|
+
setattr(cur_scenario_device, cur_feature_mapping.attr_name, cur_feature_mapping.setup_feature)
|
|
538
518
|
|
|
539
519
|
def revert_scenario_device_feature_instances(self):
|
|
540
520
|
"""
|
|
541
521
|
This method ensures that all initialized feature instances of a scenario are set back to the initial given
|
|
542
522
|
features.
|
|
543
523
|
"""
|
|
544
|
-
for cur_scenario_device,
|
|
545
|
-
for
|
|
546
|
-
|
|
547
|
-
setattr(cur_scenario_device, cur_attr_name, old_instantiated_feature_obj)
|
|
524
|
+
for cur_scenario_device, cur_replacement_mapping in self.feature_replacement.items():
|
|
525
|
+
for cur_feature_mapping in cur_replacement_mapping.mappings:
|
|
526
|
+
setattr(cur_scenario_device, cur_feature_mapping.attr_name, cur_feature_mapping.scenario_feature)
|
|
548
527
|
|
|
549
528
|
def update_active_vdevice_device_mappings_in_all_features(self):
|
|
550
529
|
"""
|
|
@@ -552,28 +531,28 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
552
531
|
scenario-device classes are set correctly.
|
|
553
532
|
"""
|
|
554
533
|
|
|
555
|
-
for cur_setup_device,
|
|
534
|
+
for cur_setup_device, feature_vdevice_mapping in self.abs_setup_feature_vdevice_mappings.items():
|
|
556
535
|
if cur_setup_device not in self._original_active_vdevice_mappings.keys():
|
|
557
|
-
self._original_active_vdevice_mappings[cur_setup_device] =
|
|
558
|
-
for cur_setup_feature
|
|
536
|
+
self._original_active_vdevice_mappings[cur_setup_device] = FeatureVDeviceMapping()
|
|
537
|
+
for cur_setup_feature in feature_vdevice_mapping.features:
|
|
538
|
+
vdev_dev_mappings_of_setup_feat = feature_vdevice_mapping.get_mappings_for_feature(cur_setup_feature)
|
|
559
539
|
|
|
560
|
-
cur_setup_feature_vdevice =
|
|
561
|
-
cur_mapped_setup_device =
|
|
540
|
+
cur_setup_feature_vdevice = vdev_dev_mappings_of_setup_feat[0].vdevice
|
|
541
|
+
cur_mapped_setup_device = vdev_dev_mappings_of_setup_feat[0].device
|
|
562
542
|
|
|
563
543
|
# first save old value to revert it later
|
|
564
|
-
self._original_active_vdevice_mappings[cur_setup_device]
|
|
565
|
-
cur_setup_feature
|
|
544
|
+
self._original_active_vdevice_mappings[cur_setup_device].add(
|
|
545
|
+
feature=cur_setup_feature,
|
|
546
|
+
mappings=cur_setup_feature.active_vdevices
|
|
547
|
+
)
|
|
566
548
|
# now set new value
|
|
567
549
|
cur_setup_feature.active_vdevices = {cur_setup_feature_vdevice: cur_mapped_setup_device}
|
|
568
550
|
|
|
569
551
|
# now also determine the mapping for the scenario-feature (if there exists one)
|
|
570
552
|
cur_scenario_device = self.get_scenario_device_for(cur_setup_device)
|
|
571
|
-
cur_scenario_feature =
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
if cur_replacement_setup_feature == cur_setup_feature:
|
|
575
|
-
cur_scenario_feature = cur_replacement_scenario_feature
|
|
576
|
-
break
|
|
553
|
+
cur_scenario_feature = self.feature_replacement[cur_scenario_device].get_replaced_scenario_feature_for(
|
|
554
|
+
cur_setup_feature
|
|
555
|
+
)
|
|
577
556
|
if cur_scenario_feature is None:
|
|
578
557
|
# there exists no scenario feature -> we can ignore this
|
|
579
558
|
pass
|
|
@@ -587,10 +566,12 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
587
566
|
# only if there exists exactly one scenario vdevice with the same name
|
|
588
567
|
|
|
589
568
|
if cur_scenario_device not in self._original_active_vdevice_mappings.keys():
|
|
590
|
-
self._original_active_vdevice_mappings[cur_scenario_device] =
|
|
569
|
+
self._original_active_vdevice_mappings[cur_scenario_device] = FeatureVDeviceMapping()
|
|
591
570
|
# first save old value to revert it later
|
|
592
|
-
self._original_active_vdevice_mappings[cur_scenario_device]
|
|
593
|
-
cur_scenario_feature
|
|
571
|
+
self._original_active_vdevice_mappings[cur_scenario_device].add(
|
|
572
|
+
feature=cur_scenario_feature,
|
|
573
|
+
mappings=cur_scenario_feature.active_vdevices
|
|
574
|
+
)
|
|
594
575
|
# now set new value
|
|
595
576
|
cur_scenario_feature.active_vdevices = \
|
|
596
577
|
{cur_scenario_feature_vdevice[0]: self.get_scenario_device_for(cur_mapped_setup_device)}
|
|
@@ -598,10 +579,14 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
598
579
|
def revert_active_vdevice_device_mappings_in_all_features(self):
|
|
599
580
|
"""
|
|
600
581
|
This method ensures that the `active_vdevices` property that was changed with
|
|
601
|
-
`
|
|
582
|
+
`update_active_vdevice_device_mappings_in_all_features()` will be reverted correctly.
|
|
602
583
|
"""
|
|
603
|
-
for
|
|
604
|
-
for cur_feature
|
|
584
|
+
for cur_feature_vdevice_mapping in self._original_active_vdevice_mappings.values():
|
|
585
|
+
for cur_feature in cur_feature_vdevice_mapping.features:
|
|
586
|
+
cur_original_mapping = {
|
|
587
|
+
mapping.vdevice:mapping.device
|
|
588
|
+
for mapping in cur_feature_vdevice_mapping.get_mappings_for_feature(cur_feature)
|
|
589
|
+
}
|
|
605
590
|
cur_feature.active_vdevices = cur_original_mapping
|
|
606
591
|
|
|
607
592
|
def exchange_unmapped_vdevice_references(self):
|
|
@@ -661,7 +646,7 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
661
646
|
cur_vdevice, cur_device = cur_feature.active_vdevice_device_mapping
|
|
662
647
|
if cur_vdevice is not None and cur_device is not None:
|
|
663
648
|
cur_vdevice_controller = VDeviceController.get_for(cur_vdevice)
|
|
664
|
-
cur_vdevice_all_features = cur_vdevice_controller.
|
|
649
|
+
cur_vdevice_all_features = cur_vdevice_controller.get_all_instantiated_feature_objects()
|
|
665
650
|
|
|
666
651
|
cur_device_controller = DeviceController.get_for(cur_device)
|
|
667
652
|
cur_device_all_features = cur_device_controller.get_all_instantiated_feature_objects()
|
|
@@ -722,64 +707,54 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
722
707
|
|
|
723
708
|
# now iterate over every feature, that is used by the scenario and determine the class-based feature connections
|
|
724
709
|
# of the mapped scenario feature (and its vDevice)
|
|
725
|
-
for cur_setup_device,
|
|
710
|
+
for cur_setup_device, feature_vdev_mapping in self.abs_setup_feature_vdevice_mappings.items():
|
|
726
711
|
cur_scenario_device = self.get_scenario_device_for(cur_setup_device)
|
|
727
|
-
for cur_setup_feature,
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
cur_setup_feature_vdevice = list(mapping_dict.keys())[0]
|
|
733
|
-
cur_mapped_setup_device = list(mapping_dict.values())[0]
|
|
712
|
+
for cur_setup_feature, vdev_mappings_of_setup_feature in feature_vdev_mapping.items():
|
|
713
|
+
cur_scenario_feature: Feature = (
|
|
714
|
+
self.feature_replacement[cur_scenario_device].get_replaced_scenario_feature_for(
|
|
715
|
+
setup_feature=cur_setup_feature)
|
|
716
|
+
)
|
|
734
717
|
|
|
735
|
-
if
|
|
718
|
+
if vdev_mappings_of_setup_feature[0].device not in self.base_device_mapping.values():
|
|
736
719
|
raise NotApplicableVariationException(
|
|
737
|
-
f'the mapped setup device `{
|
|
738
|
-
f'VDevice `{
|
|
720
|
+
f'the mapped setup device `{vdev_mappings_of_setup_feature[0].device.__qualname__}` which is '
|
|
721
|
+
f'mapped to the VDevice `{vdev_mappings_of_setup_feature[0].vdevice.__qualname__}` is no part '
|
|
722
|
+
f'of this variation')
|
|
739
723
|
|
|
740
|
-
cur_mapped_scenario_device = self.get_scenario_device_for(
|
|
724
|
+
cur_mapped_scenario_device = self.get_scenario_device_for(vdev_mappings_of_setup_feature[0].device)
|
|
741
725
|
|
|
742
726
|
# get relevant class based connections for the current feature on setup level (this is really be used
|
|
743
727
|
# here)
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
cur_setup_feature.__class__).get_abs_class_based_for_vdevice()[cur_setup_feature_vdevice]
|
|
728
|
+
feat_cnn = FeatureController.get_for(cur_setup_feature.__class__)\
|
|
729
|
+
.get_abs_class_based_for_vdevice()[vdev_mappings_of_setup_feature[0].vdevice]
|
|
747
730
|
# connection that are relevant for this feature
|
|
748
731
|
relevant_cnns = [
|
|
749
732
|
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)
|
|
733
|
+
if (cnn.has_connection_from_to(cur_scenario_device, end_device=cur_mapped_scenario_device)
|
|
734
|
+
and max(single_feat_cnn.contained_in(cnn, ignore_metadata=True)
|
|
735
|
+
for single_feat_cnn in feat_cnn.get_singles())
|
|
736
|
+
)
|
|
751
737
|
]
|
|
752
738
|
|
|
753
|
-
relevant_device_cnn = None
|
|
754
|
-
|
|
755
739
|
if len(relevant_cnns) > 1:
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
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
|
|
772
|
-
elif len(relevant_cnns) == 1:
|
|
773
|
-
relevant_device_cnn = relevant_cnns[0]
|
|
774
|
-
if relevant_device_cnn is None:
|
|
740
|
+
raise UnclearAssignableFeatureConnectionError(
|
|
741
|
+
f"the devices {cur_scenario_device.__name__} and {cur_mapped_scenario_device.__name__} have "
|
|
742
|
+
f"multiple parallel connections - the device `{cur_scenario_device.__name__}` uses a feature "
|
|
743
|
+
f"`{cur_scenario_feature.__class__.__name__}` that matches with the device "
|
|
744
|
+
f"`{cur_mapped_scenario_device.__name__}`, but it is not clear which of the parallel "
|
|
745
|
+
f"connection could be used")
|
|
746
|
+
|
|
747
|
+
if len(relevant_cnns) == 0:
|
|
775
748
|
# todo this does not map here
|
|
776
749
|
raise ValueError("can not find matching connection on scenario level")
|
|
777
750
|
|
|
751
|
+
relevant_device_cnn = relevant_cnns[0]
|
|
752
|
+
|
|
778
753
|
# now cleanup the scenario-device connection `relevant_device_cnn` according to the class-based feature
|
|
779
754
|
# connection
|
|
780
755
|
new_cnn_to_replace = Connection.based_on(OrConnectionRelation(*[
|
|
781
756
|
cur_old_cnn_single for cur_old_cnn_single in relevant_device_cnn.get_singles()
|
|
782
|
-
if
|
|
757
|
+
if feat_cnn.contained_in(cur_old_cnn_single, ignore_metadata=True)
|
|
783
758
|
]))
|
|
784
759
|
new_cnn_to_replace.set_metadata_for_all_subitems(relevant_device_cnn.metadata)
|
|
785
760
|
|
|
@@ -896,8 +871,12 @@ class VariationExecutor(BasicExecutableExecutor):
|
|
|
896
871
|
|
|
897
872
|
cur_setup_feature_controller.set_active_method_variation(method_selection=method_var_selection)
|
|
898
873
|
|
|
899
|
-
def
|
|
874
|
+
def resolve_and_exchange_unresolved_parametrization(self):
|
|
900
875
|
"""resolves the parametrization if there are any :class:`UnresolvedParametrizedTestcaseExecutor` in the tree"""
|
|
876
|
+
replaced_executors = []
|
|
901
877
|
for cur_child in self._testcase_executors:
|
|
902
878
|
if isinstance(cur_child, UnresolvedParametrizedTestcaseExecutor):
|
|
903
|
-
cur_child.
|
|
879
|
+
replaced_executors.extend(cur_child.get_resolved_parametrized_testcase_executors())
|
|
880
|
+
else:
|
|
881
|
+
replaced_executors.append(cur_child)
|
|
882
|
+
self._testcase_executors = replaced_executors
|
_balder/feature.py
CHANGED
|
@@ -3,9 +3,10 @@ from typing import Type, Dict, Tuple, Union
|
|
|
3
3
|
|
|
4
4
|
from _balder.device import Device
|
|
5
5
|
from _balder.vdevice import VDevice
|
|
6
|
+
from _balder.utils.inner_device_managing_metaclass import InnerDeviceManagingMetaclass
|
|
6
7
|
|
|
7
8
|
|
|
8
|
-
class Feature:
|
|
9
|
+
class Feature(metaclass=InnerDeviceManagingMetaclass):
|
|
9
10
|
"""
|
|
10
11
|
This is the basic feature class. It represents an abstract class that should not be used directly. It is the base
|
|
11
12
|
class for all feature elements.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
from typing import Union, Type
|
|
2
|
+
import dataclasses
|
|
3
|
+
from .device import Device
|
|
4
|
+
from .feature import Feature
|
|
5
|
+
from .controllers import DeviceController
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FeatureReplacementMapping:
|
|
9
|
+
"""
|
|
10
|
+
helper object that stores mappings between scenario and setup features - is used in :class:`VariationExecutor`
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
@dataclasses.dataclass
|
|
14
|
+
class FeatureMapping:
|
|
15
|
+
"""
|
|
16
|
+
stores a single mapping
|
|
17
|
+
"""
|
|
18
|
+
#: the feature attribute name in scenario device
|
|
19
|
+
attr_name: str
|
|
20
|
+
#: the scenario feature instance or None if the current variation does not use this setup feature in scenario
|
|
21
|
+
scenario_feature: Union[Feature, None]
|
|
22
|
+
#: the setup feature that is used for the scenario feature
|
|
23
|
+
setup_feature: Feature
|
|
24
|
+
|
|
25
|
+
def __init__(self):
|
|
26
|
+
self._mappings: list[FeatureReplacementMapping.FeatureMapping] = []
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def mappings(self) -> list[FeatureMapping]:
|
|
30
|
+
"""
|
|
31
|
+
returns all existing mappings
|
|
32
|
+
"""
|
|
33
|
+
return list(self._mappings)
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def attr_names(self) -> list[str]:
|
|
37
|
+
"""
|
|
38
|
+
returns all used attribute names
|
|
39
|
+
"""
|
|
40
|
+
return [mapping.attr_name for mapping in self._mappings]
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def all_scenario_features(self) -> list[Feature]:
|
|
44
|
+
"""
|
|
45
|
+
returns all scenario features
|
|
46
|
+
"""
|
|
47
|
+
return [mapping.scenario_feature for mapping in self._mappings]
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def all_setup_features(self) -> list[Feature]:
|
|
51
|
+
"""
|
|
52
|
+
returns all setup features
|
|
53
|
+
"""
|
|
54
|
+
return [mapping.setup_feature for mapping in self._mappings]
|
|
55
|
+
|
|
56
|
+
def add(self, attr_name: str, scenario_feature: Union[Feature, None], setup_feature: Feature):
|
|
57
|
+
"""
|
|
58
|
+
adds a new mapping
|
|
59
|
+
|
|
60
|
+
:param attr_name: the feature attribute name in scenario device
|
|
61
|
+
:param scenario_feature: the scenario feature instance or None if the current variation does not use this setup
|
|
62
|
+
feature in scenario
|
|
63
|
+
:param setup_feature: the setup feature that is used for the scenario feature
|
|
64
|
+
"""
|
|
65
|
+
if attr_name in self.attr_names:
|
|
66
|
+
raise KeyError(f'entry for property name `{attr_name}` already exist - can not define it multiple times')
|
|
67
|
+
self._mappings.append(FeatureReplacementMapping.FeatureMapping(attr_name, scenario_feature, setup_feature))
|
|
68
|
+
|
|
69
|
+
def get_features_for_attr_name(self, attr_name: str) -> tuple[Feature, Feature]:
|
|
70
|
+
"""
|
|
71
|
+
returns the scenario and its mapped setup feature for a specific attribute name used in the scenario device
|
|
72
|
+
"""
|
|
73
|
+
for mapping in self._mappings:
|
|
74
|
+
if mapping.attr_name == attr_name:
|
|
75
|
+
return mapping.scenario_feature, mapping.setup_feature
|
|
76
|
+
raise KeyError(f'entry for property name `{attr_name}` does not exist')
|
|
77
|
+
|
|
78
|
+
def get_replaced_scenario_feature_for(self, setup_feature: Feature) -> Union[Feature, None]:
|
|
79
|
+
"""
|
|
80
|
+
returns the mapped scenario feature for a given setup feature
|
|
81
|
+
"""
|
|
82
|
+
for mapping in self._mappings:
|
|
83
|
+
if mapping.setup_feature == setup_feature:
|
|
84
|
+
return mapping.scenario_feature
|
|
85
|
+
raise KeyError(f'cannot find setup feature for {setup_feature}')
|
|
86
|
+
|
|
87
|
+
def add_remaining_setup_features_as_autonomous(self, cur_setup_device: Type[Device]):
|
|
88
|
+
"""
|
|
89
|
+
Adds all features that were not added as autonomous features.
|
|
90
|
+
"""
|
|
91
|
+
cur_setup_features = DeviceController.get_for(cur_setup_device).get_all_instantiated_feature_objects()
|
|
92
|
+
|
|
93
|
+
# also add all setup features that are not assigned as autonomous features
|
|
94
|
+
for cur_setup_feature in cur_setup_features.values():
|
|
95
|
+
if cur_setup_feature not in self.all_setup_features:
|
|
96
|
+
# determine free name
|
|
97
|
+
idx = 0
|
|
98
|
+
autonomous_name = None
|
|
99
|
+
while (autonomous_name is None
|
|
100
|
+
or autonomous_name in self.attr_names):
|
|
101
|
+
autonomous_name = f"_autonomous_feat_{idx}"
|
|
102
|
+
idx += 1
|
|
103
|
+
self.add(
|
|
104
|
+
attr_name=autonomous_name,
|
|
105
|
+
scenario_feature=None,
|
|
106
|
+
setup_feature=cur_setup_feature
|
|
107
|
+
)
|