Skip to content

Commit c24a90d

Browse files
committed
Job dependencies
This commit introduces job dependency feature. With this feature, you can define common dependency for each test inside job or with Job API inside suite. With this feature, it should be easier to create tests which share their dependencies. It reads all the dependencies from the json file, where the user can specify all the dependencies needed for this job. It uses the same json format as is used in test docstrings. Part of this commit is a documentation update which describes this feature more deeply. Reference: avocado-framework#5504 Signed-off-by: Jan Richter <[email protected]>
1 parent 617b0a8 commit c24a90d

File tree

6 files changed

+150
-3
lines changed

6 files changed

+150
-3
lines changed

avocado/plugins/dependency.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,17 @@
1111
#
1212
# Copyright: Red Hat Inc. 2021
1313
# Authors: Willian Rampazzo <[email protected]>
14+
import json
1415

15-
from avocado.core.plugin_interfaces import PreTest
16+
from avocado.core.dependencies.dependency import Dependency
17+
from avocado.core.exceptions import JobBaseException
18+
from avocado.core.plugin_interfaces import JobPre, PreTest
19+
20+
21+
class DependencyResolverError(JobBaseException):
22+
"""
23+
Error raised when issue occurred during dependency file resolution.
24+
"""
1625

1726

1827
class DependencyResolver(PreTest):
@@ -36,3 +45,33 @@ def pre_test_runnables(test_runnable, suite_config=None): # pylint: disable=W02
3645
for dependency in unique_dependencies:
3746
dependency_runnables.append(dependency.to_runnable(test_runnable.config))
3847
return dependency_runnables
48+
49+
50+
class SuiteDependency(JobPre):
51+
name = "suite-dependency"
52+
description = "Applies a set of dependencies to every test within the suite"
53+
54+
def pre(self, job):
55+
for suite in job.test_suites:
56+
dependency_file_path = suite.config.get("job.run.dependency")
57+
if dependency_file_path:
58+
try:
59+
with open(
60+
dependency_file_path, encoding="utf-8"
61+
) as dependency_file:
62+
try:
63+
dependencies_dict = json.load(dependency_file)
64+
except json.JSONDecodeError as e:
65+
raise DependencyResolverError(
66+
f"Issue with parsing dependency file at {dependency_file_path}: {e}"
67+
)
68+
except FileNotFoundError as e:
69+
raise DependencyResolverError(
70+
f"Dependency file not found at {dependency_file_path}: {e}"
71+
)
72+
dependencies = []
73+
for dependency in dependencies_dict:
74+
dependencies.append(Dependency.from_dictionary(dependency))
75+
for runnable in suite.tests:
76+
dependencies.extend(runnable.dependencies)
77+
runnable.dependencies = dependencies

avocado/plugins/run.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,19 @@ def configure(self, parser):
170170
long_arg="--job-category",
171171
)
172172

