diff options
author | Greg Becker <becker33@llnl.gov> | 2020-11-18 02:39:02 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-18 02:39:02 -0800 |
commit | 77b2e578ec47f7713cae965fede1ab6e60aa69c4 (patch) | |
tree | a03377956a08356bc3b73dc23b4d466c4f2f5aa6 /var | |
parent | b81bbfb6e9691036fc284f034e749a3b9361bf5a (diff) | |
download | spack-77b2e578ec47f7713cae965fede1ab6e60aa69c4.tar.gz spack-77b2e578ec47f7713cae965fede1ab6e60aa69c4.tar.bz2 spack-77b2e578ec47f7713cae965fede1ab6e60aa69c4.tar.xz spack-77b2e578ec47f7713cae965fede1ab6e60aa69c4.zip |
spack test (#15702)
Users can add test() methods to their packages to run smoke tests on
installations with the new `spack test` command (the old `spack test` is
now `spack unit-test`). spack test is environment-aware, so you can
`spack install` an environment and then run `spack test run` to run smoke
tests on all of its packages. Historical test logs can be perused with
`spack test results`. Generic smoke tests for MPI implementations, C,
C++, and Fortran compilers as well as specific smoke tests for 18
packages.
Inside the test method, individual tests can be run separately (and
continue to run best-effort after a test failure) using the `run_test`
method. The `run_test` method encapsulates finding test executables,
running and checking return codes, checking output, and error handling.
This handles the following trickier aspects of testing with direct
support in Spack's package API:
- [x] Caching source or intermediate build files at build time for
use at test time.
- [x] Test dependencies,
- [x] packages that require a compiler for testing (such as library only
packages).
See the packaging guide for more details on using Spack testing support.
Included is support for package.py files for virtual packages. This does
not change the Spack interface, but is a major change in internals.
Co-authored-by: Tamara Dahlgren <dahlgren1@llnl.gov>
Co-authored-by: wspear <wjspear@gmail.com>
Co-authored-by: Adam J. Stewart <ajstewart426@gmail.com>
Diffstat (limited to 'var')
76 files changed, 1209 insertions, 47 deletions
diff --git a/var/spack/repos/builtin.mock/packages/printing-package/package.py b/var/spack/repos/builtin.mock/packages/printing-package/package.py index 1d4d32d54d..096a49d211 100644 --- a/var/spack/repos/builtin.mock/packages/printing-package/package.py +++ b/var/spack/repos/builtin.mock/packages/printing-package/package.py @@ -24,3 +24,8 @@ class PrintingPackage(Package): make('install') print("AFTER INSTALL") + + def test(self): + print("BEFORE TEST") + self.run_test('true') # run /bin/true + print("AFTER TEST") diff --git a/var/spack/repos/builtin.mock/packages/test-error/package.py b/var/spack/repos/builtin.mock/packages/test-error/package.py new file mode 100644 index 0000000000..ce36ee7ca3 --- /dev/null +++ b/var/spack/repos/builtin.mock/packages/test-error/package.py @@ -0,0 +1,21 @@ +# Copyright 2013-2020 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) + +from spack import * + + +class TestError(Package): + """This package has a test method that fails in a subprocess.""" + + homepage = "http://www.example.com/test-failure" + url = "http://www.test-failure.test/test-failure-1.0.tar.gz" + + version('1.0', 'foobarbaz') + + def install(self, spec, prefix): + mkdirp(prefix.bin) + + def test(self): + self.run_test('false') diff --git a/var/spack/repos/builtin.mock/packages/test-fail/package.py b/var/spack/repos/builtin.mock/packages/test-fail/package.py new file mode 100644 index 0000000000..6587ef2bb9 --- /dev/null +++ b/var/spack/repos/builtin.mock/packages/test-fail/package.py @@ -0,0 +1,21 @@ +# Copyright 2013-2020 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) + +from spack import * + + +class TestFail(Package): + """This package has a test method that fails in a subprocess.""" + + homepage = "http://www.example.com/test-failure" + url = "http://www.test-failure.test/test-failure-1.0.tar.gz" + + version('1.0', 'foobarbaz') + + def install(self, spec, prefix): + mkdirp(prefix.bin) + + def test(self): + self.run_test('true', expected=['not in the output']) diff --git a/var/spack/repos/builtin/packages/bazel/package.py b/var/spack/repos/builtin/packages/bazel/package.py index 66c039cafb..ad1239529d 100644 --- a/var/spack/repos/builtin/packages/bazel/package.py +++ b/var/spack/repos/builtin/packages/bazel/package.py @@ -184,7 +184,7 @@ class Bazel(Package): @run_after('install') @on_package_attributes(run_tests=True) - def test(self): + def install_test(self): # https://github.com/Homebrew/homebrew-core/blob/master/Formula/bazel.rb # Bazel does not work properly on NFS, switch to /tmp diff --git a/var/spack/repos/builtin/packages/berkeley-db/package.py b/var/spack/repos/builtin/packages/berkeley-db/package.py index e72d823cb5..0385de81a1 100644 --- a/var/spack/repos/builtin/packages/berkeley-db/package.py +++ b/var/spack/repos/builtin/packages/berkeley-db/package.py @@ -3,8 +3,6 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) -from spack import * - class BerkeleyDb(AutotoolsPackage): """Oracle Berkeley DB""" @@ -47,3 +45,15 @@ class BerkeleyDb(AutotoolsPackage): config_args.append('--disable-atomicsupport') return config_args + + def test(self): + """Perform smoke tests on the installed package binaries.""" + exes = [ + 'db_checkpoint', 'db_deadlock', 'db_dump', 'db_load', + 'db_printlog', 'db_stat', 'db_upgrade', 'db_verify' + ] + for exe in exes: + reason = 'test version of {0} is {1}'.format(exe, + self.spec.version) + self.run_test(exe, ['-V'], [self.spec.version.string], + installed=True, purpose=reason, skip_missing=True) diff --git a/var/spack/repos/builtin/packages/binutils/package.py b/var/spack/repos/builtin/packages/binutils/package.py index e2ddfe8c1e..f79015cf6b 100644 --- a/var/spack/repos/builtin/packages/binutils/package.py +++ b/var/spack/repos/builtin/packages/binutils/package.py @@ -129,3 +129,29 @@ class Binutils(AutotoolsPackage, GNUMirrorPackage): if self.spec.satisfies('@:2.34 %gcc@10:'): flags.append('-fcommon') return (flags, None, None) + + def test(self): + spec_vers = str(self.spec.version) + + checks = { + 'ar': spec_vers, + 'c++filt': spec_vers, + 'coffdump': spec_vers, + 'dlltool': spec_vers, + 'elfedit': spec_vers, + 'gprof': spec_vers, + 'ld': spec_vers, + 'nm': spec_vers, + 'objdump': spec_vers, + 'ranlib': spec_vers, + 'readelf': spec_vers, + 'size': spec_vers, + 'strings': spec_vers, + } + + for exe in checks: + expected = checks[exe] + reason = 'test: ensuring version of {0} is {1}' \ + .format(exe, expected) + self.run_test(exe, '--version', expected, installed=True, + purpose=reason, skip_missing=True) diff --git a/var/spack/repos/builtin/packages/c/package.py b/var/spack/repos/builtin/packages/c/package.py new file mode 100644 index 0000000000..72a3343aa1 --- /dev/null +++ b/var/spack/repos/builtin/packages/c/package.py @@ -0,0 +1,27 @@ +# Copyright 2013-2020 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 + + +class C(Package): + """Virtual package for C compilers.""" + homepage = 'http://open-std.org/JTC1/SC22/WG14/www/standards' + virtual = True + + def test(self): + test_source = self.test_suite.current_test_data_dir + + for test in os.listdir(test_source): + filepath = test_source.join(test) + exe_name = '%s.exe' % test + + cc_exe = os.environ['CC'] + cc_opts = ['-o', exe_name, filepath] + compiled = self.run_test(cc_exe, options=cc_opts, installed=True) + + if compiled: + expected = ['Hello world', 'YES!'] + self.run_test(exe_name, expected=expected) diff --git a/var/spack/repos/builtin/packages/c/test/hello.c b/var/spack/repos/builtin/packages/c/test/hello.c new file mode 100644 index 0000000000..de950e1e88 --- /dev/null +++ b/var/spack/repos/builtin/packages/c/test/hello.c @@ -0,0 +1,7 @@ +#include <stdio.h> +int main() +{ + printf ("Hello world from C!\n"); + printf ("YES!"); + return 0; +} diff --git a/var/spack/repos/builtin/packages/cantera/package.py b/var/spack/repos/builtin/packages/cantera/package.py index 773cc6d8cf..9846fff48d 100644 --- a/var/spack/repos/builtin/packages/cantera/package.py +++ b/var/spack/repos/builtin/packages/cantera/package.py @@ -146,7 +146,7 @@ class Cantera(SConsPackage): return args - def test(self): + def build_test(self): if '+python' in self.spec: # Tests will always fail if Python dependencies aren't built # In addition, 3 of the tests fail when run in parallel diff --git a/var/spack/repos/builtin/packages/cmake/package.py b/var/spack/repos/builtin/packages/cmake/package.py index 97168c05f1..a3bad699e1 100644 --- a/var/spack/repos/builtin/packages/cmake/package.py +++ b/var/spack/repos/builtin/packages/cmake/package.py @@ -2,6 +2,7 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) + import re @@ -250,7 +251,7 @@ class Cmake(Package): @run_after('build') @on_package_attributes(run_tests=True) - def test(self): + def build_test(self): # Some tests fail, takes forever make('test') @@ -262,3 +263,12 @@ class Cmake(Package): filter_file('mpcc_r)', 'mpcc_r mpifcc)', f, string=True) filter_file('mpc++_r)', 'mpc++_r mpiFCC)', f, string=True) filter_file('mpifc)', 'mpifc mpifrt)', f, string=True) + + def test(self): + """Perform smoke tests on the installed package.""" + spec_vers_str = 'version {0}'.format(self.spec.version) + + for exe in ['ccmake', 'cmake', 'cpack', 'ctest']: + reason = 'test version of {0} is {1}'.format(exe, spec_vers_str) + self.run_test(exe, ['--version'], [spec_vers_str], + installed=True, purpose=reason, skip_missing=True) diff --git a/var/spack/repos/builtin/packages/conduit/package.py b/var/spack/repos/builtin/packages/conduit/package.py index 7b6edf21f9..57d49da70e 100644 --- a/var/spack/repos/builtin/packages/conduit/package.py +++ b/var/spack/repos/builtin/packages/conduit/package.py @@ -217,7 +217,7 @@ class Conduit(Package): @run_after('build') @on_package_attributes(run_tests=True) - def test(self): + def build_test(self): with working_dir('spack-build'): print("Running Conduit Unit Tests...") make("test") diff --git a/var/spack/repos/builtin/packages/cxx/package.py b/var/spack/repos/builtin/packages/cxx/package.py new file mode 100644 index 0000000000..0be36c3ae5 --- /dev/null +++ b/var/spack/repos/builtin/packages/cxx/package.py @@ -0,0 +1,38 @@ +# Copyright 2013-2020 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 + + +class Cxx(Package): + """Virtual package for the C++ language.""" + homepage = 'https://isocpp.org/std/the-standard' + virtual = True + + def test(self): + test_source = self.test_suite.current_test_data_dir + + for test in os.listdir(test_source): + filepath = os.path.join(test_source, test) + exe_name = '%s.exe' % test + + cxx_exe = os.environ['CXX'] + + # standard options + # Hack to get compiler attributes + # TODO: remove this when compilers are dependencies + c_name = clang if self.spec.satisfies('llvm+clang') else self.name + c_spec = spack.spec.CompilerSpec(c_name, self.spec.version) + c_cls = spack.compilers.class_for_compiler_name(c_name) + compiler = c_cls(c_spec, None, None, ['fakecc', 'fakecxx']) + + cxx_opts = [compiler.cxx11_flag] if 'c++11' in test else [] + + cxx_opts += ['-o', exe_name, filepath] + compiled = self.run_test(cxx_exe, options=cxx_opts, installed=True) + + if compiled: + expected = ['Hello world', 'YES!'] + self.run_test(exe_name, expected=expected) diff --git a/var/spack/repos/builtin/packages/cxx/test/hello.c++ b/var/spack/repos/builtin/packages/cxx/test/hello.c++ new file mode 100644 index 0000000000..f0ad7caffb --- /dev/null +++ b/var/spack/repos/builtin/packages/cxx/test/hello.c++ @@ -0,0 +1,9 @@ +#include <stdio.h> + +int main() +{ + printf ("Hello world from C++\n"); + printf ("YES!"); + + return 0; +} diff --git a/var/spack/repos/builtin/packages/cxx/test/hello.cc b/var/spack/repos/builtin/packages/cxx/test/hello.cc new file mode 100644 index 0000000000..2a85869996 --- /dev/null +++ b/var/spack/repos/builtin/packages/cxx/test/hello.cc @@ -0,0 +1,9 @@ +#include <iostream> +using namespace std; + +int main() +{ + cout << "Hello world from C++!" << endl; + cout << "YES!" << endl; + return (0); +} diff --git a/var/spack/repos/builtin/packages/cxx/test/hello.cpp b/var/spack/repos/builtin/packages/cxx/test/hello.cpp new file mode 100644 index 0000000000..b49db59f4a --- /dev/null +++ b/var/spack/repos/builtin/packages/cxx/test/hello.cpp @@ -0,0 +1,9 @@ +#include <iostream> +using namespace std; + +int main() +{ + cout << "Hello world from C++!" << endl; + cout << "YES!" << endl; + return (0); +} diff --git a/var/spack/repos/builtin/packages/cxx/test/hello_c++11.cc b/var/spack/repos/builtin/packages/cxx/test/hello_c++11.cc new file mode 100644 index 0000000000..10f57c3f75 --- /dev/null +++ b/var/spack/repos/builtin/packages/cxx/test/hello_c++11.cc @@ -0,0 +1,17 @@ +#include <iostream> +#include <regex> + +using namespace std; + +int main() +{ + auto func = [] () { cout << "Hello world from C++11" << endl; }; + func(); // now call the function + + std::regex r("st|mt|tr"); + std::cout << "std::regex r(\"st|mt|tr\")" << " match tr? "; + if (std::regex_match("tr", r) == 0) + std::cout << "NO!\n ==> Using pre g++ 4.9.2 libstdc++ which doesn't implement regex properly" << std::endl; + else + std::cout << "YES!\n ==> Correct libstdc++11 implementation of regex (4.9.2 or later)" << std::endl; +} diff --git a/var/spack/repos/builtin/packages/emacs/package.py b/var/spack/repos/builtin/packages/emacs/package.py index 393def5cc5..0759fd28d5 100644 --- a/var/spack/repos/builtin/packages/emacs/package.py +++ b/var/spack/repos/builtin/packages/emacs/package.py @@ -80,3 +80,18 @@ class Emacs(AutotoolsPackage, GNUMirrorPackage): args.append('--without-gnutls') return args + + def _test_check_versions(self): + """Perform version checks on installed package binaries.""" + checks = ['ctags', 'ebrowse', 'emacs', 'emacsclient', 'etags'] + + for exe in checks: + expected = str(self.spec.version) + reason = 'test version of {0} is {1}'.format(exe, expected) + self.run_test(exe, ['--version'], expected, installed=True, + purpose=reason, skip_missing=True) + + def test(self): + """Perform smoke tests on the installed package.""" + # Simple version check tests on known binaries + self._test_check_versions() diff --git a/var/spack/repos/builtin/packages/fortran/package.py b/var/spack/repos/builtin/packages/fortran/package.py new file mode 100644 index 0000000000..6383ff856b --- /dev/null +++ b/var/spack/repos/builtin/packages/fortran/package.py @@ -0,0 +1,28 @@ +# Copyright 2013-2020 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 + + +class Fortran(Package): + """Virtual package for the Fortran language.""" + homepage = 'https://wg5-fortran.org/' + virtual = True + + def test(self): + test_source = self.test_suite.current_test_data_dir + + for test in os.listdir(test_source): + filepath = os.path.join(test_source, test) + exe_name = '%s.exe' % test + + fc_exe = os.environ['FC'] + fc_opts = ['-o', exe_name, filepath] + + compiled = self.run_test(fc_exe, options=fc_opts, installed=True) + + if compiled: + expected = ['Hello world', 'YES!'] + self.run_test(exe_name, expected=expected) diff --git a/var/spack/repos/builtin/packages/fortran/test/hello.F b/var/spack/repos/builtin/packages/fortran/test/hello.F new file mode 100644 index 0000000000..886046eaed --- /dev/null +++ b/var/spack/repos/builtin/packages/fortran/test/hello.F @@ -0,0 +1,6 @@ + program line + + write (*,*) "Hello world from FORTRAN" + write (*,*) "YES!" + + end diff --git a/var/spack/repos/builtin/packages/fortran/test/hello.f90 b/var/spack/repos/builtin/packages/fortran/test/hello.f90 new file mode 100644 index 0000000000..21717d11dd --- /dev/null +++ b/var/spack/repos/builtin/packages/fortran/test/hello.f90 @@ -0,0 +1,6 @@ +program line + + write (*,*) "Hello world from FORTRAN" + write (*,*) "YES!" + +end program line diff --git a/var/spack/repos/builtin/packages/gdal/package.py b/var/spack/repos/builtin/packages/gdal/package.py index 1162ffe9ae..a6f1dfd909 100644 --- a/var/spack/repos/builtin/packages/gdal/package.py +++ b/var/spack/repos/builtin/packages/gdal/package.py @@ -124,7 +124,7 @@ class Gdal(AutotoolsPackage): depends_on('hdf5', when='+hdf5') depends_on('kealib', when='+kea @2:') depends_on('netcdf-c', when='+netcdf') - depends_on('jasper@1.900.1', patches='uuid.patch', when='+jasper') + depends_on('jasper@1.900.1', patches=[patch('uuid.patch')], when='+jasper') depends_on('openjpeg', when='+openjpeg') depends_on('xerces-c', when='+xerces') depends_on('expat', when='+expat') diff --git a/var/spack/repos/builtin/packages/hdf/package.py b/var/spack/repos/builtin/packages/hdf/package.py index d40a0c21fe..76c2205f27 100644 --- a/var/spack/repos/builtin/packages/hdf/package.py +++ b/var/spack/repos/builtin/packages/hdf/package.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import sys +import os class Hdf(AutotoolsPackage): @@ -151,3 +152,67 @@ class Hdf(AutotoolsPackage): def check(self): with working_dir(self.build_directory): make('check', parallel=False) + + extra_install_tests = 'hdf/util/testfiles' + + @run_after('install') + def setup_build_tests(self): + """Copy the build test files after the package is installed to an + install test subdirectory for use during `spack test run`.""" + self.cache_extra_test_sources(self.extra_install_tests) + + def _test_check_versions(self): + """Perform version checks on selected installed package binaries.""" + spec_vers_str = 'Version {0}'.format(self.spec.version.up_to(2)) + + exes = ['hdfimport', 'hrepack', 'ncdump', 'ncgen'] + for exe in exes: + reason = 'test: ensuring version of {0} is {1}' \ + .format(exe, spec_vers_str) + self.run_test(exe, ['-V'], spec_vers_str, installed=True, + purpose=reason, skip_missing=True) + + def _test_gif_converters(self): + """This test performs an image conversion sequence and diff.""" + work_dir = '.' + storm_fn = os.path.join(self.install_test_root, + self.extra_install_tests, 'storm110.hdf') + gif_fn = 'storm110.gif' + new_hdf_fn = 'storm110gif.hdf' + + # Convert a test HDF file to a gif + self.run_test('hdf2gif', [storm_fn, gif_fn], '', installed=True, + purpose="test: hdf-to-gif", work_dir=work_dir) + + # Convert the gif to an HDF file + self.run_test('gif2hdf', [gif_fn, new_hdf_fn], '', installed=True, + purpose="test: gif-to-hdf", work_dir=work_dir) + + # Compare the original and new HDF files + self.run_test('hdiff', [new_hdf_fn, storm_fn], '', installed=True, + purpose="test: compare orig to new hdf", + work_dir=work_dir) + + def _test_list(self): + """This test compares low-level HDF file information to expected.""" + storm_fn = os.path.join(self.install_test_root, + self.extra_install_tests, 'storm110.hdf') + test_data_dir = self.test_suite.current_test_data_dir + work_dir = '.' + + reason = 'test: checking hdfls output' + details_file = os.path.join(test_data_dir, 'storm110.out') + expected = get_escaped_text_output(details_file) + self.run_test('hdfls', [storm_fn], expected, installed=True, + purpose=reason, skip_missing=True, work_dir=work_dir) + + def test(self): + """Perform smoke tests on the installed package.""" + # Simple version check tests on subset of known binaries that respond + self._test_check_versions() + + # Run gif converter sequence test + self._test_gif_converters() + + # Run hdfls output + self._test_list() diff --git a/var/spack/repos/builtin/packages/hdf/test/storm110.out b/var/spack/repos/builtin/packages/hdf/test/storm110.out new file mode 100644 index 0000000000..f17e4ce2b3 --- /dev/null +++ b/var/spack/repos/builtin/packages/hdf/test/storm110.out @@ -0,0 +1,17 @@ +File library version: Major= 0, Minor=0, Release=0 +String= + +Number type : (tag 106) + Ref nos: 110 +Machine type : (tag 107) + Ref nos: 4369 +Image Dimensions-8 : (tag 200) + Ref nos: 110 +Raster Image-8 : (tag 202) + Ref nos: 110 +Image Dimensions : (tag 300) + Ref nos: 110 +Raster Image Data : (tag 302) + Ref nos: 110 +Raster Image Group : (tag 306) + Ref nos: 110 diff --git a/var/spack/repos/builtin/packages/hdf5/package.py b/var/spack/repos/builtin/packages/hdf5/package.py index e592ab5e9f..b37c7ede65 100644 --- a/var/spack/repos/builtin/packages/hdf5/package.py +++ b/var/spack/repos/builtin/packages/hdf5/package.py @@ -6,8 +6,6 @@ import shutil import sys -from spack import * - class Hdf5(AutotoolsPackage): """HDF5 is a data model, library, and file format for storing and managing @@ -327,6 +325,9 @@ class Hdf5(AutotoolsPackage): @run_after('install') @on_package_attributes(run_tests=True) def check_install(self): + self._check_install() + + def _check_install(self): # Build and run a small program to test the installed HDF5 library spec = self.spec print("Checking HDF5 installation...") @@ -375,3 +376,55 @@ HDF5 version {version} {version} print('-' * 80) raise RuntimeError("HDF5 install check failed") shutil.rmtree(checkdir) + + def _test_check_versions(self): + """Perform version checks on selected installed package binaries.""" + spec_vers_str = 'Version {0}'.format(self.spec.version) + + exes = [ + 'h5copy', 'h5diff', 'h5dump', 'h5format_convert', 'h5ls', + 'h5mkgrp', 'h5repack', 'h5stat', 'h5unjam', + ] + use_short_opt = ['h52gif', 'h5repart', 'h5unjam'] + for exe in exes: + reason = 'test: ensuring version of {0} is {1}' \ + .format(exe, spec_vers_str) + option = '-V' if exe in use_short_opt else '--version' + self.run_test(exe, option, spec_vers_str, installed=True, + purpose=reason, skip_missing=True) + + def _test_example(self): + """This test performs copy, dump, and diff on an example hdf5 file.""" + test_data_dir = self.test_suite.current_test_data_dir + + filename = 'spack.h5' + h5_file = test_data_dir.join(filename) + + reason = 'test: ensuring h5dump produces expected output' + expected = get_escaped_text_output(test_data_dir.join('dump.out')) + self.run_test('h5dump', filename, expected, installed=True, + purpose=reason, skip_missing=True, + work_dir=test_data_dir) + + reason = 'test: ensuring h5copy runs' + options = ['-i', h5_file, '-s', 'Spack', '-o', 'test.h5', '-d', + 'Spack'] + self.run_test('h5copy', options, [], installed=True, + purpose=reason, skip_missing=True, work_dir='.') + + reason = ('test: ensuring h5diff shows no differences between orig and' + ' copy') + self.run_test('h5diff', [h5_file, 'test.h5'], [], installed=True, + purpose=reason, skip_missing=True, work_dir='.') + + def test(self): + """Perform smoke tests on the installed package.""" + # Simple version check tests on known binaries + self._test_check_versions() + + # Run sequence of commands on an hdf5 file + self._test_example() + + # Run existing install check + # TODO: Restore once address built vs. installed state + # self._check_install() diff --git a/var/spack/repos/builtin/packages/hdf5/test/dump.out b/var/spack/repos/builtin/packages/hdf5/test/dump.out new file mode 100644 index 0000000000..58decefc12 --- /dev/null +++ b/var/spack/repos/builtin/packages/hdf5/test/dump.out @@ -0,0 +1,45 @@ +HDF5 "spack.h5" { +GROUP "/" { + GROUP "Spack" { + GROUP "Software" { + ATTRIBUTE "Distribution" { + DATATYPE H5T_STRING { + STRSIZE H5T_VARIABLE; + STRPAD H5T_STR_NULLTERM; + CSET H5T_CSET_UTF8; + CTYPE H5T_C_S1; + } + DATASPACE SCALAR + DATA { + (0): "Open Source" + } + } + DATASET "data" { + DATATYPE H5T_IEEE_F64LE + DATASPACE SIMPLE { ( 7, 11 ) / ( 7, 11 ) } + DATA { + (0,0): 0.371141, 0.508482, 0.585975, 0.0944911, 0.684849, + (0,5): 0.580396, 0.720271, 0.693561, 0.340432, 0.217145, + (0,10): 0.636083, + (1,0): 0.686996, 0.773501, 0.656767, 0.617543, 0.226132, + (1,5): 0.768632, 0.0548711, 0.54572, 0.355544, 0.591548, + (1,10): 0.233007, + (2,0): 0.230032, 0.192087, 0.293845, 0.0369338, 0.038727, + (2,5): 0.0977931, 0.966522, 0.0821391, 0.857921, 0.495703, + (2,10): 0.746006, + (3,0): 0.598494, 0.990266, 0.993009, 0.187481, 0.746391, + (3,5): 0.140095, 0.122661, 0.929242, 0.542415, 0.802758, + (3,10): 0.757941, + (4,0): 0.372124, 0.411982, 0.270479, 0.950033, 0.329948, + (4,5): 0.936704, 0.105097, 0.742285, 0.556565, 0.18988, 0.72797, + (5,0): 0.801669, 0.271807, 0.910649, 0.186251, 0.868865, + (5,5): 0.191484, 0.788371, 0.920173, 0.582249, 0.682022, + (5,10): 0.146883, + (6,0): 0.826824, 0.0886705, 0.402606, 0.0532444, 0.72509, + (6,5): 0.964683, 0.330362, 0.833284, 0.630456, 0.411489, 0.247806 + } + } + } + } +} +} diff --git a/var/spack/repos/builtin/packages/hdf5/test/spack.h5 b/var/spack/repos/builtin/packages/hdf5/test/spack.h5 Binary files differnew file mode 100644 index 0000000000..c2f3a6f39d --- /dev/null +++ b/var/spack/repos/builtin/packages/hdf5/test/spack.h5 diff --git a/var/spack/repos/builtin/packages/jq/package.py b/var/spack/repos/builtin/packages/jq/package.py index 13d3d939a2..9f67ce5bbe 100644 --- a/var/spack/repos/builtin/packages/jq/package.py +++ b/var/spack/repos/builtin/packages/jq/package.py @@ -21,7 +21,7 @@ class Jq(AutotoolsPackage): @run_after('install') @on_package_attributes(run_tests=True) - def installtest(self): + def install_test(self): jq = self.spec['jq'].command f = os.path.join(os.path.dirname(__file__), 'input.json') diff --git a/var/spack/repos/builtin/packages/kcov/package.py b/var/spack/repos/builtin/packages/kcov/package.py index 8f01ffc985..5e7bf48bd5 100644 --- a/var/spack/repos/builtin/packages/kcov/package.py +++ b/var/spack/repos/builtin/packages/kcov/package.py @@ -27,7 +27,7 @@ class Kcov(CMakePackage): @run_after('install') @on_package_attributes(run_tests=True) - def test(self): + def test_install(self): # The help message exits with an exit code of 1 kcov = Executable(self.prefix.bin.kcov) kcov('-h', ignore_errors=1) diff --git a/var/spack/repos/builtin/packages/libsigsegv/package.py b/var/spack/repos/builtin/packages/libsigsegv/package.py index 7aab695b76..119778f018 100644 --- a/var/spack/repos/builtin/packages/libsigsegv/package.py +++ b/var/spack/repos/builtin/packages/libsigsegv/package.py @@ -3,8 +3,6 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) -from spack import * - class Libsigsegv(AutotoolsPackage, GNUMirrorPackage): """GNU libsigsegv is a library for handling page faults in user mode.""" @@ -18,5 +16,60 @@ class Libsigsegv(AutotoolsPackage, GNUMirrorPackage): patch('patch.new_config_guess', when='@2.10') + test_requires_compiler = True + def configure_args(self): return ['--enable-shared'] + + extra_install_tests = 'tests/.libs' + + @run_after('install') + def setup_build_tests(self): + """Copy the build test files after the package is installed to an + install test subdirectory for use during `spack test run`.""" + self.cache_extra_test_sources(self.extra_install_tests) + + def _run_smoke_tests(self): + """Build and run the added smoke (install) test.""" + data_dir = self.test_suite.current_test_data_dir + prog = 'smoke_test' + src = data_dir.join('{0}.c'.format(prog)) + + options = [ + '-I{0}'.format(self.prefix.include), + src, + '-o', + prog, + '-L{0}'.format(self.prefix.lib), + '-lsigsegv', + '{0}{1}'.format(self.compiler.cc_rpath_arg, self.prefix.lib)] + reason = 'test: checking ability to link to the library' + self.run_test('cc', options, [], installed=False, purpose=reason) + + # Now run the program and confirm the output matches expectations + expected = get_escaped_text_output(data_dir.join('smoke_test.out')) + reason = 'test: checking ability to use the library' + self.run_test(prog, [], expected, purpose=reason) + + def _run_build_tests(self): + """Run selected build tests.""" + passed = 'Test passed' + checks = { + 'sigsegv1': [passed], + 'sigsegv2': [passed], + 'sigsegv3': ['caught', passed], + 'stackoverflow1': ['recursion', 'Stack overflow', passed], + 'stackoverflow2': ['recursion', 'overflow', 'violation', passed], + } + + for exe, expected in checks.items(): + reason = 'test: checking {0} output'.format(exe) + self.run_test(exe, [], expected, installed=True, purpose=reason, + skip_missing=True) + + def test(self): + # Run the simple built-in smoke test + self._run_smoke_tests() + + # Run test programs pulled from the build + self._run_build_tests() diff --git a/var/spack/repos/builtin/packages/libsigsegv/test/smoke_test.c b/var/spack/repos/builtin/packages/libsigsegv/test/smoke_test.c new file mode 100644 index 0000000000..f1ab68cd53 --- /dev/null +++ b/var/spack/repos/builtin/packages/libsigsegv/test/smoke_test.c @@ -0,0 +1,70 @@ +/* Simple "Hello World" test set up to handle a single page fault + * + * Inspired by libsigsegv's test cases with argument names for handlers + * taken from the header files. + */ + +#include "sigsegv.h" +#include <stdio.h> +#include <stdlib.h> /* for exit */ +# include <stddef.h> /* for NULL on SunOS4 (per libsigsegv examples) */ +#include <setjmp.h> /* for controlling handler-related flow */ + + +/* Calling environment */ +jmp_buf calling_env; + +char *message = "Hello, World!"; + +/* Track the number of times the handler is called */ +volatile int times_called = 0; + + +/* Continuation function, which relies on the latest libsigsegv API */ +static void +resume(void *cont_arg1, void *cont_arg2, void *cont_arg3) +{ + /* Go to calling environment and restore state. */ + longjmp(calling_env, times_called); +} + +/* sigsegv handler */ +int +handle_sigsegv(void *fault_address, int serious) +{ + times_called++; + + /* Generate handler output for the test. */ + printf("Caught sigsegv #%d\n", times_called); + + return sigsegv_leave_handler(resume, NULL, NULL, NULL); +} + +/* "Buggy" function used to demonstrate non-local goto */ +void printit(char *m) +{ + if (times_called < 1) { + /* Force SIGSEGV only on the first call. */ + volatile int *fail_ptr = 0; + int failure = *fail_ptr; + printf("%s\n", m); + } else { + /* Print it correctly. */ + printf("%s\n", m); + } +} + +int +main(void) +{ + /* Install the global SIGSEGV handler */ + sigsegv_install_handler(&handle_sigsegv); + + char *msg = "Hello World!"; + int calls = setjmp(calling_env); /* Resume here after detecting sigsegv */ + + /* Call the function that will trigger the page fault. */ + printit(msg); + + return 0; +} diff --git a/var/spack/repos/builtin/packages/libsigsegv/test/smoke_test.out b/var/spack/repos/builtin/packages/libsigsegv/test/smoke_test.out new file mode 100644 index 0000000000..31071777e2 --- /dev/null +++ b/var/spack/repos/builtin/packages/libsigsegv/test/smoke_test.out @@ -0,0 +1,2 @@ +Caught sigsegv #1 +Hello World! diff --git a/var/spack/repos/builtin/packages/libxml2/package.py b/var/spack/repos/builtin/packages/libxml2/package.py index 2602378f89..9cbc8a6817 100644 --- a/var/spack/repos/builtin/packages/libxml2/package.py +++ b/var/spack/repos/builtin/packages/libxml2/package.py @@ -2,6 +2,8 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import llnl.util.filesystem as fs +import llnl.util.tty as tty from spack import * @@ -82,3 +84,34 @@ class Libxml2(AutotoolsPackage): if '+python' in self.spec: with working_dir('spack-test', create=True): python('-c', 'import libxml2') + + def test(self): + """Perform smoke tests on the installed package""" + # Start with what we already have post-install + tty.msg('test: Performing simple import test') + self.import_module_test() + + data_dir = self.test_suite.current_test_data_dir + + # Now run defined tests based on expected executables + dtd_path = data_dir.join('info.dtd') + test_filename = 'test.xml' + exec_checks = { + 'xml2-config': [ + ('--version', [str(self.spec.version)], 0)], + 'xmllint': [ + (['--auto', '-o', test_filename], [], 0), + (['--postvalid', test_filename], + ['validity error', 'no DTD found', 'does not validate'], 3), + (['--dtdvalid', dtd_path, test_filename], + ['validity error', 'does not follow the DTD'], 3), + (['--dtdvalid', dtd_path, data_dir.join('info.xml')], [], 0)], + 'xmlcatalog': [ + ('--create', ['<catalog xmlns', 'catalog"/>'], 0)], + } + for exe in exec_checks: + for options, expected, status in exec_checks[exe]: + self.run_test(exe, options, expected, status) + + # Perform some cleanup + fs.force_remove(test_filename) diff --git a/var/spack/repos/builtin/packages/libxml2/test/info.dtd b/var/spack/repos/builtin/packages/libxml2/test/info.dtd new file mode 100644 index 0000000000..aec2dbe705 --- /dev/null +++ b/var/spack/repos/builtin/packages/libxml2/test/info.dtd @@ -0,0 +1,2 @@ +<!ELEMENT info (data)> +<!ELEMENT data (#PCDATA)> diff --git a/var/spack/repos/builtin/packages/libxml2/test/info.xml b/var/spack/repos/builtin/packages/libxml2/test/info.xml new file mode 100644 index 0000000000..23803694a7 --- /dev/null +++ b/var/spack/repos/builtin/packages/libxml2/test/info.xml @@ -0,0 +1,4 @@ +<?xml version="1.0"?> +<info> +<data>abc</data> +</info> diff --git a/var/spack/repos/builtin/packages/m4/package.py b/var/spack/repos/builtin/packages/m4/package.py index 6695cdf862..b0d037b3f2 100644 --- a/var/spack/repos/builtin/packages/m4/package.py +++ b/var/spack/repos/builtin/packages/m4/package.py @@ -74,3 +74,16 @@ class M4(AutotoolsPackage, GNUMirrorPackage): args.append('ac_cv_type_struct_sched_param=yes') return args + + def test(self): + spec_vers = str(self.spec.version) + reason = 'test: ensuring m4 version is {0}'.format(spec_vers) + self.run_test('m4', '--version', spec_vers, installed=True, + purpose=reason, skip_missing=False) + + reason = 'test: ensuring m4 example succeeds' + test_data_dir = self.test_suite.current_test_data_dir + hello_file = test_data_dir.join('hello.m4') + expected = get_escaped_text_output(test_data_dir.join('hello.out')) + self.run_test('m4', hello_file, expected, installed=True, + purpose=reason, skip_missing=False) diff --git a/var/spack/repos/builtin/packages/m4/test/hello.m4 b/var/spack/repos/builtin/packages/m4/test/hello.m4 new file mode 100644 index 0000000000..6132c41093 --- /dev/null +++ b/var/spack/repos/builtin/packages/m4/test/hello.m4 @@ -0,0 +1,4 @@ +define(NAME, World) +dnl This line should not show up +// macro is ifdef(`NAME', , not)defined +Hello, NAME! diff --git a/var/spack/repos/builtin/packages/m4/test/hello.out b/var/spack/repos/builtin/packages/m4/test/hello.out new file mode 100644 index 0000000000..c8d3be7e16 --- /dev/null +++ b/var/spack/repos/builtin/packages/m4/test/hello.out @@ -0,0 +1,3 @@ + +// macro is defined +Hello, World! diff --git a/var/spack/repos/builtin/packages/mpi/package.py b/var/spack/repos/builtin/packages/mpi/package.py new file mode 100644 index 0000000000..731a5ac731 --- /dev/null +++ b/var/spack/repos/builtin/packages/mpi/package.py @@ -0,0 +1,31 @@ +# Copyright 2013-2020 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 + + +class Mpi(Package): + """Virtual package for the Message Passing Interface.""" + homepage = 'https://www.mpi-forum.org/' + virtual = True + + def test(self): + for lang in ('c', 'f'): + filename = self.test_suite.current_test_data_dir.join( + 'mpi_hello.' + lang) + + compiler_var = 'MPICC' if lang == 'c' else 'MPIF90' + compiler = os.environ[compiler_var] + + exe_name = 'mpi_hello_%s' % lang + mpirun = join_path(self.prefix.bin, 'mpirun') + + compiled = self.run_test(compiler, + options=['-o', exe_name, filename]) + if compiled: + self.run_test(mpirun, + options=['-np', '1', exe_name], + expected=[r'Hello world! From rank \s*0 of \s*1'] + ) diff --git a/var/spack/repos/builtin/packages/mpi/test/mpi_hello.c b/var/spack/repos/builtin/packages/mpi/test/mpi_hello.c new file mode 100644 index 0000000000..9db7c5a436 --- /dev/null +++ b/var/spack/repos/builtin/packages/mpi/test/mpi_hello.c @@ -0,0 +1,16 @@ +#include <stdio.h> +#include <mpi.h> + +int main(int argc, char** argv) { + MPI_Init(&argc, &argv); + + int rank; + int num_ranks; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &num_ranks); + + printf("Hello world! From rank %d of %d\n", rank, num_ranks); + + MPI_Finalize(); + return(0); +} diff --git a/var/spack/repos/builtin/packages/mpi/test/mpi_hello.f b/var/spack/repos/builtin/packages/mpi/test/mpi_hello.f new file mode 100644 index 0000000000..ecc7005d00 --- /dev/null +++ b/var/spack/repos/builtin/packages/mpi/test/mpi_hello.f @@ -0,0 +1,11 @@ +c Fortran example + program hello + include 'mpif.h' + integer rank, num_ranks, err_flag + + call MPI_INIT(err_flag) + call MPI_COMM_SIZE(MPI_COMM_WORLD, num_ranks, err_flag) + call MPI_COMM_RANK(MPI_COMM_WORLD, rank, err_flag) + print*, 'Hello world! From rank', rank, 'of ', num_ranks + call MPI_FINALIZE(err_flag) + end diff --git a/var/spack/repos/builtin/packages/ninja-fortran/package.py b/var/spack/repos/builtin/packages/ninja-fortran/package.py index 8e9fcb9851..d85a5b4542 100644 --- a/var/spack/repos/builtin/packages/ninja-fortran/package.py +++ b/var/spack/repos/builtin/packages/ninja-fortran/package.py @@ -51,7 +51,7 @@ class NinjaFortran(Package): @run_after('configure') @on_package_attributes(run_tests=True) - def test(self): + def configure_test(self): ninja = Executable('./ninja') ninja('-j{0}'.format(make_jobs), 'ninja_test') ninja_test = Executable('./ninja_test') diff --git a/var/spack/repos/builtin/packages/ninja/package.py b/var/spack/repos/builtin/packages/ninja/package.py index 40890c212e..96cd0252a2 100644 --- a/var/spack/repos/builtin/packages/ninja/package.py +++ b/var/spack/repos/builtin/packages/ninja/package.py @@ -2,7 +2,6 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) -import re class Ninja(Package): @@ -40,7 +39,7 @@ class Ninja(Package): @run_after('configure') @on_package_attributes(run_tests=True) - def test(self): + def configure_test(self): ninja = Executable('./ninja') ninja('-j{0}'.format(make_jobs), 'ninja_test') ninja_test = Executable('./ninja_test') diff --git a/var/spack/repos/builtin/packages/node-js/package.py b/var/spack/repos/builtin/packages/node-js/package.py index b35e1d0def..28def78333 100644 --- a/var/spack/repos/builtin/packages/node-js/package.py +++ b/var/spack/repos/builtin/packages/node-js/package.py @@ -127,7 +127,7 @@ class NodeJs(Package): @run_after('build') @on_package_attributes(run_tests=True) - def test(self): + def build_test(self): make('test') make('test-addons') diff --git a/var/spack/repos/builtin/packages/openmpi/package.py b/var/spack/repos/builtin/packages/openmpi/package.py index b56c10fb67..124973bbc1 100644 --- a/var/spack/repos/builtin/packages/openmpi/package.py +++ b/var/spack/repos/builtin/packages/openmpi/package.py @@ -336,6 +336,8 @@ class Openmpi(AutotoolsPackage): filter_compiler_wrappers('openmpi/*-wrapper-data*', relative_root='share') + extra_install_tests = 'examples' + @classmethod def determine_version(cls, exe): output = Executable(exe)(output=str, error=str) @@ -846,6 +848,149 @@ class Openmpi(AutotoolsPackage): else: copy(script_stub, exe) + @run_after('install') + def setup_install_tests(self): + """ + Copy the example files after the package is installed to an + install test subdirectory for use during `spack test run`. + """ + self.cache_extra_test_sources(self.extra_install_tests) + + def _test_bin_ops(self): + info = ([], ['Ident string: {0}'.format(self.spec.version), 'MCA'], + 0) + + ls = (['-n', '1', 'ls', '..'], + ['openmpi-{0}'.format(self.spec.version)], 0) + + checks = { + 'mpirun': ls, + 'ompi_info': info, + 'oshmem_info': info, + 'oshrun': ls, + 'shmemrun': ls, + } + + for exe in checks: + options, expected, status = checks[exe] + reason = 'test: checking {0} output'.format(exe) + self.run_test(exe, options, expected, status, installed=True, + purpose=reason, skip_missing=True) + + def _test_check_versions(self): + comp_vers = str(self.spec.compiler.version) + spec_vers = str(self.spec.version) + checks = { + # Binaries available in at least versions 2.0.0 through 4.0.3 + 'mpiCC': comp_vers, + 'mpic++': comp_vers, + 'mpicc': comp_vers, + 'mpicxx': comp_vers, + 'mpiexec': spec_vers, + 'mpif77': comp_vers, + 'mpif90': comp_vers, + 'mpifort': comp_vers, + 'mpirun': spec_vers, + 'ompi_info': spec_vers, + 'ortecc': comp_vers, + 'orterun': spec_vers, + + # Binaries available in versions 2.0.0 through 2.1.6 + 'ompi-submit': spec_vers, + 'orte-submit': spec_vers, + + # Binaries available in versions 2.0.0 through 3.1.5 + 'ompi-dvm': spec_vers, + 'orte-dvm': spec_vers, + 'oshcc': comp_vers, + 'oshfort': comp_vers, + 'oshmem_info': spec_vers, + 'oshrun': spec_vers, + 'shmemcc': comp_vers, + 'shmemfort': comp_vers, + 'shmemrun': spec_vers, + + # Binary available in version 3.1.0 through 3.1.5 + 'prun': spec_vers, + + # Binaries available in versions 3.0.0 through 3.1.5 + 'oshCC': comp_vers, + 'oshc++': comp_vers, + 'oshcxx': comp_vers, + 'shmemCC': comp_vers, + 'shmemc++': comp_vers, + 'shmemcxx': comp_vers, + } + + for exe in checks: + expected = checks[exe] + purpose = 'test: ensuring version of {0} is {1}' \ + .format(exe, expected) + self.run_test(exe, '--version', expected, installed=True, + purpose=purpose, skip_missing=True) + + def _test_examples(self): + # First build the examples + self.run_test('make', ['all'], [], + purpose='test: ensuring ability to build the examples', + work_dir=join_path(self.install_test_root, + self.extra_install_tests)) + + # Now run those with known results + have_spml = self.spec.satisfies('@2.0.0:2.1.6') + + hello_world = (['Hello, world', 'I am', '0 of', '1'], 0) + + max_red = (['0/1 dst = 0 1 2'], 0) + + missing_spml = (['No available spml components'], 1) + + no_out = ([''], 0) + + ring_out = (['1 processes in ring', '0 exiting'], 0) + + strided = (['not in valid range'], 255) + + checks = { + 'hello_c': hello_world, + 'hello_cxx': hello_world, + 'hello_mpifh': hello_world, + 'hello_oshmem': hello_world if have_spml else missing_spml, + 'hello_oshmemcxx': hello_world if have_spml else missing_spml, + 'hello_oshmemfh': hello_world if have_spml else missing_spml, + 'hello_usempi': hello_world, + 'hello_usempif08': hello_world, + 'oshmem_circular_shift': ring_out if have_spml else missing_spml, + 'oshmem_max_reduction': max_red if have_spml else missing_spml, + 'oshmem_shmalloc': no_out if have_spml else missing_spml, + 'oshmem_strided_puts': strided if have_spml else missing_spml, + 'oshmem_symmetric_data': no_out if have_spml else missing_spml, + 'ring_c': ring_out, + 'ring_cxx': ring_out, + 'ring_mpifh': ring_out, + 'ring_oshmem': ring_out if have_spml else missing_spml, + 'ring_oshmemfh': ring_out if have_spml else missing_spml, + 'ring_usempi': ring_out, + 'ring_usempif08': ring_out, + } + + for exe in checks: + expected = checks[exe] + reason = 'test: checking example {0} output'.format(exe) + self.run_test(exe, [], expected, 0, installed=True, + purpose=reason, skip_missing=True) + + def test(self): + """Perform smoke tests on the installed package.""" + # Simple version check tests on known packages + self._test_check_versions() + + # Test the operation of selected executables + self._test_bin_ops() + + # Test example programs pulled from the build + self._test_examples() + def get_spack_compiler_spec(path): spack_compilers = spack.compilers.find_compilers([path]) diff --git a/var/spack/repos/builtin/packages/patchelf/package.py b/var/spack/repos/builtin/packages/patchelf/package.py index d17bb3bea1..796fd533eb 100644 --- a/var/spack/repos/builtin/packages/patchelf/package.py +++ b/var/spack/repos/builtin/packages/patchelf/package.py @@ -2,8 +2,8 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - from spack import * +import os class Patchelf(AutotoolsPackage): @@ -18,3 +18,24 @@ class Patchelf(AutotoolsPackage): version('0.10', sha256='b2deabce05c34ce98558c0efb965f209de592197b2c88e930298d740ead09019') version('0.9', sha256='f2aa40a6148cb3b0ca807a1bf836b081793e55ec9e5540a5356d800132be7e0a') version('0.8', sha256='14af06a2da688d577d64ff8dac065bb8903bbffbe01d30c62df7af9bf4ce72fe') + + def test(self): + # Check patchelf in prefix and reports the correct version + reason = 'test: ensuring patchelf version is {0}' \ + .format(self.spec.version) + self.run_test('patchelf', + options='--version', + expected=['patchelf %s' % self.spec.version], + installed=True, + purpose=reason) + + # Check the rpath is changed + currdir = os.getcwd() + hello_file = self.test_suite.current_test_data_dir.join('hello') + self.run_test('patchelf', ['--set-rpath', currdir, hello_file], + purpose='test: ensuring that patchelf can change rpath') + + self.run_test('patchelf', + options=['--print-rpath', hello_file], + expected=[currdir], + purpose='test: ensuring that patchelf changed rpath') diff --git a/var/spack/repos/builtin/packages/patchelf/test/hello b/var/spack/repos/builtin/packages/patchelf/test/hello Binary files differnew file mode 100755 index 0000000000..8767836f8e --- /dev/null +++ b/var/spack/repos/builtin/packages/patchelf/test/hello diff --git a/var/spack/repos/builtin/packages/perl/package.py b/var/spack/repos/builtin/packages/perl/package.py index 744b55495a..2532f97160 100644 --- a/var/spack/repos/builtin/packages/perl/package.py +++ b/var/spack/repos/builtin/packages/perl/package.py @@ -204,7 +204,7 @@ class Perl(Package): # Perl doesn't use Autotools, it should subclass Package @run_after('build') @on_package_attributes(run_tests=True) - def test(self): + def build_test(self): make('test') def install(self, spec, prefix): @@ -364,3 +364,16 @@ class Perl(Package): # Perl doesn't use Autotools, it should subclass Package else: msg = 'Unable to locate {0} command in {1}' raise RuntimeError(msg.format(self.spec.name, self.prefix.bin)) + + def test(self): + """Smoke tests""" + exe = self.spec['perl'].command.name + + reason = 'test: checking version is {0}'.format(self.spec.version) + self.run_test(exe, '--version', ['perl', str(self.spec.version)], + installed=True, purpose=reason) + + reason = 'test: ensuring perl runs' + msg = 'Hello, World!' + options = ['-e', 'use warnings; use strict;\nprint("%s\n");' % msg] + self.run_test(exe, options, msg, installed=True, purpose=reason) diff --git a/var/spack/repos/builtin/packages/py-cloudpickle/package.py b/var/spack/repos/builtin/packages/py-cloudpickle/package.py index ff1e459e09..0f7e525290 100644 --- a/var/spack/repos/builtin/packages/py-cloudpickle/package.py +++ b/var/spack/repos/builtin/packages/py-cloudpickle/package.py @@ -19,6 +19,6 @@ class PyCloudpickle(PythonPackage): depends_on('py-setuptools', type='build') - def test(self): + def build_test(self): # PyPI tarball does not come with unit tests pass diff --git a/var/spack/repos/builtin/packages/py-cython/package.py b/var/spack/repos/builtin/packages/py-cython/package.py index aa30f56237..2dd532be2f 100644 --- a/var/spack/repos/builtin/packages/py-cython/package.py +++ b/var/spack/repos/builtin/packages/py-cython/package.py @@ -47,6 +47,6 @@ class PyCython(PythonPackage): """Returns the Cython command""" return Executable(self.prefix.bin.cython) - def test(self): + def build_test(self): # Warning: full suite of unit tests takes a very long time python('runtests.py', '-j', str(make_jobs)) diff --git a/var/spack/repos/builtin/packages/py-fiona/package.py b/var/spack/repos/builtin/packages/py-fiona/package.py index b6ad22a9a7..b4213d5f61 100644 --- a/var/spack/repos/builtin/packages/py-fiona/package.py +++ b/var/spack/repos/builtin/packages/py-fiona/package.py @@ -34,6 +34,6 @@ class PyFiona(PythonPackage): depends_on('py-ordereddict', type=('build', 'run'), when='^python@:2.6') depends_on('py-enum34', type=('build', 'run'), when='^python@:3.3') - def test(self): + def build_test(self): # PyPI tarball does not come with unit tests pass diff --git a/var/spack/repos/builtin/packages/py-matplotlib/package.py b/var/spack/repos/builtin/packages/py-matplotlib/package.py index c2ce697ec2..ebb95033cf 100644 --- a/var/spack/repos/builtin/packages/py-matplotlib/package.py +++ b/var/spack/repos/builtin/packages/py-matplotlib/package.py @@ -183,6 +183,6 @@ class PyMatplotlib(PythonPackage): setup.write('system_freetype = True\n') setup.write('system_qhull = True\n') - def test(self): + def build_test(self): pytest = which('pytest') pytest() diff --git a/var/spack/repos/builtin/packages/py-numpy/package.py b/var/spack/repos/builtin/packages/py-numpy/package.py index 53b1f759a6..fd09019469 100644 --- a/var/spack/repos/builtin/packages/py-numpy/package.py +++ b/var/spack/repos/builtin/packages/py-numpy/package.py @@ -306,7 +306,7 @@ class PyNumpy(PythonPackage): return args - def test(self): + def build_test(self): # `setup.py test` is not supported. Use one of the following # instead: # diff --git a/var/spack/repos/builtin/packages/py-py/package.py b/var/spack/repos/builtin/packages/py-py/package.py index 2cb000a846..995612d20a 100644 --- a/var/spack/repos/builtin/packages/py-py/package.py +++ b/var/spack/repos/builtin/packages/py-py/package.py @@ -28,6 +28,6 @@ class PyPy(PythonPackage): depends_on('py-setuptools', type='build') depends_on('py-setuptools-scm', type='build') - def test(self): + def build_test(self): # Tests require pytest, creating a circular dependency pass diff --git a/var/spack/repos/builtin/packages/py-py2cairo/package.py b/var/spack/repos/builtin/packages/py-py2cairo/package.py index 1427c7e45c..5c492a9167 100644 --- a/var/spack/repos/builtin/packages/py-py2cairo/package.py +++ b/var/spack/repos/builtin/packages/py-py2cairo/package.py @@ -23,7 +23,7 @@ class PyPy2cairo(WafPackage): depends_on('py-pytest', type='test') - def installtest(self): + def install_test(self): with working_dir('test'): pytest = which('py.test') pytest() diff --git a/var/spack/repos/builtin/packages/py-pybind11/package.py b/var/spack/repos/builtin/packages/py-pybind11/package.py index 3fe7402a0f..1c07734e6f 100644 --- a/var/spack/repos/builtin/packages/py-pybind11/package.py +++ b/var/spack/repos/builtin/packages/py-pybind11/package.py @@ -74,7 +74,7 @@ class PyPybind11(CMakePackage): @run_after('install') @on_package_attributes(run_tests=True) - def test(self): + def install_test(self): with working_dir('spack-test', create=True): # test include helper points to right location python = self.spec['python'].command diff --git a/var/spack/repos/builtin/packages/py-pygments/package.py b/var/spack/repos/builtin/packages/py-pygments/package.py index 87476c64d6..d7559b36d8 100644 --- a/var/spack/repos/builtin/packages/py-pygments/package.py +++ b/var/spack/repos/builtin/packages/py-pygments/package.py @@ -29,6 +29,6 @@ class PyPygments(PythonPackage): depends_on('python@3.5:', type=('build', 'run'), when='@2.6:') depends_on('py-setuptools', type=('build', 'run')) - def test(self): + def build_test(self): # Unit tests require sphinx, but that creates a circular dependency pass diff --git a/var/spack/repos/builtin/packages/py-python-dateutil/package.py b/var/spack/repos/builtin/packages/py-python-dateutil/package.py index 13e04b4e6e..16bff6858d 100644 --- a/var/spack/repos/builtin/packages/py-python-dateutil/package.py +++ b/var/spack/repos/builtin/packages/py-python-dateutil/package.py @@ -31,7 +31,7 @@ class PyPythonDateutil(PythonPackage): # depends_on('py-hypothesis', type='test') # depends_on('py-freezegun', type='test') - def test(self): + def build_test(self): # Tests require freezegun, which depends on python-dateutil, # creating circular dependency # pytest = which('pytest') diff --git a/var/spack/repos/builtin/packages/py-scipy/package.py b/var/spack/repos/builtin/packages/py-scipy/package.py index 533d404fa6..afeae0dd1c 100644 --- a/var/spack/repos/builtin/packages/py-scipy/package.py +++ b/var/spack/repos/builtin/packages/py-scipy/package.py @@ -99,7 +99,7 @@ class PyScipy(PythonPackage): return args - def test(self): + def build_test(self): # `setup.py test` is not supported. Use one of the following # instead: # diff --git a/var/spack/repos/builtin/packages/py-setuptools/package.py b/var/spack/repos/builtin/packages/py-setuptools/package.py index 27786cd27e..1a2930498b 100644 --- a/var/spack/repos/builtin/packages/py-setuptools/package.py +++ b/var/spack/repos/builtin/packages/py-setuptools/package.py @@ -71,6 +71,6 @@ class PySetuptools(PythonPackage): return url - def test(self): + def build_test(self): # Unit tests require pytest, creating a circular dependency pass diff --git a/var/spack/repos/builtin/packages/py-shapely/package.py b/var/spack/repos/builtin/packages/py-shapely/package.py index 6dc62888ab..c03106a6be 100644 --- a/var/spack/repos/builtin/packages/py-shapely/package.py +++ b/var/spack/repos/builtin/packages/py-shapely/package.py @@ -64,5 +64,5 @@ class PyShapely(PythonPackage): else: env.prepend_path('LD_LIBRARY_PATH', libs) - def test(self): + def test_install(self): python('-m', 'pytest') diff --git a/var/spack/repos/builtin/packages/py-sphinxcontrib-applehelp/package.py b/var/spack/repos/builtin/packages/py-sphinxcontrib-applehelp/package.py index 25f1a7ce5f..67ba38134c 100644 --- a/var/spack/repos/builtin/packages/py-sphinxcontrib-applehelp/package.py +++ b/var/spack/repos/builtin/packages/py-sphinxcontrib-applehelp/package.py @@ -18,6 +18,6 @@ class PySphinxcontribApplehelp(PythonPackage): depends_on('python@3.5:', type=('build', 'run')) depends_on('py-setuptools', type='build') - def test(self): + def build_test(self): # Requires sphinx, creating a circular dependency pass diff --git a/var/spack/repos/builtin/packages/py-sphinxcontrib-devhelp/package.py b/var/spack/repos/builtin/packages/py-sphinxcontrib-devhelp/package.py index ff90a9a5d4..1954fc9677 100644 --- a/var/spack/repos/builtin/packages/py-sphinxcontrib-devhelp/package.py +++ b/var/spack/repos/builtin/packages/py-sphinxcontrib-devhelp/package.py @@ -18,6 +18,6 @@ class PySphinxcontribDevhelp(PythonPackage): depends_on('python@3.5:', type=('build', 'run')) depends_on('py-setuptools', type='build') - def test(self): + def build_test(self): # Requires sphinx, creating a circular dependency pass diff --git a/var/spack/repos/builtin/packages/py-sphinxcontrib-htmlhelp/package.py b/var/spack/repos/builtin/packages/py-sphinxcontrib-htmlhelp/package.py index 96a51d3113..95f6819d59 100644 --- a/var/spack/repos/builtin/packages/py-sphinxcontrib-htmlhelp/package.py +++ b/var/spack/repos/builtin/packages/py-sphinxcontrib-htmlhelp/package.py @@ -18,6 +18,6 @@ class PySphinxcontribHtmlhelp(PythonPackage): depends_on('python@3.5:', type=('build', 'run')) depends_on('py-setuptools', type='build') - def test(self): + def build_test(self): # Requires sphinx, creating a circular dependency pass diff --git a/var/spack/repos/builtin/packages/py-sphinxcontrib-jsmath/package.py b/var/spack/repos/builtin/packages/py-sphinxcontrib-jsmath/package.py index 45ee46bc67..add0160ac8 100644 --- a/var/spack/repos/builtin/packages/py-sphinxcontrib-jsmath/package.py +++ b/var/spack/repos/builtin/packages/py-sphinxcontrib-jsmath/package.py @@ -17,6 +17,6 @@ class PySphinxcontribJsmath(PythonPackage): depends_on('python@3.5:', type=('build', 'run')) depends_on('py-setuptools', type='build') - def test(self): + def build_test(self): # Requires sphinx, creating a circular dependency pass diff --git a/var/spack/repos/builtin/packages/py-sphinxcontrib-qthelp/package.py b/var/spack/repos/builtin/packages/py-sphinxcontrib-qthelp/package.py index 86a58d456f..19fd328f37 100644 --- a/var/spack/repos/builtin/packages/py-sphinxcontrib-qthelp/package.py +++ b/var/spack/repos/builtin/packages/py-sphinxcontrib-qthelp/package.py @@ -18,6 +18,6 @@ class PySphinxcontribQthelp(PythonPackage): depends_on('python@3.5:', type=('build', 'run')) depends_on('py-setuptools', type='build') - def test(self): + def build_test(self): # Requires sphinx, creating a circular dependency pass diff --git a/var/spack/repos/builtin/packages/py-sphinxcontrib-serializinghtml/package.py b/var/spack/repos/builtin/packages/py-sphinxcontrib-serializinghtml/package.py index 97b79a8012..3bad6d661a 100644 --- a/var/spack/repos/builtin/packages/py-sphinxcontrib-serializinghtml/package.py +++ b/var/spack/repos/builtin/packages/py-sphinxcontrib-serializinghtml/package.py @@ -18,6 +18,6 @@ class PySphinxcontribSerializinghtml(PythonPackage): depends_on('python@3.5:', type=('build', 'run')) depends_on('py-setuptools', type='build') - def test(self): + def build_test(self): # Requires sphinx, creating a circular dependency pass diff --git a/var/spack/repos/builtin/packages/py-sphinxcontrib-websupport/package.py b/var/spack/repos/builtin/packages/py-sphinxcontrib-websupport/package.py index c5a8f80a5b..1e4d1051a3 100644 --- a/var/spack/repos/builtin/packages/py-sphinxcontrib-websupport/package.py +++ b/var/spack/repos/builtin/packages/py-sphinxcontrib-websupport/package.py @@ -26,6 +26,6 @@ class PySphinxcontribWebsupport(PythonPackage): depends_on('python@2.7:2.8,3.4:', type=('build', 'run')) depends_on('py-setuptools', type='build') - def test(self): + def build_test(self): # Unit tests require sphinx, creating a circular dependency pass diff --git a/var/spack/repos/builtin/packages/py-statsmodels/package.py b/var/spack/repos/builtin/packages/py-statsmodels/package.py index 26c006bccf..b00e51730b 100644 --- a/var/spack/repos/builtin/packages/py-statsmodels/package.py +++ b/var/spack/repos/builtin/packages/py-statsmodels/package.py @@ -42,7 +42,7 @@ class PyStatsmodels(PythonPackage): depends_on('py-pytest', type='test') - def test(self): + def build_test(self): dirs = glob.glob("build/lib*") # There can be only one... with working_dir(dirs[0]): pytest = which('pytest') diff --git a/var/spack/repos/builtin/packages/python/package.py b/var/spack/repos/builtin/packages/python/package.py index 53924a85b0..4d0df211e6 100644 --- a/var/spack/repos/builtin/packages/python/package.py +++ b/var/spack/repos/builtin/packages/python/package.py @@ -1127,3 +1127,21 @@ class Python(AutotoolsPackage): view.remove_file(src, dst) else: os.remove(dst) + + def test(self): + # do not use self.command because we are also testing the run env + exe = self.spec['python'].command.name + + # test hello world + msg = 'hello world!' + reason = 'test: running {0}'.format(msg) + options = ['-c', 'print("{0}")'.format(msg)] + self.run_test(exe, options=options, expected=[msg], installed=True, + purpose=reason) + + # checks import works and executable comes from the spec prefix + reason = 'test: checking import and executable' + print_str = self.print_string('sys.executable') + options = ['-c', 'import sys; {0}'.format(print_str)] + self.run_test(exe, options=options, expected=[self.spec.prefix], + installed=True, purpose=reason) diff --git a/var/spack/repos/builtin/packages/raja/package.py b/var/spack/repos/builtin/packages/raja/package.py index 7da9c6c4fd..8d1db659cc 100644 --- a/var/spack/repos/builtin/packages/raja/package.py +++ b/var/spack/repos/builtin/packages/raja/package.py @@ -3,8 +3,6 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) -from spack import * - class Raja(CMakePackage, CudaPackage): """RAJA Parallel Framework.""" @@ -74,3 +72,52 @@ class Raja(CMakePackage, CudaPackage): options.append('-DENABLE_TESTS=ON') return options + + @property + def build_relpath(self): + """Relative path to the cmake build subdirectory.""" + return join_path('..', self.build_dirname) + + @run_after('install') + def setup_build_tests(self): + """Copy the build test files after the package is installed to a + relative install test subdirectory for use during `spack test run`.""" + # Now copy the relative files + self.cache_extra_test_sources(self.build_relpath) + + # Ensure the path exists since relying on a relative path at the + # same level as the normal stage source path. + mkdirp(self.install_test_root) + + @property + def _extra_tests_path(self): + # TODO: The tests should be converted to re-build and run examples + # TODO: using the installed libraries. + return join_path(self.install_test_root, self.build_relpath, 'bin') + + def _test_examples(self): + """Perform very basic checks on a subset of copied examples.""" + checks = [ + ('ex5_line-of-sight_solution', + [r'RAJA sequential', r'RAJA OpenMP', r'result -- PASS']), + ('ex6_stencil-offset-layout_solution', + [r'RAJA Views \(permuted\)', r'result -- PASS']), + ('ex8_tiled-matrix-transpose_solution', + [r'parallel top inner loop', + r'collapsed inner loops', r'result -- PASS']), + ('kernel-dynamic-tile', [r'Running index', r'(24,24)']), + ('plugin-example', + [r'Launching host kernel for the 10 time']), + ('tut_batched-matrix-multiply', [r'result -- PASS']), + ('wave-eqn', [r'Max Error = 2', r'Evolved solution to time']) + ] + for exe, expected in checks: + reason = 'test: checking output of {0} for {1}' \ + .format(exe, expected) + self.run_test(exe, [], expected, installed=False, + purpose=reason, skip_missing=True, + work_dir=self._extra_tests_path) + + def test(self): + """Perform smoke tests.""" + self._test_examples() diff --git a/var/spack/repos/builtin/packages/serf/package.py b/var/spack/repos/builtin/packages/serf/package.py index 4c762bf9a5..96df6f7579 100644 --- a/var/spack/repos/builtin/packages/serf/package.py +++ b/var/spack/repos/builtin/packages/serf/package.py @@ -63,7 +63,7 @@ class Serf(SConsPackage): return args - def test(self): + def build_test(self): # FIXME: Several test failures: # # There were 14 failures: diff --git a/var/spack/repos/builtin/packages/sqlite/package.py b/var/spack/repos/builtin/packages/sqlite/package.py index b400965b3f..db456cb0d7 100644 --- a/var/spack/repos/builtin/packages/sqlite/package.py +++ b/var/spack/repos/builtin/packages/sqlite/package.py @@ -3,7 +3,6 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) -from spack import * from spack import architecture @@ -129,3 +128,41 @@ class Sqlite(AutotoolsPackage): cc(self.compiler.cc_pic_flag, '-lm', '-shared', 'extension-functions.c', '-o', libraryname) install(libraryname, self.prefix.lib) + + def _test_example(self): + """Ensure a sequence of commands on example db are successful.""" + + test_data_dir = self.test_suite.current_test_data_dir + db_filename = test_data_dir.join('packages.db') + exe = 'sqlite3' + + # Ensure the database only contains one table + expected = 'packages' + reason = 'test: ensuring only table is "{0}"'.format(expected) + self.run_test(exe, [db_filename, '.tables'], expected, installed=True, + purpose=reason, skip_missing=False) + + # Ensure the database dump matches expectations, where special + # characters are replaced with spaces in the expected and actual + # output to avoid pattern errors. + reason = 'test: checking dump output' + expected = get_escaped_text_output(test_data_dir.join('dump.out')) + self.run_test(exe, [db_filename, '.dump'], expected, installed=True, + purpose=reason, skip_missing=False) + + def _test_version(self): + """Perform version check on the installed package.""" + exe = 'sqlite3' + vers_str = str(self.spec.version) + + reason = 'test: ensuring version of {0} is {1}'.format(exe, vers_str) + self.run_test(exe, '-version', vers_str, installed=True, + purpose=reason, skip_missing=False) + + def test(self): + """Perform smoke tests on the installed package.""" + # Perform a simple version check + self._test_version() + + # Run a sequence of operations + self._test_example() diff --git a/var/spack/repos/builtin/packages/sqlite/test/dump.out b/var/spack/repos/builtin/packages/sqlite/test/dump.out new file mode 100644 index 0000000000..3dda19d1c5 --- /dev/null +++ b/var/spack/repos/builtin/packages/sqlite/test/dump.out @@ -0,0 +1,10 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE packages ( +name varchar(80) primary key, +has_code integer, +url varchar(160)); +INSERT INTO packages VALUES('sqlite',1,'https://www.sqlite.org'); +INSERT INTO packages VALUES('readline',1,'https://tiswww.case.edu/php/chet/readline/rltop.html'); +INSERT INTO packages VALUES('xsdk',0,'http://xsdk.info'); +COMMIT; diff --git a/var/spack/repos/builtin/packages/sqlite/test/packages.db b/var/spack/repos/builtin/packages/sqlite/test/packages.db Binary files differnew file mode 100644 index 0000000000..252962235c --- /dev/null +++ b/var/spack/repos/builtin/packages/sqlite/test/packages.db diff --git a/var/spack/repos/builtin/packages/subversion/package.py b/var/spack/repos/builtin/packages/subversion/package.py index 1f5f65215c..98874ee2bd 100644 --- a/var/spack/repos/builtin/packages/subversion/package.py +++ b/var/spack/repos/builtin/packages/subversion/package.py @@ -98,7 +98,7 @@ class Subversion(AutotoolsPackage): perl = spec['perl'].command perl('Makefile.PL', 'INSTALL_BASE={0}'.format(prefix)) - def test(self): + def check(self): make('check') if '+perl' in self.spec: make('check-swig-pl') diff --git a/var/spack/repos/builtin/packages/umpire/package.py b/var/spack/repos/builtin/packages/umpire/package.py index 08b6d487ff..6b39aad5f6 100644 --- a/var/spack/repos/builtin/packages/umpire/package.py +++ b/var/spack/repos/builtin/packages/umpire/package.py @@ -3,8 +3,8 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - -from spack import * +import llnl.util.lang as lang +import llnl.util.tty as tty class Umpire(CMakePackage, CudaPackage): @@ -115,3 +115,189 @@ class Umpire(CMakePackage, CudaPackage): 'Off' if 'tests=none' in spec else 'On')) return options + + @property + def build_relpath(self): + """Relative path to the cmake build subdirectory.""" + return join_path('..', self.build_dirname) + + @run_after('install') + def setup_build_tests(self): + """Copy the build test files after the package is installed to an + install test subdirectory for use during `spack test run`.""" + # Now copy the relative files + self.cache_extra_test_sources(self.build_relpath) + + # Ensure the path exists since relying on a relative path at the + # same level as the normal stage source path. + mkdirp(self.install_test_root) + + @property + @lang.memoized + def _extra_tests_path(self): + # TODO: The tests should be converted to re-build and run examples + # TODO: using the installed libraries. + return join_path(self.install_test_root, self.build_relpath) + + @property + @lang.memoized + def _has_bad_strategy(self): + return self.spec.satisfies('@0.2.0:0.2.3') + + def _run_checks(self, dirs, checks): + """Run the specified checks in the provided directories.""" + + if not dirs or not checks: + return + + for exe in checks: + if exe == 'strategy_example' and self._has_bad_strategy: + # Skip this test until install testing can properly capture + # the abort associated with this version. + # (An umpire::util::Exception is thrown; status value is -6.) + tty.warn('Skipping {0} test until Spack can handle core dump' + .format(exe)) + continue + + expected, status = checks[exe] + for work_dir in dirs: + src = 'from build ' if 'spack-build' in work_dir else '' + reason = 'test {0} {1}output'.format(exe, src) + self.run_test(exe, [], expected, status, installed=False, + purpose=reason, skip_missing=True, + work_dir=work_dir) + + def _run_bench_checks(self): + """Run the benchmark smoke test checks.""" + tty.info('Running benchmark checks') + + dirs = [] + if self.spec.satisfies('@0.3.3:1.0.1'): + dirs.append(join_path(self._extra_tests_path, 'benchmarks')) + elif self.spec.satisfies('@1.1.0:'): + dirs.append(self.prefix.bin) + + checks = { + # Versions 0.3.3:1.0.1 (spack-build/bin/benchmarks) + # Versions 1.1.0:2.1.0 (spack-build/bin) + 'allocator_benchmarks': ( + ['Malloc/malloc', 'Malloc/free', 'ns', + 'Host/allocate', 'Host/deallocate', + 'FixedPoolHost/allocate', + 'FixedPoolHost/deallocate'], 0), + 'copy_benchmarks': (['benchmark_copy/host_host', 'ns'], 0), + 'debuglog_benchmarks': (['benchmark_DebugLogger', 'ns'], 0), + } + self._run_checks(dirs, checks) + + def _run_cookbook_checks(self): + """Run the cookbook smoke test checks.""" + tty.info('Running cookbook checks') + + dirs = [] + cb_subdir = join_path('examples', 'cookbook') + if self.spec.satisfies('@0.3.3:1.0.1'): + dirs.append(join_path(self._extra_tests_path, cb_subdir)) + elif self.spec.satisfies('@1.1.0'): + dirs.append(join_path(self.prefix.bin, cb_subdir)) + elif self.spec.satisfies('@2.0.0:'): + dirs.append(self.prefix.bin) + + checks = { + # Versions 0.3.3:1.0.1 (spack-build/bin/examples/cookbook) + # Versions 2.0.0:2.1.0 (spack-build/bin) + # Versions 1.1.0 (prefix.bin/examples/cookbook) + # Versions 2.0.0:2.1.0 (prefix.bin) + 'recipe_dynamic_pool_heuristic': (['in the pool', 'releas'], 0), + 'recipe_no_introspection': (['has allocated', 'used'], 0), + } + self._run_checks(dirs, checks) + + def _run_example_checks(self): + """Run the example smoke test checks.""" + tty.info('Running example checks') + + dirs = [] + if self.spec.satisfies('@0.1.3:0.3.1'): + dirs.append(self._extra_tests_path) + elif self.spec.satisfies('@0.3.3:1.0.1'): + dirs.append(join_path(self._extra_tests_path, 'examples')) + elif self.spec.satisfies('@1.1.0'): + dirs.append(join_path(self.prefix.bin, 'examples')) + elif self.spec.satisfies('@2.0.0:'): + dirs.append(self.prefix.bin) + + # Check the results from a subset of the (potentially) available + # executables + checks = { + # Versions 0.1.3:0.3.1 (spack-build/bin) + # Versions 0.3.3:1.0.1 (spack-build/bin/examples) + # Versions 2.0.0:2.1.0 (spack-build/bin) + # Version 1.1.0 (prefix.bin/examples) + # Versions 2.0.0:2.1.0 (prefix.bin) + 'malloc': (['99 should be 99'], 0), + 'strategy_example': (['Available allocators', 'HOST'], 0), + 'vector_allocator': ([''], 0), + } + self._run_checks(dirs, checks) + + def _run_plots_checks(self): + """Run the plots smoke test checks.""" + tty.info('Running plots checks') + + dirs = [self.prefix.bin] if self.spec.satisfies('@0.3.3:0.3.5') else [] + checks = { + # Versions 0.3.3:0.3.5 (prefix.bin) + 'plot_allocations': ([''], 0), + } + self._run_checks(dirs, checks) + + def _run_tools_checks(self): + """Run the tools smoke test checks.""" + tty.info('Running tools checks') + + dirs = [self.prefix.bin] if self.spec.satisfies('@0.3.3:0.3.5') else [] + checks = { + # Versions 0.3.3:0.3.5 (spack-build/bin/tools) + 'replay': (['No input file'], 0), + } + self._run_checks(dirs, checks) + + def _run_tut_checks(self): + """Run the tutorial smoke test checks.""" + tty.info('Running tutorials checks') + + dirs = [] + tut_subdir = join_path('examples', 'tutorial') + if self.spec.satisfies('@0.2.4:0.3.1'): + dirs.append(self._extra_tests_path) + elif self.spec.satisfies('@0.3.3:1.0.1'): + dirs.append(join_path(self._extra_tests_path, tut_subdir)) + elif self.spec.satisfies('@1.1.0'): + dirs.append(join_path(self.prefix.bin, tut_subdir)) + elif self.spec.satisfies('@2.0.0:'): + dirs.append(self.prefix.bin) + + checks = { + # Versions 0.2.4:0.3.1 (spack-build/bin) + # Versions 0.3.3:1.0.1 (spack-build/bin/examples/tutorial) + # Versions 2.0.0:2.1.0 (spack-build/bin) + # Version 1.1.0 (prefix.bin/examples/tutorial) + # Versions 2.0.0:2.1.0 (prefix.bin) + 'tut_copy': (['Copied source data'], 0), + 'tut_introspection': ( + ['Allocator used is HOST', 'size of the allocation'], 0), + 'tut_memset': (['Set data from HOST'], 0), + 'tut_move': (['Moved source data', 'HOST'], 0), + 'tut_reallocate': (['Reallocated data'], 0), + } + self._run_checks(dirs, checks) + + def test(self): + """Perform smoke tests on the installed package.""" + self._run_bench_checks() + self._run_cookbook_checks() + self._run_example_checks() + self._run_plots_checks() + self._run_tools_checks() + self._run_tut_checks() |