Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
6ca9a88
remove useless appsec references in non appsec tests
christophe-papazian Nov 6, 2025
55d30f9
moving tests to appsec file
christophe-papazian Nov 6, 2025
62204db
fix lint and imports
christophe-papazian Nov 6, 2025
f000589
Merge branch 'main' into christophe-papazian/put_appsec_tests_in_thei…
christophe-papazian Nov 6, 2025
bb06476
add missing fixtures
christophe-papazian Nov 6, 2025
38e6e2c
generate tracestats
christophe-papazian Nov 6, 2025
4720663
mv remote config appsec tests to appsec and update codeowners
christophe-papazian Nov 6, 2025
00c2093
remove tracestats file
christophe-papazian Nov 6, 2025
5d2c82e
Merge branch 'main' into christophe-papazian/put_appsec_tests_in_thei…
christophe-papazian Nov 7, 2025
93a611e
update test-agent
christophe-papazian Nov 7, 2025
a35fc3f
Merge branch 'christophe-papazian/put_appsec_tests_in_their_own_files…
christophe-papazian Nov 7, 2025
ecc0c73
revert and codeowners update
christophe-papazian Nov 7, 2025
2b0214e
fix stats snapshot
christophe-papazian Nov 7, 2025
4e0ee8c
fixing ownership
christophe-papazian Nov 7, 2025
3ed18c5
Merge branch 'main' into christophe-papazian/put_appsec_tests_in_thei…
christophe-papazian Nov 7, 2025
0648887
update ST
christophe-papazian Nov 7, 2025
6974289
Merge branch 'main' into christophe-papazian/put_appsec_tests_in_thei…
avara1986 Nov 11, 2025
fcb7866
Merge branch 'main' into christophe-papazian/put_appsec_tests_in_thei…
avara1986 Nov 12, 2025
96cbf66
Merge branch 'main' into christophe-papazian/put_appsec_tests_in_thei…
avara1986 Nov 12, 2025
85f03d8
Merge branch 'main' into christophe-papazian/put_appsec_tests_in_thei…
christophe-papazian Nov 12, 2025
5bf39ba
Merge branch 'main' into christophe-papazian/put_appsec_tests_in_thei…
avara1986 Nov 12, 2025
d879211
fix for CI from Brett
christophe-papazian Nov 12, 2025
4b7859d
add Munir suggestions
christophe-papazian Nov 12, 2025
b01f537
fix
christophe-papazian Nov 12, 2025
3f2c549
Merge branch 'main' into christophe-papazian/put_appsec_tests_in_thei…
christophe-papazian Nov 12, 2025
4657e8a
Merge remote-tracking branch 'origin/main' into christophe-papazian/p…
christophe-papazian Nov 13, 2025
80cce7d
revert snapshot
christophe-papazian Nov 13, 2025
06a76ca
lint
christophe-papazian Nov 13, 2025
9bfd5ab
fix previous merge
christophe-papazian Nov 13, 2025
145ae23
Merge branch 'main' into christophe-papazian/put_appsec_tests_in_thei…
christophe-papazian Nov 13, 2025
fab55bc
Merge branch 'main' into christophe-papazian/put_appsec_tests_in_thei…
christophe-papazian Nov 13, 2025
e6099e7
Merge branch 'main' into christophe-papazian/put_appsec_tests_in_thei…
christophe-papazian Nov 14, 2025
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
11 changes: 8 additions & 3 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ tests/utils.py @DataDog/python-guild
tests/suitespec.yml @DataDog/python-guild @DataDog/apm-core-python
tests/suitespec.py @DataDog/python-guild @DataDog/apm-core-python
scripts/bump_ddtrace.py @DataDog/python-guild
tests/smoke_test.py @DataDog/python-guild

