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.environment as ev
import spack.cmd as cmd import spack.cmd as cmd
import spack.cmd.common.arguments as arguments
import spack.repo import spack.repo
import spack.store import spack.store
from spack.filesystem_view import YamlFilesystemView from spack.filesystem_view import YamlFilesystemView
@ -20,20 +21,16 @@
def setup_parser(subparser): def setup_parser(subparser):
subparser.add_argument( arguments.add_common_arguments(subparser, ['long', 'very_long'])
'-l', '--long', action='store_true', dest='long',
help='show dependency hashes as well as versions')
subparser.add_argument('-d', '--deps', action='store_true', subparser.add_argument('-d', '--deps', action='store_true',
help='output dependencies along with found specs') help='output dependencies along with found specs')
subparser.add_argument('-p', '--paths', action='store_true', subparser.add_argument('-p', '--paths', action='store_true',
help='show paths to package install directories') help='show paths to package install directories')
subparser.add_argument( subparser.add_argument(
'-s', '--show', dest='show', metavar='TYPE', type=str, '-s', '--show', action='store', default='all',
default='all', choices=("packages", "installed", "activated", "all"),
help="one of packages, installed, activated, all") help="show only part of output")
subparser.add_argument( subparser.add_argument(
'-v', '--view', metavar='VIEW', type=str, '-v', '--view', metavar='VIEW', type=str,
help="the view to operate on") help="the view to operate on")
@ -47,27 +44,7 @@ def extensions(parser, args):
if not args.spec: if not args.spec:
tty.die("extensions requires a package 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 # Checks
#
spec = cmd.parse_specs(args.spec) spec = cmd.parse_specs(args.spec)
if len(spec) > 1: if len(spec) > 1:
tty.die("Can only list extensions for one package.") tty.die("Can only list extensions for one package.")
@ -81,8 +58,7 @@ def extensions(parser, args):
if not spec.package.extendable: if not spec.package.extendable:
tty.die("%s does not have extensions." % spec.short_spec) tty.die("%s does not have extensions." % spec.short_spec)
if show_packages: if args.show in ("packages", "all"):
#
# List package names of extensions # List package names of extensions
extensions = spack.repo.path.extensions_for(spec) extensions = spack.repo.path.extensions_for(spec)
if not extensions: if not extensions:
@ -99,14 +75,12 @@ def extensions(parser, args):
view = YamlFilesystemView(target, spack.store.layout) view = YamlFilesystemView(target, spack.store.layout)
if show_installed: if args.show in ("installed", "all"):
#
# List specs of installed extensions. # List specs of installed extensions.
#
installed = [ installed = [
s.spec for s in spack.store.db.installed_extensions_for(spec)] s.spec for s in spack.store.db.installed_extensions_for(spec)]
if show_all: if args.show == "all":
print print
if not installed: if not installed:
tty.msg("None installed.") tty.msg("None installed.")
@ -114,15 +88,13 @@ def extensions(parser, args):
tty.msg("%d installed:" % len(installed)) tty.msg("%d installed:" % len(installed))
cmd.display_specs(installed, args) cmd.display_specs(installed, args)
if show_activated: if args.show in ("activated", "all"):
#
# List specs of activated extensions. # List specs of activated extensions.
#
activated = view.extensions_layout.extension_map(spec) activated = view.extensions_layout.extension_map(spec)
if show_all: if args.show == "all":
print print
if not activated: if not activated:
tty.msg("None activated.") tty.msg("None activated.")
else: else:
tty.msg("%d currently activated:" % len(activated)) tty.msg("%d activated:" % len(activated))
cmd.display_specs(activated.values(), args) 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) # 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 os
import pytest import pytest
@ -13,23 +17,23 @@
from spack.filesystem_view import YamlFilesystemView from spack.filesystem_view import YamlFilesystemView
from spack.repo import RepoPath 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, monkeypatch):
def create_ext_pkg(name, prefix, extendee_spec):
ext_spec = spack.spec.Spec(name) ext_spec = spack.spec.Spec(name)
ext_spec._concrete = True ext_spec._concrete = True
ext_spec.package.spec.prefix = prefix ext_spec.package.spec.prefix = prefix
ext_pkg = ext_spec.package 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 return ext_pkg
def create_python_ext_pkg(name, prefix, python_spec, namespace=None): def create_python_ext_pkg(name, prefix, python_spec, monkeypatch,
ext_pkg = create_ext_pkg(name, prefix, python_spec) namespace=None):
ext_pkg = create_ext_pkg(name, prefix, python_spec, monkeypatch)
ext_pkg.py_namespace = namespace ext_pkg.py_namespace = namespace
return ext_pkg 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, 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_prefix, ext_prefix = python_and_extension_dirs
python_spec = spack.spec.Spec('python@2.7.12') python_spec = spack.spec.Spec('python@2.7.12')
python_spec._concrete = True python_spec._concrete = True
python_spec.package.spec.prefix = python_prefix 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 = python_spec.package
python_pkg.activate(ext_pkg, python_pkg.view()) 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, 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_prefix, ext_prefix = python_and_extension_dirs
python_spec = spack.spec.Spec('python@2.7.12') python_spec = spack.spec.Spec('python@2.7.12')
python_spec._concrete = True python_spec._concrete = True
python_spec.package.spec.prefix = python_prefix 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')) view_dir = str(tmpdir.join('view'))
layout = YamlDirectoryLayout(view_dir) 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')) assert os.path.exists(os.path.join(view_dir, 'bin/py-ext-tool'))
def test_python_ignore_namespace_init_conflict(tmpdir, namespace_extensions, def test_python_ignore_namespace_init_conflict(
builtin_and_mock_packages): tmpdir, namespace_extensions, builtin_and_mock_packages, monkeypatch):
"""Test the view update logic in PythonPackage ignores conflicting """Test the view update logic in PythonPackage ignores conflicting
instances of __init__ for packages which are in the same namespace. 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 python_spec._concrete = True
ext1_pkg = create_python_ext_pkg('py-extension1', ext1_prefix, python_spec, 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, ext2_pkg = create_python_ext_pkg('py-extension2', ext2_prefix, python_spec,
py_namespace) monkeypatch, py_namespace)
view_dir = str(tmpdir.join('view')) view_dir = str(tmpdir.join('view'))
layout = YamlDirectoryLayout(view_dir) 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)) assert os.path.exists(os.path.join(view_dir, init_file))
def test_python_keep_namespace_init(tmpdir, namespace_extensions, def test_python_keep_namespace_init(
builtin_and_mock_packages): tmpdir, namespace_extensions, builtin_and_mock_packages, monkeypatch):
"""Test the view update logic in PythonPackage keeps the namespace """Test the view update logic in PythonPackage keeps the namespace
__init__ file as long as one package in the namespace still __init__ file as long as one package in the namespace still
exists. exists.
@ -238,9 +244,9 @@ def test_python_keep_namespace_init(tmpdir, namespace_extensions,
python_spec._concrete = True python_spec._concrete = True
ext1_pkg = create_python_ext_pkg('py-extension1', ext1_prefix, python_spec, 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, ext2_pkg = create_python_ext_pkg('py-extension2', ext2_prefix, python_spec,
py_namespace) monkeypatch, py_namespace)
view_dir = str(tmpdir.join('view')) view_dir = str(tmpdir.join('view'))
layout = YamlDirectoryLayout(view_dir) 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, 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 """Test the view update logic in PythonPackage reports an error when two
python extensions with different namespaces have a conflicting __init__ python extensions with different namespaces have a conflicting __init__
file. file.
@ -281,9 +287,9 @@ def test_python_namespace_conflict(tmpdir, namespace_extensions,
python_spec._concrete = True python_spec._concrete = True
ext1_pkg = create_python_ext_pkg('py-extension1', ext1_prefix, python_spec, 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, ext2_pkg = create_python_ext_pkg('py-extension2', ext2_prefix, python_spec,
other_namespace) monkeypatch, other_namespace)
view_dir = str(tmpdir.join('view')) view_dir = str(tmpdir.join('view'))
layout = YamlDirectoryLayout(view_dir) 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) 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 # Note the lib directory is based partly on the perl version
perl_spec = spack.spec.Spec('perl@5.24.1') perl_spec = spack.spec.Spec('perl@5.24.1')
perl_spec._concrete = True perl_spec._concrete = True
@ -357,21 +363,23 @@ def test_perl_activation(tmpdir, builtin_and_mock_packages):
ext_name = 'perl-extension' ext_name = 'perl-extension'
tmpdir.ensure(ext_name, dir=True) 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 = perl_spec.package
perl_pkg.activate(ext_pkg, perl_pkg.view()) perl_pkg.activate(ext_pkg, perl_pkg.view())
def test_perl_activation_with_files(tmpdir, perl_and_extension_dirs, 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_prefix, ext_prefix = perl_and_extension_dirs
perl_spec = spack.spec.Spec('perl@5.24.1') perl_spec = spack.spec.Spec('perl@5.24.1')
perl_spec._concrete = True perl_spec._concrete = True
perl_spec.package.spec.prefix = perl_prefix 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 = perl_spec.package
perl_pkg.activate(ext_pkg, perl_pkg.view()) 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, 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_prefix, ext_prefix = perl_and_extension_dirs
perl_spec = spack.spec.Spec('perl@5.24.1') perl_spec = spack.spec.Spec('perl@5.24.1')
perl_spec._concrete = True perl_spec._concrete = True
perl_spec.package.spec.prefix = perl_prefix 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')) view_dir = str(tmpdir.join('view'))
layout = YamlDirectoryLayout(view_dir) layout = YamlDirectoryLayout(view_dir)

View File

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

View File

@ -13,6 +13,7 @@ class PyExtension2(PythonPackage):
homepage = "http://www.example.com" homepage = "http://www.example.com"
url = "http://www.example.com/extension2-1.0.tar.gz" url = "http://www.example.com/extension2-1.0.tar.gz"
extends("python")
depends_on('py-extension1', type=('build', 'run')) depends_on('py-extension1', type=('build', 'run'))
version('1.0', 'hash-extension2-1.0') version('1.0', 'hash-extension2-1.0')
@ -21,10 +22,3 @@ def install(self, spec, prefix):
mkdirp(prefix.bin) mkdirp(prefix.bin)
with open(os.path.join(prefix.bin, 'py-extension2'), 'w+') as fout: with open(os.path.join(prefix.bin, 'py-extension2'), 'w+') as fout:
fout.write(str(spec.version)) 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