Add scratch module roots to test configuration (#19477)

fixes #19476

Module file content is written to file in a
temporary location and read back to be analyzed
by unit tests.

The approach to patch "open" and write to a
StringIO in memory has been abandoned, since
over time other operations insisting on the
filesystem have been added to the module file
generator.
This commit is contained in:
Massimiliano Culpo 2020-10-22 22:59:39 +02:00 committed by GitHub
parent d6f19eeed2
commit 4ec404dfc0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 23 additions and 82 deletions

View File

@ -425,7 +425,17 @@ def configuration_dir(tmpdir_factory, linux_os):
# Create temporary 'defaults', 'site' and 'user' folders
tmpdir.ensure('user', dir=True)
# Slightly modify compilers.yaml to look like Linux
# Slightly modify config.yaml and compilers.yaml
config_yaml = test_config.join('config.yaml')
modules_root = tmpdir_factory.mktemp('share')
tcl_root = modules_root.ensure('modules', dir=True)
lmod_root = modules_root.ensure('lmod', dir=True)
content = ''.join(config_yaml.read()).format(
str(tcl_root), str(lmod_root)
)
t = tmpdir.join('site', 'config.yaml')
t.write(content)
compilers_yaml = test_config.join('compilers.yaml')
content = ''.join(compilers_yaml.read()).format(linux_os)
t = tmpdir.join('site', 'compilers.yaml')

View File

@ -14,4 +14,5 @@ config:
checksum: true
dirty: false
module_roots:
tcl: $spack/share/spack/modules
tcl: {0}
lmod: {1}

View File

@ -2,16 +2,9 @@
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import os.path
import collections
import contextlib
import inspect
import ruamel.yaml as yaml
import pytest
from six import StringIO
import spack.config
import spack.paths
import spack.spec
import spack.modules.common
@ -19,34 +12,7 @@
@pytest.fixture()
def file_registry():
"""Fake filesystem for modulefiles test"""
return collections.defaultdict(StringIO)
@pytest.fixture()
def filename_dict(file_registry, monkeypatch):
"""Returns a fake open that writes on a StringIO instance instead
of disk.
"""
@contextlib.contextmanager
def _mock(filename, mode):
if not mode == 'w':
raise RuntimeError('opening mode must be "w" [stringio_open]')
try:
yield file_registry[filename]
finally:
handle = file_registry[filename]
file_registry[filename] = handle.getvalue()
handle.close()
# Patch 'open' in the appropriate module
monkeypatch.setattr(spack.modules.common, 'open', _mock, raising=False)
return file_registry
@pytest.fixture()
def modulefile_content(filename_dict, request):
def modulefile_content(request):
"""Returns a function that generates the content of a module file
as a list of lines.
"""
@ -58,59 +24,21 @@ def _impl(spec_str):
spec = spack.spec.Spec(spec_str)
spec.concretize()
generator = writer_cls(spec)
generator.write()
generator.write(overwrite=True)
# Get its filename
filename = generator.layout.filename
# Retrieve the content
content = filename_dict[filename].split('\n')
with open(filename) as f:
content = f.readlines()
content = ''.join(content).split('\n')
generator.remove()
return content
return _impl
@pytest.fixture()
def patch_configuration(monkeypatch, request):
"""Reads a configuration file from the mock ones prepared for tests
and monkeypatches the right classes to hook it in.
"""
# Class of the module file writer
writer_cls = getattr(request.module, 'writer_cls')
# Module where the module file writer is defined
writer_mod = inspect.getmodule(writer_cls)
# Key for specific settings relative to this module type
writer_key = str(writer_mod.__name__).split('.')[-1]
# Root folder for configuration
root_for_conf = os.path.join(
spack.paths.test_path, 'data', 'modules', writer_key
)
def _impl(filename):
file = os.path.join(root_for_conf, filename + '.yaml')
with open(file) as f:
configuration = yaml.load(f)
monkeypatch.setattr(
spack.modules.common,
'configuration',
configuration
)
monkeypatch.setattr(
writer_mod,
'configuration',
configuration[writer_key]
)
monkeypatch.setattr(
writer_mod,
'configuration_registry',
{}
)
return _impl
@pytest.fixture()
def update_template_dirs(config, monkeypatch):
"""Mocks the template directories for tests"""

View File

@ -133,8 +133,10 @@ def test_blacklist(self, modulefile_content, module_configuration):
assert len([x for x in content if 'is-loaded' in x]) == 1
assert len([x for x in content if 'module load ' in x]) == 1
# Returns a StringIO instead of a string as no module file was written
with pytest.raises(AttributeError):
# Catch "Exception" to avoid using FileNotFoundError on Python 3
# and IOError on Python 2 or common bases like EnvironmentError
# which are not officially documented
with pytest.raises(Exception):
modulefile_content('callpath arch=x86-linux')
content = modulefile_content('zmpi arch=x86-linux')