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
4 changes: 2 additions & 2 deletions reframe/core/builtins.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def sanity_function(fn):
'''Decorate a test member function to mark it as a sanity check.

This decorator will convert the given function into a
:func:`~RegressionMixin.deferrable` and mark it to be executed during the
:func:`~RegressionTestPlugin.deferrable` and mark it to be executed during the
test's sanity stage. When this decorator is used, manually assigning a
value to :attr:`~RegressionTest.sanity_patterns` in the test is not
allowed.
Expand All @@ -118,7 +118,7 @@ def sanity_function(fn):
classes may also decorate a different method as the test's sanity
function. Decorating multiple member functions in the same class is not
allowed. However, a :class:`RegressionTest` may inherit from multiple
:class:`RegressionMixin` classes with their own sanity functions. In this
:class:`RegressionTestPlugin` classes with their own sanity functions. In this
case, the derived class will follow Python's `MRO
<https://docs.python.org/3/library/stdtypes.html#class.__mro__>`_ to find
a suitable sanity function.
Expand Down
4 changes: 2 additions & 2 deletions reframe/core/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ def access_fixture_resources(self):
that these classes can use the same built-in functionalities as in regular
tests decorated with
:func:`@rfm.simple_test<reframe.core.decorators.simple_test>`. This
includes the :func:`~reframe.core.pipeline.RegressionMixin.parameter`
includes the :func:`~reframe.core.pipeline.RegressionTestPlugin.parameter`
built-in, where fixtures may have more than one
:ref:`variant<test-variants>`. When this occurs, a parent test may select
to either treat a parameterized fixture as a test parameter, or instead,
Expand Down Expand Up @@ -595,7 +595,7 @@ class TestE(rfm.RegressionTest):
A parent test may also specify the value of different variables in the
fixture class to be set before its instantiation. Each variable must have
been declared in the fixture class with the
:func:`~reframe.core.pipeline.RegressionMixin.variable` built-in,
:func:`~reframe.core.pipeline.RegressionTestPlugin.variable` built-in,
otherwise it is silently ignored. This variable specification is
equivalent to deriving a new class from the fixture class, and setting
these variable values in the class body of a newly derived class.
Expand Down
63 changes: 54 additions & 9 deletions reframe/core/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
#

__all__ = [
'CompileOnlyRegressionTest', 'RegressionTest', 'RunOnlyRegressionTest',
'RegressionMixin'
'CompileOnlyRegressionTest', 'RegressionMixin',
'RegressionTest', 'RunOnlyRegressionTest', 'RegressionTestPlugin'
]


Expand Down Expand Up @@ -47,6 +47,7 @@
ReframeError)
from reframe.core.meta import RegressionTestMeta
from reframe.core.schedulers import Job
from reframe.core.warnings import user_deprecation_warning


class _NoRuntime(ContainerPlatform):
Expand Down Expand Up @@ -103,23 +104,67 @@ def launch_command(self, stagedir):
_RFM_TEST_KIND_RUN = 2


class RegressionMixin(metaclass=RegressionTestMeta):
class RegressionTestPlugin(metaclass=RegressionTestMeta):
'''A reusable test plugin.

This is a non-test base class that other tests can inherit from in order
to augment their behaviour. A plugin can define variables, parameters,
hooks etc. The following example shows a plugin that defines a variable
and adds a specific job option for every test that uses it.

.. code-block:: python

class MyPlugin(RegressionTestPlugin):
foo = variable(int, value=0)

@run_before('run', always_last=True)
def add_foo_opt(self):
if self.foo:
self.job.options = [f'--foo={self.foo}']


@simple_test
class MyTestA(RegressionTest, MyPlugin):
"""A test using the plugin"""

@simple_test
class MyTestB(RegressionTest, MyPlugin):
"""Another test using the plugin"""


This class is equivalent to the deprecated :class:`RegressionMixin`.

.. versionadded:: 4.9
'''
_rfm_regression_class_kind = _RFM_TEST_KIND_MIXIN


class RegressionMixin(RegressionTestPlugin):
'''Base mixin class for regression tests.

Multiple inheritance from more than one
:class:`RegressionTest` class is not allowed in ReFrame. Hence, mixin
classes provide the flexibility to bundle reusable test add-ons, leveraging
the metaclass magic implemented in
Multiple inheritance from more than one :class:`RegressionTest` class is
not allowed. Hence, mixin classes provide the flexibility to bundle
reusable test add-ons, leveraging the metaclass magic implemented in
:class:`RegressionTestMeta`. Using this metaclass allows mixin classes to
use powerful ReFrame features, such as hooks, parameters or variables.

.. versionadded:: 3.4.2

.. deprecated:: 4.9

