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
43 changes: 23 additions & 20 deletions reframe/core/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
]


import contextlib
import functools
import glob
import inspect
Expand Down Expand Up @@ -211,7 +210,7 @@ def pipeline_hooks(cls):
#: by this test.
#:
#: :type: :class:`List[str]`
#: :default: ``None``
#: :default: ``required``
#:
#: .. note::
#: .. versionchanged:: 2.12
Expand All @@ -223,7 +222,9 @@ def pipeline_hooks(cls):
#: .. versionchanged:: 3.3
#: Default value changed from ``[]`` to ``None``.
#:
valid_prog_environs = variable(typ.List[str], type(None), value=None)
#: .. versionchanged:: 3.6
#: Default value changed from ``None`` to ``required``.
valid_prog_environs = variable(typ.List[str])

#: List of systems supported by this test.
#: The general syntax for systems is ``<sysname>[:<partname>]``.
Expand All @@ -236,13 +237,15 @@ def pipeline_hooks(cls):
#: .. versionchanged:: 3.3
#: Default value changed from ``[]`` to ``None``.
#:
valid_systems = variable(typ.List[str], type(None), value=None)
#: .. versionchanged:: 3.6
#: Default value changed from ``None`` to ``required``.
valid_systems = variable(typ.List[str])

#: A detailed description of the test.
#:
#: :type: :class:`str`
#: :default: ``self.name``
descr = variable(str, type(None), value=None)
descr = variable(str)

#: The path to the source file or source directory of the test.
#:
Expand Down Expand Up @@ -337,7 +340,7 @@ def pipeline_hooks(cls):
#:
#: :type: :class:`str`
#: :default: ``os.path.join('.', self.name)``
executable = variable(str, type(None), value=None)
executable = variable(str)

#: List of options to be passed to the :attr:`executable`.
#:
Expand Down Expand Up @@ -586,25 +589,27 @@ def pipeline_hooks(cls):
#: Refer to the :doc:`ReFrame Tutorials </tutorials>` for concrete usage
#: examples.
#:
#: If set to :class:`None`, a sanity error will be raised during sanity
#: checking.
#: If not set a sanity error will be raised during sanity checking.
#:
#: :type: A deferrable expression (i.e., the result of a :doc:`sanity
#: function </sanity_functions_reference>`) or :class:`None`
#: :default: :class:`None`
#: function </sanity_functions_reference>`)
#: :default: :class:`required`
#:
#: .. note::
#: .. versionchanged:: 2.9
#: The default behaviour has changed and it is now considered a
#: sanity failure if this attribute is set to :class:`None`.
#: sanity failure if this attribute is set to :class:`required`.
#:
#: If a test doesn't care about its output, this must be stated
#: explicitly as follows:
#:
#: ::
#:
#: self.sanity_patterns = sn.assert_true(1)
sanity_patterns = variable(_DeferredExpression, type(None), value=None)
#:
#: .. versionchanged:: 3.6
#: The default value has changed from ``None`` to ``required``.
sanity_patterns = variable(_DeferredExpression)

#: Patterns for verifying the performance of this test.
#:
Expand Down Expand Up @@ -829,14 +834,12 @@ def _rfm_init(self, name=None, prefix=None):
self.name = name

# Pass if descr is a required variable.
with contextlib.suppress(AttributeError):
if self.descr is None:
self.descr = self.name
if not hasattr(self, 'descr'):
self.descr = self.name

# Pass if the executable is a required variable.
with contextlib.suppress(AttributeError):
if self.executable is None:
self.executable = os.path.join('.', self.name)
if not hasattr(self, 'executable'):
self.executable = os.path.join('.', self.name)

self._perfvalues = {}

Expand Down Expand Up @@ -1520,11 +1523,11 @@ def check_sanity(self):
sn.assert_eq(self.job.exitcode, 0,
msg='job exited with exit code {0}')
]
if self.sanity_patterns is not None:
if hasattr(self, 'sanity_patterns'):
sanity_patterns.append(self.sanity_patterns)

self.sanity_patterns = sn.all(sanity_patterns)
elif self.sanity_patterns is None:
elif not hasattr(self, 'sanity_patterns'):
raise SanityError('sanity_patterns not set')