# Core / Language Platform
tests/internal @DataDog/apm-core-python
Expand Down Expand Up @@ -125,10 +126,9 @@ ddtrace/internal/iast/ @DataDog/asm-python
tests/appsec/ @DataDog/asm-python
tests/contrib/subprocess @DataDog/asm-python
tests/snapshots/tests*appsec*.json @DataDog/asm-python
tests/contrib/*/test*appsec*.py @DataDog/asm-python
tests/contrib/*/test*iast*.py @DataDog/asm-python
scripts/iast/* @DataDog/asm-python


# Profiling
ddtrace/profiling @DataDog/profiling-python
ddtrace/internal/settings/profiling.py @DataDog/profiling-python
Expand Down Expand Up @@ -240,7 +240,7 @@ tests/contrib/azure_functions @DataDog/serverless
tests/contrib/azure_functions_eventhubs @DataDog/serverless @DataDog/apm-serverless
tests/contrib/azure_functions_servicebus @DataDog/serverless @DataDog/apm-serverless
tests/contrib/azure_servicebus @DataDog/serverless @DataDog/apm-serverless
tests/internal/test_serverless.py @DataDog/apm-core-python @DataDog/apm-serverless
tests/internal/test_serverless.py @DataDog/apm-core-python @DataDog/apm-serverless @DataDog/asm-python
tests/snapshots/tests.contrib.aws_lambda.*. @DataDog/apm-serverless
tests/snapshots/tests.contrib.azure_eventhubs.* @DataDog/serverless @DataDog/apm-serverless
tests/snapshots/tests.contrib.azure_functions.* @DataDog/serverless @DataDog/apm-serverless
Expand All @@ -251,3 +251,8 @@ tests/snapshots/tests.contrib.azure_servicebus.* @DataDog/serverless
# Data Streams Monitoring
ddtrace/internal/datastreams @DataDog/data-streams-monitoring
tests/datastreams @DataDog/data-streams-monitoring

# ASM (order matters)
tests/**/*appsec* @DataDog/asm-python
tests/**/*iast* @DataDog/asm-python
tests/tracer/test_propagation.py @DataDog/apm-sdk-capabilities-python @DataDog/asm-python
4 changes: 2 additions & 2 deletions tests/integration/test_integration_snapshots.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ def test_flush_spans_before_writer_recreate():
long_running_span = tracer.trace("long_running_operation")

writer = tracer._span_aggregator.writer
# Enable appsec to trigger the recreation of the agent writer
tracer.configure(appsec_enabled=True)
# Enable compute stats to trigger the recreation of the agent writer
tracer._recreate(reset_buffer=False)
assert tracer._span_aggregator.writer is not writer, "Writer should be recreated"
# Finish the long running span after the writer has been recreated
long_running_span.finish()
Expand Down
12 changes: 6 additions & 6 deletions tests/tracer/test_endpoint_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def mock_getresponse_enabled_after_4_retries(self):
response.status = 500
response.reason = "KO"
else:
response.read.return_value = b'{"dd_iast_enabled": true}'
response.read.return_value = b'{"dd_product_enabled": true}'
response.status = 200
response.reason = "OK"
response.fp = BytesIO(response.read.return_value)
Expand All @@ -34,7 +34,7 @@ def mock_getresponse_enabled_after_4_retries(self):

def mock_getresponse_enabled(self):
response = mock.Mock(spec=HTTPResponse)
response.read.return_value = b'{"dd_iast_enabled": true}'
response.read.return_value = b'{"dd_product_enabled": true}'
response.status = 200
response.reason = "OK"
response.chunked = False
Expand All @@ -46,7 +46,7 @@ def mock_getresponse_enabled(self):

def mock_getresponse_403(self):
response = mock.Mock(spec=HTTPResponse)
response.read.return_value = b'{"dd_iast_enabled": true}'
response.read.return_value = b'{"dd_product_enabled": true}'
response.status = 403
response.reason = "KO"
response.chunked = False
Expand All @@ -58,7 +58,7 @@ def mock_getresponse_403(self):

def mock_getresponse_500(self):
response = mock.Mock(spec=HTTPResponse)
response.read.return_value = b'{"dd_iast_enabled": true}'
response.read.return_value = b'{"dd_product_enabled": true}'
response.status = 500
response.reason = "KO"
response.chunked = False
Expand Down Expand Up @@ -99,7 +99,7 @@ def test_set_config_endpoint_enabled(caplog):
), mock.patch.object(
HTTPConnection, "getresponse", new=mock_getresponse_enabled
):
assert fetch_config_from_endpoint() == {"dd_iast_enabled": True}
assert fetch_config_from_endpoint() == {"dd_product_enabled": True}
if caplog.text:
assert "Configuration endpoint not set. Skipping fetching configuration." not in caplog.text
assert "Failed to fetch configuration from endpoint" not in caplog.text
Expand Down Expand Up @@ -181,4 +181,4 @@ def test_set_config_endpoint_retries(caplog):
), mock.patch(
"ddtrace.internal.settings.endpoint_config._get_retries", return_value=5
):
assert fetch_config_from_endpoint() == {"dd_iast_enabled": True}
assert fetch_config_from_endpoint() == {"dd_product_enabled": True}
8 changes: 4 additions & 4 deletions tests/tracer/test_processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ def test_aggregator_reset_apm_opt_out_preserves_sampling():
def test_aggregator_reset_with_args(writer_class):
"""
Validates that the span aggregator can reset trace buffers, sampling processor,
user processors/filters and trace api version (when ASM is enabled)
user processors/filters.
"""