Use :class:`RegressionTestPlugin` instead.
'''

_rfm_regression_class_kind = _RFM_TEST_KIND_MIXIN
@classmethod
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
user_deprecation_warning(
'`RegressionMixin` is deprecated; '
'please inherit from `RegresssionTestPlugin` instead'
)


class RegressionTest(RegressionMixin, jsonext.JSONSerializable):
class RegressionTest(RegressionTestPlugin, jsonext.JSONSerializable):
'''Base class for regression tests.

All regression tests must eventually inherit from this class.
Expand Down
4 changes: 2 additions & 2 deletions reframe/utility/typecheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ class ConvertibleType(abc.ABCMeta):
For example, a class whose constructor accepts and :class:`int` may need
to support a cast-from-string conversion. This is particular useful if you
want a custom-typed test
:attr:`~reframe.core.pipeline.RegressionMixin.variable` to be able to be
set from the command line using the :option:`-S` option.
:attr:`~reframe.core.pipeline.RegressionTestPlugin.variable` to be able to
be set from the command line using the :option:`-S` option.

In order to support such conversions, a class must use this metaclass and
define a class method, named as :obj:`__rfm_cast_<type>__`, for each of
Expand Down
50 changes: 25 additions & 25 deletions unittests/test_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,48 +20,48 @@ class Foo:
# Wrong fixture classes

with pytest.raises(ValueError):
class MyTest(rfm.RegressionMixin):
class MyTest(rfm.RegressionTestPlugin):
f = fixture(Foo)

with pytest.raises(ValueError):
class MyTest(rfm.RegressionMixin):
f = fixture(rfm.RegressionMixin)
class MyTest(rfm.RegressionTestPlugin):
f = fixture(rfm.RegressionTestPlugin)

# Session and partition scopes must be run-only.

with pytest.raises(ValueError):
class MyTest(rfm.RegressionMixin):
class MyTest(rfm.RegressionTestPlugin):
f = fixture(rfm.RegressionTest, scope='session')

with pytest.raises(ValueError):
class MyTest(rfm.RegressionMixin):
class MyTest(rfm.RegressionTestPlugin):
f = fixture(rfm.RegressionTest, scope='partition')

with pytest.raises(ValueError):
class MyTest(rfm.RegressionMixin):
class MyTest(rfm.RegressionTestPlugin):
f = fixture(rfm.CompileOnlyRegressionTest, scope='session')

with pytest.raises(ValueError):
class MyTest(rfm.RegressionMixin):
class MyTest(rfm.RegressionTestPlugin):
f = fixture(rfm.CompileOnlyRegressionTest, scope='partition')


def test_fixture_args():
'''Test invalid fixture arguments.'''
with pytest.raises(ValueError):
class MyTest(rfm.RegressionMixin):
class MyTest(rfm.RegressionTestPlugin):
f = fixture(rfm.RegressionTest, scope='other')

with pytest.raises(ValueError):
class MyTest(rfm.RegressionMixin):
class MyTest(rfm.RegressionTestPlugin):
f = fixture(rfm.RegressionTest, action='other')

with pytest.raises(ValueError):
class MyTest(rfm.RegressionMixin):
class MyTest(rfm.RegressionTestPlugin):
f = fixture(rfm.RegressionTest, variants='other')

with pytest.raises(TypeError):
class MyTest(rfm.RegressionMixin):
class MyTest(rfm.RegressionTestPlugin):
f = fixture(rfm.RegressionTest, variables='other')


Expand All @@ -72,7 +72,7 @@ class Foo(rfm.RegressionTest):
p = parameter()

with pytest.raises(ValueError):
class MyTest(rfm.RegressionMixin):
class MyTest(rfm.RegressionTestPlugin):
f = fixture(Foo)


Expand All @@ -83,15 +83,15 @@ class Foo(rfm.RegressionTest):
p = parameter(range(4))

with pytest.raises(ValueError):
class MyTest(rfm.RegressionMixin):
class MyTest(rfm.RegressionTestPlugin):
f = fixture(Foo, variants={'p': lambda x: x > 10})

with pytest.raises(ValueError):
class MyTest(rfm.RegressionMixin):
class MyTest(rfm.RegressionTestPlugin):
f = fixture(Foo, variants=())

# Test default variants argument 'all'
class MyTest(rfm.RegressionMixin):
class MyTest(rfm.RegressionTestPlugin):
f = fixture(Foo, variants='all')

assert MyTest.fixture_space['f'].variants == (0, 1, 2, 3,)
Expand All @@ -103,7 +103,7 @@ def test_fork_join_variants():
class Foo(rfm.RegressionTest):
p = parameter(range(4))

