diff --git a/python/FactorySystem/Parser.py b/python/FactorySystem/Parser.py index 558a2d33f236..f01303ed4f87 100644 --- a/python/FactorySystem/Parser.py +++ b/python/FactorySystem/Parser.py @@ -56,7 +56,19 @@ def parse(self, filename, default_values = None): self.root = root(0) # make the [Tests] block the root self.check() - self._parseNode(filename, self.root, default_values) + + # Convert any provided default values (from the testroot file) into a + # simple dictionary so that we can merge values without relying on + # pyhit.Node's type conversion rules. + if default_values is not None: + if isinstance(default_values, dict): + defaults = default_values + else: + defaults = {k: v for k, v in default_values.params()} + else: + defaults = {} + + self._parseNode(filename, self.root, defaults) def check(self): """Perform error checking on the loaded hit tree""" @@ -143,6 +155,19 @@ def checkParams(self, params, node): # private: def _parseNode(self, filename, node, default_values): + # Build a new set of default values for any child blocks by combining + # the inherited defaults with parameters defined on this node. This + # allows values supplied in the [Tests] block to propagate to every + # test contained within it. + child_defaults = dict(default_values) if default_values is not None else {} + for key, value in node.params(): + if key == 'type': + continue + if key == 'cli_args' and key in child_defaults: + child_defaults[key] = child_defaults[key] + ' ' + value + else: + child_defaults[key] = value + if 'type' in node: moose_type = node['type'] @@ -153,12 +178,20 @@ def _parseNode(self, filename, node, default_values): params.addParam('hit_path', node.fullpath, 'HIT path to test in spec file') # Apply any new defaults - for key, value in default_values.params(): + for key, value in default_values.items(): if key in params.keys(): if key == 'cli_args': - params[key].append(value) + params[key].append(value) + elif params.type(key) == list: + if isinstance(value, str): + value = value.replace('\n', ' ') + params[key] = re.split(r'\s+', value) + elif isinstance(value, (list, tuple)): + params[key] = list(value) + else: + params[key] = [str(value)] else: - params[key] = value + params[key] = value # Extract the parameters from the hit node self.extractParams(params, node) @@ -201,9 +234,11 @@ def _parseNode(self, filename, node, default_values): elif node.parent.fullpath == 'Tests' and self._check_for_type and not self._looksLikeValidSubBlock(node): self.error('missing "type" parameter in block "{}"'.format(node.fullpath), node=node) - # Loop over the section names and parse them + # Loop over the section names and parse them using the newly + # constructed defaults which include any parameters defined at this + # level. for child in node: - self._parseNode(filename, child, default_values) + self._parseNode(filename, child, child_defaults) # This routine returns a Boolean indicating whether a given block # looks like a valid subblock. In the Testing system, a valid subblock diff --git a/python/TestHarness/tests/test_CapabilitiesPropagation.py b/python/TestHarness/tests/test_CapabilitiesPropagation.py new file mode 100644 index 000000000000..ddd270fc2302 --- /dev/null +++ b/python/TestHarness/tests/test_CapabilitiesPropagation.py @@ -0,0 +1,21 @@ +#* This file is part of the MOOSE framework +#* https://mooseframework.inl.gov +#* +#* All rights reserved, see COPYRIGHT for full restrictions +#* https://github.com/idaholab/moose/blob/master/COPYRIGHT +#* +#* Licensed under LGPL 2.1, please see LICENSE for details +#* https://www.gnu.org/licenses/lgpl-2.1.html + +from TestHarnessTestCase import TestHarnessTestCase + +class TestHarnessTester(TestHarnessTestCase): + def testGlobalCapabilitiesPropagated(self): + result = self.runTests('-i', 'global_capabilities', '--dry-run') + test_results = result.results['tests']['tests/test_harness']['tests']['always_ok'] + self.assertEqual(test_results['capabilities'], 'foo') + + def testGlobalPrereqPropagated(self): + result = self.runTests('-i', 'global_prereq', '--dry-run') + test_results = result.results['tests']['tests/test_harness']['tests']['parent']['tests']['child'] + self.assertEqual(test_results['prereq'], ['pre']) diff --git a/test/tests/test_harness/global_capabilities b/test/tests/test_harness/global_capabilities new file mode 100644 index 000000000000..4627f4216f56 --- /dev/null +++ b/test/tests/test_harness/global_capabilities @@ -0,0 +1,7 @@ +[Tests] + capabilities = 'foo' + [./always_ok] + type = RunApp + input = good.i + [../] +[] diff --git a/test/tests/test_harness/global_prereq b/test/tests/test_harness/global_prereq new file mode 100644 index 000000000000..2671592c96cb --- /dev/null +++ b/test/tests/test_harness/global_prereq @@ -0,0 +1,13 @@ +[Tests] + [parent] + prereq = pre + [pre] + type = RunCommand + command = 'true' + [] + [child] + type = RunCommand + command = 'true' + [] + [] +[]