Speed up traverse unit tests (#33840)

This commit is contained in:
Harmen Stoppels 2022-11-14 09:34:14 +01:00 committed by GitHub
parent 3812edd0db
commit a4cec82841
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 107 additions and 161 deletions

View file

@ -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}

View file

@ -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")

View file

@ -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")

View file

@ -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")

View file

@ -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")