2222import reframe .core .warnings as warn
2323import reframe .core .hooks as hooks
2424from reframe .core .exceptions import ReframeSyntaxError , SkipTestError , what
25+ from reframe .core .fixtures import FixtureRegistry
2526from reframe .core .logging import getlogger
2627from reframe .core .pipeline import RegressionTest
2728from reframe .utility .versioning import VersionValidator
2829
2930
31+ # NOTE: we should consider renaming this module in 4.0; it practically takes
32+ # care of the registration and instantiation of the tests.
33+
34+
3035class TestRegistry :
3136 '''Regression test registry.
3237
@@ -61,14 +66,20 @@ def skip(self, test):
6166
6267 def instantiate_all (self ):
6368 '''Instantiate all the registered tests.'''
64- ret = []
69+
70+ # We first instantiate the leaf tests and then walk up their
71+ # dependencies to instantiate all the fixtures. Fixtures can only
72+ # establish their exact dependencies at instantiation time, so the
73+ # dependency graph grows dynamically.
74+
75+ leaf_tests = []
6576 for test , variants in self ._tests .items ():
6677 if test in self ._skip_tests :
6778 continue
6879
6980 for args , kwargs in variants :
7081 try :
71- ret .append (test (* args , ** kwargs ))
82+ leaf_tests .append (test (* args , ** kwargs ))
7283 except SkipTestError as e :
7384 getlogger ().warning (
7485 f'skipping test { test .__qualname__ !r} : { e } '
@@ -82,7 +93,30 @@ def instantiate_all(self):
8293 )
8394 getlogger ().verbose (traceback .format_exc ())
8495
85- return ret
96+ # Instantiate fixtures
97+
98+ # Do a level-order traversal of the fixture registries of all leaf
99+ # tests, instantiate all fixtures and generate the final set of
100+ # candidate tests; the leaf tests are consumed at the end of the
101+ # traversal and all instantiated tests (including fixtures) are stored
102+ # in `final_tests`.
103+ final_tests = []
104+ fixture_registry = FixtureRegistry ()
105+ while leaf_tests :
106+ tmp_registry = FixtureRegistry ()
107+ while leaf_tests :
108+ c = leaf_tests .pop ()
109+ reg = getattr (c , '_rfm_fixture_registry' , None )
110+ final_tests .append (c )
111+ if reg :
112+ tmp_registry .update (reg )
113+
114+ # Instantiate the new fixtures and update the registry
115+ new_fixtures = tmp_registry .difference (fixture_registry )
116+ leaf_tests = new_fixtures .instantiate_all ()
117+ fixture_registry .update (new_fixtures )
118+
119+ return final_tests
86120
87121 def __iter__ (self ):
88122 '''Iterate over the registered test classes.'''
0 commit comments