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:
parent
f51b541ef8
commit
40e9171390
3 changed files with 55 additions and 2 deletions
|
@ -610,8 +610,14 @@ def child_process(child_pipe, input_stream):
|
||||||
child_result = parent_pipe.recv()
|
child_result = parent_pipe.recv()
|
||||||
p.join()
|
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):
|
if isinstance(child_result, ChildError):
|
||||||
|
child_result.print_context()
|
||||||
raise child_result
|
raise child_result
|
||||||
|
|
||||||
return child_result
|
return child_result
|
||||||
|
|
||||||
|
|
||||||
|
@ -753,6 +759,9 @@ def long_message(self):
|
||||||
|
|
||||||
return out.getvalue()
|
return out.getvalue()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.message + self.long_message + self.traceback
|
||||||
|
|
||||||
def __reduce__(self):
|
def __reduce__(self):
|
||||||
"""__reduce__ is used to serialize (pickle) ChildErrors.
|
"""__reduce__ is used to serialize (pickle) ChildErrors.
|
||||||
|
|
||||||
|
|
|
@ -45,11 +45,27 @@ def __init__(self, message, long_message=None):
|
||||||
# traceback as a string and print it in the parent.
|
# traceback as a string and print it in the parent.
|
||||||
self.traceback = None
|
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
|
@property
|
||||||
def long_message(self):
|
def long_message(self):
|
||||||
return self._long_message
|
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
|
# basic debug message
|
||||||
tty.error(self.message)
|
tty.error(self.message)
|
||||||
if self.long_message:
|
if self.long_message:
|
||||||
|
@ -66,6 +82,11 @@ def die(self):
|
||||||
# run parent exception hook.
|
# run parent exception hook.
|
||||||
sys.excepthook(*sys.exc_info())
|
sys.excepthook(*sys.exc_info())
|
||||||
|
|
||||||
|
sys.stderr.flush()
|
||||||
|
self.printed = True
|
||||||
|
|
||||||
|
def die(self):
|
||||||
|
self.print_context()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
import spack
|
||||||
import spack.cmd.install
|
import spack.cmd.install
|
||||||
from spack.spec import Spec
|
from spack.spec import Spec
|
||||||
from spack.main import SpackCommand
|
from spack.main import SpackCommand
|
||||||
|
@ -42,7 +43,7 @@ def parser():
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
def _install_package_and_dependency(
|
def test_install_package_and_dependency(
|
||||||
tmpdir, builtin_mock, mock_archive, mock_fetch, config,
|
tmpdir, builtin_mock, mock_archive, mock_fetch, config,
|
||||||
install_mockery):
|
install_mockery):
|
||||||
|
|
||||||
|
@ -58,6 +59,9 @@ def _install_package_and_dependency(
|
||||||
assert 'failures="0"' in content
|
assert 'failures="0"' in content
|
||||||
assert 'errors="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(
|
def test_install_package_already_installed(
|
||||||
tmpdir, builtin_mock, mock_archive, mock_fetch, config,
|
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.
|
# right place in the build log.
|
||||||
assert "BEFORE INSTALL\n==> './configure'" in out
|
assert "BEFORE INSTALL\n==> './configure'" in out
|
||||||
assert "'install'\nAFTER INSTALL" 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
|
||||||
|
|
Loading…
Reference in a new issue