Skip to content
Open
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
48 changes: 48 additions & 0 deletions docs/config_reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2313,6 +2313,53 @@ General Configuration
Save any log files generated by ReFrame to its output directory


.. py:attribute:: general.stagedir_hashes

:required: No
:default: :obj:`True`

Use parameter hashes in the stage and output directories of parameterized tests.

This is useful to avoid long directory names with special characters as well as to avoid conflicts between different parameterized variants of the same test when the parameters are formatted in the same way.
However this makes it harder to associate a stage directory to a specific test variant (users would have to check the ReFrame's output to do the matching).

If human-readable stage directories are important, users can set this to :obj:`False` but should make sure to format their parameters in a way that avoids too complex syntaxes.
For example, the parameter ``plist`` in the following test is a list of strings:

.. code-block:: python

@rfm.simple_test
class MyTest(rfm.RegressionTest):
plist = parameter([["one", "two"], ["three", "four"]])

If ``stagedir_hashes=False``, the stage directory of the first test variant will be the following:

.. code-block:: console

$STAGE_DIR/<system>/<partition>/<environment>/MyTest_plist=["one", "two"]

Accessing this from a shell would require excessive escaping of the special characters which can be error-prone.
The users should instead format the parameter by defining a more shell-friendly formatting as follows:

.. code-block:: python

@rfm.simple_test
class MyTest(rfm.RegressionTest):
plist = parameter([["one", "two"], ["three", "four"]], fmt=lambda x: ",".join(x))

In this case, the stage directory of the first test variant will be the following:

.. code-block:: console

$STAGE_DIR/<system>/<partition>/<environment>/MyTest_plist=one,two


.. note::
This option has the same effect also on the output directory of the tests.


.. versionadded:: 4.11

.. py:attribute:: general.target_systems

:required: No
Expand All @@ -2328,6 +2375,7 @@ General Configuration
- :attr:`~general.git_timeout`
- :attr:`~general.use_login_shell`
- :attr:`~general.flex_alloc_strict`
- :attr:`~general.stagedir_hashes`
- :attr:`~general.trap_job_errors`


Expand Down
15 changes: 15 additions & 0 deletions docs/manpage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2453,6 +2453,21 @@ Whenever an environment variable is associated with a configuration option, its
================================== ==================


.. envvar:: RFM_STAGEDIR_HASHES

Use parameter hashes in the stage and output directories of parameterized tests.

.. table::
:align: left

================================== ==================
Associated command line option N/A
Associated configuration parameter :attr:`~config.general.stagedir_hashes`
================================== ==================

.. versionadded:: 4.11


.. envvar:: RFM_SQLITE_CONN_TIMEOUT

Timeout for SQLite database connections.
Expand Down
9 changes: 7 additions & 2 deletions reframe/core/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -2407,14 +2407,19 @@ def _setup_paths(self):
self.logger.debug('Setting up test paths')
try:
runtime = rt.runtime()
if runtime.get_option('general/0/stagedir_hashes'):
test_name = self.short_name
else:
test_name = self.display_name.replace(' ', '')

self._stagedir = runtime.make_stagedir(
self.current_system.name, self._current_partition.name,
self._current_environ.name, self.short_name
self._current_environ.name, test_name
)
if not self.is_dry_run():
self._outputdir = runtime.make_outputdir(
self.current_system.name, self._current_partition.name,
self._current_environ.name, self.short_name
self._current_environ.name, test_name
)
except OSError as e:
raise PipelineError('failed to set up paths') from e
Expand Down
7 changes: 7 additions & 0 deletions reframe/frontend/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -923,6 +923,13 @@ def main():
help='DB file permissions (SQLite backend)',
type=functools.partial(int, base=8)
)
output_options.add_argument(
dest='stagedir_hashes',
envvar='RFM_STAGEDIR_HASHES',
configvar='general/stagedir_hashes',
action='store_true',
help='Use hashes in stage and output directory names',
)
argparser.add_argument(
dest='syslog_address',
envvar='RFM_SYSLOG_ADDRESS',
Expand Down
2 changes: 2 additions & 0 deletions reframe/schemas/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,7 @@
"report_junit": {"type": ["string", "null"]},
"resolve_module_conflicts": {"type": "boolean"},
"save_log_files": {"type": "boolean"},
"stagedir_hashes": {"type": "boolean"},
"target_systems": {"$ref": "#/defs/system_ref"},
"table_format": {"enum": ["csv", "plain", "pretty"]},
"table_format_delim": {"type": "string"},
Expand Down Expand Up @@ -638,6 +639,7 @@
"general/report_junit": null,
"general/resolve_module_conflicts": true,
"general/save_log_files": false,
"general/stagedir_hashes": true,
"general/table_format": "pretty",
"general/table_format_delim": ",",
"general/target_systems": ["*"],
Expand Down
1 change: 1 addition & 0 deletions unittests/resources/config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ def hostname():
},
{
'git_timeout': 20,
'stagedir_hashes': False,
'target_systems': ['sys2:part2']
}
]
Expand Down
16 changes: 16 additions & 0 deletions unittests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,22 @@ def test_dont_restage(run_reframe, tmp_path):
assert returncode != 0


def test_stagedir_no_hashes(run_reframe, tmp_path):
returncode, stdout, stderr = run_reframe(
system='sys2:part2',
checkpath=['unittests/resources/checks/hellocheck.py'],
more_options=['-n', '^HelloTest$', '--repeat=1', '--keep-stage-files'],
action='run'
)
assert returncode == 0
assert 'Traceback' not in stdout
assert 'Traceback' not in stderr
assert os.path.exists(tmp_path / 'stage' / 'sys2' / 'part2' /
'builtin' / r'HelloTest%.repeat_no=0')
assert os.path.exists(tmp_path / 'output' / 'sys2' / 'part2' /
'builtin' / r'HelloTest%.repeat_no=0')


def test_checkpath_symlink(run_reframe, tmp_path):
# FIXME: This should move to test_loader.py
checks_symlink = tmp_path / 'checks_symlink'
Expand Down
Loading