Skip to content

Commit 6653b73

Browse files
authored
Merge pull request #3393 from vkarak/bugfix/dont-restage-skip-clone
[bugfix] Do not copy or `git clone` `sourcesdir` if `--dont-restage` is passed
2 parents 7ff5e29 + 140f049 commit 6653b73

File tree

3 files changed

+55
-15
lines changed

3 files changed

+55
-15
lines changed

docs/manpage.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,10 @@ Options controlling ReFrame output
477477

478478
.. versionadded:: 3.1
479479

480+
.. warning::
481+
482+
Running a test with :option:`--dont-restage` on a stage directory that was created with a different ReFrame version is undefined behaviour.
483+
480484
.. option:: --keep-stage-files
481485

482486
Keep test stage directories even for tests that finish successfully.

reframe/core/pipeline.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import numbers
2121
import os
2222
import shutil
23+
from pathlib import Path
2324

2425
import reframe.core.fields as fields
2526
import reframe.core.hooks as hooks
@@ -1779,6 +1780,21 @@ def setup(self, partition, environ, **job_opts):
17791780
self._setup_container_platform()
17801781
self._resolve_fixtures()
17811782

1783+
def _requires_stagedir_contents(self):
1784+
'''Return true if the contents of the stagedir need to be generated'''
1785+
1786+
# Every time the stage directory is created a fresh mark is created.
1787+
# Normally, this is wiped out before running the test, unless
1788+
# `--dont-restage` is passed. In this case, we want to leave the
1789+
# existing stagedir untouched.
1790+
1791+
mark = Path(self.stagedir) / '.rfm_mark'
1792+
if mark.exists():
1793+
return False
1794+
else:
1795+
mark.touch()
1796+
return True
1797+
17821798
def _copy_to_stagedir(self, path):
17831799
self.logger.debug(f'Copying {path} to stage directory')
17841800
self.logger.debug(f'Symlinking files: {self.readonly_files}')
@@ -1832,11 +1848,12 @@ def compile(self):
18321848
f'interpreted as relative to it'
18331849
)
18341850

1835-
if osext.is_url(self.sourcesdir):
1836-
self._clone_to_stagedir(self.sourcesdir)
1837-
else:
1838-
self._copy_to_stagedir(os.path.join(self._prefix,
1839-
self.sourcesdir))
1851+
if self._requires_stagedir_contents():
1852+
if osext.is_url(self.sourcesdir):
1853+
self._clone_to_stagedir(self.sourcesdir)
1854+
else:
1855+
self._copy_to_stagedir(os.path.join(self._prefix,
1856+
self.sourcesdir))
18401857

18411858
# Set executable (only if hasn't been provided)
18421859
if not hasattr(self, 'executable'):
@@ -2628,7 +2645,7 @@ def run(self):
26282645
The resources of the test are copied to the stage directory and the
26292646
rest of execution is delegated to the :func:`RegressionTest.run()`.
26302647
'''
2631-
if self.sourcesdir:
2648+
if self.sourcesdir and self._requires_stagedir_contents():
26322649
if osext.is_url(self.sourcesdir):
26332650
self._clone_to_stagedir(self.sourcesdir)
26342651
else:

unittests/test_cli.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -339,23 +339,42 @@ def test_check_sanity_failure(run_reframe, tmp_path, run_action):
339339

340340

341341
def test_dont_restage(run_reframe, tmp_path):
342-
run_reframe(
343-
checkpath=['unittests/resources/checks/frontend_checks.py'],
344-
more_options=['-n', 'SanityFailureCheck']
345-
)
342+
# Here we test four properties of `--dont-restage`
343+
# 1. If the stage directory has not been populated before, it will
344+
# 2. If the stage directory has been populated, it will stay untouched
345+
# 3. The sourcesdir will not be copied again
346+
# 4. When combined with `--max-retries`, the stage directory is reused
347+
348+
returncode = run_reframe(
349+
checkpath=['unittests/resources/checks/'],
350+
more_options=['-n', 'SanityFailureCheck', '-n', '^HelloTest$',
351+
'--dont-restage', '--keep-stage-files']
352+
)[0]
353+
# Assert property (1)
354+
assert returncode != 0
346355

347-
# Place a random file in the test's stage directory and rerun with
348-
# `--dont-restage` and `--max-retries`
356+
stagedir_runonly = (tmp_path / 'stage' / 'generic' / 'default' /
357+
'builtin' / 'SanityFailureCheck')
349358
stagedir = (tmp_path / 'stage' / 'generic' / 'default' /
350-
'builtin' / 'SanityFailureCheck')
359+
'builtin' / 'HelloTest')
360+
361+
# Place a new file in the stagedir to test (2)
351362
(stagedir / 'foobar').touch()
363+
(stagedir_runonly / 'foobar').touch()
364+
365+
# Remove a not-needed file to test (2) and (3)
366+
(stagedir / 'Makefile').unlink()
367+
(stagedir_runonly / 'Makefile').unlink()
368+
369+
# Use `--max-retries` to test (4)
352370
returncode, stdout, stderr = run_reframe(
353371
checkpath=['unittests/resources/checks/frontend_checks.py'],
354372
more_options=['-n', 'SanityFailureCheck',
355373
'--dont-restage', '--max-retries=1']
356374
)
357-
assert os.path.exists(stagedir / 'foobar')
358-
assert not os.path.exists(f'{stagedir}_retry1')
375+
assert os.path.exists(stagedir_runonly / 'foobar')
376+
assert not os.path.exists(stagedir_runonly / 'Makefile')
377+
assert not os.path.exists(f'{stagedir_runonly}_retry1')
359378

360379
# And some standard assertions
361380
assert 'Traceback' not in stdout

0 commit comments

Comments
 (0)