tests: add tests for spack extensions command

- add tests for `spack extensions`
- refactor `test_activations` test to use real extensions.
This commit is contained in:
Todd Gamblin 2019-09-02 18:00:22 -07:00
parent 1b877e8e0f
commit da7fed86a8
6 changed files with 132 additions and 88 deletions

View File

@ -10,6 +10,7 @@
import spack.environment as ev
import spack.cmd as cmd
import spack.cmd.common.arguments as arguments
import spack.repo
import spack.store
from spack.filesystem_view import YamlFilesystemView
@ -20,20 +21,16 @@
def setup_parser(subparser):
subparser.add_argument(
'-l', '--long', action='store_true', dest='long',
help='show dependency hashes as well as versions')
arguments.add_common_arguments(subparser, ['long', 'very_long'])
subparser.add_argument('-d', '--deps', action='store_true',
help='output dependencies along with found specs')
subparser.add_argument('-p', '--paths', action='store_true',
help='show paths to package install directories')
subparser.add_argument(
'-s', '--show', dest='show', metavar='TYPE', type=str,
default='all',
help="one of packages, installed, activated, all")
'-s', '--show', action='store', default='all',
choices=("packages", "installed", "activated", "all"),
help="show only part of output")
subparser.add_argument(
'-v', '--view', metavar='VIEW', type=str,
help="the view to operate on")
@ -47,27 +44,7 @@ def extensions(parser, args):
if not args.spec:
tty.die("extensions requires a package spec.")
show_packages = False
show_installed = False
show_activated = False
show_all = False
if args.show == 'packages':
show_packages = True
elif args.show == 'installed':
show_installed = True
elif args.show == 'activated':
show_activated = True
elif args.show == 'all':
show_packages = True
show_installed = True
show_activated = True
show_all = True
else:
tty.die('unrecognized show type: %s' % args.show)
#
# Checks
#
spec = cmd.parse_specs(args.spec)
if len(spec) > 1:
tty.die("Can only list extensions for one package.")
@ -81,8 +58,7 @@ def extensions(parser, args):
if not spec.package.extendable:
tty.die("%s does not have extensions." % spec.short_spec)
if show_packages:
#
if args.show in ("packages", "all"):
# List package names of extensions
extensions = spack.repo.path.extensions_for(spec)
if not extensions:
@ -99,14 +75,12 @@ def extensions(parser, args):
view = YamlFilesystemView(target, spack.store.layout)
if show_installed:
#
if args.show in ("installed", "all"):
# List specs of installed extensions.
#
installed = [
s.spec for s in spack.store.db.installed_extensions_for(spec)]
if show_all:
if args.show == "all":
print
if not installed:
tty.msg("None installed.")
@ -114,15 +88,13 @@ def extensions(parser, args):
tty.msg("%d installed:" % len(installed))
cmd.display_specs(installed, args)
if show_activated:
#
if args.show in ("activated", "all"):
# List specs of activated extensions.
#
activated = view.extensions_layout.extension_map(spec)
if show_all:
if args.show == "all":
print
if not activated:
tty.msg("None activated.")
else:
tty.msg("%d currently activated:" % len(activated))
tty.msg("%d activated:" % len(activated))
cmd.display_specs(activated.values(), args)

View File

@ -0,0 +1,79 @@
# Copyright 2013-2019 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 pytest
from spack.main import SpackCommand, SpackCommandError
from spack.spec import Spec
extensions = SpackCommand('extensions')
@pytest.fixture
def python_database(mock_packages, mutable_database):
specs = [Spec(s).concretized() for s in [
'python',
'py-extension1',
'py-extension2',
]]
for spec in specs:
spec.package.do_install(fake=True, explicit=True)
yield
@pytest.mark.db
def test_extensions(mock_packages, python_database, capsys):
ext2 = Spec("py-extension2").concretized()
def check_output(ni, na):
with capsys.disabled():
output = extensions("python")
packages = extensions("-s", "packages", "python")
installed = extensions("-s", "installed", "python")
activated = extensions("-s", "activated", "python")
assert "==> python@2.7.11" in output
assert "==> 3 extensions" in output
assert "flake8" in output
assert "py-extension1" in output
assert "py-extension2" in output
assert "==> 3 extensions" in packages
assert "flake8" in packages
assert "py-extension1" in packages
assert "py-extension2" in packages
assert "installed" not in packages
assert "activated" not in packages
assert ("%s installed" % (ni if ni else "None")) in output
assert ("%s activated" % (na if na else "None")) in output
assert ("%s installed" % (ni if ni else "None")) in installed
assert ("%s activated" % (na if na else "None")) in activated
check_output(2, 0)
ext2.package.do_activate()
check_output(2, 2)
ext2.package.do_deactivate(force=True)
check_output(2, 1)
ext2.package.do_activate()
check_output(2, 2)
ext2.package.do_uninstall(force=True)
check_output(1, 1)
def test_extensions_raises_if_not_extendable(mock_packages):
with pytest.raises(SpackCommandError):
extensions("flake8")
def test_extensions_raises_if_multiple_specs(mock_packages):
with pytest.raises(SpackCommandError):
extensions("python", "flake8")

