Skip to content

Commit

Permalink
Fix/empty dict to dependencies indicating all drivers start concurren…
Browse files Browse the repository at this point in the history
…tly (#1103)

* fix dependencies behaviour at empty dict

* add newsfrag

* address review comments
  • Loading branch information
zhenyu-ms authored Jun 20, 2024
1 parent 5075146 commit e47fba0
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 24 deletions.
7 changes: 5 additions & 2 deletions doc/en/multitest.rst
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,11 @@ A MultiTest instance can be constructed from the following parameters:
:py:class:`drivers <testplan.testing.multitest.driver.base.Driver>`.
Drivers on the value side should only start after drivers on the key side are
fully started. When specified, Testplan will try to schedule more drivers
starting parallelly based on the dependencies. Click
:ref:`here <multitest_drivers>` for more information.
starting concurrently based on the dependencies. Drivers included in
``environment`` while not presented in ``dependencies`` will be started
concurrently at the very beginning. Using empty dict here to instruct all
drivers to start concurrently. Click :ref:`here <multitest_drivers>` for more
information.

* **Runtime Information**: The environment always contains a member called
``runtime_info`` which contains information about the current state of the
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Users now can make all drivers of a certain ``Test`` start concurrently by passing an empty dict to ``dependencies`` argument.
3 changes: 1 addition & 2 deletions testplan/testing/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -440,8 +440,7 @@ def _set_dependencies(self) -> None:
deps = parse_dependency(self.cfg.dependencies())
else:
deps = self.cfg.dependencies
if deps:
self.resources.set_dependency(deps)
self.resources.set_dependency(deps)

def _start_resource(self) -> None:
if len(self.resources) == 0:
Expand Down
5 changes: 4 additions & 1 deletion testplan/testing/environment/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ def __init__(self, parent: Optional["Test"] = None):
self.__dict__["_rt_dependency"]: Optional[DriverDepGraph] = None
self.__dict__["_pocketwatches"]: Dict[str, DriverPocketwatch] = dict()

def set_dependency(self, dependency: DriverDepGraph):
def set_dependency(self, dependency: Optional[DriverDepGraph]):
if dependency is None:
return

for d in dependency.vertices.values():
if (
d.uid() not in self._resources
Expand Down
58 changes: 39 additions & 19 deletions tests/functional/testplan/testing/test_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,40 +55,60 @@ def __missing__(self, key):
return self[key]


def _assert_orig_dep(env):
assert env.__dict__["_orig_dependency"] is not None


@skip_on_windows(reason="Bash files skipped on Windows.")
@pytest.mark.parametrize(
"driver_dependencies",
"driver_dependencies, use_callable",
[
[("a", "b")],
[("a", "b"), ("b", "c"), ("a", "c")],
[("a", "b"), ("c", "d"), ("a", "d"), ("c", "b")],
([], False),
([], True),
([("a", "b")], False),
([("a", "b"), ("b", "c"), ("a", "c")], True),
([("a", "b"), ("c", "d"), ("a", "d"), ("c", "b")], False),
],
)
def test_testing_environment(mockplan, driver_dependencies, named_temp_file):

def test_testing_environment(
mockplan, named_temp_file, driver_dependencies, use_callable
):
drivers = DriverGeneratorDict(named_temp_file)
dependencies = defaultdict(list)
for k in ["a", "b"]:
drivers[k] = MyDriver(named_temp_file, k)

predicates = list()
for side_a, side_b in driver_dependencies:
dependencies[drivers[side_a]].append(drivers[side_b])
predicates.append(
lambda line_of: line_of[f"{drivers[side_a].name}_POST"]
< line_of[f"{drivers[side_b].name}_PRE"]
)
if driver_dependencies is None:
dependencies = None
else:
dependencies = defaultdict(list)
for side_a, side_b in driver_dependencies:
dependencies[drivers[side_a]].append(drivers[side_b])
predicates.append(
lambda line_of: line_of[f"{drivers[side_a].name}_POST"]
< line_of[f"{drivers[side_b].name}_PRE"]
)

mockplan.add_resource(ProcessPool(name="I'm not local."))
mockplan.schedule(
target=DummyTest(
name="MyTest",
binary=binary_path,
environment=list(drivers.values()),
dependencies=dependencies,
environment=lambda: list(drivers.values())
if use_callable
else list(drivers.values()),
dependencies=lambda: dependencies
if use_callable
else dependencies,
after_start=_assert_orig_dep,
),
resource="I'm not local.",
resource=None,
)
assert mockplan.run().success is True
assert "lifespan" in mockplan.result.report.entries[0].children[0].timer
assert "lifespan" in mockplan.result.report.entries[0].children[1].timer

for i in range(len(drivers)):
assert (
"lifespan" in mockplan.result.report.entries[0].children[i].timer
)

with open(named_temp_file, "r") as f:
lines = f.read().splitlines()
Expand Down

0 comments on commit e47fba0

Please sign in to comment.