diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index 72ff65f5878cee1c539f15336e02227306a3798e..9d9e03c1c1a8ec8de86dbb89bc3d071efeab6a60 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -880,16 +880,21 @@ def child_process(child_pipe, input_stream): package_context = get_package_context(tb) build_log = None - if hasattr(pkg, 'log_path'): + if context == 'build' and hasattr(pkg, 'log_path'): build_log = pkg.log_path + test_log = None + if context == 'test': + test_log = os.path.join(os.getcwd(), pkg.test_log_name) + # make a pickleable exception to send to parent. msg = "%s: %s" % (exc_type.__name__, str(exc)) ce = ChildError(msg, exc_type.__module__, exc_type.__name__, - tb_string, build_log, package_context) + tb_string, package_context, + build_log, test_log) child_pipe.send(ce) finally: @@ -1050,14 +1055,15 @@ class ChildError(InstallError): # context instead of Python context. build_errors = [('spack.util.executable', 'ProcessError')] - def __init__(self, msg, module, classname, traceback_string, build_log, - context): + def __init__(self, msg, module, classname, traceback_string, context, + build_log, test_log): super(ChildError, self).__init__(msg) self.module = module self.name = classname self.traceback = traceback_string - self.build_log = build_log self.context = context + self.build_log = build_log + self.test_log = test_log @property def long_message(self): @@ -1066,22 +1072,29 @@ def long_message(self): if (self.module, self.name) in ChildError.build_errors: # The error happened in some external executed process. Show - # the build log with errors or warnings highlighted. - if self.build_log and os.path.exists(self.build_log): - errors, warnings = parse_log_events(self.build_log) + # the log with errors or warnings highlighted. + def write_log_summary(log_type, log): + errors, warnings = parse_log_events(log) nerr = len(errors) nwar = len(warnings) if nerr > 0: # If errors are found, only display errors out.write( - "\n%s found in build log:\n" % plural(nerr, 'error')) + "\n%s found in %s log:\n" % + (plural(nerr, 'error'), log_type)) out.write(make_log_context(errors)) elif nwar > 0: # If no errors are found but warnings are, display warnings out.write( - "\n%s found in build log:\n" % plural(nwar, 'warning')) + "\n%s found in %s log:\n" % + (plural(nwar, 'warning'), log_type)) out.write(make_log_context(warnings)) + if self.build_log and os.path.exists(self.build_log): + write_log_summary('build', self.build_log) + if self.test_log and os.path.exists(self.test_log): + write_log_summary('test', self.test_log) + else: # The error happened in in the Python code, so try to show # some context from the Package itself. @@ -1097,6 +1110,10 @@ def long_message(self): out.write('See build log for details:\n') out.write(' %s\n' % self.build_log) + if self.test_log and os.path.exists(self.test_log): + out.write('See test log for details:\n') + out.write(' %s\n' % self.test_log) + return out.getvalue() def __str__(self): @@ -1113,13 +1130,16 @@ def __reduce__(self): self.module, self.name, self.traceback, + self.context, self.build_log, - self.context) + self.test_log) -def _make_child_error(msg, module, name, traceback, build_log, context): +def _make_child_error(msg, module, name, traceback, context, + build_log, test_log): """Used by __reduce__ in ChildError to reconstruct pickled errors.""" - return ChildError(msg, module, name, traceback, build_log, context) + return ChildError(msg, module, name, traceback, context, + build_log, test_log) class StopPhase(spack.error.SpackError): diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 40ee8fc4213a9026b3acc8632cf1e74278f398c1..b15ab324b35c1b033e224168d2567a4ac55e4b1f 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -1599,21 +1599,25 @@ def test_process(): print('Error: %s: %s' % (exc_type.__name__, getattr(e, 'message', 'No error message'))) + + # construct arguments to re-raise error from type + args = [] + if hasattr(e, 'message'): + args.append(e.message) + if hasattr(e, 'long_message'): + args.append(e.long_message) + if sys.version_info[0] < 3: # ugly hack: exec to avoid the fact this is a syntax # error in python 3 - exec("raise exc_type, None, traceback", + exec("raise exc_type(*args), None, traceback", globals(), locals()) else: - raise exc_type().with_traceback(traceback) + raise exc_type(*args).with_traceback(traceback) tty.set_debug(old_debug) - try: - spack.build_environment.fork( - self, test_process, dirty=dirty, fake=False, context='test') - except Exception as e: - tty.error('Tests failed. See test log for details\n' - ' %s\n' % test_log_file) + spack.build_environment.fork( + self, test_process, dirty=dirty, fake=False, context='test') def test(self): pass diff --git a/var/spack/repos/builtin/packages/python/package.py b/var/spack/repos/builtin/packages/python/package.py index cbbe7c05ed9d9e78bf148f86c35dc9a0ecea96e2..402c51852021d68b360c0f2e2192343ffebed4c6 100644 --- a/var/spack/repos/builtin/packages/python/package.py +++ b/var/spack/repos/builtin/packages/python/package.py @@ -1118,7 +1118,9 @@ def test(self): # run hello world output = self.command('-c', 'print("hello world!")', output=str.split, error=str.split) - assert output == "hello world!" + assert output == "hello world!\n" + + self.command('-c', 'assert False', output=str.split, error=str.split) # error = self.command('-c', 'print("Error: failed.")', # output=str.split, error=str.split)