baldertest 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. _balder/__init__.py +12 -0
  2. _balder/_version.py +34 -0
  3. _balder/balder_plugin.py +73 -0
  4. _balder/balder_session.py +341 -0
  5. _balder/balder_settings.py +15 -0
  6. _balder/cnnrelations/__init__.py +7 -0
  7. _balder/cnnrelations/and_connection_relation.py +176 -0
  8. _balder/cnnrelations/base_connection_relation.py +270 -0
  9. _balder/cnnrelations/or_connection_relation.py +65 -0
  10. _balder/collector.py +874 -0
  11. _balder/connection.py +863 -0
  12. _balder/connection_metadata.py +255 -0
  13. _balder/console/__init__.py +0 -0
  14. _balder/console/balder.py +58 -0
  15. _balder/controllers/__init__.py +12 -0
  16. _balder/controllers/base_device_controller.py +72 -0
  17. _balder/controllers/controller.py +29 -0
  18. _balder/controllers/device_controller.py +446 -0
  19. _balder/controllers/feature_controller.py +715 -0
  20. _balder/controllers/normal_scenario_setup_controller.py +402 -0
  21. _balder/controllers/scenario_controller.py +524 -0
  22. _balder/controllers/setup_controller.py +134 -0
  23. _balder/controllers/vdevice_controller.py +95 -0
  24. _balder/decorator_connect.py +104 -0
  25. _balder/decorator_covered_by.py +74 -0
  26. _balder/decorator_fixture.py +29 -0
  27. _balder/decorator_for_vdevice.py +118 -0
  28. _balder/decorator_gateway.py +34 -0
  29. _balder/decorator_insert_into_tree.py +52 -0
  30. _balder/decorator_parametrize.py +31 -0
  31. _balder/decorator_parametrize_by_feature.py +36 -0
  32. _balder/device.py +18 -0
  33. _balder/exceptions.py +182 -0
  34. _balder/executor/__init__.py +0 -0
  35. _balder/executor/basic_executable_executor.py +133 -0
  36. _balder/executor/basic_executor.py +205 -0
  37. _balder/executor/executor_tree.py +217 -0
  38. _balder/executor/parametrized_testcase_executor.py +52 -0
  39. _balder/executor/scenario_executor.py +169 -0
  40. _balder/executor/setup_executor.py +163 -0
  41. _balder/executor/testcase_executor.py +203 -0
  42. _balder/executor/unresolved_parametrized_testcase_executor.py +184 -0
  43. _balder/executor/variation_executor.py +882 -0
  44. _balder/exit_code.py +19 -0
  45. _balder/feature.py +74 -0
  46. _balder/feature_replacement_mapping.py +107 -0
  47. _balder/feature_vdevice_mapping.py +88 -0
  48. _balder/fixture_definition_scope.py +19 -0
  49. _balder/fixture_execution_level.py +22 -0
  50. _balder/fixture_manager.py +483 -0
  51. _balder/fixture_metadata.py +26 -0
  52. _balder/node_gateway.py +103 -0
  53. _balder/objects/__init__.py +0 -0
  54. _balder/objects/connections/__init__.py +0 -0
  55. _balder/objects/connections/osi_1_physical.py +116 -0
  56. _balder/objects/connections/osi_2_datalink.py +35 -0
  57. _balder/objects/connections/osi_3_network.py +47 -0
  58. _balder/objects/connections/osi_4_transport.py +40 -0
  59. _balder/objects/connections/osi_5_session.py +13 -0
  60. _balder/objects/connections/osi_6_presentation.py +13 -0
  61. _balder/objects/connections/osi_7_application.py +83 -0
  62. _balder/objects/devices/__init__.py +0 -0
  63. _balder/objects/devices/this_device.py +12 -0
  64. _balder/parametrization.py +75 -0
  65. _balder/plugin_manager.py +138 -0
  66. _balder/previous_executor_mark.py +23 -0
  67. _balder/routing_path.py +335 -0
  68. _balder/scenario.py +20 -0
  69. _balder/setup.py +18 -0
  70. _balder/solver.py +246 -0
  71. _balder/testresult.py +163 -0
  72. _balder/unmapped_vdevice.py +13 -0
  73. _balder/utils/__init__.py +0 -0
  74. _balder/utils/functions.py +103 -0
  75. _balder/utils/inner_device_managing_metaclass.py +14 -0
  76. _balder/utils/mixin_can_be_covered_by_executor.py +24 -0
  77. _balder/utils/typings.py +4 -0
  78. _balder/vdevice.py +9 -0
  79. balder/__init__.py +56 -0
  80. balder/connections.py +43 -0
  81. balder/devices.py +9 -0
  82. balder/exceptions.py +44 -0
  83. balder/parametrization.py +8 -0
  84. baldertest-0.1.0.dist-info/METADATA +356 -0
  85. baldertest-0.1.0.dist-info/RECORD +89 -0
  86. baldertest-0.1.0.dist-info/WHEEL +5 -0
  87. baldertest-0.1.0.dist-info/entry_points.txt +2 -0
  88. baldertest-0.1.0.dist-info/licenses/LICENSE +21 -0
  89. baldertest-0.1.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,270 @@
