Refactor unit-tests in test/architecture.py (#25848)

Modifications:
- Export platforms from spack.platforms directly, so that client modules don't have to import submodules
- Use only plain imports in test/architecture.py
- Parametrized test in test/architecture.py and put most of the setup/teardown in fixtures
This commit is contained in:
Massimiliano Culpo 2021-09-09 17:34:47 +02:00 committed by GitHub
parent d8b95a496c
commit 5fddd48f80
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 109 additions and 129 deletions

View File

@ -30,6 +30,7 @@
import spack.main import spack.main
import spack.modules import spack.modules
import spack.paths import spack.paths
import spack.platforms
import spack.repo import spack.repo
import spack.spec import spack.spec
import spack.store import spack.store
@ -178,9 +179,6 @@ def __init__(self, conf):
self.url = conf['info']['url'] self.url = conf['info']['url']
def try_import(self, module, abstract_spec_str): def try_import(self, module, abstract_spec_str):
# This import is local since it is needed only on Cray
import spack.platforms.linux
if _try_import_from_store(module, abstract_spec_str): if _try_import_from_store(module, abstract_spec_str):
return True return True
@ -192,7 +190,7 @@ def try_import(self, module, abstract_spec_str):
# On Cray we want to use Linux binaries if available from mirrors # On Cray we want to use Linux binaries if available from mirrors
bincache_platform = spack.architecture.real_platform() bincache_platform = spack.architecture.real_platform()
if str(bincache_platform) == 'cray': if str(bincache_platform) == 'cray':
bincache_platform = spack.platforms.linux.Linux() bincache_platform = spack.platforms.Linux()
with spack.architecture.use_platform(bincache_platform): with spack.architecture.use_platform(bincache_platform):
abstract_spec = spack.spec.Spec( abstract_spec = spack.spec.Spec(
abstract_spec_str + ' ^' + spec_for_current_python() abstract_spec_str + ' ^' + spec_for_current_python()

View File

@ -2,3 +2,14 @@
# Spack Project Developers. See the top-level COPYRIGHT file for details. # Spack Project Developers. See the top-level COPYRIGHT file for details.
# #
# SPDX-License-Identifier: (Apache-2.0 OR MIT) # SPDX-License-Identifier: (Apache-2.0 OR MIT)
from .cray import Cray
from .darwin import Darwin
from .linux import Linux
from .test import Test
__all__ = [
'Cray',
'Darwin',
'Linux',
'Test'
]

View File

@ -2,141 +2,112 @@
# Spack Project Developers. See the top-level COPYRIGHT file for details. # Spack Project Developers. See the top-level COPYRIGHT file for details.
# #
# SPDX-License-Identifier: (Apache-2.0 OR MIT) # SPDX-License-Identifier: (Apache-2.0 OR MIT)
""" Test checks if the architecture class is created correctly and also that
the functions are looking for the correct architecture name
"""
import itertools
import os import os
import platform as py_platform import platform
import pytest import pytest
import spack.architecture import spack.architecture
import spack.concretize import spack.concretize
from spack.platforms.cray import Cray import spack.platforms
from spack.platforms.darwin import Darwin import spack.spec
from spack.platforms.linux import Linux
from spack.spec import Spec
def test_dict_functions_for_architecture(): @pytest.fixture
def sample_arch():
"""Sample test architecture"""
arch = spack.architecture.Arch() arch = spack.architecture.Arch()
arch.platform = spack.architecture.platform() arch.platform = spack.architecture.platform()
arch.os = arch.platform.operating_system('default_os') arch.os = arch.platform.operating_system('default_os')
arch.target = arch.platform.target('default_target') arch.target = arch.platform.target('default_target')
return arch
new_arch = spack.architecture.Arch.from_dict(arch.to_dict())
assert arch == new_arch
assert isinstance(arch, spack.architecture.Arch)
assert isinstance(arch.platform, spack.architecture.Platform)
assert isinstance(arch.os, spack.architecture.OperatingSystem)
assert isinstance(arch.target, spack.architecture.Target)
assert isinstance(new_arch, spack.architecture.Arch)
assert isinstance(new_arch.platform, spack.architecture.Platform)
assert isinstance(new_arch.os, spack.architecture.OperatingSystem)
assert isinstance(new_arch.target, spack.architecture.Target)
def test_platform(): @pytest.fixture
output_platform_class = spack.architecture.real_platform() def current_host_platform():
"""Return the platform of the current host as detected by the
'platform' stdlib package.
"""
if os.path.exists('/opt/cray/pe'): if os.path.exists('/opt/cray/pe'):
my_platform_class = Cray() current_platform = spack.platforms.Cray()
elif 'Linux' in py_platform.system(): elif 'Linux' in platform.system():
my_platform_class = Linux() current_platform = spack.platforms.Linux()
elif 'Darwin' in py_platform.system(): elif 'Darwin' in platform.system():
my_platform_class = Darwin() current_platform = spack.platforms.Darwin()
return current_platform
assert str(output_platform_class) == str(my_platform_class)
def test_boolness(): # Valid keywords for os=xxx or target=xxx
valid_keywords = ["fe", "be", "frontend", "backend"]
@pytest.fixture(
params=([x for x in spack.platforms.Test().targets]
+ valid_keywords + ['default_target'])
)
def target_str(request):
"""All the possible strings that can be used for targets"""
return str(request.param)
@pytest.fixture(
params=([x for x in spack.platforms.Test().operating_sys]
+ valid_keywords + ['default_os'])
)
def os_str(request):
"""All the possible strings that can be used for operating systems"""
return str(request.param)
def test_dict_round_trip(sample_arch):
"""Check that a round trip through dict return an equivalent architecture"""
sample_arch_copy = spack.architecture.Arch.from_dict(sample_arch.to_dict())
assert sample_arch == sample_arch_copy
for current_arch in (sample_arch, sample_arch_copy):
assert isinstance(current_arch, spack.architecture.Arch)
assert isinstance(current_arch.platform, spack.architecture.Platform)
assert isinstance(current_arch.os, spack.architecture.OperatingSystem)
assert isinstance(current_arch.target, spack.architecture.Target)
def test_platform(current_host_platform):
"""Check that current host detection return the correct platform"""
detected_platform = spack.architecture.real_platform()
assert str(detected_platform) == str(current_host_platform)
@pytest.mark.parametrize('attribute_name,expected', [
# Make sure architecture reports that it's False when nothing's set. # Make sure architecture reports that it's False when nothing's set.
(None, False),
# ... and it reports True otherwise
('platform', True),
('os', True),
('target', True)
])
def test_boolness(sample_arch, attribute_name, expected):
"""Boolean checks on an architecture object"""
arch = spack.architecture.Arch() arch = spack.architecture.Arch()
assert not arch if attribute_name:
setattr(arch, attribute_name, getattr(sample_arch, attribute_name))
# Dummy architecture parts assert bool(arch) is expected
plat = spack.architecture.platform()
plat_os = plat.operating_system('default_os')
plat_target = plat.target('default_target')
# Make sure architecture reports that it's True when anything is set.
arch = spack.architecture.Arch()
arch.platform = plat
assert arch
arch = spack.architecture.Arch()
arch.os = plat_os
assert arch
arch = spack.architecture.Arch()
arch.target = plat_target
assert arch
def test_user_front_end_input(config): def test_user_input_combination(config, target_str, os_str):
"""Test when user inputs just frontend that both the frontend target """Test for all the valid user input combinations that both the target and
and frontend operating system match the operating system match.
""" """
platform = spack.architecture.platform() platform = spack.platforms.Test()
frontend_os = str(platform.operating_system('frontend')) spec_str = "libelf"
frontend_target = platform.target('frontend') if os_str != "default_os":
spec_str += " os={0}".format(os_str)
if target_str != "default_target":
spec_str += " target={0}".format(target_str)
spec = spack.spec.Spec(spec_str).concretized()
frontend_spec = Spec('libelf os=frontend target=frontend') assert spec.architecture.os == str(platform.operating_system(os_str))
frontend_spec.concretize() assert spec.architecture.target == platform.target(target_str)
assert frontend_os == frontend_spec.architecture.os
assert frontend_target == frontend_spec.architecture.target
def test_user_back_end_input(config):
"""Test when user inputs backend that both the backend target and
backend operating system match
"""
platform = spack.architecture.platform()
backend_os = str(platform.operating_system("backend"))
backend_target = platform.target("backend")
backend_spec = Spec("libelf os=backend target=backend")
backend_spec.concretize()
assert backend_os == backend_spec.architecture.os
assert backend_target == backend_spec.architecture.target
def test_user_defaults(config):
platform = spack.architecture.platform()
default_os = str(platform.operating_system("default_os"))
default_target = platform.target("default_target")
default_spec = Spec("libelf") # default is no args
default_spec.concretize()
assert default_os == default_spec.architecture.os
assert default_target == default_spec.architecture.target
def test_user_input_combination(config):
valid_keywords = ["fe", "be", "frontend", "backend"]
possible_targets = ([x for x in spack.architecture.platform().targets]
+ valid_keywords)
possible_os = ([x for x in spack.architecture.platform().operating_sys]
+ valid_keywords)
for target, operating_system in itertools.product(
possible_targets, possible_os
):
platform = spack.architecture.platform()
spec_str = "libelf os={0} target={1}".format(operating_system, target)
spec = Spec(spec_str)
spec.concretize()
assert spec.architecture.os == str(
platform.operating_system(operating_system)
)
assert spec.architecture.target == platform.target(target)
def test_operating_system_conversion_to_dict(): def test_operating_system_conversion_to_dict():
@ -234,16 +205,15 @@ def test_satisfy_strict_constraint_when_not_concrete(
@pytest.mark.parametrize('root_target_range,dep_target_range,result', [ @pytest.mark.parametrize('root_target_range,dep_target_range,result', [
(('x86_64:nocona', 'x86_64:core2', 'nocona')), # pref not in intersection ('x86_64:nocona', 'x86_64:core2', 'nocona'), # pref not in intersection
(('x86_64:core2', 'x86_64:nocona', 'nocona')), ('x86_64:core2', 'x86_64:nocona', 'nocona'),
(('x86_64:haswell', 'x86_64:mic_knl', 'core2')), # pref in intersection ('x86_64:haswell', 'x86_64:mic_knl', 'core2'), # pref in intersection
(('ivybridge', 'nocona:skylake', 'ivybridge')), # one side concrete ('ivybridge', 'nocona:skylake', 'ivybridge'), # one side concrete
(('haswell:icelake', 'broadwell', 'broadwell')), ('haswell:icelake', 'broadwell', 'broadwell'),
# multiple ranges in lists with multiple overlaps # multiple ranges in lists with multiple overlaps
(('x86_64:nocona,haswell:broadwell', 'nocona:haswell,skylake:', ('x86_64:nocona,haswell:broadwell', 'nocona:haswell,skylake:', 'nocona'),
'nocona')),
# lists with concrete targets, lists compared to ranges # lists with concrete targets, lists compared to ranges
(('x86_64,haswell', 'core2:broadwell', 'haswell')) ('x86_64,haswell', 'core2:broadwell', 'haswell')
]) ])
@pytest.mark.usefixtures('mock_packages', 'config') @pytest.mark.usefixtures('mock_packages', 'config')
def test_concretize_target_ranges( def test_concretize_target_ranges(
@ -251,8 +221,9 @@ def test_concretize_target_ranges(
): ):
# use foobar=bar to make the problem simpler for the old concretizer # use foobar=bar to make the problem simpler for the old concretizer
# the new concretizer should not need that help # the new concretizer should not need that help
spec = Spec('a %%gcc@10 foobar=bar target=%s ^b target=%s' % spec_str = ('a %%gcc@10 foobar=bar target=%s ^b target=%s' %
(root_target_range, dep_target_range)) (root_target_range, dep_target_range))
spec = spack.spec.Spec(spec_str)
with spack.concretize.disable_compiler_existence_check(): with spack.concretize.disable_compiler_existence_check():
spec.concretize() spec.concretize()

View File

@ -15,7 +15,7 @@
import spack.compilers import spack.compilers
import spack.concretize import spack.concretize
import spack.error import spack.error
import spack.platforms.test import spack.platforms
import spack.repo import spack.repo
from spack.concretize import find_spec from spack.concretize import find_spec
from spack.spec import Spec from spack.spec import Spec
@ -101,8 +101,8 @@ def current_host(request, monkeypatch):
# this function is memoized, so clear its state for testing # this function is memoized, so clear its state for testing
spack.architecture.get_platform.cache.clear() spack.architecture.get_platform.cache.clear()
monkeypatch.setattr(spack.platforms.test.Test, 'default', cpu) monkeypatch.setattr(spack.platforms.Test, 'default', cpu)
monkeypatch.setattr(spack.platforms.test.Test, 'front_end', cpu) monkeypatch.setattr(spack.platforms.Test, 'front_end', cpu)
if not is_preference: if not is_preference:
monkeypatch.setattr(archspec.cpu, 'host', lambda: target) monkeypatch.setattr(archspec.cpu, 'host', lambda: target)
yield target yield target

View File

@ -35,7 +35,7 @@
import spack.package import spack.package
import spack.package_prefs import spack.package_prefs
import spack.paths import spack.paths
import spack.platforms.test import spack.platforms
import spack.repo import spack.repo
import spack.stage import spack.stage
import spack.store import spack.store
@ -345,7 +345,7 @@ def _skip_if_missing_executables(request):
@pytest.fixture(scope='session') @pytest.fixture(scope='session')
def test_platform(): def test_platform():
return spack.platforms.test.Test() return spack.platforms.Test()
@pytest.fixture(autouse=True, scope='session') @pytest.fixture(autouse=True, scope='session')