Skip to content

Commit

Permalink
Merge pull request #33 from Anaconda-Platform/bug-report-stderr
Browse files Browse the repository at this point in the history
Output crash details to stderr as well as file when stdin is not inte…
  • Loading branch information
havocp committed Mar 6, 2017
2 parents 5971c91 + 63d07b0 commit 940d8f9
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 2 deletions.
12 changes: 11 additions & 1 deletion anaconda_project/commands/bug_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import sys

import anaconda_project.commands.console_utils as console_utils
from anaconda_project.internal.slugify import slugify


Expand Down Expand Up @@ -45,6 +46,9 @@ def handle_bugs(main_func, program_name, details_dict):
print("An unexpected error occurred, most likely a bug in %s." % program_name, file=sys.stderr)
print(" (The error was: %s: %s)" % (exception_type.__name__, str(exception_value)), file=sys.stderr)

# so batch jobs have the details in their logs
output_to_console = not console_utils.stdin_is_interactive()

when = datetime.date.today().isoformat()
prefix = "bug_details_%s_%s_" % (slugified_program_name, when)
with tempfile.NamedTemporaryFile(prefix=prefix, suffix=".txt", delete=False) as bugfile:
Expand All @@ -53,6 +57,8 @@ def handle_bugs(main_func, program_name, details_dict):
def output(s):
bugfile.write(s.encode('utf-8'))
bugfile.write("\n".encode('utf-8'))
if output_to_console:
print(s, file=sys.stderr)

output("Bug details for %s error on %s" % (program_name, when))
output("")
Expand All @@ -61,7 +67,11 @@ def output(s):
output(pprint.pformat(details_dict))
output("")
output("\n".join(traceback.format_exception(exception_type, exception_value, exception_trace)))
print("Details about the error were saved to %s" % report_name, file=sys.stderr)

if output_to_console:
print("Above details were also saved to %s" % report_name, file=sys.stderr)
else:
print("Details about the error were saved to %s" % report_name, file=sys.stderr)
except Exception:
# re-raise the original exception, which is probably more useful
# than reporting whatever was broken about our bug handling code
Expand Down
59 changes: 58 additions & 1 deletion anaconda_project/commands/test/test_bug_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ def unbuggy_main():
assert '' == err


def test_bug_handling(capsys):
def test_bug_handling(capsys, monkeypatch):
def mock_is_interactive():
return True

monkeypatch.setattr('anaconda_project.commands.console_utils.stdin_is_interactive', mock_is_interactive)

def buggy_main():
raise AssertionError("It did not work")

Expand Down Expand Up @@ -68,6 +73,58 @@ def buggy_main():
os.remove(filename)


def test_bug_handling_not_interactive(capsys, monkeypatch):
def mock_is_interactive():
return False

monkeypatch.setattr('anaconda_project.commands.console_utils.stdin_is_interactive', mock_is_interactive)

def buggy_main():
raise AssertionError("It did not work")

# we name the program something wonky to be sure we slugify
# it, and use a non-BMP unicode char to be sure we handle that
code = handle_bugs(buggy_main,
program_name=u"my$ 🌟program",
details_dict=dict(thing1="foo",
thing2="bar",
thing3=u"🌟"))

assert code is 1
out, err = capsys.readouterr()

assert '' == out

assert u"""An unexpected error occurred, most likely a bug in my$ 🌟program.
(The error was: AssertionError: It did not work)""" in err
assert u"Bug details for my$ 🌟program" in err
assert u"sys.argv:" in err
assert u"Traceback" in err
assert u"raise AssertionError" in err
assert u"Above details were also saved to" in err

filename = err.split()[-1]
assert filename.endswith(".txt")
assert os.path.basename(filename).startswith("bug_details_my---program_")
assert os.path.isfile(filename)

with codecs.open(filename, 'r', 'utf-8') as f:
lines = f.readlines()
report = "".join(lines)

# we can't easily test the exact value (it contains line
# numbers of full file paths), but check the major items are
# in there.
assert report.startswith(u"Bug details for my$ 🌟program error on ")
assert 'sys.argv' in report
assert 'test_bug_handler.py' in report
assert 'Traceback' in report
assert 'AssertionError' in report
assert 'It did not work' in report

os.remove(filename)


def test_bug_handling_is_buggy(capsys, monkeypatch):
def buggy_main():
raise AssertionError("It did not work")
Expand Down
5 changes: 5 additions & 0 deletions anaconda_project/commands/test/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ def test_main_calls_prepare(monkeypatch, capsys):
def test_main_when_buggy(capsys, monkeypatch):
from anaconda_project.commands.main import main

def mock_is_interactive():
return True

monkeypatch.setattr('anaconda_project.commands.console_utils.stdin_is_interactive', mock_is_interactive)

def mock_main():
raise AssertionError("It did not work")

Expand Down

0 comments on commit 940d8f9

Please sign in to comment.