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>
This commit is contained in:
Greg Becker
2020-11-18 02:39:02 -08:00
committed by GitHub
parent b81bbfb6e9
commit 77b2e578ec
131 changed files with 3567 additions and 644 deletions

View File

@@ -24,3 +24,8 @@ def install(self, spec, prefix):
make('install')
print("AFTER INSTALL")
def test(self):
print("BEFORE TEST")
self.run_test('true') # run /bin/true
print("AFTER TEST")

View File

@@ -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')

View File

@@ -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'])

View File

@@ -184,7 +184,7 @@ def install(self, spec, prefix):
@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

View File

@@ -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 @@ def configure_args(self):
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)

View File

@@ -129,3 +129,29 @@ def flag_handler(self, name, flags):
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)

View File

@@ -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)

View File

@@ -0,0 +1,7 @@
#include <stdio.h>
int main()
{
printf ("Hello world from C!\n");
printf ("YES!");
return 0;
}

View File

@@ -146,7 +146,7 @@ def build_args(self, spec, prefix):
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

View File

@@ -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 @@ def build(self, spec, prefix):
@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 @@ def install(self, spec, prefix):
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)

View File

@@ -217,7 +217,7 @@ def build(self, spec, prefix):
@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")

View File

@@ -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)

View File

@@ -0,0 +1,9 @@
#include <stdio.h>
int main()
{
printf ("Hello world from C++\n");
printf ("YES!");
return 0;
}

View File

@@ -0,0 +1,9 @@
#include <iostream>
using namespace std;
int main()
{
cout << "Hello world from C++!" << endl;
cout << "YES!" << endl;
return (0);
}

View File

@@ -0,0 +1,9 @@
#include <iostream>
using namespace std;
int main()
{
cout << "Hello world from C++!" << endl;
cout << "YES!" << endl;
return (0);
}

View File

@@ -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;
}

View File

@@ -80,3 +80,18 @@ def configure_args(self):
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()

View File

@@ -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)

View File

@@ -0,0 +1,6 @@
program line
write (*,*) "Hello world from FORTRAN"
write (*,*) "YES!"
end

View File

@@ -0,0 +1,6 @@
program line
write (*,*) "Hello world from FORTRAN"
write (*,*) "YES!"
end program line

View File

@@ -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')

View File

@@ -4,6 +4,7 @@
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import sys
import os
class Hdf(AutotoolsPackage):
@@ -151,3 +152,67 @@ def configure_args(self):
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()

View File

@@ -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

View File

@@ -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 @@ def patch_postdeps(self):
@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 @@ def check_install(self):
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()

View File

@@ -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
}
}
}
}
}
}

Binary file not shown.

View File

@@ -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')

View File

@@ -27,7 +27,7 @@ def cmake_args(self):
@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)

View File

@@ -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()

View File

@@ -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;
}

View File

@@ -0,0 +1,2 @@
Caught sigsegv #1
Hello World!

View File

@@ -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 @@ def import_module_test(self):
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)

View File

@@ -0,0 +1,2 @@
<!ELEMENT info (data)>
<!ELEMENT data (#PCDATA)>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0"?>
<info>
<data>abc</data>
</info>

View File

@@ -74,3 +74,16 @@ def configure_args(self):
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)

View File

@@ -0,0 +1,4 @@
define(NAME, World)
dnl This line should not show up
// macro is ifdef(`NAME', , not)defined
Hello, NAME!

View File

@@ -0,0 +1,3 @@
// macro is defined
Hello, World!

View File

@@ -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']
)

View File

@@ -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);
}

View File

@@ -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

View File

@@ -51,7 +51,7 @@ def configure(self, spec, prefix):
@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')

View File

@@ -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 @@ def configure(self, spec, prefix):
@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')

View File

@@ -127,7 +127,7 @@ def build(self, spec, prefix):
@run_after('build')
@on_package_attributes(run_tests=True)
def test(self):
def build_test(self):
make('test')
make('test-addons')

View File

@@ -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 @@ def delete_mpirun_mpiexec(self):
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])

View File

@@ -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')

Binary file not shown.

View File

@@ -204,7 +204,7 @@ def build(self, spec, prefix):
@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 @@ def command(self):
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)

View File

@@ -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

View File

@@ -47,6 +47,6 @@ def command(self):
"""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))

View File

@@ -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

View File

@@ -183,6 +183,6 @@ def configure(self):
setup.write('system_freetype = True\n')
setup.write('system_qhull = True\n')
def test(self):
def build_test(self):
pytest = which('pytest')
pytest()

View File

@@ -306,7 +306,7 @@ def build_args(self, spec, prefix):
return args
def test(self):
def build_test(self):
# `setup.py test` is not supported. Use one of the following
# instead:
#

View File

@@ -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

View File

@@ -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()

View File

@@ -74,7 +74,7 @@ def install(self, spec, prefix):
@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

View File

@@ -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

View File

@@ -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')

View File

@@ -99,7 +99,7 @@ def build_args(self, spec, prefix):
return args
def test(self):
def build_test(self):
# `setup.py test` is not supported. Use one of the following
# instead:
#

View File

@@ -71,6 +71,6 @@ def url_for_version(self, version):
return url
def test(self):
def build_test(self):
# Unit tests require pytest, creating a circular dependency
pass

View File

@@ -64,5 +64,5 @@ def setup_build_environment(self, env):
else:
env.prepend_path('LD_LIBRARY_PATH', libs)
def test(self):
def test_install(self):
python('-m', 'pytest')

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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')

View File

@@ -1127,3 +1127,21 @@ def remove_files_from_view(self, view, merge_map):
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)

View File

@@ -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 @@ def cmake_args(self):
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()

View File

@@ -63,7 +63,7 @@ def build_args(self, spec, prefix):
return args
def test(self):
def build_test(self):
# FIXME: Several test failures:
#
# There were 14 failures:

View File

@@ -3,7 +3,6 @@
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
from spack import *
from spack import architecture
@@ -129,3 +128,41 @@ def build_libsqlitefunctions(self):
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()

View File

@@ -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;

View File

@@ -98,7 +98,7 @@ def build(self, spec, prefix):
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')

View File

@@ -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 @@ def cmake_args(self):
'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()