dd_proc = DummyProcessor()
Expand All @@ -204,12 +204,12 @@ def test_aggregator_reset_with_args(writer_class):
assert aggr.sampling_processor.apm_opt_out is False
assert aggr.sampling_processor._compute_stats_enabled is False
# Reset the aggregator with new args and new user processors and expect the new values to be set
aggr.reset(user_processors=[], compute_stats=True, apm_opt_out=True, appsec_enabled=True, reset_buffer=False)
aggr.reset(user_processors=[], compute_stats=True, reset_buffer=False)
assert aggr.user_processors == []
assert dd_proc in aggr.dd_processors
assert aggr.sampling_processor.apm_opt_out is True
assert aggr.sampling_processor.apm_opt_out is False
assert aggr.sampling_processor._compute_stats_enabled is True
assert aggr.writer._api_version == "v0.4"
assert aggr.writer._api_version == "v0.5"
assert span.trace_id in aggr._traces
assert len(aggr._span_metrics["spans_created"]) == 1

Expand Down
125 changes: 0 additions & 125 deletions tests/tracer/test_trace_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@
from ddtrace._trace.pin import Pin
from ddtrace.contrib.internal import trace_utils
from ddtrace.contrib.internal.trace_utils import _get_request_header_client_ip
from ddtrace.ext import SpanTypes
from ddtrace.ext import http
from ddtrace.ext import net
from ddtrace.internal.compat import ensure_text
from ddtrace.internal.settings._config import Config
from ddtrace.internal.settings.integration import IntegrationConfig
Expand All @@ -28,7 +26,6 @@
from ddtrace.propagation.http import HTTPPropagator
from ddtrace.trace import Context
from ddtrace.trace import Span
from tests.appsec.utils import asm_context
from tests.utils import override_global_config


Expand Down Expand Up @@ -389,128 +386,6 @@ def test_set_http_meta_with_http_header_tags_config():
assert response_span.get_tag("third-header") == "value3"


@pytest.mark.parametrize("appsec_enabled", [False, True])
@pytest.mark.parametrize("span_type", [SpanTypes.WEB, SpanTypes.HTTP, None])
@pytest.mark.parametrize(
"method,url,status_code,status_msg,query,request_headers,response_headers,uri,path_params,cookies,target_host",
[
("GET", "http://localhost/", 0, None, None, None, None, None, None, None, "localhost"),
("GET", "http://localhost/", 200, "OK", None, None, None, None, None, None, "localhost"),
(None, None, None, None, None, None, None, None, None, None, None),
(
"GET",
"http://localhost/",
200,
"OK",
None,
{"my-header": "value1"},
{"resp-header": "val"},
"http://localhost/",
None,
None,
"localhost",
),
(
"GET",
"http://localhost/",
200,
"OK",
"q=test+query&q2=val",
{"my-header": "value1"},
{"resp-header": "val"},
"http://localhost/search?q=test+query&q2=val",
{"id": "val", "name": "vlad"},
None,
"localhost",
),
("GET", "http://user:pass@localhost/", 0, None, None, None, None, None, None, None, None),
("GET", "http://user@localhost/", 0, None, None, None, None, None, None, None, None),
("GET", "http://user:pass@localhost/api?q=test", 0, None, None, None, None, None, None, None, None),
("GET", "http://localhost/api@test", 0, None, None, None, None, None, None, None, None),
("GET", "http://localhost/?api@test", 0, None, None, None, None, None, None, None, None),
],
)
def test_set_http_meta(
span,
int_config,
method,
url,
target_host,
status_code,
status_msg,
query,
request_headers,
response_headers,
uri,
path_params,
cookies,
appsec_enabled,
span_type,
):
int_config.myint.http.trace_headers(["my-header"])
int_config.myint.http.trace_query_string = True
span.span_type = span_type
with asm_context(config={"_asm_enabled": appsec_enabled}):
trace_utils.set_http_meta(
span,
int_config.myint,
method=method,
url=url,
target_host=target_host,
status_code=status_code,
status_msg=status_msg,
query=query,
raw_uri=uri,
request_headers=request_headers,
response_headers=response_headers,
request_cookies=cookies,
request_path_params=path_params,
)
if method is not None:
assert span.get_tag(http.METHOD) == method
else:
assert http.METHOD not in span.get_tags()

