From da7fed86a825f6ffafd121505053f0b62e5f2155 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Mon, 2 Sep 2019 18:00:22 -0700 Subject: tests: add tests for `spack extensions` command - add tests for `spack extensions` - refactor `test_activations` test to use real extensions. --- lib/spack/spack/cmd/extensions.py | 50 +++----------- lib/spack/spack/test/cmd/extensions.py | 79 ++++++++++++++++++++++ lib/spack/spack/test/test_activations.py | 67 ++++++++++-------- .../packages/perl-extension/package.py | 9 +-- .../builtin.mock/packages/py-extension1/package.py | 7 +- .../builtin.mock/packages/py-extension2/package.py | 8 +-- 6 files changed, 132 insertions(+), 88 deletions(-) create mode 100644 lib/spack/spack/test/cmd/extensions.py diff --git a/lib/spack/spack/cmd/extensions.py b/lib/spack/spack/cmd/extensions.py index 5ba0281462..c9dcf6c4eb 100644 --- a/lib/spack/spack/cmd/extensions.py +++ b/lib/spack/spack/cmd/extensions.py @@ -10,6 +10,7 @@ from llnl.util.tty.colify import colify 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 @@ level = "long" 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) diff --git a/lib/spack/spack/test/cmd/extensions.py b/lib/spack/spack/test/cmd/extensions.py new file mode 100644 index 0000000000..544133698f --- /dev/null +++ b/lib/spack/spack/test/cmd/extensions.py @@ -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") diff --git a/lib/spack/spack/test/test_activations.py b/lib/spack/spack/test/test_activations.py index 092a004d4f..11de2e5431 100644 --- a/lib/spack/spack/test/test_activations.py +++ b/lib/spack/spack/test/test_activations.py @@ -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.directory_layout import YamlDirectoryLayout 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) diff --git a/var/spack/repos/builtin.mock/packages/perl-extension/package.py b/var/spack/repos/builtin.mock/packages/perl-extension/package.py index d229e99080..18bd53e13d 100644 --- a/var/spack/repos/builtin.mock/packages/perl-extension/package.py +++ b/var/spack/repos/builtin.mock/packages/perl-extension/package.py @@ -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 diff --git a/var/spack/repos/builtin.mock/packages/py-extension1/package.py b/var/spack/repos/builtin.mock/packages/py-extension1/package.py index a929415c2d..8bce48e9ce 100644 --- a/var/spack/repos/builtin.mock/packages/py-extension1/package.py +++ b/var/spack/repos/builtin.mock/packages/py-extension1/package.py @@ -20,9 +20,4 @@ class PyExtension1(PythonPackage): 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') diff --git a/var/spack/repos/builtin.mock/packages/py-extension2/package.py b/var/spack/repos/builtin.mock/packages/py-extension2/package.py index 326c73710f..d60608d9ea 100644 --- a/var/spack/repos/builtin.mock/packages/py-extension2/package.py +++ b/var/spack/repos/builtin.mock/packages/py-extension2/package.py @@ -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 @@ class PyExtension2(PythonPackage): 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 -- cgit v1.2.3-60-g2f50