import pytest import os import sys import time from . import make_dsn, run, Envelope from .conditions import has_crashpad from .assertions import assert_crashpad_upload, assert_session pytestmark = pytest.mark.skipif(not has_crashpad, reason="tests need crashpad backend") # Windows and Linux are currently able to flush all the state on crash flushes_state = sys.platform != "darwin" def test_crashpad_capture(cmake, httpserver): tmp_path = cmake(["sentry_example"], {"SENTRY_BACKEND": "crashpad"}) httpserver.expect_request("/api/123456/envelope/").respond_with_data("OK") run( tmp_path, "sentry_example", ["log", "start-session", "capture-event"], check=True, env=dict(os.environ, SENTRY_DSN=make_dsn(httpserver)), ) assert len(httpserver.log) == 2 def test_crashpad_reinstall(cmake, httpserver): tmp_path = cmake(["sentry_example"], {"SENTRY_BACKEND": "crashpad"}) env = dict(os.environ, SENTRY_DSN=make_dsn(httpserver)) httpserver.expect_oneshot_request("/api/123456/minidump/").respond_with_data("OK") with httpserver.wait(timeout=10) as waiting: child = run(tmp_path, "sentry_example", ["log", "reinstall", "crash"], env=env) assert child.returncode # well, its a crash after all assert waiting.result run(tmp_path, "sentry_example", ["log", "no-setup"], check=True, env=env) assert len(httpserver.log) == 1 def test_crashpad_crash(cmake, httpserver): tmp_path = cmake(["sentry_example"], {"SENTRY_BACKEND": "crashpad"}) env = dict(os.environ, SENTRY_DSN=make_dsn(httpserver)) httpserver.expect_oneshot_request("/api/123456/minidump/").respond_with_data("OK") httpserver.expect_request("/api/123456/envelope/").respond_with_data("OK") with httpserver.wait(timeout=10) as waiting: child = run( tmp_path, "sentry_example", ["log", "start-session", "attachment", "overflow-breadcrumbs", "crash"], env=env, ) assert child.returncode # well, its a crash after all assert waiting.result # the session crash heuristic on mac uses timestamps, so make sure we have # a small delay here time.sleep(1) run(tmp_path, "sentry_example", ["log", "no-setup"], check=True, env=env) assert len(httpserver.log) == 2 outputs = (httpserver.log[0][0], httpserver.log[1][0]) session, multipart = ( (outputs[0].get_data(), outputs[1]) if b'"type":"session"' in outputs[0].get_data() else (outputs[1].get_data(), outputs[0]) ) envelope = Envelope.deserialize(session) assert_session(envelope, {"status": "crashed", "errors": 1}) assert_crashpad_upload(multipart) @pytest.mark.skipif( sys.platform == "linux", reason="linux clears the signal handlers on shutdown" ) def test_crashpad_crash_after_shutdown(cmake, httpserver): tmp_path = cmake(["sentry_example"], {"SENTRY_BACKEND": "crashpad"}) env = dict(os.environ, SENTRY_DSN=make_dsn(httpserver)) httpserver.expect_oneshot_request("/api/123456/minidump/").respond_with_data("OK") with httpserver.wait(timeout=10) as waiting: child = run( tmp_path, "sentry_example", ["log", "crash-after-shutdown"], env=env, ) assert child.returncode # well, its a crash after all assert waiting.result # the session crash heuristic on mac uses timestamps, so make sure we have # a small delay here time.sleep(1) run(tmp_path, "sentry_example", ["log", "no-setup"], check=True, env=env) assert len(httpserver.log) == 1 assert_crashpad_upload(httpserver.log[0][0]) @pytest.mark.skipif(not flushes_state, reason="test needs state flushing") def test_crashpad_dump_inflight(cmake, httpserver): tmp_path = cmake(["sentry_example"], {"SENTRY_BACKEND": "crashpad"}) env = dict(os.environ, SENTRY_DSN=make_dsn(httpserver)) httpserver.expect_oneshot_request("/api/123456/minidump/").respond_with_data("OK") httpserver.expect_request("/api/123456/envelope/").respond_with_data("OK") with httpserver.wait(timeout=10) as waiting: child = run( tmp_path, "sentry_example", ["log", "capture-multiple", "crash"], env=env ) assert child.returncode # well, its a crash after all assert waiting.result run(tmp_path, "sentry_example", ["log", "no-setup"], check=True, env=env) # we trigger 10 normal events, and 1 crash assert len(httpserver.log) >= 11