Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 59 additions & 25 deletions tests/system/test_apport_retrace.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""System tests for apport-retrace."""

import io
import os
import pathlib
import re
Expand All @@ -8,18 +9,45 @@
import subprocess
import tempfile
import textwrap
from collections.abc import Iterator
import unittest.mock
from collections.abc import Callable, Iterator

import pytest

from apport.packaging_impl.apt_dpkg import impl
from apport.report import Report
from tests.helper import has_internet
from tests.paths import get_test_data_directory, local_test_environment
from tests.helper import has_internet, import_module_from_file
from tests.paths import (
get_bin_directory,
get_test_data_directory,
local_test_environment,
)

CODENAME_DISTRO_RELEASE_MAP = {"jammy": "Ubuntu 22.04"}


@pytest.fixture(name="apport_retrace_main", scope="module")
def fixture_apport_retrace_main() -> Iterator[Callable[[list[str]], int]]:
"""Apply the needed environment variables and import main() from apport-retrace."""
orig_environ = os.environ.copy()
os.environ |= local_test_environment()
apport_retrace = import_module_from_file(get_bin_directory() / "apport-retrace")
yield apport_retrace.main
os.environ.clear()
os.environ.update(orig_environ)


@pytest.fixture(autouse=True)
def reset_impl() -> Iterator[None]:
"""Reset APT cache between test cases."""
# pylint: disable=protected-access
orig_conf = impl.configuration
impl._apt_cache = None
impl._sandbox_apt_cache = None
yield
impl.configuration = orig_conf


@pytest.fixture(name="module_workdir", scope="module")
def fixture_module_workdir() -> Iterator[pathlib.Path]:
"""Create a temporary work directory for all test case in this module."""
Expand Down Expand Up @@ -201,13 +229,14 @@ def _assert_cache_has_content(
reason="GDB has issues with divide-by-zero on s390x (LP: #2075204)",
)
def test_retrace_system_sandbox(
workdir: pathlib.Path, module_cachedir: pathlib.Path, divide_by_zero_crash: str
apport_retrace_main: Callable[[list[str]], int],
workdir: pathlib.Path,
module_cachedir: pathlib.Path,
divide_by_zero_crash: str,
) -> None:
"""Retrace a divide-by-zero crash in a system sandbox."""
retraced_report_filename = workdir / "retraced.crash"
env = os.environ | local_test_environment()
cmd = [
"apport-retrace",
"-v",
"-o",
str(retraced_report_filename),
Expand All @@ -217,7 +246,7 @@ def test_retrace_system_sandbox(
str(module_cachedir),
divide_by_zero_crash,
]
subprocess.run(cmd, check=True, env=env)
assert apport_retrace_main(cmd) == 0

report = _read_and_print_retraced_report(retraced_report_filename)
_assert_is_retraced(report)
Expand All @@ -230,13 +259,14 @@ def test_retrace_system_sandbox(
reason="GDB sandbox is only available on amd64",
)
def test_retrace_system_sandbox_gdb_sandbox_nonamd64(
workdir: pathlib.Path, module_cachedir: pathlib.Path, divide_by_zero_crash: str
apport_retrace_main: Callable[[list[str]], int],
workdir: pathlib.Path,
module_cachedir: pathlib.Path,
divide_by_zero_crash: str,
) -> None:
"""Refuse to retrace a crash in a non-amd64 system sandbox with a GDB sandbox."""
retraced_report_filename = workdir / "retraced.crash"
env = os.environ | local_test_environment()
cmd = [
"apport-retrace",
"-v",
"-o",
str(retraced_report_filename),
Expand All @@ -247,9 +277,10 @@ def test_retrace_system_sandbox_gdb_sandbox_nonamd64(
str(module_cachedir),
divide_by_zero_crash,
]
ret = subprocess.run(cmd, check=False, env=env, capture_output=True, text=True)
assert ret.returncode == 3
assert "gdb sandboxes are only implemented for amd64 hosts" in ret.stderr

with unittest.mock.patch("sys.stderr", new_callable=io.StringIO) as stderr:
assert apport_retrace_main(cmd) == 3
assert "gdb sandboxes are only implemented for amd64 hosts" in stderr.getvalue()


@pytest.mark.skipif(not has_internet(), reason="online test")
Expand All @@ -258,13 +289,14 @@ def test_retrace_system_sandbox_gdb_sandbox_nonamd64(
reason="Testing the GDB sandbox erroring out on non-AMD64",
)
def test_retrace_system_sandbox_gdb_sandbox(
workdir: pathlib.Path, module_cachedir: pathlib.Path, divide_by_zero_crash: str
apport_retrace_main: Callable[[list[str]], int],
workdir: pathlib.Path,
module_cachedir: pathlib.Path,
divide_by_zero_crash: str,
) -> None:
"""Retrace a divide-by-zero crash in a system sandbox with a GDB sandbox."""
retraced_report_filename = workdir / "retraced.crash"
env = os.environ | local_test_environment()
cmd = [
"apport-retrace",
"-v",
"-o",
str(retraced_report_filename),
Expand All @@ -275,7 +307,7 @@ def test_retrace_system_sandbox_gdb_sandbox(
str(module_cachedir),
divide_by_zero_crash,
]
subprocess.run(cmd, check=True, env=env)
assert apport_retrace_main(cmd) == 0

report = _read_and_print_retraced_report(retraced_report_filename)
_assert_is_retraced(report)
Expand All @@ -288,14 +320,15 @@ def test_retrace_system_sandbox_gdb_sandbox(
reason="gdb-multiarch is needed for proper retracing on foreign architectures",
)
def test_retrace_jammy_sandbox(
workdir: pathlib.Path, module_cachedir: pathlib.Path, sandbox_config: pathlib.Path
apport_retrace_main: Callable[[list[str]], int],
workdir: pathlib.Path,
module_cachedir: pathlib.Path,
sandbox_config: pathlib.Path,
) -> None:
"""Retrace a sleep crash from jammy in a sandbox."""
crash = get_test_data_directory() / "jammy_usr_bin_sleep.1000.crash"
retraced_report_filename = workdir / "retraced.crash"
env = os.environ | local_test_environment()
cmd = [
"apport-retrace",
"-v",
"-o",
str(retraced_report_filename),
Expand All @@ -307,7 +340,7 @@ def test_retrace_jammy_sandbox(
str(workdir / "apport_sandbox"),
str(crash),
]
subprocess.run(cmd, check=True, env=env)
assert apport_retrace_main(cmd) == 0

report = _read_and_print_retraced_report(retraced_report_filename)
_assert_is_retraced(report)
Expand All @@ -321,14 +354,15 @@ def test_retrace_jammy_sandbox(
reason="GDB sandbox only available on amd64",
)
def test_retrace_jammy_sandbox_gdb_sandbox(
workdir: pathlib.Path, module_cachedir: pathlib.Path, sandbox_config: pathlib.Path
apport_retrace_main: Callable[[list[str]], int],
workdir: pathlib.Path,
module_cachedir: pathlib.Path,
sandbox_config: pathlib.Path,
) -> None:
"""Retrace a sleep crash from jammy in a sandbox with a GDB sandbox."""
crash = get_test_data_directory() / "jammy_usr_bin_sleep.1000.crash"
retraced_report_filename = workdir / "retraced.crash"
env = os.environ | local_test_environment()
cmd = [
"apport-retrace",
"-v",
"-o",
str(retraced_report_filename),
Expand All @@ -341,7 +375,7 @@ def test_retrace_jammy_sandbox_gdb_sandbox(
str(workdir / "apport_sandbox"),
str(crash),
]
subprocess.run(cmd, check=True, env=env)
assert apport_retrace_main(cmd) == 0

report = _read_and_print_retraced_report(retraced_report_filename)
_assert_is_retraced(report)
Expand Down
Loading