-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathtest_crashtracking.py
More file actions
126 lines (102 loc) · 5.91 KB
/
test_crashtracking.py
File metadata and controls
126 lines (102 loc) · 5.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
"""Test the crashtracking (RC) feature of the APM libraries."""
import base64
import json
import pytest
from utils import features, scenarios, logger
from utils.docker_fixtures import TestAgentAPI, ParametricTestClientApi as APMLibrary
@scenarios.parametric
@features.crashtracking
class Test_Crashtracking:
@pytest.mark.parametrize("library_env", [{"DD_CRASHTRACKING_ENABLED": "true"}])
def test_report_crash(self, test_agent: TestAgentAPI, test_library: APMLibrary):
test_library.crash()
while True:
event = test_agent.wait_for_telemetry_event("logs", wait_loops=400)
# Handling both v1 and v2 of the crashtracking payload so that we can
# update to v2 without breaking the test.
if isinstance(event.get("payload"), list):
if "is_crash_ping:true" not in event["payload"][0]["tags"]:
self.assert_crash_report_v1(test_library, event)
break
elif "is_crash_ping:true" not in event["payload"]["logs"][0]["tags"]:
self.assert_crash_report_v2(test_library, event)
break
@pytest.mark.parametrize("library_env", [{"DD_CRASHTRACKING_ENABLED": "false"}])
def test_disable_crashtracking(self, test_agent: TestAgentAPI, test_library: APMLibrary):
test_library.crash()
requests = test_agent.raw_telemetry(clear=True)
for req in requests:
event = json.loads(base64.b64decode(req["body"]))
if event["request_type"] == "logs":
if isinstance(event.get("payload"), list):
with pytest.raises(AssertionError):
self.assert_crash_report_v1(test_library, event)
else: # If payload is a dict
with pytest.raises(AssertionError):
self.assert_crash_report_v2(test_library, event)
@pytest.mark.parametrize("library_env", [{"DD_CRASHTRACKING_ENABLED": "true"}])
def test_telemetry_timeout(self, test_agent: TestAgentAPI, test_library: APMLibrary):
test_agent.set_trace_delay(60)
test_library.crash()
try:
# container.wait will throw if the application doesn't exit in time
test_library.container.wait(timeout=10)
finally:
test_agent.set_trace_delay(0)
def assert_crash_report_v1(self, test_library: APMLibrary, event: dict):
logger.debug(f"event: {json.dumps(event, indent=2)}")
assert isinstance(event.get("payload"), list), event.get("payload")
assert event["payload"], event["payload"]
assert isinstance(event["payload"][0], dict), event["payload"][0]
assert "tags" in event["payload"][0]
tags = event["payload"][0]["tags"]
tags_dict = dict(item.split(":") for item in tags.split(","))
logger.debug(f"tags_dict: {json.dumps(tags_dict, indent=2)}")
# Until the crash tracking RFC is out, there is no standard way to identify crash reports.
# Most client libraries are using libdatadog so tesing signum tag would work,
# but Java isn't so we end up with testing for severity tag.
if test_library.lang == "java":
assert "severity" in tags_dict, tags_dict
assert tags_dict["severity"] == "crash", tags_dict
else:
# those values are defined in python's module signal. But it's more clear to have this defined here
SIGABRT = 6 # noqa: N806
SIGSEGV = 11 # noqa: N806
# According to the RFC, si_signo should be set to 11 for SIGSEGV
# though, it's difficult for .NET to simulate a segfault, so SIGABRT is used instead
expected_signal_value = f"{SIGABRT}" if test_library.lang == "dotnet" else f"{SIGSEGV}"
if "signum" in tags_dict:
assert tags_dict["signum"] == expected_signal_value
elif "si_signo" in tags_dict:
assert tags_dict["si_signo"] == expected_signal_value
else:
raise AssertionError("signum/si_signo not found in tags_dict")
def assert_crash_report_v2(self, test_library: APMLibrary, event: dict):
logger.debug(f"event: {json.dumps(event, indent=2)}")
assert isinstance(event.get("payload"), dict), event.get("payload")
assert isinstance(event["payload"].get("logs"), list), event["payload"].get("logs")
assert event["payload"]["logs"], event["payload"]["logs"]
assert isinstance(event["payload"]["logs"][0], dict), event["payload"]["logs"][0]
assert "tags" in event["payload"]["logs"][0]
tags = event["payload"]["logs"][0]["tags"]
tags_dict = dict(item.split(":") for item in tags.split(","))
logger.debug(f"tags_dict: {json.dumps(tags_dict, indent=2)}")
# Until the crash tracking RFC is out, there is no standard way to identify crash reports.
# Most client libraries are using libdatadog so tesing signum tag would work,
# but Java isn't so we end up with testing for severity tag.
if test_library.lang == "java":
assert "severity" in tags_dict, tags_dict
assert tags_dict["severity"] == "crash", tags_dict
else:
# those values are defined in python's module signal. But it's more clear to have this defined here
SIGABRT = 6 # noqa: N806
SIGSEGV = 11 # noqa: N806
# According to the RFC, si_signo should be set to 11 for SIGSEGV
# though, it's difficult for .NET to simulate a segfault, so SIGABRT is used instead
expected_signal_value = f"{SIGABRT}" if test_library.lang == "dotnet" else f"{SIGSEGV}"
if "signum" in tags_dict:
assert tags_dict["signum"] == expected_signal_value
elif "si_signo" in tags_dict:
assert tags_dict["si_signo"] == expected_signal_value
else:
raise AssertionError("signum/si_signo not found in tags_dict")