Skip to content

Commit cf99977

Browse files
committed
Added try...finally blocks to _run_test_phase()
Turned gather_tasks() into tasks() iterator Moved child function docstrings for tasks() into the function body Moved the extra discover phase to full.sh test to save time
1 parent 7f44a80 commit cf99977

7 files changed

Lines changed: 82 additions & 137 deletions

File tree

tests/execute/upgrade/data/plan.fmf

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ execute:
1414
/no-path:
1515
summary: Basic upgrade test with no upgrade path
1616
/path:
17-
summary: Basic upgrade test with upgrade path
17+
summary: Basic upgrade test with multiple discover phases
18+
discover+:
19+
- name: extra-phase
20+
how: fmf
21+
filter: tag:extra
1822
execute+:
1923
upgrade-path: $@{upgrade-path}
2024
/skip-tests:
@@ -27,11 +31,3 @@ execute:
2731
execute+:
2832
upgrade-path: $@{upgrade-path}
2933
skip-tests-after: true
30-
/multi-phase-discover:
31-
summary: Upgrade test with multiple discover phases
32-
discover+:
33-
- name: extra-phase
34-
how: fmf
35-
filter: tag:extra
36-
execute+:
37-
upgrade-path: $@{upgrade-path}

tests/execute/upgrade/full.sh

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,22 @@ rlJournalStart
1616
run --id $run --scratch --rm -vvv --before finish \
1717
plan --name /plan/path" 0 "Run the upgrade test"
1818

19-
# 1 test before + 3 upgrade tasks + 1 test after
20-
rlAssertGrep "5 tests passed" $rlRun_LOG
19+
# 2 test before + 3 upgrade tasks + 2 test after
20+
rlAssertGrep "7 tests passed" $rlRun_LOG
21+
22+
# There should only be 1 execute task
23+
rlAssertGrep "execute task #1:" $rlRun_LOG
24+
rlAssertNotGrep "execute task #2:" $rlRun_LOG
25+
26+
rlAssertEquals "system upgrade should happen only once" "$(grep -o 'upgrade: perform the system upgrade' $rlRun_LOG | wc -l)" 1
2127

2228
# Check that the IN_PLACE_UPGRADE variable was set
23-
rlAssertGrep "IN_PLACE_UPGRADE=old" "$run/plan/path/execute/data/guest/default-0/old/test-1/output.txt"
24-
rlAssertGrep "IN_PLACE_UPGRADE=new" "$run/plan/path/execute/data/guest/default-0/new/test-1/output.txt"
29+
rlAssertGrep "IN_PLACE_UPGRADE=old" "$run/plan/path/execute/data/guest/default-0/old/default-0/test-1/output.txt"
30+
rlAssertGrep "IN_PLACE_UPGRADE=new" "$run/plan/path/execute/data/guest/default-0/new/default-0/test-1/output.txt"
31+
32+
# Check that the extra discover phase test was run before and after the upgrade
33+
rlAssertExists "$run/plan/path/execute/data/guest/default-0/old/extra-phase/extra-test-2/output.txt"
34+
rlAssertExists "$run/plan/path/execute/data/guest/default-0/new/extra-phase/extra-test-2/output.txt"
2535
rlPhaseEnd
2636

2737
rlPhaseStartCleanup

tests/execute/upgrade/main.fmf

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ duration: 10m
22
tier: 4
33

44
/full:
5-
summary: Perform a full distro upgrade
5+
summary: Perform a full distro upgrade with multiple discover phases
66
test: ./full.sh
77
# dnf upgrade is run, this may take quite long
88
duration: 1h
@@ -34,12 +34,3 @@ tier: 4
3434
tag+:
3535
- provision-only
3636
- provision-virtual
37-
38-
/multi-phase-discover:
39-
summary: Perform a full distro upgrade with multiple discover phases
40-
test: ./multi-phase-discover.sh
41-
# dnf upgrade is run, this may take quite long
42-
duration: 1h
43-
tag+:
44-
- provision-only
45-
- provision-virtual

tests/execute/upgrade/multi-phase-discover.sh

Lines changed: 0 additions & 41 deletions
This file was deleted.

