# Copyright 2013-2022 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import os
import pytest
import spack.directives
import spack.fetch_strategy
import spack.repo
from spack.paths import mock_packages_path
from spack.spec import Spec
from spack.util.naming import mod_to_class
from spack.version import VersionChecksumError
[docs]@pytest.mark.usefixtures('config', 'mock_packages')
class TestPackage(object):
[docs] def test_load_package(self):
spack.repo.get('mpich')
[docs] def test_package_name(self):
pkg = spack.repo.get('mpich')
assert pkg.name == 'mpich'
[docs] def test_package_filename(self):
repo = spack.repo.Repo(mock_packages_path)
filename = repo.filename_for_package_name('mpich')
assert filename == os.path.join(
mock_packages_path,
'packages',
'mpich',
'package.py'
)
[docs] def test_nonexisting_package_filename(self):
repo = spack.repo.Repo(mock_packages_path)
filename = repo.filename_for_package_name('some-nonexisting-package')
assert filename == os.path.join(
mock_packages_path,
'packages',
'some-nonexisting-package',
'package.py'
)
[docs] def test_package_class_names(self):
assert 'Mpich' == mod_to_class('mpich')
assert 'PmgrCollective' == mod_to_class('pmgr_collective')
assert 'PmgrCollective' == mod_to_class('pmgr-collective')
assert 'Pmgrcollective' == mod_to_class('PmgrCollective')
assert '_3db' == mod_to_class('3db')
# Below tests target direct imports of spack packages from the
# spack.pkg namespace
[docs] def test_import_package(self):
import spack.pkg.builtin.mock.mpich # type: ignore[import] # noqa
[docs] def test_import_package_as(self):
import spack.pkg.builtin.mock # noqa
import spack.pkg.builtin.mock as m # noqa
import spack.pkg.builtin.mock.mpich as mp # noqa
from spack.pkg.builtin import mock # noqa
[docs] def test_inheritance_of_diretives(self):
p = spack.repo.get('simple-inheritance')
# Check dictionaries that should have been filled by directives
assert len(p.dependencies) == 3
assert 'cmake' in p.dependencies
assert 'openblas' in p.dependencies
assert 'mpi' in p.dependencies
assert len(p.provided) == 2
# Check that Spec instantiation behaves as we expect
s = Spec('simple-inheritance')
s.concretize()
assert '^cmake' in s
assert '^openblas' in s
assert '+openblas' in s
assert 'mpi' in s
s = Spec('simple-inheritance~openblas')
s.concretize()
assert '^cmake' in s
assert '^openblas' not in s
assert '~openblas' in s
assert 'mpi' in s
[docs] @pytest.mark.regression('11844')
def test_inheritance_of_patches(self):
s = Spec('patch-inheritance')
# Will error if inheritor package cannot find inherited patch files
s.concretize()
[docs] def test_dependency_extensions(self):
s = Spec('extension2')
s.concretize()
deps = set(x.name for x in s.package.dependency_activations())
assert deps == set(['extension1'])
[docs] def test_import_class_from_package(self):
from spack.pkg.builtin.mock.mpich import Mpich # noqa
[docs] def test_import_module_from_package(self):
from spack.pkg.builtin.mock import mpich # noqa
[docs] def test_import_namespace_container_modules(self):
import spack.pkg # noqa
import spack.pkg as p # noqa
import spack.pkg.builtin # noqa
import spack.pkg.builtin as b # noqa
import spack.pkg.builtin.mock # noqa
import spack.pkg.builtin.mock as m # noqa
from spack import pkg # noqa
from spack.pkg import builtin # noqa
from spack.pkg.builtin import mock # noqa
[docs]@pytest.mark.regression('2737')
def test_urls_for_versions(mock_packages, config):
"""Version directive without a 'url' argument should use default url."""
for spec_str in ('url_override@0.9.0', 'url_override@1.0.0'):
s = Spec(spec_str).concretized()
url = s.package.url_for_version('0.9.0')
assert url == 'http://www.anothersite.org/uo-0.9.0.tgz'
url = s.package.url_for_version('1.0.0')
assert url == 'http://www.doesnotexist.org/url_override-1.0.0.tar.gz'
url = s.package.url_for_version('0.8.1')
assert url == 'http://www.doesnotexist.org/url_override-0.8.1.tar.gz'
[docs]def test_url_for_version_with_no_urls(mock_packages, config):
pkg = spack.repo.get('git-test')
with pytest.raises(spack.package.NoURLError):
pkg.url_for_version('1.0')
with pytest.raises(spack.package.NoURLError):
pkg.url_for_version('1.1')
[docs]def test_url_for_version_with_only_overrides(mock_packages, config):
spec = Spec('url-only-override')
spec.concretize()
pkg = spack.repo.get(spec)
# these exist and should just take the URL provided in the package
assert pkg.url_for_version('1.0.0') == 'http://a.example.com/url_override-1.0.0.tar.gz'
assert pkg.url_for_version('0.9.0') == 'http://b.example.com/url_override-0.9.0.tar.gz'
assert pkg.url_for_version('0.8.1') == 'http://c.example.com/url_override-0.8.1.tar.gz'
# these don't exist but should still work, even if there are only overrides
assert pkg.url_for_version('1.0.5') == 'http://a.example.com/url_override-1.0.5.tar.gz'
assert pkg.url_for_version('0.9.5') == 'http://b.example.com/url_override-0.9.5.tar.gz'
assert pkg.url_for_version('0.8.5') == 'http://c.example.com/url_override-0.8.5.tar.gz'
assert pkg.url_for_version('0.7.0') == 'http://c.example.com/url_override-0.7.0.tar.gz'
[docs]def test_url_for_version_with_only_overrides_with_gaps(mock_packages, config):
spec = Spec('url-only-override-with-gaps')
spec.concretize()
pkg = spack.repo.get(spec)
# same as for url-only-override -- these are specific
assert pkg.url_for_version('1.0.0') == 'http://a.example.com/url_override-1.0.0.tar.gz'
assert pkg.url_for_version('0.9.0') == 'http://b.example.com/url_override-0.9.0.tar.gz'
assert pkg.url_for_version('0.8.1') == 'http://c.example.com/url_override-0.8.1.tar.gz'
# these don't have specific URLs, but should still work by extrapolation
assert pkg.url_for_version('1.0.5') == 'http://a.example.com/url_override-1.0.5.tar.gz'
assert pkg.url_for_version('0.9.5') == 'http://b.example.com/url_override-0.9.5.tar.gz'
assert pkg.url_for_version('0.8.5') == 'http://c.example.com/url_override-0.8.5.tar.gz'
assert pkg.url_for_version('0.7.0') == 'http://c.example.com/url_override-0.7.0.tar.gz'
[docs]def test_git_top_level(mock_packages, config):
"""Ensure that top-level git attribute can be used as a default."""
pkg = spack.repo.get('git-top-level')
fetcher = spack.fetch_strategy.for_package_version(pkg, '1.0')
assert isinstance(fetcher, spack.fetch_strategy.GitFetchStrategy)
assert fetcher.url == 'https://example.com/some/git/repo'
[docs]def test_svn_top_level(mock_packages, config):
"""Ensure that top-level svn attribute can be used as a default."""
pkg = spack.repo.get('svn-top-level')
fetcher = spack.fetch_strategy.for_package_version(pkg, '1.0')
assert isinstance(fetcher, spack.fetch_strategy.SvnFetchStrategy)
assert fetcher.url == 'https://example.com/some/svn/repo'
[docs]def test_hg_top_level(mock_packages, config):
"""Ensure that top-level hg attribute can be used as a default."""
pkg = spack.repo.get('hg-top-level')
fetcher = spack.fetch_strategy.for_package_version(pkg, '1.0')
assert isinstance(fetcher, spack.fetch_strategy.HgFetchStrategy)
assert fetcher.url == 'https://example.com/some/hg/repo'
[docs]def test_two_vcs_fetchers_top_level(mock_packages, config):
"""Verify conflict when two VCS strategies are specified together."""
pkg = spack.repo.get('git-url-svn-top-level')
with pytest.raises(spack.fetch_strategy.FetcherConflict):
spack.fetch_strategy.for_package_version(pkg, '1.0')
pkg = spack.repo.get('git-svn-top-level')
with pytest.raises(spack.fetch_strategy.FetcherConflict):
spack.fetch_strategy.for_package_version(pkg, '1.0')
[docs]def test_git_url_top_level_url_versions(mock_packages, config):
"""Test URL fetch strategy inference when url is specified with git."""
pkg = spack.repo.get('git-url-top-level')
# leading 62 zeros of sha256 hash
leading_zeros = '0' * 62
fetcher = spack.fetch_strategy.for_package_version(pkg, '2.0')
assert isinstance(fetcher, spack.fetch_strategy.URLFetchStrategy)
assert fetcher.url == 'https://example.com/some/tarball-2.0.tar.gz'
assert fetcher.digest == leading_zeros + '20'
fetcher = spack.fetch_strategy.for_package_version(pkg, '2.1')
assert isinstance(fetcher, spack.fetch_strategy.URLFetchStrategy)
assert fetcher.url == 'https://example.com/some/tarball-2.1.tar.gz'
assert fetcher.digest == leading_zeros + '21'
fetcher = spack.fetch_strategy.for_package_version(pkg, '2.2')
assert isinstance(fetcher, spack.fetch_strategy.URLFetchStrategy)
assert fetcher.url == 'https://www.example.com/foo2.2.tar.gz'
assert fetcher.digest == leading_zeros + '22'
fetcher = spack.fetch_strategy.for_package_version(pkg, '2.3')
assert isinstance(fetcher, spack.fetch_strategy.URLFetchStrategy)
assert fetcher.url == 'https://www.example.com/foo2.3.tar.gz'
assert fetcher.digest == leading_zeros + '23'
[docs]def test_git_url_top_level_git_versions(mock_packages, config):
"""Test git fetch strategy inference when url is specified with git."""
pkg = spack.repo.get('git-url-top-level')
fetcher = spack.fetch_strategy.for_package_version(pkg, '3.0')
assert isinstance(fetcher, spack.fetch_strategy.GitFetchStrategy)
assert fetcher.url == 'https://example.com/some/git/repo'
assert fetcher.tag == 'v3.0'
assert fetcher.commit is None
assert fetcher.branch is None
fetcher = spack.fetch_strategy.for_package_version(pkg, '3.1')
assert isinstance(fetcher, spack.fetch_strategy.GitFetchStrategy)
assert fetcher.url == 'https://example.com/some/git/repo'
assert fetcher.tag == 'v3.1'
assert fetcher.commit == 'abc31'
assert fetcher.branch is None
fetcher = spack.fetch_strategy.for_package_version(pkg, '3.2')
assert isinstance(fetcher, spack.fetch_strategy.GitFetchStrategy)
assert fetcher.url == 'https://example.com/some/git/repo'
assert fetcher.tag is None
assert fetcher.commit is None
assert fetcher.branch == 'releases/v3.2'
fetcher = spack.fetch_strategy.for_package_version(pkg, '3.3')
assert isinstance(fetcher, spack.fetch_strategy.GitFetchStrategy)
assert fetcher.url == 'https://example.com/some/git/repo'
assert fetcher.tag is None
assert fetcher.commit == 'abc33'
assert fetcher.branch == 'releases/v3.3'
fetcher = spack.fetch_strategy.for_package_version(pkg, '3.4')
assert isinstance(fetcher, spack.fetch_strategy.GitFetchStrategy)
assert fetcher.url == 'https://example.com/some/git/repo'
assert fetcher.tag is None
assert fetcher.commit == 'abc34'
assert fetcher.branch is None
fetcher = spack.fetch_strategy.for_package_version(pkg, 'submodules')
assert isinstance(fetcher, spack.fetch_strategy.GitFetchStrategy)
assert fetcher.url == 'https://example.com/some/git/repo'
assert fetcher.tag is None
assert fetcher.commit is None
assert fetcher.branch is None
fetcher = spack.fetch_strategy.for_package_version(pkg, 'develop')
assert isinstance(fetcher, spack.fetch_strategy.GitFetchStrategy)
assert fetcher.url == 'https://example.com/some/git/repo'
assert fetcher.tag is None
assert fetcher.commit is None
assert fetcher.branch == 'develop'
[docs]def test_git_url_top_level_conflicts(mock_packages, config):
"""Test git fetch strategy inference when url is specified with git."""
pkg = spack.repo.get('git-url-top-level')
with pytest.raises(spack.fetch_strategy.FetcherConflict):
spack.fetch_strategy.for_package_version(pkg, '1.0')
with pytest.raises(spack.fetch_strategy.FetcherConflict):
spack.fetch_strategy.for_package_version(pkg, '1.1')
with pytest.raises(spack.fetch_strategy.FetcherConflict):
spack.fetch_strategy.for_package_version(pkg, '1.2')
with pytest.raises(spack.fetch_strategy.FetcherConflict):
spack.fetch_strategy.for_package_version(pkg, '1.3')
[docs]def test_rpath_args(mutable_database):
"""Test a package's rpath_args property."""
rec = mutable_database.get_record('mpich')
rpath_args = rec.spec.package.rpath_args
assert '-rpath' in rpath_args
assert 'mpich' in rpath_args
[docs]def test_bundle_version_checksum(mock_directive_bundle,
clear_directive_functions):
"""Test raising exception on a version checksum with a bundle package."""
with pytest.raises(VersionChecksumError, match="Checksums not allowed"):
version = spack.directives.version('1.0', checksum='1badpkg')
version(mock_directive_bundle)
[docs]def test_bundle_patch_directive(mock_directive_bundle,
clear_directive_functions):
"""Test raising exception on a patch directive with a bundle package."""
with pytest.raises(spack.directives.UnsupportedPackageDirective,
match="Patches are not allowed"):
patch = spack.directives.patch('mock/patch.txt')
patch(mock_directive_bundle)
[docs]def test_fetch_options(mock_packages, config):
"""Test fetch options inference."""
pkg = spack.repo.get('fetch-options')
fetcher = spack.fetch_strategy.for_package_version(pkg, '1.0')
assert isinstance(fetcher, spack.fetch_strategy.URLFetchStrategy)
assert fetcher.digest == '00000000000000000000000000000010'
assert fetcher.extra_options == {'timeout': 42, 'cookie': 'foobar'}
fetcher = spack.fetch_strategy.for_package_version(pkg, '1.1')
assert isinstance(fetcher, spack.fetch_strategy.URLFetchStrategy)
assert fetcher.digest == '00000000000000000000000000000011'
assert fetcher.extra_options == {'timeout': 65}
fetcher = spack.fetch_strategy.for_package_version(pkg, '1.2')
assert isinstance(fetcher, spack.fetch_strategy.URLFetchStrategy)
assert fetcher.digest == '00000000000000000000000000000012'
assert fetcher.extra_options == {'cookie': 'baz'}
[docs]def test_has_test_method_fails(capsys):
with pytest.raises(SystemExit):
spack.package.has_test_method('printing-package')
captured = capsys.readouterr()[1]
assert 'is not a class' in captured