with osext.change_dir(self._stagedir):
Expand Down
5 changes: 2 additions & 3 deletions reframe/frontend/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,9 @@ def _validate_check(self, check):

name = type(check).__name__
checkfile = os.path.relpath(inspect.getfile(type(check)))
required_attrs = ['sanity_patterns',
'valid_systems', 'valid_prog_environs']
required_attrs = ['valid_systems', 'valid_prog_environs']
for attr in required_attrs:
if getattr(check, attr) is None:
if not hasattr(check, attr):
getlogger().warning(
f'{checkfile}: {attr!r} not defined for test {name!r}; '
f'skipping...'
Expand Down
2 changes: 0 additions & 2 deletions unittests/resources/checks/bad/invalid_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@
# SPDX-License-Identifier: BSD-3-Clause

import reframe as rfm
import reframe.utility.sanity as sn


@rfm.simple_test
class SomeTest(rfm.RegressionTest):
def __init__(self):
self.valid_systems = []
self.valid_prog_environs = []
self.sanity_patterns = sn.assert_true(1)


class NotATest:
Expand Down
2 changes: 0 additions & 2 deletions unittests/resources/checks/emptycheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@
# SPDX-License-Identifier: BSD-3-Clause

import reframe as rfm
import reframe.utility.sanity as sn


@rfm.simple_test
class EmptyTest(rfm.RegressionTest):
def __init__(self):
self.valid_systems = []
self.valid_prog_environs = []
self.sanity_patterns = sn.assert_true(1)
2 changes: 0 additions & 2 deletions unittests/resources/checks/frontend_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,6 @@ class TestWithGenerator(rfm.RunOnlyRegressionTest):
def __init__(self):
self.valid_systems = ['*']
self.valid_prog_environs = ['*']
self.sanity_patterns = sn.assert_true(1)

def foo():
yield True
Expand All @@ -258,7 +257,6 @@ class TestWithFileObject(rfm.RunOnlyRegressionTest):
def __init__(self):
self.valid_systems = ['*']
self.valid_prog_environs = ['*']
self.sanity_patterns = sn.assert_true(1)
with open(__file__) as fp:
pass

Expand Down
2 changes: 0 additions & 2 deletions unittests/resources/checks_unlisted/good.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#

import reframe as rfm
import reframe.utility.sanity as sn

# We just import this individually for testing purposes
from reframe.core.pipeline import RegressionTest
Expand All @@ -18,7 +17,6 @@ class _Base(RegressionTest):
def __init__(self):
self.valid_systems = ['*']
self.valid_prog_environs = ['*']
self.sanity_patterns = sn.assert_true(1)


@rfm.parameterized_test(*((x, y) for x in range(3) for y in range(2)))
Expand Down
2 changes: 0 additions & 2 deletions unittests/resources/checks_unlisted/kbd_interrupt.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
#

import reframe as rfm
import reframe.utility.sanity as sn


@rfm.simple_test
Expand All @@ -22,7 +21,6 @@ def __init__(self):
self.valid_systems = ['*']
self.valid_prog_environs = ['*']
self.tags = {self.name}
self.sanity_patterns = sn.assert_true(1)

@rfm.run_before('setup')
def raise_keyboard_interrupt(self):
Expand Down
17 changes: 17 additions & 0 deletions unittests/test_pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,23 @@ def __init__(self):
_run(MyTest(), *local_exec_ctx)


def test_run_only_set_sanity_in_a_hook(local_exec_ctx):
@fixtures.custom_prefix('unittests/resources/checks')
class MyTest(rfm.RunOnlyRegressionTest):
executable = './hello.sh'
executable_opts = ['Hello, World!']
local = True
valid_prog_environs = ['*']
valid_systems = ['*']

@rfm.run_after('run')
def set_sanity(self):
self.sanity_patterns = sn.assert_found(
r'Hello, World\!', self.stdout)

_run(MyTest(), *local_exec_ctx)


def test_run_only_no_srcdir(local_exec_ctx):
@fixtures.custom_prefix('foo/bar/')
class MyTest(rfm.RunOnlyRegressionTest):
Expand Down