diff --git a/reframe/frontend/autodetect.py b/reframe/frontend/autodetect.py index be026f55e3..50b85a8fc1 100644 --- a/reframe/frontend/autodetect.py +++ b/reframe/frontend/autodetect.py @@ -8,6 +8,7 @@ import os import shutil import tempfile +import traceback import reframe as rfm import reframe.core.runtime as runtime @@ -19,6 +20,10 @@ from reframe.utility.cpuinfo import cpuinfo +# This is meant to be used by the unit tests +_TREAT_WARNINGS_AS_ERRORS = False + + def _contents(filename): '''Return the contents of a file.''' @@ -36,7 +41,6 @@ def _log_contents(filename): class _copy_reframe: def __init__(self, prefix): self._prefix = prefix - self._prefix = runtime().get_option('general/0/remote_workdir') self._workdir = None def __enter__(self): @@ -82,6 +86,9 @@ def _load_info(filename, schema=None): with open(filename) as fp: return _validate_info(json.load(fp), schema) except OSError as e: + if _TREAT_WARNINGS_AS_ERRORS: + raise + getlogger().warning( f'could not load file: {filename!r}: {e}' ) @@ -101,9 +108,14 @@ def _save_info(filename, topo_info): with open(filename, 'w') as fp: json.dump(topo_info, fp, indent=2) except OSError as e: + if _TREAT_WARNINGS_AS_ERRORS: + raise + getlogger().warning( f'could not save topology file: {filename!r}: {e}' ) + else: + getlogger().debug(f'> saved topology in {filename!r}') def _is_part_local(part): @@ -143,7 +155,11 @@ def _emit_script(job, env): _log_contents(job.stderr) topo_info = json.loads(_contents('topo.json')) except Exception as e: + if _TREAT_WARNINGS_AS_ERRORS: + raise + getlogger().warning(f'failed to retrieve remote processor info: {e}') + getlogger().debug(traceback.format_exc()) return topo_info @@ -226,14 +242,11 @@ def detect_topology(): _save_info(topo_file, part.processor.info) elif detect_remote_systems: - with runtime.temp_environment(modules=temp_modules, - variables=temp_vars): + with runtime.temp_environment(modules=modules, variables=vars): part._processor = ProcessorInfo(_remote_detect(part)) if part.processor.info: _save_info(topo_file, part.processor.info) - getlogger().debug(f'> saved topology in {topo_file!r}') - if not found_devinfo: getlogger().debug(f'> device auto-detection is not supported') diff --git a/unittests/test_autodetect.py b/unittests/test_autodetect.py index 0703de24e6..46c17ffe58 100644 --- a/unittests/test_autodetect.py +++ b/unittests/test_autodetect.py @@ -7,16 +7,17 @@ import os import pytest - +import reframe.frontend.autodetect as autodetect +import unittests.utility as test_util from reframe.core.runtime import runtime -from reframe.frontend.autodetect import detect_topology from reframe.utility.cpuinfo import cpuinfo @pytest.fixture -def exec_ctx(make_exec_ctx_g, tmp_path, monkeypatch): +def temp_topo(tmp_path, monkeypatch): # Monkey-patch HOME, since topology is always written there monkeypatch.setenv('HOME', str(tmp_path)) + monkeypatch.setattr(autodetect, '_TREAT_WARNINGS_AS_ERRORS', True) # Create a devices file manually, since it is not auto-generated meta_prefix = tmp_path / '.reframe' / 'topology' / 'generic-default' @@ -30,13 +31,12 @@ def exec_ctx(make_exec_ctx_g, tmp_path, monkeypatch): } ], fp) - yield from make_exec_ctx_g() - @pytest.fixture -def invalid_topo_exec_ctx(make_exec_ctx_g, tmp_path, monkeypatch): +def invalid_topo(tmp_path, monkeypatch): # Monkey-patch HOME, since topology is always written there monkeypatch.setenv('HOME', str(tmp_path)) + monkeypatch.setattr(autodetect, '_TREAT_WARNINGS_AS_ERRORS', True) # Create invalid processor and devices files meta_prefix = tmp_path / '.reframe' / 'topology' / 'generic-default' @@ -47,11 +47,30 @@ def invalid_topo_exec_ctx(make_exec_ctx_g, tmp_path, monkeypatch): with open(meta_prefix / 'devices.json', 'w') as fp: fp.write('{') + +@pytest.fixture +def default_exec_ctx(make_exec_ctx_g, temp_topo): + yield from make_exec_ctx_g() + + +@pytest.fixture +def remote_exec_ctx(make_exec_ctx, temp_topo): + if test_util.USER_CONFIG_FILE is None: + pytest.skip('no user configuration file supplied') + + ctx = make_exec_ctx(test_util.USER_CONFIG_FILE, + test_util.USER_SYSTEM, + {'general/remote_detect': True}) + yield ctx + + +@pytest.fixture +def invalid_topo_exec_ctx(make_exec_ctx_g, invalid_topo): yield from make_exec_ctx_g() -def test_autotect(exec_ctx): - detect_topology() +def test_autotect(default_exec_ctx): + autodetect.detect_topology() part = runtime().system.partitions[0] assert part.processor.info == cpuinfo() if part.processor.info: @@ -80,7 +99,18 @@ def test_autotect(exec_ctx): def test_autotect_with_invalid_files(invalid_topo_exec_ctx): - detect_topology() + autodetect.detect_topology() part = runtime().system.partitions[0] assert part.processor.info == cpuinfo() assert part.devices == [] + + +def test_remote_autodetect(remote_exec_ctx): + # All we can do with this test is to trigger the remote auto-detection + # path; since we don't know what the remote user system is, we cannot test + # if the topology is right. + partition = test_util.partition_by_scheduler() + if not partition: + pytest.skip('job submission not supported') + + autodetect.detect_topology()