class MyTest(rfm.RegressionMixin):
class MyTest(rfm.RegressionTestPlugin):
f0 = fixture(Foo, action='fork')
f1 = fixture(Foo, action='join')

Expand All @@ -119,7 +119,7 @@ class MyTest(rfm.RegressionMixin):


def test_default_args():
class Foo(rfm.RegressionMixin):
class Foo(rfm.RegressionTestPlugin):
f = fixture(rfm.RegressionTest)

assert Foo.fixture_space['f'].variables == {}
Expand All @@ -132,10 +132,10 @@ def test_fixture_inheritance():
class Fix(rfm.RunOnlyRegressionTest):
pass

class Foo(rfm.RegressionMixin):
class Foo(rfm.RegressionTestPlugin):
f0 = fixture(Fix, scope='test')

class Bar(rfm.RegressionMixin):
class Bar(rfm.RegressionTestPlugin):
f1 = fixture(Fix, scope='environment')
f2 = fixture(Fix, scope='partition')

Expand All @@ -151,10 +151,10 @@ class Baz(Foo, Bar):
def test_fixture_inheritance_clash():
'''Fixture name clash is not permitted.'''

class Foo(rfm.RegressionMixin):
class Foo(rfm.RegressionTestPlugin):
f0 = fixture(rfm.RegressionTest)

class Bar(rfm.RegressionMixin):
class Bar(rfm.RegressionTestPlugin):
f0 = fixture(rfm.RegressionTest)

# Multiple inheritance clash
Expand All @@ -166,7 +166,7 @@ class Baz(Foo, Bar):
def test_fixture_override():
'''A child class may only redefine a fixture with the fixture builtin.'''

class Foo(rfm.RegressionMixin):
class Foo(rfm.RegressionTestPlugin):
f0 = fixture(rfm.RegressionTest)

class Bar(Foo):
Expand All @@ -180,14 +180,14 @@ class Baz(Foo):
Bar.f0 = 4

with pytest.raises(ReframeSyntaxError):
class Baz(rfm.RegressionMixin):
class Baz(rfm.RegressionTestPlugin):
f0 = fixture(rfm.RegressionTest)
f0 = 4


def test_fixture_access_in_class_body():
with pytest.raises(ReframeSyntaxError):
class Foo(rfm.RegressionMixin):
class Foo(rfm.RegressionTestPlugin):
f0 = fixture(rfm.RegressionTest)
print(f0)

Expand Down Expand Up @@ -218,7 +218,7 @@ def test_fixture_space_access():
class P0(rfm.RunOnlyRegressionTest):
p0 = parameter(range(2))

class Foo(rfm.RegressionMixin):
class Foo(rfm.RegressionTestPlugin):
f0 = fixture(P0, scope='test', action='fork')
f1 = fixture(P0, scope='environment', action='join')
f2 = fixture(P0, scope='partition', action='fork')
Expand Down
10 changes: 5 additions & 5 deletions unittests/test_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,10 +199,10 @@ class MyTest(ExtendParams):


def test_param_space_clash():
class Spam(rfm.RegressionMixin):
class Spam(rfm.RegressionTestPlugin):
P0 = parameter([1])

class Ham(rfm.RegressionMixin):
class Ham(rfm.RegressionTestPlugin):
P0 = parameter([2])

with pytest.raises(ReframeSyntaxError):
Expand All @@ -211,10 +211,10 @@ class Eggs(Spam, Ham):


def test_multiple_inheritance():
class Spam(rfm.RegressionMixin):
class Spam(rfm.RegressionTestPlugin):
P0 = parameter()

class Ham(rfm.RegressionMixin):
class Ham(rfm.RegressionTestPlugin):
P0 = parameter([2])

class Eggs(Spam, Ham):
Expand Down Expand Up @@ -276,7 +276,7 @@ class Foo(rfm.RegressionTest):


def test_param_space_read_only():
class Foo(rfm.RegressionMixin):
class Foo(rfm.RegressionTestPlugin):
pass

with pytest.raises(ValueError):
Expand Down
4 changes: 2 additions & 2 deletions unittests/test_pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -1065,7 +1065,7 @@ class BaseTest(HelloTest):
def x(self):
self.var += 1

class C(rfm.RegressionMixin):
class C(rfm.RegressionTestPlugin):
@run_before('run')
def y(self):
self.foo = 1
Expand Down Expand Up @@ -1099,7 +1099,7 @@ def weird_mro_test(HelloTest):
# See example in https://www.python.org/download/releases/2.3/mro/
#
# The MRO of A is ABECDFX, which means that E is more specialized than C!
class X(rfm.RegressionMixin):
class X(rfm.RegressionTestPlugin):
pass

class D(X):
Expand Down
Loading
Loading