"""Tests for showing the failure itself in a triage issue.""" from __future__ import annotations import pytest from ariadne.services import hermes_incident_evidence_section as module from ariadne.services import hermes_incident_body as body TRACE = ( "tests/test_utils.py:212: in test_safe_error_detail\n" " assert 'bad things' in safe_error_detail(exc)\n" "E AssertionError: assert 'bad things' in 'http 400'" ) def _bundle(**jenkins): return {"jenkins": jenkins} def test_the_traceback_is_shown_not_merely_cited() -> None: """Citing a console line number makes a maintainer reconstruct the failure.""" section = module.evidence_section( _bundle(failed_tests=[{"name": "t", "errorStackTrace": TRACE}]) ) assert section.startswith("## Evidence") assert "The failing test's traceback" in section assert "AssertionError: assert 'bad things' in 'http 400'" in section assert section.count("```") == 2 def test_the_stack_trace_is_preferred_over_the_assertion_line() -> None: """The assertion says what was wrong; the trace says where.""" section = module.evidence_section( _bundle(failed_tests=[{"errorDetails": "AssertionError: nope", "errorStackTrace": TRACE}]) ) assert "tests/test_utils.py:212" in section assert "AssertionError: nope" not in section def test_the_assertion_is_used_when_no_trace_was_published() -> None: section = module.evidence_section( _bundle(failed_tests=[{"errorDetails": "AssertionError: nope"}]) ) assert "AssertionError: nope" in section def test_a_test_without_either_field_is_skipped() -> None: section = module.evidence_section( _bundle( failed_tests=[ {"name": "a"}, {"name": "b", "errorStackTrace": " "}, "not-a-dict", {"name": "c", "errorStackTrace": TRACE}, ] ) ) assert "tests/test_utils.py:212" in section def test_the_console_region_is_used_when_no_tests_were_published() -> None: """A build whose runner published nothing still has a console to quote.""" section = module.evidence_section( _bundle(console_failures=[{"text": "Traceback\n File x\nValueError: boom"}]) ) assert "The earliest failure region" in section assert "ValueError: boom" in section def test_the_region_keeps_its_last_lines_when_it_is_long() -> None: """The tail of a failure region holds the failure; the head approaches it.""" text = "\n".join([f"line {i}" for i in range(100)] + ["ValueError: boom"]) section = module.evidence_section(_bundle(console_failures=[{"text": text}])) assert "ValueError: boom" in section assert "line 0" not in section def test_a_long_trace_is_truncated_with_a_pointer_to_the_build() -> None: section = module.evidence_section( _bundle(failed_tests=[{"errorStackTrace": "x" * 9000}]) ) assert len(section) < 3000 assert "truncated" in section assert section.rstrip().endswith("```") def test_a_fence_inside_the_excerpt_cannot_end_the_block_early() -> None: """Raw log text must not be able to break out into the rendered issue.""" section = module.evidence_section( _bundle(failed_tests=[{"errorStackTrace": "before\n```\nafter"}]) ) assert section.count("```") == 2 assert "after" in section @pytest.mark.parametrize( "bundle", [ None, {}, "not-a-dict", {"jenkins": "not-a-dict"}, {"jenkins": {}}, {"jenkins": {"failed_tests": [], "console_failures": []}}, {"jenkins": {"failed_tests": None, "console_failures": None}}, {"jenkins": {"console_failures": [{"text": " "}, "not-a-dict"]}}, ], ) def test_a_bundle_with_nothing_to_quote_renders_no_heading(bundle) -> None: """An empty Evidence heading is worse than no heading.""" assert module.evidence_section(bundle) == "" def test_the_issue_body_carries_the_excerpt_and_keeps_its_marker() -> None: rendered = body.issue_body( { "incident_id": "ariadne/408", "job": "ariadne", "build_number": 408, "classification": "pytest_test_failure", "reason": "a repository test failure", "run_id": "run-1", "bundle": _bundle(failed_tests=[{"errorStackTrace": TRACE}]), } ) assert "## Evidence" in rendered assert "tests/test_utils.py:212" in rendered assert rendered.index("## Evidence") < rendered.index("## Links") assert rendered.rstrip().endswith("-->") def test_an_issue_without_a_bundle_still_renders() -> None: rendered = body.issue_body( {"incident_id": "a/1", "job": "a", "build_number": 1, "reason": "r", "run_id": "x"} ) assert "## Evidence" not in rendered assert rendered.rstrip().endswith("-->")