if target_host is not None:
assert span.get_tag(net.TARGET_HOST) == target_host
else:
assert net.TARGET_HOST not in span.get_tags()

if url is not None:
if url.startswith("http://user"):
# Remove any userinfo that may be in the original url
expected_url = url[: url.index(":")] + "://" + url[url.index("@") + 1 :]
else:
expected_url = url

if query and int_config.myint.http.trace_query_string:
assert span.get_tag(http.URL) == str(expected_url + "?" + query)
else:
assert span.get_tag(http.URL) == str(expected_url)
else:
assert http.URL not in span.get_tags()

if status_code is not None:
assert span.get_tag(http.STATUS_CODE) == str(status_code)
if 500 <= int(status_code) < 600:
assert span.error == 1
else:
assert span.error == 0
else:
assert http.STATUS_CODE not in span.get_tags()

if status_msg is not None:
assert span.get_tag(http.STATUS_MSG) == str(status_msg)

if query is not None and int_config.myint.http.trace_query_string:
assert span.get_tag(http.QUERY_STRING) == query

if request_headers is not None:
for header, value in request_headers.items():
tag = "http.request.headers." + header
assert span.get_tag(tag) == value


@mock.patch("ddtrace.internal.settings._config.log")
@pytest.mark.parametrize(
"error_codes,status_code,error,log_call",
Expand Down
29 changes: 0 additions & 29 deletions tests/tracer/test_tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
from ddtrace.ext import user
import ddtrace.internal
from ddtrace.internal.compat import PYTHON_VERSION_INFO
from ddtrace.internal.rate_limiter import RateLimiter
from ddtrace.internal.serverless import has_aws_lambda_agent_extension
from ddtrace.internal.serverless import in_aws_lambda
from ddtrace.internal.settings._config import Config
Expand All @@ -51,7 +50,6 @@ class TracerTestCases(TracerTestCase):
@pytest.fixture(autouse=True)
def inject_fixtures(self, tracer, caplog):
self._caplog = caplog
self._tracer_appsec = tracer

def test_tracer_vars(self):
span = self.trace("a", service="s", resource="r", span_type="t")
Expand Down Expand Up @@ -1842,33 +1840,6 @@ def test_top_level(tracer):
assert child_span2._is_top_level


@pytest.mark.parametrize("sca_enabled", ["true", "false"])
@pytest.mark.parametrize("appsec_enabled", [True, False])
@pytest.mark.parametrize("iast_enabled", [True, False])
def test_asm_standalone_configuration(sca_enabled, appsec_enabled, iast_enabled):
if not appsec_enabled and not iast_enabled and sca_enabled == "false":
pytest.skip("SCA, AppSec or IAST must be enabled")

with override_env({"DD_APPSEC_SCA_ENABLED": sca_enabled}):
ddtrace.config._reset()
tracer = DummyTracer()
tracer.configure(appsec_enabled=appsec_enabled, iast_enabled=iast_enabled, apm_tracing_disabled=True)
if sca_enabled == "true":
assert bool(ddtrace.config._sca_enabled) is True
assert tracer.enabled is False

assert isinstance(tracer._sampler.limiter, RateLimiter)
assert tracer._sampler.limiter.rate_limit == 1
assert tracer._sampler.limiter.time_window == 60e9

assert tracer._span_aggregator.sampling_processor._compute_stats_enabled is False

# reset tracer values
with override_env({"DD_APPSEC_SCA_ENABLED": "false"}):
ddtrace.config._reset()
tracer.configure(appsec_enabled=False, iast_enabled=False, apm_tracing_disabled=False)


def test_gc_not_used_on_root_spans():
gc.freeze()

Expand Down
Loading
Loading