1
+ from __future__ import annotations
2
+ from typing import List, Union, Type, Dict, TypeVar, TYPE_CHECKING
3
+ from abc import ABC, abstractmethod
4
+ from _balder.utils.functions import cnn_type_check_and_convert
5
+
6
+ if TYPE_CHECKING:
7
+ from ..connection import Connection
8
+ from ..connection import ConnectionMetadata
9
+ from ..device import Device
10
+ from .and_connection_relation import AndConnectionRelation
11
+ from .or_connection_relation import OrConnectionRelation
12
+
13
+ BaseConnectionRelationT = TypeVar('BaseConnectionRelationT', bound='BaseConnectionRelation')
14
+
15
+
16
+ class BaseConnectionRelation(ABC):
17
+ """
18
+ This is the base connection list class, which provides the general functionality of connection collections.
19
+ """
20
+
21
+ def __init__(self, *connections: Union[Type[Connection], Connection, BaseConnectionRelationT]):
22
+ self._connections = []
23
+ # add it over append for type checking
24
+ for connection in connections:
25
+ self.append(connection)
26
+
27
+ def __iter__(self):
28
+ return self._connections.__iter__()
29
+
30
+ def __getitem__(self, item):
31
+ return self._connections.__getitem__(item)
32
+
33
+ def __len__(self):
34
+ return len(self._connections)
35
+
36
+ def __hash__(self):
37
+ all_hashes = 0
38
+ for cur_elem in self.connections:
39
+ all_hashes += hash(cur_elem) + hash(self.__class__.__name__)
40
+ return all_hashes
41
+
42
+ def __and__(
43
+ self,
44
+ other: Union[Connection, Type[Connection], AndConnectionRelation, OrConnectionRelation]
45
+ ) -> AndConnectionRelation:
46
+
47
+ from .and_connection_relation import AndConnectionRelation # pylint: disable=import-outside-toplevel
48
+
49
+ new_list = AndConnectionRelation()
50
+ new_list.append(self)
51
+ new_list.append(cnn_type_check_and_convert(other))
52
+ return new_list
53
+
54
+ def __or__(
55
+ self,
56
+ other: Union[Connection, Type[Connection], AndConnectionRelation, OrConnectionRelation]
57
+ ) -> OrConnectionRelation:
58
+
59
+ from .or_connection_relation import OrConnectionRelation # pylint: disable=import-outside-toplevel
60
+
61
+ new_list = OrConnectionRelation()
62
+ new_list.append(self)
63
+ new_list.append(cnn_type_check_and_convert(other))
64
+ return new_list
65
+
66
+ @property
67
+ def connections(self) -> List[Union[Connection, BaseConnectionRelationT]]:
68
+ """
69
+ returns the components of this connection relation
70
+ """
71
+ return self._connections.copy()
72
+
73
+ @property
74
+ def metadata(self) -> ConnectionMetadata | None:
75
+ """
76
+ returns the metadata of this connection relation
77
+ """
78
+ if not self.connections:
79
+ return None
80
+
81
+ # get all unique metadata objects
82
+ existing_metadata = list({elem.metadata for elem in self.connections if elem})
83
+ if len(existing_metadata) > 1:
84
+ raise ValueError(f'different metadata detected: `{existing_metadata}`')
85
+ return existing_metadata[0]
86
+
87
+ @abstractmethod
88
+ def get_simplified_relation(self) -> OrConnectionRelation:
89
+ """
90
+ This method simplifies the connection relation. It will convert every possible relation into an
91
+ OrConnectionRelation[Connection, AndConnectionRelation].
92
+ """
93
+
94
+ def clone(self):
95
+ """
96
+ clones this connection relation
97
+ """
98
+ return self.__class__(*[cnn.clone() for cnn in self._connections])
99
+
100
+ def append(self, connection: Union[Type[Connection], Connection, BaseConnectionRelationT]):
101
+ """
102
+ appends a component to this connection relation
103
+ """
104
+ from ..connection import Connection # pylint: disable=import-outside-toplevel
105
+
106
+ if isinstance(connection, type):
107
+ if issubclass(connection, Connection):
108
+ connection = connection()
109
+ else:
110
+ raise TypeError(f'can not append a element `{connection.__name__}`')
111
+ if not isinstance(connection, Connection) and not isinstance(connection, BaseConnectionRelation):
112
+ raise TypeError('the element that should be appended to the relation needs to be a Connection or another '
113
+ 'relation')
114
+ if isinstance(connection, self.__class__):
115
+ # directly add children (because it has the same type)
116
+ for cur_inner_connection in connection.connections:
117
+ self._connections.append(cur_inner_connection)
118
+ else:
119
+ self._connections.append(connection)
120
+
121
+ def extend(self, relation: BaseConnectionRelationT):
122
+ """
123
+ extends the relation with the elements of provided relation
124
+ """
125
+ if not isinstance(relation, self.__class__):
126
+ raise TypeError(f'the relation with the elements that should be appended needs to be from same type (is '
127
+ f'`{relation.__class__}` | expected `{self.__class__}`)')
128
+ for cur_elem in relation.connections:
129
+ self.append(cur_elem)
130
+
131
+ def set_metadata_for_all_subitems(self, metadata: Union[Dict[str, Union[Device, str]], None]):
132
+ """
133
+ This method sets the metadata for all existing Connection items in this element.
134
+
135
+ :param metadata: the metadata that should be set (if the value is explicitly set to None, it removes the
136
+ metadata from every item)
137
+ """
138
+ for cur_cnn in self._connections:
139
+ cur_cnn.set_metadata_for_all_subitems(metadata)
140
+
141
+ def get_all_used_connection_types(self) -> List[Type[Connection]]:
142
+ """
143
+ This method returns all available connection types, that are used within this connection relation.
144
+ """
145
+ from ..connection import Connection # pylint: disable=import-outside-toplevel
146
+
147
+ result = []
148
+ for cur_inner_elem in self._connections:
149
+ if isinstance(cur_inner_elem, Connection):
150
+ result.append(cur_inner_elem.__class__)
151
+ elif isinstance(cur_inner_elem, BaseConnectionRelation):
152
+ result.extend(cur_inner_elem.get_all_used_connection_types())
153
+ else:
154
+ raise TypeError(f'unexpected type for inner item `{cur_inner_elem.__class__.__name__}`')
155
+ return list(set(result))
156
+
157
+ @abstractmethod
158
+ def get_tree_str(self) -> str:
159
+ """
160
+ returns the tree string for this part of the connection tree
161
+ """
162
+
163
+ def is_resolved(self) -> bool:
164
+ """
165
+ returns whether this connection relation is part of a single connection
166
+ """
167
+ if len(self._connections) == 0:
168
+ return True
169
+ return min(cnn.is_resolved() for cnn in self._connections)
170
+
171
+ def get_resolved(self) -> BaseConnectionRelationT:
172
+ """
173
+ This method returns a resolved Connection Tree. This means that it convert the based_on references so that
174
+ every based on connection is a direct parent of the current element. It secures that there are no undefined
175
+ connection layers between an object and the given parent.
176
+ """
177
+ return self.__class__(*[cnn.get_resolved() for cnn in self._connections])
178
+
179
+ @abstractmethod
180
+ def is_single(self) -> bool:
181
+ """
182
+ returns whether this connection relation is part of a single connection
183
+ """
184
+
185
+ @abstractmethod
186
+ def get_singles(self) -> List[Connection]:
187
+ """
188
+ returns the single connections of all components of this connection relation
189
+ """
190
+
191
+ def cnn_are_in_other(self, other: BaseConnectionRelationT, ignore_metadata: bool=False) -> bool:
192
+ """
193
+ This method validates that the elements from this relation are contained in the other relation. Elements matches
194
+ with each other, as soon as they are equal.
195
+
196
+ .. note::
197
+ This method only checks that every single connections from the first element is contained in the second too.
198
+ It does not check the other direction. If you want to validate this, you need to call this method with both
199
+ possibilities.
200
+
201
+ :param other: the first list of connections
202
+ :param other: the other relation object
203
+ :param ignore_metadata: True, if the metadata of the single connections should be ignored
204
+ :return: True in case that every connection of the first list is equal with one in the second list, otherwise
205
+ False
206
+ """
207
+ for cur_cnn in self._connections:
208
+ found_equal = False
209
+ for cur_other_cnn in other.connections:
210
+ if cur_cnn.equal_with(cur_other_cnn, ignore_metadata=ignore_metadata):
211
+ found_equal = True
212
+ break
213
+ if not found_equal:
214
+ return False
215
+ return True
216
+
217
+ @abstractmethod
218
+ def cut_into_all_possible_subtree_branches(self):
219
+ """
220
+ This method returns a list of all possible connection tree branches. A branch is a single connection, while
221
+ this method returns a list of all possible singles where every single connection has this connection as head.
222
+ """
223
+
224
+ def equal_with(self, other_relation: BaseConnectionRelationT, ignore_metadata=False) -> bool:
225
+ """
226
+ This method returns True if the current relation matches with the other relation object. It always converts the
227
+ elements to a resolved version and checks if both of them are exactly the same.
228
+
229
+ .. note::
230
+ Note that both connection relations need to be resolved.
231
+
232
+ .. note::
233
+ Note that both Connection objects have to have the same ending parent elements. Only the order of the inner
234
+ connection elements are irrelevant.
235
+
236
+ :param other_relation: the other connection relation (needs to be the same type)
237
+
238
+ :param ignore_metadata: if this value is true the method ignores the metadata
239
+
240
+ :return: returns True if both elements are same
241
+ """
242
+ if self.__class__ != other_relation.__class__:
243
+ return False
244
+
245
+ if not self.is_resolved():
246
+ raise ValueError('can not execute method, because connection relation is not resolved')
247
+ if not other_relation.is_resolved():
248
+ raise ValueError('can not execute method, because other connection relation is not resolved')
249
+
250
+ # check inner connection elements (if they match all in both directions)
251
+ return (self.cnn_are_in_other(other_relation, ignore_metadata=ignore_metadata)
252
+ and other_relation.cnn_are_in_other(self, ignore_metadata=ignore_metadata))
253
+
254
+ @abstractmethod
255
+ def contained_in(self, other_conn: Union[Connection, BaseConnectionRelationT], ignore_metadata=False) -> bool:
256
+ """
257
+ This method helps to find out whether this connection relation fits within a given connection tree. A connection
258
+ object is a certain part of the large connection tree that Balder has at its disposal. This method checks
259
+ whether a possibility of this connection tree fits in one possibility of the given connection tree.
260
+
261
+ .. note::
262
+ The method returns true if one single connection of this object fits in another single connection that is
263
+ given by `other_conn`.
264
+
265
+ :param other_conn: the other connection
266
+
267
+ :param ignore_metadata: if this value is true the method ignores the metadata
268
+
269
+ :return: true if the self object is contained in the `other_conn`, otherwise false
270
+ """
@@ -0,0 +1,65 @@
1
+ from __future__ import annotations
2
+ from typing import List, Union, TYPE_CHECKING
3
+
4
+ from .base_connection_relation import BaseConnectionRelation, BaseConnectionRelationT
5
+
6
+ if TYPE_CHECKING:
7
+ from ..connection import Connection
8
+
9
+
10
+ class OrConnectionRelation(BaseConnectionRelation):
11
+ """
12
+ describes a OR relation between connections
13
+ """
14
+
15
+ def get_tree_str(self) -> str:
16
+ based_on_strings = [cur_elem.get_tree_str() for cur_elem in self._connections]
17
+ return f"({' & '.join(based_on_strings)})"
18
+
19
+ def get_simplified_relation(self) -> OrConnectionRelation:
20
+ from ..connection import Connection # pylint: disable=import-outside-toplevel
21
+
22
+ result = OrConnectionRelation()
23
+ for cur_inner_elem in self.connections:
24
+ if isinstance(cur_inner_elem, Connection):
25
+ # that is fine - just add it again
26
+ result.append(cur_inner_elem)
27
+ elif isinstance(cur_inner_elem, BaseConnectionRelation):
28
+ # simplify this AND/OR relation and add the items of it
29
+ # (the simplified version is always an OR relation!)
30
+ result.extend(cur_inner_elem.get_simplified_relation())
31
+ else:
32
+ raise TypeError(f'detect unexpected element type `{cur_inner_elem.__class__}` in inner elements')
33
+ return result
34
+
35
+ def is_single(self) -> bool:
36
+ if len(self.connections) == 0:
37
+ return True
38
+ if len(self.connections) == 1:
39
+ return self.connections[0].is_single()
40
+ return False
41
+
42
+ def get_singles(self) -> List[Connection]:
43
+ result = []
44
+ for elem in self.connections:
45
+ result.extend(elem.get_singles())
46
+ return result
47
+
48
+ def cut_into_all_possible_subtree_branches(self) -> List[OrConnectionRelation]:
49
+ if not self.is_single():
50
+ raise ValueError('can not execute method, because relation is not single')
51
+ result = [OrConnectionRelation()]
52
+ if len(self.connections) == 0:
53
+ return result
54
+ result.extend(self.connections[0].cut_into_all_possible_subtree_branches())
55
+ return result
56
+
57
+ def contained_in(self, other_conn: Union[Connection, BaseConnectionRelationT], ignore_metadata=False) -> bool:
58
+ if not self.is_resolved():
59
+ raise ValueError('can not execute method, because connection relation is not resolved')
60
+ if not other_conn.is_resolved():
61
+ raise ValueError('can not execute method, because other connection relation is not resolved')
62
+ for cur_inner_cnn in self._connections:
63
+ if cur_inner_cnn.contained_in(other_conn, ignore_metadata=ignore_metadata):
64
+ return True
65
+ return False