Add testing for new build output.

- Update handling of ChildError so that its output is capturable from a
  SpackCommand

- Update cmd/install test to make sure Python and build log output is
  being displayed properly.
This commit is contained in:
Todd Gamblin 2017-08-22 14:38:39 -07:00
parent f51b541ef8
commit 40e9171390
3 changed files with 55 additions and 2 deletions

View file

@ -610,8 +610,14 @@ def child_process(child_pipe, input_stream):
child_result = parent_pipe.recv()
p.join()
# If the child process raised an error, print its output here rather
# than waiting until the call to SpackError.die() in main(). This
# allows exception handling output to be logged from within Spack.
# see spack.main.SpackCommand.
if isinstance(child_result, ChildError):
child_result.print_context()
raise child_result
return child_result
@ -753,6 +759,9 @@ def long_message(self):
return out.getvalue()
def __str__(self):
return self.message + self.long_message + self.traceback
def __reduce__(self):
"""__reduce__ is used to serialize (pickle) ChildErrors.

View file

@ -45,11 +45,27 @@ def __init__(self, message, long_message=None):
# traceback as a string and print it in the parent.
self.traceback = None
# we allow exceptions to print debug info via print_context()
# before they are caught at the top level. If they *haven't*
# printed context early, we do it by default when die() is
# called, so we need to remember whether it's been called.
self.printed = False
@property
def long_message(self):
return self._long_message
def die(self):
def print_context(self):
"""Print extended debug information about this exception.
This is usually printed when the top-level Spack error handler
calls ``die()``, but it acn be called separately beforehand if a
lower-level error handler needs to print error context and
continue without raising the exception to the top level.
"""
if self.printed:
return
# basic debug message
tty.error(self.message)
if self.long_message:
@ -66,6 +82,11 @@ def die(self):
# run parent exception hook.
sys.excepthook(*sys.exc_info())
sys.stderr.flush()
self.printed = True
def die(self):
self.print_context()
sys.exit(1)
def __str__(self):

View file

@ -27,6 +27,7 @@
import pytest
import spack
import spack.cmd.install
from spack.spec import Spec
from spack.main import SpackCommand
@ -42,7 +43,7 @@ def parser():
return parser
def _install_package_and_dependency(
def test_install_package_and_dependency(
tmpdir, builtin_mock, mock_archive, mock_fetch, config,
install_mockery):
@ -58,6 +59,9 @@ def _install_package_and_dependency(
assert 'failures="0"' in content
assert 'errors="0"' in content
s = Spec('libdwarf').concretized()
assert not spack.repo.get(s).stage.created
def test_install_package_already_installed(
tmpdir, builtin_mock, mock_archive, mock_fetch, config,
@ -107,3 +111,22 @@ def test_package_output(tmpdir, capsys, install_mockery, mock_fetch):
# right place in the build log.
assert "BEFORE INSTALL\n==> './configure'" in out
assert "'install'\nAFTER INSTALL" in out
def _test_install_output_on_build_error(builtin_mock, mock_archive, mock_fetch,
config, install_mockery, capfd):
# capfd interferes with Spack's capturing
with capfd.disabled():
out = install('build-error', fail_on_error=False)
assert isinstance(install.error, spack.build_environment.ChildError)
assert install.error.name == 'ProcessError'
assert 'configure: error: in /path/to/some/file:' in out
assert 'configure: error: cannot run C compiled programs.' in out
def test_install_output_on_python_error(builtin_mock, mock_archive, mock_fetch,
config, install_mockery):
out = install('failing-build', fail_on_error=False)
assert isinstance(install.error, spack.build_environment.ChildError)
assert install.error.name == 'InstallError'
assert 'raise InstallError("Expected failure.")' in out