tmt/steps/execute/__init__.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import signal as _signal
55
import subprocess
66
import threading
7-
from collections.abc import Sequence
7+
from collections.abc import Iterator, Sequence
88
from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union, cast
99

1010
import click
@@ -978,16 +978,15 @@ def timeout_hint(self, invocation: TestInvocation) -> None:
978978
)
979979

980980
@abc.abstractmethod
981-
def gather_tasks(
981+
def tasks(
982982
self,
983-
) -> list[tuple['ExecutePlugin[ExecuteStepData]', list['Guest']]]:
983+
) -> Iterator[tuple['ExecutePlugin[ExecuteStepData]', list['Guest']]]:
984984
"""
985-
Return tasks to be enqueued for execution.
985+
Iterate over tasks to be enqueued for execution.
986986
987-
This method returns a list of tuples, each containing a plugin phase
988-
copy and the list of guests it should run on.
987+
:yields: tuple of two items, a plugin phase copy
988+
and the list of guests it should run on.
989989
"""
990-
991990
raise NotImplementedError
992991

993992
@abc.abstractmethod
@@ -1218,7 +1217,7 @@ def go(self, force: bool = False) -> None:
12181217
queue.enqueue_action(phase=phase)
12191218

12201219
elif isinstance(phase, ExecutePlugin):
1221-
for phase_copy, guests in phase.gather_tasks():
1220+
for phase_copy, guests in phase.tasks():
12221221
queue.enqueue_plugin(phase=phase_copy, guests=guests)
12231222

12241223
failed_tasks: list[Union[ActionTask, PluginTask[ExecuteStepData, None]]] = []

tmt/steps/execute/internal.py

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import copy
2+
from collections.abc import Iterator
23
from typing import Any, Optional, cast
34

45
import tmt.base.core
@@ -272,39 +273,31 @@ def __init__(self, **kwargs: Any):
272273
super().__init__(**kwargs)
273274
self._previous_progress_message = ""
274275

275-
def gather_tasks(
276+
def tasks(
276277
self,
277-
) -> list[tuple['ExecutePlugin[ExecuteStepData]', list['Guest']]]:
278-
"""
279-
Return tasks to be enqueued for execution.
280-
281-
A single execute plugin is expected to process (potentially)
282-
multiple discover phases. There must be a way to tell the execute
283-
plugin which discover phase to focus on. Unfortunately, the
284-
current way is the execute plugin checking its `discover`
285-
attribute. For each discover phase, we need a copy of the execute
286-
plugin, so we could point it to that discover phase rather than
287-
let it "see" all tests, or test in different discover phase.
288-
"""
289-
tasks: list[tuple[ExecutePlugin[ExecuteStepData], list[Guest]]] = []
278+
) -> Iterator[tuple['ExecutePlugin[ExecuteStepData]', list['Guest']]]:
279+
# A single execute plugin is expected to process (potentially)
280+
# multiple discover phases. There must be a way to tell the execute
281+
# plugin which discover phase to focus on. Unfortunately, the
282+
# current way is the execute plugin checking its `discover`
283+
# attribute. For each discover phase, we need a copy of the execute
284+
# plugin, so we could point it to that discover phase rather than
285+
# let it "see" all tests, or test in different discover phase.
290286
for discover in self.step.plan.discover.phases(classes=(DiscoverPlugin,)):
291287
if not discover.enabled_by_when:
292288
continue
293289

294290
phase_copy = cast(ExecutePlugin[ExecuteStepData], copy.copy(self))
295291
phase_copy.discover_phase = discover.name
296292

