Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion reframe/core/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

__all__ = [
'parameterized_test', 'simple_test', 'required_version',
'run_before', 'run_after'
'require_deps', 'run_before', 'run_after'
]


Expand Down Expand Up @@ -168,6 +168,13 @@ def deco(func):
else:
func._rfm_attach = [phase]

try:
# no need to resolve dependencies independently; this function is
# already attached to a different phase
func._rfm_resolve_deps = False
except AttributeError:
pass

@functools.wraps(func)
def _fn(*args, **kwargs):
func(*args, **kwargs)
Expand Down Expand Up @@ -197,3 +204,15 @@ def run_after(stage):

'''
return _runx('post_' + stage)


def require_deps(func):
tests = inspect.getfullargspec(func).args[1:]
func._rfm_resolve_deps = True

@functools.wraps(func)
def _fn(obj, *args):
newargs = [functools.partial(obj.getdep, t) for t in tests]
func(obj, *newargs)

return _fn
11 changes: 10 additions & 1 deletion reframe/core/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ def __init__(cls, name, bases, namespace, **kwargs):
super().__init__(name, bases, namespace, **kwargs)

# Set up the hooks for the pipeline stages based on the _rfm_attach
# attribute
# attribute; all dependencies will be resolved first in the post-setup
# phase if not assigned elsewhere
hooks = {}
fn_with_deps = []
for v in namespace.values():
if hasattr(v, '_rfm_attach'):
for phase in v._rfm_attach:
Expand All @@ -18,4 +20,11 @@ def __init__(cls, name, bases, namespace, **kwargs):
except KeyError:
hooks[phase] = [v]

try:
if v._rfm_resolve_deps:
fn_with_deps.append(v)
except AttributeError:
pass

hooks['post_setup'] = fn_with_deps + hooks.get('post_setup', [])
cls._rfm_pipeline_hooks = hooks
10 changes: 9 additions & 1 deletion reframe/core/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -1313,7 +1313,15 @@ def depends_on(self, target, how=DEPEND_BY_ENV, subdeps=None):

self._userdeps.append((target, how, subdeps))

def getdep(self, target, environ):
def getdep(self, target, environ=None):
if self.current_environ is None:
raise DependencyError(
'cannot resolve dependencies before the setup phase'
)

if environ is None:
environ = self.current_environ.name

if self._case is None or self._case() is None:
raise DependencyError('no test case is associated with this test')

Expand Down
43 changes: 43 additions & 0 deletions unittests/test_pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,49 @@ def x(self):
_run(test, self.partition, self.prgenv)
assert test.var == 3

def test_require_deps(self):
import unittests.resources.checks.hellocheck as mod
import reframe.frontend.dependency as dependency
import reframe.frontend.executors as executors

class T0(mod.HelloTest):
def __init__(self):
super().__init__()
self._prefix = 'unittests/resources/checks'
self.name = type(self).__name__
self.executable = os.path.join('.', self.name)
self.x = 1

class T1(mod.HelloTest):
def __init__(self):
super().__init__()
self._prefix = 'unittests/resources/checks'
self.name = type(self).__name__
self.executable = os.path.join('.', self.name)
self.depends_on('T0')

@rfm.require_deps
def sety(self, T0):
self.y = T0().x + 1

@rfm.run_before('run')
@rfm.require_deps
def setz(self, T0):
self.z = T0().x + 2

cases = executors.generate_testcases([T0(), T1()])
deps = dependency.build_deps(cases)
for c in dependency.toposort(deps):
_run(*c)

for c in cases:
t = c.check
if t.name == 'T0':
assert t.x == 1
elif t.name == 'T1':
assert t.y == 2
assert t.z == 3


class TestSyntax(unittest.TestCase):
def test_regression_test(self):
Expand Down
9 changes: 9 additions & 0 deletions unittests/test_policies.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import reframe.frontend.executors.policies as policies
import reframe.utility as util
import reframe.utility.os_ext as os_ext
from reframe.core.environments import Environment
from reframe.core.exceptions import DependencyError, JobNotStartedError
from reframe.frontend.loader import RegressionCheckLoader
import unittests.fixtures as fixtures
Expand Down Expand Up @@ -530,6 +531,14 @@ def test_build_deps(self):
# Pick a check to test getdep()
check_e0 = find_case('Test1_exact', 'e0', cases).check
check_e1 = find_case('Test1_exact', 'e1', cases).check

with pytest.raises(DependencyError):
check_e0.getdep('Test0')

# Set the current environment
check_e0._current_environ = Environment('e0')
check_e1._current_environ = Environment('e1')

assert check_e0.getdep('Test0', 'e0').name == 'Test0'
assert check_e0.getdep('Test0', 'e1').name == 'Test0'
assert check_e1.getdep('Test0', 'e1').name == 'Test0'
Expand Down