Speed up traverse unit tests (#33840)
This commit is contained in:
parent
3812edd0db
commit
a4cec82841
5 changed files with 107 additions and 161 deletions
|
@ -3,28 +3,102 @@
|
|||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import pytest
|
||||
|
||||
import spack.traverse as traverse
|
||||
from spack.spec import Spec
|
||||
|
||||
|
||||
def key_by_hash(spec):
|
||||
return spec.dag_hash()
|
||||
def create_dag(nodes, edges):
|
||||
"""
|
||||
Arguments:
|
||||
nodes: list of package names
|
||||
edges: list of tuples (from, to, deptype)
|
||||
Returns:
|
||||
dict: mapping from package name to abstract Spec with proper deps.
|
||||
"""
|
||||
specs = {name: Spec(name) for name in nodes}
|
||||
for parent, child, deptype in edges:
|
||||
specs[parent].add_dependency_edge(specs[child], deptype)
|
||||
return specs
|
||||
|
||||
|
||||
def test_breadth_first_traversal(config, mock_packages):
|
||||
@pytest.fixture()
|
||||
def abstract_specs_dtuse():
|
||||
nodes = [
|
||||
"dtbuild1",
|
||||
"dtbuild2",
|
||||
"dtbuild3",
|
||||
"dtlink1",
|
||||
"dtlink2",
|
||||
"dtlink3",
|
||||
"dtlink4",
|
||||
"dtlink5",
|
||||
"dtrun1",
|
||||
"dtrun2",
|
||||
"dtrun3",
|
||||
"dttop",
|
||||
"dtuse",
|
||||
]
|
||||
edges = [
|
||||
("dtbuild1", "dtbuild2", ("build")),
|
||||
("dtbuild1", "dtlink2", ("build", "link")),
|
||||
("dtbuild1", "dtrun2", ("run")),
|
||||
("dtlink1", "dtlink3", ("build", "link")),
|
||||
("dtlink3", "dtbuild2", ("build")),
|
||||
("dtlink3", "dtlink4", ("build", "link")),
|
||||
("dtrun1", "dtlink5", ("build", "link")),
|
||||
("dtrun1", "dtrun3", ("run")),
|
||||
("dtrun3", "dtbuild3", ("build")),
|
||||
("dttop", "dtbuild1", ("build",)),
|
||||
("dttop", "dtlink1", ("build", "link")),
|
||||
("dttop", "dtrun1", ("run")),
|
||||
("dtuse", "dttop", ("build", "link")),
|
||||
]
|
||||
return create_dag(nodes, edges)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def abstract_specs_dt_diamond():
|
||||
nodes = ["dt-diamond", "dt-diamond-left", "dt-diamond-right", "dt-diamond-bottom"]
|
||||
edges = [
|
||||
("dt-diamond", "dt-diamond-left", ("build", "link")),
|
||||
("dt-diamond", "dt-diamond-right", ("build", "link")),
|
||||
("dt-diamond-right", "dt-diamond-bottom", ("build", "link", "run")),
|
||||
("dt-diamond-left", "dt-diamond-bottom", ("build")),
|
||||
]
|
||||
return create_dag(nodes, edges)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def abstract_specs_chain():
|
||||
# Chain a -> b -> c -> d with skip connections
|
||||
# from a -> c and a -> d.
|
||||
nodes = ["chain-a", "chain-b", "chain-c", "chain-d"]
|
||||
edges = [
|
||||
("chain-a", "chain-b", ("build", "link")),
|
||||
("chain-b", "chain-c", ("build", "link")),
|
||||
("chain-c", "chain-d", ("build", "link")),
|
||||
("chain-a", "chain-c", ("build", "link")),
|
||||
("chain-a", "chain-d", ("build", "link")),
|
||||
]
|
||||
return create_dag(nodes, edges)
|
||||
|
||||
|
||||
def test_breadth_first_traversal(abstract_specs_dtuse):
|
||||
# That that depth of discovery is non-decreasing
|
||||
s = Spec("dttop").concretized()
|
||||
s = abstract_specs_dtuse["dttop"]
|
||||
depths = [
|
||||
depth
|
||||
for (depth, _) in traverse.traverse_nodes(
|
||||
[s], order="breadth", key=key_by_hash, depth=True
|
||||
[s], order="breadth", key=lambda s: s.name, depth=True
|
||||
)
|
||||
]
|
||||
assert depths == sorted(depths)
|
||||
|
||||
|
||||
def test_breadth_first_deptype_traversal(config, mock_packages):
|
||||
s = Spec("dtuse").concretized()
|
||||
def test_breadth_first_deptype_traversal(abstract_specs_dtuse):
|
||||
s = abstract_specs_dtuse["dtuse"]
|
||||
|
||||
names = [
|
||||
"dtuse",
|
||||
|
@ -37,25 +111,21 @@ def test_breadth_first_deptype_traversal(config, mock_packages):
|
|||
"dtlink4",
|
||||
]
|
||||
|
||||
traversal = traverse.traverse_nodes(
|
||||
[s], order="breadth", key=key_by_hash, deptype=("build", "link")
|
||||
)
|
||||
traversal = traverse.traverse_nodes([s], order="breadth", key=id, deptype=("build", "link"))
|
||||
assert [x.name for x in traversal] == names
|
||||
|
||||
|
||||
def test_breadth_firsrt_traversal_deptype_with_builddeps(config, mock_packages):
|
||||
s = Spec("dttop").concretized()
|
||||
def test_breadth_firsrt_traversal_deptype_with_builddeps(abstract_specs_dtuse):
|
||||
s = abstract_specs_dtuse["dttop"]
|
||||
|
||||
names = ["dttop", "dtbuild1", "dtlink1", "dtbuild2", "dtlink2", "dtlink3", "dtlink4"]
|
||||
|
||||
traversal = traverse.traverse_nodes(
|
||||
[s], order="breadth", key=key_by_hash, deptype=("build", "link")
|
||||
)
|
||||
traversal = traverse.traverse_nodes([s], order="breadth", key=id, deptype=("build", "link"))
|
||||
assert [x.name for x in traversal] == names
|
||||
|
||||
|
||||
def test_breadth_first_traversal_deptype_full(config, mock_packages):
|
||||
s = Spec("dttop").concretized()
|
||||
def test_breadth_first_traversal_deptype_full(abstract_specs_dtuse):
|
||||
s = abstract_specs_dtuse["dttop"]
|
||||
|
||||
names = [
|
||||
"dttop",
|
||||
|
@ -72,21 +142,24 @@ def test_breadth_first_traversal_deptype_full(config, mock_packages):
|
|||
"dtbuild3",
|
||||
]
|
||||
|
||||
traversal = traverse.traverse_nodes([s], order="breadth", key=key_by_hash, deptype="all")
|
||||
traversal = traverse.traverse_nodes([s], order="breadth", key=id, deptype="all")
|
||||
assert [x.name for x in traversal] == names
|
||||
|
||||
|
||||
def test_breadth_first_traversal_deptype_run(config, mock_packages):
|
||||
s = Spec("dttop").concretized()
|
||||
def test_breadth_first_traversal_deptype_run(abstract_specs_dtuse):
|
||||
s = abstract_specs_dtuse["dttop"]
|
||||
names = ["dttop", "dtrun1", "dtrun3"]
|
||||
traversal = traverse.traverse_nodes([s], order="breadth", key=key_by_hash, deptype="run")
|
||||
traversal = traverse.traverse_nodes([s], order="breadth", key=id, deptype="run")
|
||||
assert [x.name for x in traversal] == names
|
||||
|
||||
|
||||
def test_breadth_first_traversal_reverse(config, mock_packages):
|
||||
s = Spec("dt-diamond").concretized()
|
||||
def test_breadth_first_traversal_reverse(abstract_specs_dt_diamond):
|
||||
gen = traverse.traverse_nodes(
|
||||
[s["dt-diamond-bottom"]], order="breadth", key=key_by_hash, direction="parents", depth=True
|
||||
[abstract_specs_dt_diamond["dt-diamond-bottom"]],
|
||||
order="breadth",
|
||||
key=id,
|
||||
direction="parents",
|
||||
depth=True,
|
||||
)
|
||||
assert [(depth, spec.name) for (depth, spec) in gen] == [
|
||||
(0, "dt-diamond-bottom"),
|
||||
|
@ -96,20 +169,22 @@ def test_breadth_first_traversal_reverse(config, mock_packages):
|
|||
]
|
||||
|
||||
|
||||
def test_breadth_first_traversal_multiple_roots(config, mock_packages):
|
||||
def test_breadth_first_traversal_multiple_roots(abstract_specs_dt_diamond):
|
||||
# With DFS, the branch dt-diamond -> dt-diamond-left -> dt-diamond-bottom
|
||||
# is followed, with BFS, dt-diamond-bottom should be traced through the second
|
||||
# root dt-diamond-right at depth 1 instead.
|
||||
s = Spec("dt-diamond").concretized()
|
||||
roots = [s["dt-diamond"], s["dt-diamond-right"]]
|
||||
gen = traverse.traverse_edges(roots, order="breadth", key=key_by_hash, depth=True, root=False)
|
||||
roots = [
|
||||
abstract_specs_dt_diamond["dt-diamond"],
|
||||
abstract_specs_dt_diamond["dt-diamond-right"],
|
||||
]
|
||||
gen = traverse.traverse_edges(roots, order="breadth", key=id, depth=True, root=False)
|
||||
assert [(depth, edge.parent.name, edge.spec.name) for (depth, edge) in gen] == [
|
||||
(1, "dt-diamond", "dt-diamond-left"), # edge from first root "to" depth 1
|
||||
(1, "dt-diamond-right", "dt-diamond-bottom"), # edge from second root "to" depth 1
|
||||
]
|
||||
|
||||
|
||||
def test_breadth_first_versus_depth_first_tree(config, mock_packages):
|
||||
def test_breadth_first_versus_depth_first_tree(abstract_specs_chain):
|
||||
"""
|
||||
The packages chain-a, chain-b, chain-c, chain-d have the following DAG:
|
||||
a --> b --> c --> d # a chain
|
||||
|
@ -117,7 +192,7 @@ def test_breadth_first_versus_depth_first_tree(config, mock_packages):
|
|||
a --> d
|
||||
Here we test at what depth the nodes are discovered when using BFS vs DFS.
|
||||
"""
|
||||
s = Spec("chain-a").concretized()
|
||||
s = abstract_specs_chain["chain-a"]
|
||||
|
||||
# BFS should find all nodes as direct deps
|
||||
assert [
|
||||
|
@ -168,9 +243,9 @@ def test_breadth_first_versus_depth_first_tree(config, mock_packages):
|
|||
]
|
||||
|
||||
|
||||
def test_breadth_first_versus_depth_first_printing(config, mock_packages):
|
||||
def test_breadth_first_versus_depth_first_printing(abstract_specs_chain):
|
||||
"""Test breadth-first versus depth-first tree printing."""
|
||||
s = Spec("chain-a").concretized()
|
||||
s = abstract_specs_chain["chain-a"]
|
||||
|
||||
args = {"format": "{name}", "color": False}
|
||||
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
# Copyright 2013-2022 Lawrence Livermore National Security, LLC and other
|
||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
from spack.package import *
|
||||
|
||||
|
||||
class ChainA(Package):
|
||||
"""
|
||||
Part of a collection of mock packages used for testing depth-first vs
|
||||
breadth-first traversal. The DAG they form:
|
||||
a --> b --> c --> d # a chain
|
||||
a --> c # "skip" connection
|
||||
a --> d # "skip" connection
|
||||
Spack's edge order is based on the child package name.
|
||||
In depth-first traversal we get a tree that looks like a chain:
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
In breadth-first we get the tree:
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
"""
|
||||
|
||||
homepage = "https://example.com"
|
||||
has_code = False
|
||||
version("1.0")
|
||||
depends_on("chain-b")
|
||||
depends_on("chain-c")
|
||||
depends_on("chain-d")
|
|
@ -1,32 +0,0 @@
|
|||
# Copyright 2013-2022 Lawrence Livermore National Security, LLC and other
|
||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
from spack.package import *
|
||||
|
||||
|
||||
class ChainB(Package):
|
||||
"""
|
||||
Part of a collection of mock packages used for testing depth-first vs
|
||||
breadth-first traversal. The DAG they form:
|
||||
a --> b --> c --> d # a chain
|
||||
a --> c # "skip" connection
|
||||
a --> d # "skip" connection
|
||||
Spack's edge order is based on the child package name.
|
||||
In depth-first traversal we get a tree that looks like a chain:
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
In breadth-first we get the tree:
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
"""
|
||||
|
||||
homepage = "https://example.com"
|
||||
has_code = False
|
||||
version("1.0")
|
||||
depends_on("chain-c")
|
|
@ -1,32 +0,0 @@
|
|||
# Copyright 2013-2022 Lawrence Livermore National Security, LLC and other
|
||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
from spack.package import *
|
||||
|
||||
|
||||
class ChainC(Package):
|
||||
"""
|
||||
Part of a collection of mock packages used for testing depth-first vs
|
||||
breadth-first traversal. The DAG they form:
|
||||
a --> b --> c --> d # a chain
|
||||
a --> c # "skip" connection
|
||||
a --> d # "skip" connection
|
||||
Spack's edge order is based on the child package name.
|
||||
In depth-first traversal we get a tree that looks like a chain:
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
In breadth-first we get the tree:
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
"""
|
||||
|
||||
homepage = "https://example.com"
|
||||
has_code = False
|
||||
version("1.0")
|
||||
depends_on("chain-d")
|
|
@ -1,31 +0,0 @@
|
|||
# Copyright 2013-2022 Lawrence Livermore National Security, LLC and other
|
||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
from spack.package import *
|
||||
|
||||
|
||||
class ChainD(Package):
|
||||
"""
|
||||
Part of a collection of mock packages used for testing depth-first vs
|
||||
breadth-first traversal. The DAG they form:
|
||||
a --> b --> c --> d # a chain
|
||||
a --> c # "skip" connection
|
||||
a --> d # "skip" connection
|
||||
Spack's edge order is based on the child package name.
|
||||
In depth-first traversal we get a tree that looks like a chain:
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
In breadth-first we get the tree:
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
"""
|
||||
|
||||
homepage = "https://example.com"
|
||||
has_code = False
|
||||
version("1.0")
|
Loading…
Reference in a new issue