avocado_i2n.cartgraph.graph module¶
Main test suite data structure.
SUMMARY¶
The data structure contains tests as nodes in a bidirected graph with edges to their dependencies (parents) and dependables (children) but also with a separate edge for each stateful object.
Copyright: Intra2net AG
INTERFACE¶
- avocado_i2n.cartgraph.graph.set_graph_logging_level(level: int = 20) None[source]¶
Set the logging level specifically for the Cartesian graph.
This determines what descriptions of the graph will be dumped for debugging purposes.
- class avocado_i2n.cartgraph.graph.TestGraph[source]¶
Bases:
objectThe main parsed and traversed test data structure.
This data structure uses a tree for each test object all of which overlap in a directed graph. All tests are using objects that can be brought to certain states and need some specific setup. All states can thus be saved and reused for other tests, resulting in a tree structure of derived states for each object. These object trees are then interconnected as a test might use multiple objects (vms) at once resulting in a directed graph. Running all tests is nothing more but traversing this graph in DFS-like way to minimize setup repetition. The policy of this traversal determines whether an automated setup (tests not defined by the user but needed for his/her tests) will be performed, ignored, overwritten, etc. The overall graph is extracted from the given Cartesian configuration, expanding Cartesian products of tests and tracing their object dependencies.
- property objects: tuple[TestObject]¶
Read-only list of test objects.
- logdir = None¶
- new_objects(objects: list[TestObject] | TestObject) None[source]¶
Add new objects excluding (old) repeating ones as ID.
- Parameters:
objects – candidate test objects
- new_nodes(nodes: list[TestNode] | TestNode) None[source]¶
Add new nodes excluding (old) repeating ones as ID.
- Parameters:
nodes – candidate test nodes
- new_workers(workers: list[TestWorker] | TestWorker) None[source]¶
Add new workers excluding (old) repeating ones as ID.
- Parameters:
workers – candidate test workers
- load_setup_list(dump_dir: str, filename: str = 'setup_list') None[source]¶
Load the setup state of each node from a list file.
- Parameters:
dump_dir – directory for the dump image
filename – file to load the setup information from
- save_setup_list(dump_dir: str, filename: str = 'setup_list') None[source]¶
Save the setup state of each node to a list file.
- Parameters:
dump_dir – directory for the dump image
filename – file to save the setup information to
- report_progress() None[source]¶
Report the total test run progress.
The progress is counted as the number and percentage of tests that are fully finished will not be run again
The estimation includes setup tests which might be reused and therefore provides worst case scenario for the number of remaining tests. It also does not take into account the duration of each test which could vary significantly.
- visualize(dump_dir: str, tag: str = '0') None[source]¶
Dump a visual description of the Cartesian graph at a given parsing/traversal step.
- Parameters:
dump_dir – directory for the dump image
tag – tag of the dump, e.g. parsing/traversal step and slot
- flag_children(node_name: str = '', object_name: str = '', worker_name: str = '', flag_type: str = 'run', flag: function = <function TestGraph.<lambda>>, skip_parents: bool = False, skip_children: bool = False) None[source]¶
Set the run/clean flag for all children of a parent node of a given name.
- Parameters:
node_name – name of the parent node or root if None
object_name – test object whose state is set or shared root if None
worker_name – test worker whose’s run/clean policy will be modified
flag_type – ‘run’ or ‘clean’ categorization of the children
flag – whether and when the run/clean action should be executed
skip_parents – whether the parents should not be flagged (just children)
skip_children – whether the children should not be flagged (just roots)
- Raises:
AssertionErrorif obtained # of root tests is != 1
..note:: Works only with connected graphs and will skip any disconnected nodes.
- flag_intersection(graph: TestGraph, flag_type: str = 'run', flag: function = <function TestGraph.<lambda>>, skip_object_roots: bool = False, skip_shared_root: bool = False) None[source]¶
Set the run/clean flag for all test nodes intersecting with the test nodes from another graph.
- Parameters:
graph – Cartesian graph to intersect the current graph with
flag_type – ‘run’ or ‘clean’ categorization of the children
flag – whether and when the run/clean action should be executed
skip_object_roots – whether the object roots should not be flagged as well
skip_shared_root – whether the shared root should not be flagged as well
..note:: Works also with disconnected graphs and will not skip any disconnected nodes.
- static parse_flat_objects(suffix: str, category: str, restriction: str = '', params: Params = None, unique: bool = False) list[TestObject] | TestObject[source]¶
Parse flat objects for each variant of a suffix satisfying a restriction.
- Parameters:
suffix – suffix to expand into variant objects
category – category of the suffix that will determine the type of the objects
restriction – single or multi-line restriction to use
params – additional parameters to add to or overwrite all objects’ parameters
unique – whether to expect, validate, and return a unique object
- Returns:
a list of parsed flat test objects
- static parse_composite_objects(suffix: str, category: str, restriction: str = '', component_restrs: dict[str, str] = None, params: Params = None, verbose: bool = False, unique: bool = False) list[TestObject] | TestObject[source]¶
Parse a composite object for each variant from joined component variants.
- Parameters:
suffix – suffix to expand into variant objects
category – category of the suffix that will determine the type of the objects
restriction – single or multi-line restriction to use
component_restrs – object-specific suffixes (keys) and variant restrictions (values) for the components
params – runtime parameters used for extra customization
verbose – whether to print extra messages or not
unique – whether to expect, validate, and return a unique object
- Returns:
parsed test objects
- static parse_suffix_objects(category: str, suffix_restrs: dict[str, str] = None, params: Params = None, verbose: bool = False, flat: bool = False) list[TestObject][source]¶
Parse all available test objects and their configuration determined by available suffixes.
- Parameters:
category – category of suffixes that will determine the type of the objects
suffix_restrs – object-specific suffixes (keys) and variant restrictions (values) for the final objects
params – runtime parameters used for extra customization
verbose – whether to print extra messages or not
flat – whether to parse flat or composite objects
- Returns:
parsed test objects
- static parse_object_from_objects(suffix: str, category: str, test_objects: tuple[TestObject], params: Params = None, verbose: bool = False) TestObject[source]¶
Parse a unique composite object from joined already parsed component objects.
- Parameters:
suffix – suffix to expand into variant objects
category – category of the suffix that will determine the type of the objects
test_objects – fully parsed test objects to parse the composite from
params – runtime parameters used for extra customization
verbose – whether to print extra messages or not
- Returns:
parsed test objects
- Raises:
exceptions.AssertionErrorif the parsed composite is not unique
- static parse_components_for_object(test_object: TestObject, category: str, restriction: str = '', params: Params = None, verbose: bool = False, unflatten: bool = False) list[TestObject][source]¶
Parse all component objects for an already parsed composite object.
- Parameters:
test_object – flat or fully parsed test object to parse for components of
category – category of the suffix that will determine the type of the objects
restriction – restriction for the unflattened object if needed
params – runtime parameters used for extra customization
verbose – whether to print extra messages or not
unflatten – whether to unflatten flat objects with their components
- static parse_net_from_object_restrs(suffix: str, object_restrs: dict[str, str] = None) TestObject | NetObject[source]¶
Parse a default net with object strings as compatibility.
- Parameters:
suffix – suffix of the net to parse
object_restrs – object (vm) restrictions as component restrictions for the net
- Returns:
default net object
- static parse_flat_nodes(restriction: str = '', params: Params = None, unique: bool = False) list[TestNode] | TestNode[source]¶
Parse a flat node for each variant of satisfying a restriction.
- Parameters:
restriction – single or multi-line restriction to use
params – runtime parameters used for extra customization
unique – whether to expect, validate, and return a unique node
- Returns:
a list of parsed flat test nodes
- static parse_node_from_object(test_object: TestObject, restriction: str = '', prefix: str = '', params: Params = None) TestNode[source]¶
Get a unique test node of some restriction for the given object.
- Parameters:
test_object – fully parsed test object to parse the node from, typically a test net
restriction – single or multi-line restriction to use
prefix – extra name identifier for the test to be run
params – runtime parameters used for extra customization
- Returns:
parsed test node for the object
- Raises:
ValueErrorif the node is parsed from a non-net object- Raises:
param.EmptyCartesianProductif a vm variant is not compatible with another vm variant within the same test node
- parse_nodes_from_flat_node_and_object(test_node: TestNode, test_object: TestObject, prefix: str = '', params: Params = None, verbose: bool = False) list[TestNode][source]¶
Parse composite nodes from a flat node and a flat object.
- Parameters:
test_node – flat test node to use as a source of parameters and restrictions
test_object – possibly flat test object to compose the node on top of, typically a test net
prefix – extra name identifier for the test to be run
params – runtime parameters used for extra customization
verbose – whether to print extra messages or not
- Returns:
parsed test nodes
- Raises:
param.EmptyCartesianProductif no result on preselected vm
All already parsed test objects will be used to also validate test object uniqueness and main test object.
- parse_composite_nodes(restriction: str = '', test_object: TestObject = None, prefix: str = '', params: Params = None, verbose: bool = False, unique: bool = False) list[TestNode] | TestNode[source]¶
Parse all user defined tests (leaf nodes).
Use the nodes restriction string and possibly restrict to a single test object for the singleton tests.
- Parameters:
restriction – single or multi-line restriction to use
test_object – possibly flat test object to compose the node on top of, typically a test net
prefix – extra name identifier for the test to be run
params – runtime parameters used for extra customization
verbose – whether to print extra messages or not
unique – whether to expect, validate, and return a unique node
- Returns:
parsed test nodes
- Raises:
param.EmptyCartesianProductif no result on preselected vm
All already parsed test objects will be used to also validate test object uniqueness and main test object.
- static parse_object_nodes(worker: TestWorker = None, restriction: str = '', prefix: str = '', object_restrs: dict[str, str] = None, params: Params = None, verbose: bool = False) tuple[list[TestNode], list[TestObject]][source]¶
Parse test nodes based on a selection of parsable objects.
- Parameters:
worker – worker to parse the objects and nodes with or none for backward compatibility
restriction – single or multi-line restriction to use
prefix – extra name identifier for the test to be run
object_restrs – vm restrictions as component restrictions for the nets and thus nodes
params – runtime parameters used for extra customization
verbose – whether to print extra messages or not
- Returns:
parsed test nodes and test objects
- Raises:
param.EmptyCartesianProductif no test variants for the given vm variants
The rest of the parameters are identical to the methods before.
We will parse all available objects in the configs, then parse all selected nodes and finally restrict to the selected objects specified via the object strings (if set) on a test by test basis.
- parse_cloned_branches_for_node_and_object(test_node: TestNode, test_object: TestObject, test_nodes: list[TestNode]) list[TestNode][source]¶
Clone a test node and all of its descendants with one branch for each parent test node.
- Parameters:
test_node – node to use as first round clone source
test_object – stateful object whose state will be modified for cloning
test_nodes – nodes to clone the source for as first round parents
- parse_branches_for_node_and_object(test_node: TestNode, test_object: TestObject, params: Params = None) tuple[list[TestNode], list[TestNode]][source]¶
Parse all objects, parent object dependencies, and child clones for the current node and object.
- Parameters:
test_node – possibly flat test node to parse and get nodes for
test_object – possibly flat test object to get network suffixes from (currently mostly a flat net)
params – runtime parameters used for extra customization
- Returns:
a tuple of all reused and newly parsed parent test nodes as well as final child test nodes
- parse_paths_to_object_roots(test_node: TestNode, test_object: TestObject, params: Params = None) list[tuple[list[TestNode], list[TestNode], TestNode]][source]¶
Parse the setup paths from a flat node to the terminal nodes of all its objects.
- Parameters:
test_node – possibly flat test node to parse and get the complete graph paths for
test_object – possibly flat test object to get network suffixes from (currently mostly a flat net)
params – runtime parameters used for extra customization
- Returns:
a generator of all resolved pairs of parents and children
Parse the shared root node from used test objects (roots) into a connected graph.
- Parameters:
params – runtime parameters used for extra customization
- Returns:
parsed shared root node of all object trees
- static parse_workers(params: Params = None) list[TestWorker][source]¶
Parse all workers with special strings provided by the runtime.
- Parameters:
params – extra parameters to be used as overwrite dictionary
- Returns:
parsed test workers sorted by name with used ones having runtime strings
- static parse_object_trees(worker: TestWorker = None, restriction: str = '', prefix: str = '', object_restrs: dict[str, str] = None, params: Params = None, verbose: bool = False, with_shared_root: bool = True) TestGraph[source]¶
Parse a complete test graph.
- Parameters:
worker – worker traversing the graph with or none for backward compatibility
restriction – single or multi-line restriction to use
prefix – extra name identifier for the test to be run
object_restrs – vm restrictions as component restrictions for the nets and thus nodes
params – runtime parameters used for extra customization
verbose – whether to print extra messages or not
with_shared_root – whether to connect all object trees via shared root node
- Returns:
parsed graph of test nodes and test objects
Parse all user defined tests (leaves) and their dependencies (internal nodes) connecting them according to the required/provided setup states of each test object (vm) and the required/provided objects per test node (test), obtaining and independent graph copy for each worker.
- async traverse_terminal_node(object_name: str, worker: TestWorker, params: Params) bool[source]¶
Traverse an extra set of tests necessary for creating a given test object.
- Parameters:
object_name – name of the test object to be created
worker – worker traversing the terminal node
params – runtime parameters used for extra customization
- Returns:
whether the terminal node was run successfully or not
- Raises:
NotImplementedErrorif using incompatible installation variant
The current implementation with implicit knowledge on the types of test objects internally spawns an original (otherwise unmodified) install test.
- async traverse_node(test_node: TestNode, worker: TestWorker, params: Params) None[source]¶
Traverse a test node according to a given run policy and additional runner conditions.
- Parameters:
test_node – node to be traversed
worker – worker traversing the terminal node
params – runtime parameters used for extra customization
- async reverse_node(test_node: TestNode, worker: TestWorker, params: Params) None[source]¶
Reverse or traverse in the opposite direction a test node according to a given clean policy.
- Parameters:
test_node – node to be reversed (traversed in the opposite direction)
worker – worker reversing the terminal node
params – runtime parameters used for extra customization
The reversal consists of cleanup or sync of any states that could be created by this node instead of running via the test runner which is done for the traversal.
- async traverse_object_trees(worker: TestWorker, params: Params = None) None[source]¶
Run all user and system defined tests.
Optimize the setup reuse and minimize the repetition of demanded tests.
- Parameters:
worker – worker traversing the graph
params – runtime parameters used for extra customization
- Raises:
AssertionErrorif some traversal assertions are violated
The highest priority is at the setup tests (parents) since the test cannot be run without the required setup, then the current test, then a single child of its children (DFS), and finally the other children (tests that can benefit from the fact that this test/setup was done) followed by the other siblings (tests benefiting from its parent/setup.
Of course all possible children are restricted by the user-defined “only” and the number of internal test nodes is minimized for achieving this goal.