297-
tasks.append(
298-
(
299-
phase_copy,
300-
[
301-
guest
302-
for guest in self.step.plan.provision.ready_guests
303-
if discover.enabled_on_guest(guest)
304-
],
305-
)
293+
yield (
294+
phase_copy,
295+
[
296+
guest
297+
for guest in self.step.plan.provision.ready_guests
298+
if discover.enabled_on_guest(guest)
299+
],
306300
)
307-
return tasks
308301

309302
def _test_output_logger(
310303
self,

tmt/steps/execute/upgrade.py

Lines changed: 38 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import copy
2+
from collections.abc import Iterator
23
from typing import Any, Optional, Union, cast
34

45
import fmf.utils
@@ -228,29 +229,20 @@ def discover(self) -> Union[Discover, DiscoverFmf]:
228229
def discover(self, plugin: Optional[DiscoverPlugin[DiscoverStepData]]) -> None:
229230
self._discover = plugin
230231

231-
def gather_tasks(
232+
def tasks(
232233
self,
233-
) -> list[tuple['ExecutePlugin[ExecuteStepData]', list['tmt.guest.Guest']]]:
234-
"""
235-
Return tasks to be enqueued for execution.
236-
237-
upgrade plugin is expected to (potentially) execute multiple
238-
discover phases on old, perform the upgrade, then execute
239-
those same discover phases again on new. All of this should occur
240-
in a single task.
241-
"""
234+
) -> Iterator[tuple['ExecutePlugin[ExecuteStepData]', list['tmt.guest.Guest']]]:
235+
# upgrade plugin is expected to (potentially) execute multiple
236+
# discover phases on old, perform the upgrade, then execute
237+
# those same discover phases again on new. All of this should occur
238+
# in a single task.
242239
phase_copy = cast(ExecutePlugin[ExecuteStepData], copy.copy(self))
243240
# We want to run all discover phases on old and new, so set discover_phase to None.
244241
# This comes with the responsibility to later only run discover phases that are enabled
245242
# for that guest, based on discover.enabled_by_when and discover.enabled_on_guest(guest).
246243
phase_copy.discover_phase = None
247244

248-
return [
249-
(
250-
phase_copy,
251-
self.step.plan.provision.ready_guests,
252-
)
253-
]
245+
yield (phase_copy, self.step.plan.provision.ready_guests)
254246

255247
def go(
256248
self,
@@ -497,31 +489,36 @@ def _run_test_phase(self, guest: tmt.guest.Guest, prefix: str, logger: tmt.log.L
497489
# Backup the original discover phase, it should be None
498490
original_discover_phase = self.discover_phase
499491

500-
# Run discover phases one at a time,
501-
# only running phases that are enabled for this guest.
502-
for discover in self.step.plan.discover.phases(classes=(DiscoverPlugin,)):
503-
if discover.enabled_by_when and discover.enabled_on_guest(guest):
504-
self.discover_phase = discover.name
505-
506-
# Backup and modify test names for this discover phase
507-
test_name_backups: list[tuple[tmt.base.core.Test, str]] = []
508-
for test_origin in self.discover.tests(
509-
phase_name=self.discover_phase, enabled=True
510-
):
511-
test_name_backups.append((test_origin.test, test_origin.test.name))
512-
test_origin.test.name = f'/{prefix}/{test_origin.test.name.lstrip("/")}'
513-
514-
self._run_tests(
515-
guest=guest,
516-
extra_environment=Environment({STATUS_VARIABLE: EnvVarValue(prefix)}),
517-
logger=logger,
518-
)
519-
520-
# Restore test names immediately after this phase
521-
for test, original_name in test_name_backups:
522-
test.name = original_name
523-
524-
self.discover_phase = original_discover_phase
492+
try:
493+
# Run discover phases one at a time,
494+
# only running phases that are enabled for this guest.
495+
for discover in self.step.plan.discover.phases(classes=(DiscoverPlugin,)):
496+
if discover.enabled_by_when and discover.enabled_on_guest(guest):
497+
self.discover_phase = discover.name
498+
499+
test_name_backups: list[tuple[tmt.base.core.Test, str]] = []
500+
try:
501+
# Backup and modify test names for this discover phase
502+
for test_origin in self.discover.tests(
503+
phase_name=self.discover_phase, enabled=True
504+
):
505+
test_name_backups.append((test_origin.test, test_origin.test.name))
506+
test_origin.test.name = (
507+
f'/{prefix}/{test_origin.test.name.lstrip("/")}'
508+
)
509+
510+
self._run_tests(
511+
guest=guest,
512+
extra_environment=Environment({STATUS_VARIABLE: EnvVarValue(prefix)}),
513+
logger=logger,
514+
)
515+
516+
finally:
517+
# Restore test names immediately after this phase
518+
for test, original_name in test_name_backups:
519+
test.name = original_name
520+
finally:
521+
self.discover_phase = original_discover_phase
525522

526523
self._remove_old_results(prefix)
527524

0 commit comments

Comments
 (0)