Skip to content

Commit

Permalink
Recipe with dependencies fix
Browse files Browse the repository at this point in the history
This commit moves dependency serialization to Dependency class from
safeloader to runnable. This will enable the use of dependencies in
recipe files.

Reference: #5918
Signed-off-by: Jan Richter <[email protected]>
  • Loading branch information
richtja committed May 3, 2024
1 parent 58c4ec7 commit d229a56
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 17 deletions.
5 changes: 0 additions & 5 deletions avocado/core/dependencies/dependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
# Copyright: Red Hat Inc. 2024
# Authors: Jan Richter <[email protected]>

from avocado.core.nrunner.runnable import Runnable


class Dependency:
"""
Expand Down Expand Up @@ -57,9 +55,6 @@ def __eq__(self, other):
return hash(self) == hash(other)
return False

def to_runnable(self, config):
return Runnable(self.kind, self.uri, *self.args, config=config, **self.kwargs)

@classmethod
def from_dictionary(cls, dictionary):
return cls(
Expand Down
22 changes: 21 additions & 1 deletion avocado/core/nrunner/runnable.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
except ImportError:
JSONSCHEMA_AVAILABLE = False

from avocado.core.dependencies.dependency import Dependency
from avocado.core.nrunner.config import ConfigDecoder, ConfigEncoder
from avocado.core.settings import settings
from avocado.core.utils.eggenv import get_python_path_env_if_egg
Expand Down Expand Up @@ -100,7 +101,7 @@ def __init__(self, kind, uri, *args, config=None, **kwargs):
self.config = config or {}
self.args = args
self.tags = kwargs.pop("tags", None)
self.dependencies = kwargs.pop("dependencies", None)
self.dependencies = self.read_dependencies(kwargs.pop("dependencies", None))
self.variant = kwargs.pop("variant", None)
self.output_dir = kwargs.pop("output_dir", None)
#: list of (:class:`ReferenceResolutionAssetType`, str) tuples
Expand Down Expand Up @@ -345,6 +346,25 @@ def add_configuration_used(cls, kind, config):
config[config_item] = whole_config.get(config_item)
return config

def read_dependencies(self, dependencies_dict):
"""
Converts dependencies from json to avocado.core.dependencies.dependency.Dependency
:param dependencies: Runnable dependencies
:type dependencies: list of dict, or list of Dependency
:returns: Runnable dependencies in avocado.core.dependencies.dependency.Dependency format.
:rtype: list of Dependency
"""
if isinstance(dependencies_dict, list):
return list(
map(
lambda d: (
Dependency.from_dictionary(d) if isinstance(d, dict) else d
),
dependencies_dict,
)
)

def get_command_args(self):
"""
Returns the command arguments that adhere to the runner interface
Expand Down
6 changes: 1 addition & 5 deletions avocado/core/safeloader/docstring.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import json
import re

from avocado.core.dependencies.dependency import Dependency

#: Gets the docstring directive value from a string. Used to tweak
#: test behavior in various ways
DOCSTRING_DIRECTIVE_RE_RAW = (
Expand Down Expand Up @@ -80,9 +78,7 @@ def get_docstring_directives_dependencies(docstring):
if item.startswith("dependency="):
_, dependency_str = item.split("dependency=", 1)
try:
dependencies.append(
Dependency.from_dictionary(json.loads(dependency_str))
)
dependencies.append(json.loads(dependency_str))
except json.decoder.JSONDecodeError:
# ignore dependencies in case of malformed dictionary
continue
Expand Down
17 changes: 16 additions & 1 deletion avocado/plugins/dependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

from avocado.core.dependencies.dependency import Dependency
from avocado.core.exceptions import JobBaseException
from avocado.core.nrunner.runnable import Runnable
from avocado.core.plugin_interfaces import JobPre, PreTest


Expand Down Expand Up @@ -43,9 +44,23 @@ def pre_test_runnables(test_runnable, suite_config=None): # pylint: disable=W02
dependency_runnables = []
unique_dependencies = list(dict.fromkeys(test_runnable.dependencies))
for dependency in unique_dependencies:
dependency_runnables.append(dependency.to_runnable(test_runnable.config))
dependency_runnables.append(
DependencyResolver._dependency_to_runnable(
dependency, test_runnable.config
)
)
return dependency_runnables

@staticmethod
def _dependency_to_runnable(dependency, config):
return Runnable(
dependency.kind,
dependency.uri,
*dependency.args,
config=config,
**dependency.kwargs,
)


class SuiteDependency(JobPre):
name = "suite-dependency"
Expand Down
4 changes: 2 additions & 2 deletions selftests/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
"job-api-6": 4,
"job-api-7": 1,
"nrunner-interface": 70,
"nrunner-requirement": 24,
"nrunner-requirement": 28,
"unit": 669,
"jobs": 11,
"functional-parallel": 306,
"functional-serial": 6,
"functional-serial": 7,
"optional-plugins": 0,
"optional-plugins-golang": 2,
"optional-plugins-html": 3,
Expand Down
33 changes: 33 additions & 0 deletions selftests/functional/serial/requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,14 @@ def test_c(self):
]
"""

DEPENDENCY_RECIPE_FMT = """
{
"kind": "avocado-instrumented",
"uri": "{path}",
"kwargs": {"dependencies": [{"type": "package", "name": "hello"}]}
}
"""


class BasicTest(TestCaseTmpDir, Test):
"""
Expand Down Expand Up @@ -294,3 +302,28 @@ def test_job_dependency(self):
"vim-common",
result.stdout_text,
)

@skipUnless(os.getenv("CI"), skip_install_message)
def test_dependency_recipe(self):
with script.Script(
os.path.join(self.tmpdir.name, "test_multiple_success.py"),
TEST_WITHOUT_DEPENDENCY,
) as test:
dependency_recipe_data = DEPENDENCY_RECIPE_FMT.format(
path=f"{test.path}:SuccessTest.test_a"
)
with script.Script(
os.path.join(self.tmpdir.name, "dependency_recipe.json"),
dependency_recipe_data,
) as recipe:
command = self.get_command(recipe.path)
result = process.run(command, ignore_status=True)
self.assertEqual(result.exit_status, exit_codes.AVOCADO_ALL_OK)
self.assertIn(
"PASS 3",
result.stdout_text,
)
self.assertNotIn(
"vim-common",
result.stdout_text,
)
5 changes: 2 additions & 3 deletions selftests/unit/safeloader_docstring.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import unittest

from avocado.core.dependencies.dependency import Dependency
from avocado.core.safeloader.docstring import (
DOCSTRING_DIRECTIVE_RE,
check_docstring_directive,
Expand Down Expand Up @@ -166,12 +165,12 @@ def test_get_dependency_empty(self):

def test_dependency_single(self):
raw = ':avocado: dependency={"foo":"bar"}'
exp = [Dependency(kwargs={"foo": "bar"})]
exp = [{"foo": "bar"}]
self.assertEqual(get_docstring_directives_dependencies(raw), exp)

def test_dependency_double(self):
raw = ':avocado: dependency={"foo":"bar"}\n:avocado: dependency={"uri":"http://foo.bar"}'
exp = [Dependency(kwargs={"foo": "bar"}), Dependency(uri="http://foo.bar")]
exp = [{"foo": "bar"}, {"uri": "http://foo.bar"}]
self.assertEqual(get_docstring_directives_dependencies(raw), exp)

def test_directives_regex(self):
Expand Down

0 comments on commit d229a56

Please sign in to comment.