Skip to content

Commit 39fef66

Browse files
chore(aap): appsec tests in appsec files (part 2) (#15264)
## Description part 2 of #15155 - removing appsec reference from non appsec specific tests - moving appsec tests in their own files - shared test files ownership to the python guild APPSEC-59813
1 parent 53d95a7 commit 39fef66

File tree

6 files changed

+234
-190
lines changed

6 files changed

+234
-190
lines changed

.github/CODEOWNERS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ ddtrace/internal/settings/_config.py @DataDog/python-guild @DataDog/ap
4545
docs/ @DataDog/python-guild
4646
tests/utils.py @DataDog/python-guild
4747
tests/suitespec.yml @DataDog/python-guild @DataDog/apm-core-python
48+
tests/contrib/suitespec.yml @DataDog/python-guild
49+
tests/contrib/flask/app.py @DataDog/python-guild
50+
tests/contrib/django/django1_app/urls.py @DataDog/python-guild
4851
tests/suitespec.py @DataDog/python-guild @DataDog/apm-core-python
4952
scripts/bump_ddtrace.py @DataDog/python-guild
5053
tests/smoke_test.py @DataDog/python-guild

tests/contrib/urllib3/test_urllib3.py

Lines changed: 0 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from ddtrace.contrib.internal.urllib3.patch import unpatch
1313
from ddtrace.ext import http
1414
from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME
15-
from ddtrace.internal.settings.asm import config as asm_config
1615
from tests.contrib.config import HTTPBIN_CONFIG
1716
from tests.utils import TracerTestCase
1817
from tests.utils import snapshot
@@ -499,97 +498,6 @@ def test_distributed_tracing_disabled(self):
499498
timeout=mock.ANY,
500499
)
501500

502-
@pytest.mark.skip(reason="urlib3 does not set the ASM Manual keep tag so x-datadog headers are not propagated")
503-
def test_distributed_tracing_apm_opt_out_true(self):
504-
"""Tests distributed tracing headers are passed by default"""
505-
# Check that distributed tracing headers are passed down; raise an error rather than make the
506-
# request since we don't care about the response at all
507-
config.urllib3["distributed_tracing"] = True
508-
self.tracer.enabled = False
509-
# Ensure the ASM SpanProcessor is set
510-
self.tracer.configure(apm_tracing_disabled=True, appsec_enabled=True)
511-
assert asm_config._apm_opt_out
512-
with mock.patch(
513-
"urllib3.connectionpool.HTTPConnectionPool._make_request", side_effect=ValueError
514-
) as m_make_request:
515-
with pytest.raises(ValueError):
516-
self.http.request("GET", URL_200)
517-
518-
spans = self.pop_spans()
519-
s = spans[0]
520-
expected_headers = {
521-
"x-datadog-trace-id": str(s._trace_id_64bits),
522-
"x-datadog-parent-id": str(s.span_id),
523-
"x-datadog-sampling-priority": "1",
524-
"x-datadog-tags": "_dd.p.dm=-0,_dd.p.tid={}".format(_get_64_highest_order_bits_as_hex(s.trace_id)),
525-
"traceparent": s.context._traceparent,
526-
# outgoing headers must contain last parent span id in tracestate
527-
"tracestate": s.context._tracestate.replace("dd=", "dd=p:{:016x};".format(s.span_id)),
528-
}
529-
530-
if int(urllib3.__version__.split(".")[0]) >= 2:
531-
m_make_request.assert_called_with(
532-
mock.ANY,
533-
"GET",
534-
"/status/200",
535-
body=None,
536-
chunked=mock.ANY,
537-
headers=expected_headers,
538-
timeout=mock.ANY,
539-
retries=mock.ANY,
540-
response_conn=mock.ANY,
541-
preload_content=mock.ANY,
542-
decode_content=mock.ANY,
543-
)
544-
else:
545-
m_make_request.assert_called_with(
546-
mock.ANY,
547-
"GET",
548-
"/status/200",
549-
body=None,
550-
chunked=mock.ANY,
551-
headers=expected_headers,
552-
timeout=mock.ANY,
553-
)
554-
555-
def test_distributed_tracing_apm_opt_out_false(self):
556-
"""Test with distributed tracing disabled does not propagate the headers"""
557-
config.urllib3["distributed_tracing"] = True
558-
# Ensure the ASM SpanProcessor is set.
559-
self.tracer.configure(apm_tracing_disabled=False, appsec_enabled=True)
560-
self.tracer.enabled = False
561-
assert not asm_config._apm_opt_out
562-
with mock.patch(
563-
"urllib3.connectionpool.HTTPConnectionPool._make_request", side_effect=ValueError
564-
) as m_make_request:
565-
with pytest.raises(ValueError):
566-
self.http.request("GET", URL_200)
567-
568-
if int(urllib3.__version__.split(".")[0]) >= 2:
569-
m_make_request.assert_called_with(
570-
mock.ANY,
571-
"GET",
572-
"/status/200",
573-
body=None,
574-
chunked=mock.ANY,
575-
headers={},
576-
timeout=mock.ANY,
577-
retries=mock.ANY,
578-
response_conn=mock.ANY,
579-
preload_content=mock.ANY,
580-
decode_content=mock.ANY,
581-
)
582-
else:
583-
m_make_request.assert_called_with(
584-
mock.ANY,
585-
"GET",
586-
"/status/200",
587-
body=None,
588-
chunked=mock.ANY,
589-
headers={},
590-
timeout=mock.ANY,
591-
)
592-
593501