View File

@ -3,6 +3,10 @@
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
"""This includes tests for customized activation logic for specific packages
(e.g. python and perl).
"""
import os
import pytest
@ -13,23 +17,23 @@
from spack.filesystem_view import YamlFilesystemView
from spack.repo import RepoPath
"""This includes tests for customized activation logic for specific packages
(e.g. python and perl).
"""
def create_ext_pkg(name, prefix, extendee_spec):
def create_ext_pkg(name, prefix, extendee_spec, monkeypatch):
ext_spec = spack.spec.Spec(name)
ext_spec._concrete = True
ext_spec.package.spec.prefix = prefix
ext_pkg = ext_spec.package
ext_pkg.extends_spec = extendee_spec
# temporarily override extendee_spec property on the package
monkeypatch.setattr(ext_pkg.__class__, "extendee_spec", extendee_spec)
return ext_pkg
def create_python_ext_pkg(name, prefix, python_spec, namespace=None):
ext_pkg = create_ext_pkg(name, prefix, python_spec)
def create_python_ext_pkg(name, prefix, python_spec, monkeypatch,
namespace=None):
ext_pkg = create_ext_pkg(name, prefix, python_spec, monkeypatch)
ext_pkg.py_namespace = namespace
return ext_pkg
@ -148,14 +152,15 @@ def namespace_extensions(tmpdir, builtin_and_mock_packages):
def test_python_activation_with_files(tmpdir, python_and_extension_dirs,
builtin_and_mock_packages):
monkeypatch, builtin_and_mock_packages):
python_prefix, ext_prefix = python_and_extension_dirs
python_spec = spack.spec.Spec('python@2.7.12')
python_spec._concrete = True
python_spec.package.spec.prefix = python_prefix
ext_pkg = create_python_ext_pkg('py-extension1', ext_prefix, python_spec)
ext_pkg = create_python_ext_pkg(
'py-extension1', ext_prefix, python_spec, monkeypatch)
python_pkg = python_spec.package
python_pkg.activate(ext_pkg, python_pkg.view())
@ -171,14 +176,15 @@ def test_python_activation_with_files(tmpdir, python_and_extension_dirs,
def test_python_activation_view(tmpdir, python_and_extension_dirs,
builtin_and_mock_packages):
builtin_and_mock_packages, monkeypatch):
python_prefix, ext_prefix = python_and_extension_dirs
python_spec = spack.spec.Spec('python@2.7.12')
python_spec._concrete = True
python_spec.package.spec.prefix = python_prefix
ext_pkg = create_python_ext_pkg('py-extension1', ext_prefix, python_spec)
ext_pkg = create_python_ext_pkg('py-extension1', ext_prefix, python_spec,
monkeypatch)
view_dir = str(tmpdir.join('view'))
layout = YamlDirectoryLayout(view_dir)
@ -192,8 +198,8 @@ def test_python_activation_view(tmpdir, python_and_extension_dirs,
assert os.path.exists(os.path.join(view_dir, 'bin/py-ext-tool'))
def test_python_ignore_namespace_init_conflict(tmpdir, namespace_extensions,
builtin_and_mock_packages):
def test_python_ignore_namespace_init_conflict(
tmpdir, namespace_extensions, builtin_and_mock_packages, monkeypatch):
"""Test the view update logic in PythonPackage ignores conflicting
instances of __init__ for packages which are in the same namespace.
"""
@ -203,9 +209,9 @@ def test_python_ignore_namespace_init_conflict(tmpdir, namespace_extensions,
python_spec._concrete = True
ext1_pkg = create_python_ext_pkg('py-extension1', ext1_prefix, python_spec,
py_namespace)
monkeypatch, py_namespace)
ext2_pkg = create_python_ext_pkg('py-extension2', ext2_prefix, python_spec,
py_namespace)
monkeypatch, py_namespace)
view_dir = str(tmpdir.join('view'))
layout = YamlDirectoryLayout(view_dir)
@ -226,8 +232,8 @@ def test_python_ignore_namespace_init_conflict(tmpdir, namespace_extensions,
assert os.path.exists(os.path.join(view_dir, init_file))
def test_python_keep_namespace_init(tmpdir, namespace_extensions,
builtin_and_mock_packages):
def test_python_keep_namespace_init(
tmpdir, namespace_extensions, builtin_and_mock_packages, monkeypatch):
"""Test the view update logic in PythonPackage keeps the namespace
__init__ file as long as one package in the namespace still
exists.
@ -238,9 +244,9 @@ def test_python_keep_namespace_init(tmpdir, namespace_extensions,
python_spec._concrete = True
ext1_pkg = create_python_ext_pkg('py-extension1', ext1_prefix, python_spec,
py_namespace)
monkeypatch, py_namespace)
ext2_pkg = create_python_ext_pkg('py-extension2', ext2_prefix, python_spec,
py_namespace)
monkeypatch, py_namespace)
view_dir = str(tmpdir.join('view'))
layout = YamlDirectoryLayout(view_dir)
@ -269,7 +275,7 @@ def test_python_keep_namespace_init(tmpdir, namespace_extensions,
def test_python_namespace_conflict(tmpdir, namespace_extensions,
builtin_and_mock_packages):
monkeypatch, builtin_and_mock_packages):
"""Test the view update logic in PythonPackage reports an error when two
python extensions with different namespaces have a conflicting __init__
file.
@ -281,9 +287,9 @@ def test_python_namespace_conflict(tmpdir, namespace_extensions,
python_spec._concrete = True
ext1_pkg = create_python_ext_pkg('py-extension1', ext1_prefix, python_spec,
py_namespace)
monkeypatch, py_namespace)
ext2_pkg = create_python_ext_pkg('py-extension2', ext2_prefix, python_spec,
other_namespace)
monkeypatch, other_namespace)
view_dir = str(tmpdir.join('view'))
layout = YamlDirectoryLayout(view_dir)
@ -342,7 +348,7 @@ def perl_and_extension_dirs(tmpdir, builtin_and_mock_packages):
return str(perl_prefix), str(ext_prefix)
def test_perl_activation(tmpdir, builtin_and_mock_packages):
def test_perl_activation(tmpdir, builtin_and_mock_packages, monkeypatch):
# Note the lib directory is based partly on the perl version
perl_spec = spack.spec.Spec('perl@5.24.1')
perl_spec._concrete = True
@ -357,21 +363,23 @@ def test_perl_activation(tmpdir, builtin_and_mock_packages):
ext_name = 'perl-extension'
tmpdir.ensure(ext_name, dir=True)
ext_pkg = create_ext_pkg(ext_name, str(tmpdir.join(ext_name)), perl_spec)
ext_pkg = create_ext_pkg(
ext_name, str(tmpdir.join(ext_name)), perl_spec, monkeypatch)
perl_pkg = perl_spec.package
perl_pkg.activate(ext_pkg, perl_pkg.view())
def test_perl_activation_with_files(tmpdir, perl_and_extension_dirs,
builtin_and_mock_packages):
monkeypatch, builtin_and_mock_packages):
perl_prefix, ext_prefix = perl_and_extension_dirs
perl_spec = spack.spec.Spec('perl@5.24.1')
perl_spec._concrete = True
perl_spec.package.spec.prefix = perl_prefix
ext_pkg = create_ext_pkg('perl-extension', ext_prefix, perl_spec)
ext_pkg = create_ext_pkg(
'perl-extension', ext_prefix, perl_spec, monkeypatch)
perl_pkg = perl_spec.package
perl_pkg.activate(ext_pkg, perl_pkg.view())
@ -380,14 +388,15 @@ def test_perl_activation_with_files(tmpdir, perl_and_extension_dirs,
def test_perl_activation_view(tmpdir, perl_and_extension_dirs,
builtin_and_mock_packages):
monkeypatch, builtin_and_mock_packages):
perl_prefix, ext_prefix = perl_and_extension_dirs
perl_spec = spack.spec.Spec('perl@5.24.1')
perl_spec._concrete = True
perl_spec.package.spec.prefix = perl_prefix
ext_pkg = create_ext_pkg('perl-extension', ext_prefix, perl_spec)
ext_pkg = create_ext_pkg(
'perl-extension', ext_prefix, perl_spec, monkeypatch)
view_dir = str(tmpdir.join('view'))
layout = YamlDirectoryLayout(view_dir)