173+
help_msg = (
174+
"Path to the json file with list of dependencies needed for each test."
175+
)
176+
settings.register_option(
177+
section="job.run",
178+
key="dependency",
179+
help_msg=help_msg,
180+
parser=parser,
181+
default=None,
182+
metavar="FILE",
183+
long_arg="--job-dependency",
184+
)
185+
173186
settings.add_argparser_to_option(
174187
namespace="job.run.timeout",
175188
metavar="SECONDS",

docs/source/guides/user/chapters/dependencies.rst

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,52 @@ Defining a dependency in the class docstring will fulfill the dependency for
9393
every test within a test class. Defining a dependency in the test docstring
9494
will fulfill the dependency for that single test only.
9595

96+
Defining a job dependency
97+
-------------------------
98+
99+
Managing dependencies across multiple tests within a job can be streamlined
100+
using the Job Dependency Feature. If your tests share common dependencies,
101+
there's no need to specify them individually for each test. Instead, you can
102+
utilize the Job Dependency Feature to apply a set of dependencies to every
103+
test within the job.
104+
105+
Once it is enabled, Avocado will read the list of common dependencies from
106+
the specified JSON file and automatically apply them to each test within
107+
the job.
108+
109+
Enabling the Job Dependency
110+
+++++++++++++++++++++++++++
111+
112+
To enable this feature, you have two options:
113+
114+
1. Command-line Option:
115+
Use of the `--job-dependency` option of the avocado run command
116+
to specify the path to the dependency JSON file::
117+
118+
avocado run --job-dependency=dependencies.json tests/
119+
120+
2. Configuration File:
121+
Alternatively, you can set the path to the dependency JSON file
122+
using the `job.run.dependency` configuration option in the Avocado
123+
configuration file.
124+
125+
.. tip:: If you're using the Job API, you have the flexibility to define
126+
different dependencies for each suite. Simply modify the
127+
`job.run.dependency` value in the suite configuration during suite
128+
creation.
129+
130+
Dependency File Format
131+
++++++++++++++++++++++
132+
133+
The dependency file follows the same format as the test dependency defined
134+
in the docstring. If you have multiple dependencies, ensure to encapsulate
135+
them within a JSON list::
136+
137+
[
138+
{"type": "package", "name": "hello"},
139+
{"type": "package", "name": "bash"}
140+
]
141+
96142
Supported types of dependencies
97143
-------------------------------
98144

selftests/check.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@
2626
"job-api-6": 4,
2727
"job-api-7": 1,
2828
"nrunner-interface": 70,
29-
"nrunner-requirement": 20,
29+
"nrunner-requirement": 24,
3030
"unit": 669,
3131
"jobs": 11,
3232
"functional-parallel": 302,
33-
"functional-serial": 5,
33+
"functional-serial": 6,
3434
"optional-plugins": 0,
3535
"optional-plugins-golang": 2,
3636
"optional-plugins-html": 3,

selftests/functional/serial/requirements.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,32 @@ def test_a(self):
104104
self.check_hello()
105105
'''
106106

107+
TEST_WITHOUT_DEPENDENCY = """from avocado import Test
108+
from avocado.utils import process
109+
110+
class SuccessTest(Test):
111+
112+
def check_hello(self):
113+
result = process.run("hello", ignore_status=True)
114+
self.assertEqual(result.exit_status, 0)
115+
self.assertIn('Hello, world!', result.stdout_text,)
116+
117+
def test_a(self):
118+
self.check_hello()
119+
120+
def test_b(self):
121+
self.check_hello()
122+
123+
def test_c(self):
124+
self.check_hello()
125+
"""
126+
127+
DEPENDENCY_FILE = """
128+
[
129+
{"type": "package", "name": "hello"}
130+
]
131+
"""
132+
107133

108134
class BasicTest(TestCaseTmpDir, Test):
109135
"""
@@ -246,3 +272,25 @@ def test_dependency_duplicates(self):
246272
"PASS 1",
247273
result.stdout_text,
248274
)
275+
276+
@skipUnless(os.getenv("CI"), skip_install_message)
277+
def test_job_dependency(self):
278+
with script.Script(
279+
os.path.join(self.tmpdir.name, "test_multiple_success.py"),
280+
TEST_WITHOUT_DEPENDENCY,
281+
) as test:
282+
command = self.get_command(test.path)
283+
with script.Script(
284+
os.path.join(self.tmpdir.name, "dependency.json"), DEPENDENCY_FILE
285+
) as dependency_config:
286+
command = f"{command} --job-dependency={dependency_config.path}"
287+
result = process.run(command, ignore_status=True)
288+
self.assertEqual(result.exit_status, exit_codes.AVOCADO_ALL_OK)
289+
self.assertIn(
290+
"PASS 3",
291+
result.stdout_text,
292+
)
293+
self.assertNotIn(
294+
"vim-common",
295+
result.stdout_text,
296+
)

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@ def run(self):
419419
"teststmpdir = avocado.plugins.teststmpdir:TestsTmpDir",
420420
"human = avocado.plugins.human:HumanJob",
421421
"testlogsui = avocado.plugins.testlogs:TestLogsUI",
422+
"suite-dependency = avocado.plugins.dependency:SuiteDependency",
422423
],
423424
"avocado.plugins.test.pre": [
424425
"dependency = avocado.plugins.dependency:DependencyResolver",

0 commit comments

Comments
 (0)