594502
@pytest.fixture()
595503
def patch_urllib3():
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import mock
2+
import pytest
3+
import urllib3
4+
5+
from ddtrace import config
6+
from ddtrace._trace.span import _get_64_highest_order_bits_as_hex
7+
from ddtrace.internal.settings.asm import config as asm_config
8+
from tests.contrib.config import HTTPBIN_CONFIG
9+
from tests.contrib.urllib3.test_urllib3 import BaseUrllib3TestCase
10+
11+
12+
HOST = HTTPBIN_CONFIG["host"]
13+
PORT = HTTPBIN_CONFIG["port"]
14+
SOCKET = "{}:{}".format(HOST, PORT)
15+
URL_200 = "http://{}/status/200".format(SOCKET)
16+
17+
18+
class TestUrllib3(BaseUrllib3TestCase):
19+
@pytest.mark.skip(reason="urlib3 does not set the ASM Manual keep tag so x-datadog headers are not propagated")
20+
def test_distributed_tracing_apm_opt_out_true(self):
21+
"""Tests distributed tracing headers are passed by default"""
22+
# Check that distributed tracing headers are passed down; raise an error rather than make the
23+
# request since we don't care about the response at all
24+
config.urllib3["distributed_tracing"] = True
25+
self.tracer.enabled = False
26+
# Ensure the ASM SpanProcessor is set
27+
self.tracer.configure(apm_tracing_disabled=True, appsec_enabled=True)
28+
assert asm_config._apm_opt_out
29+
with mock.patch(
30+
"urllib3.connectionpool.HTTPConnectionPool._make_request", side_effect=ValueError
31+
) as m_make_request:
32+
with pytest.raises(ValueError):
33+
self.http.request("GET", URL_200)
34+
35+
spans = self.pop_spans()
36+
s = spans[0]
37+
expected_headers = {
38+
"x-datadog-trace-id": str(s._trace_id_64bits),
39+
"x-datadog-parent-id": str(s.span_id),
40+
"x-datadog-sampling-priority": "1",
41+
"x-datadog-tags": "_dd.p.dm=-0,_dd.p.tid={}".format(_get_64_highest_order_bits_as_hex(s.trace_id)),
42+
"traceparent": s.context._traceparent,
43+
# outgoing headers must contain last parent span id in tracestate
44+
"tracestate": s.context._tracestate.replace("dd=", "dd=p:{:016x};".format(s.span_id)),
45+
}
46+
47+
if int(urllib3.__version__.split(".")[0]) >= 2:
48+
m_make_request.assert_called_with(
49+
mock.ANY,
50+
"GET",
51+
"/status/200",
52+
body=None,
53+
chunked=mock.ANY,
54+
headers=expected_headers,
55+
timeout=mock.ANY,
56+
retries=mock.ANY,
57+
response_conn=mock.ANY,
58+
preload_content=mock.ANY,
59+
decode_content=mock.ANY,
60+
)
61+
else:
62+
m_make_request.assert_called_with(
63+
mock.ANY,
64+
"GET",
65+
"/status/200",
66+
body=None,
67+
chunked=mock.ANY,
68+
headers=expected_headers,
69+
timeout=mock.ANY,
70+
)
71+
72+
def test_distributed_tracing_apm_opt_out_false(self):
73+
"""Test with distributed tracing disabled does not propagate the headers"""
74+
config.urllib3["distributed_tracing"] = True
75+
# Ensure the ASM SpanProcessor is set.
76+
self.tracer.configure(apm_tracing_disabled=False, appsec_enabled=True)
77+
self.tracer.enabled = False
78+
assert not asm_config._apm_opt_out
79+
with mock.patch(
80+
"urllib3.connectionpool.HTTPConnectionPool._make_request", side_effect=ValueError
81+
) as m_make_request:
82+
with pytest.raises(ValueError):
83+
self.http.request("GET", URL_200)
84+
85+
if int(urllib3.__version__.split(".")[0]) >= 2:
86+
m_make_request.assert_called_with(
87+
mock.ANY,
88+
"GET",
89+
"/status/200",
90+
body=None,
91+
chunked=mock.ANY,
92+
headers={},
93+
timeout=mock.ANY,
94+
retries=mock.ANY,
95+
response_conn=mock.ANY,
96+
preload_content=mock.ANY,
97+
decode_content=mock.ANY,
98+
)
99+
else:
100+
m_make_request.assert_called_with(
101+
mock.ANY,
102+
"GET",
103+
"/status/200",
104+
body=None,
105+
chunked=mock.ANY,
106+
headers={},
107+
timeout=mock.ANY,
108+
)
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
from ddtrace.internal.telemetry.constants import TELEMETRY_EVENT_TYPE
2+
from ddtrace.internal.telemetry.constants import TELEMETRY_NAMESPACE
3+
4+
5+
def _assert_metric(
6+
test_agent,
7+
expected_metrics,
8+
namespace=TELEMETRY_NAMESPACE.TRACERS,
9+
type_payload=TELEMETRY_EVENT_TYPE.METRICS,
10+
):
11+
assert len(expected_metrics) > 0, "expected_metrics should not be empty"
12+
test_agent.telemetry_writer.periodic(force_flush=True)
13+
metrics_events = test_agent.get_events(type_payload.value)
14+
assert len(metrics_events) > 0, "captured metrics events should not be empty"
15+
16+
metrics = []
17+
for event in metrics_events:
18+
if event["payload"]["namespace"] == namespace.value:
19+
for metric in event["payload"]["series"]:
20+
metric["tags"].sort()
21+
metrics.append(metric)
22+
23+
for expected_metric in expected_metrics:
24+
expected_metric["tags"].sort()
25+
assert expected_metric in metrics
26+
27+
28+
def test_send_appsec_rate_metric(telemetry_writer, test_agent_session, mock_time):
29+
telemetry_writer.add_rate_metric(
30+
TELEMETRY_NAMESPACE.APPSEC,
31+
"test-metric",
32+
6,
33+
(("hi", "HELLO"), ("NAME", "CANDY")),
34+
)
35+
telemetry_writer.add_rate_metric(TELEMETRY_NAMESPACE.APPSEC, "test-metric", 6, tuple())
36+
telemetry_writer.add_rate_metric(TELEMETRY_NAMESPACE.APPSEC, "test-metric", 6, tuple())
37+
38+
expected_series = [
39+
{
40+
"common": True,
41+
"interval": 10,
42+
"metric": "test-metric",
43+
"points": [[1642544540, 0.6]],
44+
"tags": ["hi:hello", "name:candy"],
45+
"type": "rate",
46+
},
47+
{
48+
"common": True,
49+
"interval": 10,
50+
"metric": "test-metric",
51+
"points": [[1642544540, 1.2]],
52+
"tags": [],
53+
"type": "rate",
54+
},
55+
]
56+
57+
_assert_metric(test_agent_session, expected_series, namespace=TELEMETRY_NAMESPACE.APPSEC)
58+
59+
60+
def test_send_appsec_gauge_metric(telemetry_writer, test_agent_session, mock_time):
61+
telemetry_writer.add_gauge_metric(
62+
TELEMETRY_NAMESPACE.APPSEC,
63+
"test-metric",
64+
5,
65+
(
66+
("hi", "HELLO"),
67+
("NAME", "CANDY"),
68+
),
69+
)
70+
telemetry_writer.add_gauge_metric(TELEMETRY_NAMESPACE.APPSEC, "test-metric", 5, (("a", "b"),))
71+
telemetry_writer.add_gauge_metric(TELEMETRY_NAMESPACE.APPSEC, "test-metric", 6, tuple())
72+
73+
expected_series = [
74+
{
75+
"common": True,
76+
"interval": 10,
77+
"metric": "test-metric",
78+
"points": [[1642544540, 5.0]],
79+
"tags": ["hi:hello", "name:candy"],
80+
"type": "gauge",
81+
},
82+
{
83+
"common": True,
84+
"interval": 10,
85+
"metric": "test-metric",
86+
"points": [[1642544540, 5.0]],
87+
"tags": ["a:b"],
88+
"type": "gauge",
89+
},
90+
{
91+
"common": True,
92+
"interval": 10,
93+
"metric": "test-metric",
94+
"points": [[1642544540, 6.0]],
95+
"tags": [],
96+
"type": "gauge",
97+
},
98+
]
99+
_assert_metric(test_agent_session, expected_series, namespace=TELEMETRY_NAMESPACE.APPSEC)
100+
101+
102+
def test_send_appsec_distributions_metric(telemetry_writer, test_agent_session, mock_time):
103+
telemetry_writer.add_distribution_metric(TELEMETRY_NAMESPACE.APPSEC, "test-metric", 4, tuple())
104+
telemetry_writer.add_distribution_metric(TELEMETRY_NAMESPACE.APPSEC, "test-metric", 5, tuple())
105+
telemetry_writer.add_distribution_metric(TELEMETRY_NAMESPACE.APPSEC, "test-metric", 6, tuple())
106+
107+
expected_series = [
108+
{
109+
"metric": "test-metric",
110+
"points": [4.0, 5.0, 6.0],
111+
"tags": [],
112+
}
113+
]
114+
_assert_metric(
115+
test_agent_session,
116+
expected_series,
117+
namespace=TELEMETRY_NAMESPACE.APPSEC,
118+
type_payload=TELEMETRY_EVENT_TYPE.DISTRIBUTIONS,
119+
)

0 commit comments

Comments
 (0)