View File

@ -15,14 +15,9 @@ class PerlExtension(PerlPackage):
version('1.0', 'hash-extension-1.0')
version('2.0', 'hash-extension-2.0')
extends("perl")
def install(self, spec, prefix):
mkdirp(prefix.bin)
with open(os.path.join(prefix.bin, 'perl-extension'), 'w+') as fout:
fout.write(str(spec.version))
# Give the package a hook to set the extendee spec
extends_spec = 'perl'
@property
def extendee_spec(self):
return self.extends_spec

View File

@ -20,9 +20,4 @@ def install(self, spec, prefix):
with open(os.path.join(prefix.bin, 'py-extension1'), 'w+') as fout:
fout.write(str(spec.version))
# Give the package a hook to set the extendee spec
extends_spec = 'python'
@property
def extendee_spec(self):
return self.extends_spec
extends('python')

View File

@ -13,6 +13,7 @@ class PyExtension2(PythonPackage):
homepage = "http://www.example.com"
url = "http://www.example.com/extension2-1.0.tar.gz"
extends("python")
depends_on('py-extension1', type=('build', 'run'))
version('1.0', 'hash-extension2-1.0')
@ -21,10 +22,3 @@ def install(self, spec, prefix):
mkdirp(prefix.bin)
with open(os.path.join(prefix.bin, 'py-extension2'), 'w+') as fout:
fout.write(str(spec.version))
# Give the package a hook to set the extendee spec
extends_spec = 'python'
@property
def extendee_spec(self):
return self.extends_spec