Skip to content

[php] Enable v1 payload tests, and make trace assertions format-agnostic - #7843

Draft
Leiyks wants to merge 2 commits into
mainfrom
leiyks/php-v1-payload
Draft

Leiyks wants to merge 2 commits into
mainfrom
leiyks/php-v1-payload

Conversation

@Leiyks

@Leiyks Leiyks commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

Motivation

dd-trace-php is moving to the v1 (efficient) trace payload by default (DataDog/dd-trace-php#4046). Enabling the v1 tests for PHP surfaced a few assertions that only work with the v0.4 shape, and a few validators that silently skip /v1.0/traces payloads.

Changes

  • manifests/php.yml: gate tests/test_v1_payloads.py on v1.26.0-dev instead of a file-level missing_feature. Test_V1SpanLinks stays missing_feature, because PHP creates no span link from conflicting contexts (same as Test_Span_Links_From_Conflicting_Contexts).
  • PHP weblogs (plain apache-mod/php-fpm, laravel11x, symfony7x): add /add_event, which adds a span.event event to the root span through DDTrace\SpanEvent, like the Go weblogs. Test_V1SpanEvents needs it.
  • Make these assertions work with both formats (v0.4 and v1):
    • test_automated_payment_events.py, test_trace_tagging.py and api_security/test_endpoints.py read _sampling_priority_v1 from metrics. They now use get_sampling_priority(), because v1 carries the priority on the chunk.
    • test_db_integrations_sql.py::test_span_kind now checks agent spans with get_span_kind(). In idxTracerPayloads, the kind is a top-level enum (SPAN_KIND_CLIENT), not a span.kind attribute.
  • Validators that silently skipped v1 now check it:
    • Test_TraceHeaders: the diagnostic-check, trace-count and container-id checks filtered on /v0.x/traces only. They now include /v1.0/traces, and count chunks there.
    • Test_Agent::test_agent_do_not_drop_traces looked for _sampling_priority_v1 in span metrics and skipped every v1 trace.
    • Test_SamplingDeterminism only read /v0.4 and /v0.5 payloads.

I replayed the PHP CI logs of a v1 branch build (DEFAULT and INTEGRATIONS). The payment events tests, test_span_kind and the data integrity tests pass. Mutating the chunk count and the agent trace set made Test_TraceHeaders and Test_Agent fail, which shows they now really check v1 payloads.

Merge order

A master build and the v1 branch both report 1.26.0+dev.<sha>, so this version gate can't tell them apart. For that reason, this PR should land after (or together with) the dd-trace-php v1 change. If that change misses 1.26.0, the gate has to move to the next minor.

Follow-ups (not in this PR)

  • The test agent still raises NotImplementedError on array attributes in v1 span and link attributes (_convert_v1_attributes, _convert_v1_span_link_attributes). This is out of scope here.
  • tests/test_span_events.py is still incomplete_test_app for PHP. Now that /add_event exists, it can be evaluated.
  • Test_Process_Tags, Test_Otel_Span and Test_SingleSpan are disabled for PHP because process tags and _dd.top_level are missing. PHP v1 payloads carry _dd.tags.process, so these need re-checking.

- Read the sampling priority through get_sampling_priority() in the appsec
  payment, trace tagging and LLM endpoint tests: v1 carries it on the chunk.
- Check span.kind on agent spans through get_span_kind() in the SQL tests:
  the agent reports it as a top-level enum in idxTracerPayloads.
- Test_TraceHeaders, Test_Agent::test_agent_do_not_drop_traces and
  Test_SamplingDeterminism silently skipped /v1.0/traces payloads; make them
  format-agnostic so they cover v1 too.
Gate tests/test_v1_payloads.py on v1.26.0-dev, and keep Test_V1SpanLinks
disabled: PHP creates no span link from conflicting contexts.
@github-actions

Copy link
Copy Markdown
Contributor

CODEOWNERS have been resolved as:

utils/build/docker/php/weblogs/plain/add_event.php                      @DataDog/system-tests-reviewers
manifests/php.yml                                                       @DataDog/system-tests-reviewers
tests/appsec/api_security/test_endpoints.py                             @DataDog/asm-libraries
tests/appsec/test_automated_payment_events.py                           @DataDog/asm-libraries
tests/appsec/test_trace_tagging.py                                      @DataDog/asm-libraries
tests/integrations/test_db_integrations_sql.py                          @DataDog/system-tests-reviewers
tests/test_data_integrity.py                                            @DataDog/system-tests-reviewers
tests/test_sampling_rates.py                                            @DataDog/system-tests-reviewers
utils/build/docker/php/common/rewrite-rules.conf                        @DataDog/system-tests-reviewers
utils/build/docker/php/weblogs/laravel11x/routes/web.php                @DataDog/system-tests-reviewers
utils/build/docker/php/weblogs/symfony7x/src/Controller/AppController.php  @DataDog/system-tests-reviewers
utils/dd_types/_datadog_library_trace.py                                @DataDog/system-tests-core
utils/interfaces/_library/core.py                                       @DataDog/system-tests-core

@datadog-datadog-prod-us1

datadog-datadog-prod-us1 Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Pipelines  Tests

✨ Unblock PR with BitsAI

❌ Errors

Your PR has failed checks. Please review the issues below and take necessary action before merging.

🚦 67 Pipeline jobs failed

Testing the test | System Tests (php, dev) / End-to-end #1 / apache-mod-7.0 1 — ❌ 3 tests failed · 🔧 Needs a code fix, caused by this PR

View more details · View in GitHub Actions

❌ tests.test_v1_payloads.Test_V1Payloads.test_field_changes[apache-mod-7.0] from system_tests_suite
AssertionError: assert False
 &#43;  where False = isinstance([{&#39;duration&#39;: 2606159, &#39;error&#39;: 1, &#39;meta&#39;: {&#39;_dd.appsec.event_rules.version&#39;: &#39;1.18.0&#39;, &#39;_dd.appsec.fp.http.endpoint&#39;:...abled&#39;: 1.0, &#39;_dd.appsec.waf.duration&#39;: 617.0, &#39;_dd.appsec.waf.duration_ext&#39;: 904.346, &#39;_dd.rule_psr&#39;: 1.0, ...}, ...}], dict)
 &#43;    where [{&#39;duration&#39;: 2606159, &#39;error&#39;: 1, &#39;meta&#39;: {&#39;_dd.appsec.event_rules.version&#39;: &#39;1.18.0&#39;, &#39;_dd.appsec.fp.http.endpoint&#39;:...abled&#39;: 1.0, &#39;_dd.appsec.waf.duration&#39;: 617.0, &#39;_dd.appsec.waf.duration_ext&#39;: 904.346, &#39;_dd.rule_psr&#39;: 1.0, ...}, ...}] = &lt;utils.dd_types._datadog_library_trace.DataDogLibraryTraceLegacy object at 0x7f7550ba4c80&gt;.raw_trace

self = &lt;tests.test_v1_payloads.Test_V1Payloads object at 0x7f7570681610&gt;

    def test_field_changes(self):
        library_traces = list(interfaces.library.get_traces(self.r))
        agent_traces = list(interfaces.agent.get_traces(self.r))
        assert len(library_traces) == 1
...
❌ tests.test_v1_payloads.Test_V1SpanEvents.test_span_event_present[apache-mod-7.0] from system_tests_suite
AssertionError: Expected at least one span event
assert 0 &gt;= 1
 &#43;  where 0 = len([])

self = &lt;tests.test_v1_payloads.Test_V1SpanEvents object at 0x7f7570681310&gt;

    def test_span_event_present(self):
        &#34;&#34;&#34;Root span carries at least one span event in V1 format&#34;&#34;&#34;
        span = interfaces.library.get_root_span(self.r)
        assert span is not None
...
❌ tests.test_v1_payloads.Test_V1TopLevelSpans.test_root_span_is_top_level[apache-mod-7.0] from system_tests_suite
AssertionError: Root span must have _dd.top_level=1 in attributes, got: None
assert (None == 1 or None == 1.0)
 &#43;  where None = &lt;built-in method get of dict object at 0x7f75502c5e00&gt;(&#39;_dd.top_level&#39;)
 &#43;    where &lt;built-in method get of dict object at 0x7f75502c5e00&gt; = {}.get
 &#43;  and   None = &lt;built-in method get of dict object at 0x7f75502c5e00&gt;(&#39;_dd.top_level&#39;)
 &#43;    where &lt;built-in method get of dict object at 0x7f75502c5e00&gt; = {}.get

self = &lt;tests.test_v1_payloads.Test_V1TopLevelSpans object at 0x7f7570683ef0&gt;

    def test_root_span_is_top_level(self):
...
Testing the test | System Tests (php, dev) / End-to-end #1 / apache-mod-7.0-zts 1 — ❌ 3 tests failed · 🔧 Needs a code fix, caused by this PR

View more details · View in GitHub Actions

❌ tests.test_v1_payloads.Test_V1Payloads.test_field_changes[apache-mod-7.0-zts] from system_tests_suite
AssertionError: assert False
 &#43;  where False = isinstance([{&#39;duration&#39;: 2304332, &#39;error&#39;: 1, &#39;meta&#39;: {&#39;_dd.appsec.event_rules.version&#39;: &#39;1.18.0&#39;, &#39;_dd.appsec.fp.http.endpoint&#39;:...abled&#39;: 1.0, &#39;_dd.appsec.waf.duration&#39;: 574.0, &#39;_dd.appsec.waf.duration_ext&#39;: 784.965, &#39;_dd.rule_psr&#39;: 1.0, ...}, ...}], dict)
 &#43;    where [{&#39;duration&#39;: 2304332, &#39;error&#39;: 1, &#39;meta&#39;: {&#39;_dd.appsec.event_rules.version&#39;: &#39;1.18.0&#39;, &#39;_dd.appsec.fp.http.endpoint&#39;:...abled&#39;: 1.0, &#39;_dd.appsec.waf.duration&#39;: 574.0, &#39;_dd.appsec.waf.duration_ext&#39;: 784.965, &#39;_dd.rule_psr&#39;: 1.0, ...}, ...}] = &lt;utils.dd_types._datadog_library_trace.DataDogLibraryTraceLegacy object at 0x7f9fdfa41640&gt;.raw_trace

self = &lt;tests.test_v1_payloads.Test_V1Payloads object at 0x7fa002dadb50&gt;

    def test_field_changes(self):
        library_traces = list(interfaces.library.get_traces(self.r))
        agent_traces = list(interfaces.agent.get_traces(self.r))
        assert len(library_traces) == 1
...
❌ tests.test_v1_payloads.Test_V1SpanEvents.test_span_event_present[apache-mod-7.0-zts] from system_tests_suite
AssertionError: Expected at least one span event
assert 0 &gt;= 1
 &#43;  where 0 = len([])

self = &lt;tests.test_v1_payloads.Test_V1SpanEvents object at 0x7fa002daf680&gt;

    def test_span_event_present(self):
        &#34;&#34;&#34;Root span carries at least one span event in V1 format&#34;&#34;&#34;
        span = interfaces.library.get_root_span(self.r)
        assert span is not None
...
❌ tests.test_v1_payloads.Test_V1TopLevelSpans.test_root_span_is_top_level[apache-mod-7.0-zts] from system_tests_suite
AssertionError: Root span must have _dd.top_level=1 in attributes, got: None
assert (None == 1 or None == 1.0)
 &#43;  where None = &lt;built-in method get of dict object at 0x7f9fdf17e100&gt;(&#39;_dd.top_level&#39;)
 &#43;    where &lt;built-in method get of dict object at 0x7f9fdf17e100&gt; = {}.get
 &#43;  and   None = &lt;built-in method get of dict object at 0x7f9fdf17e100&gt;(&#39;_dd.top_level&#39;)
 &#43;    where &lt;built-in method get of dict object at 0x7f9fdf17e100&gt; = {}.get

self = &lt;tests.test_v1_payloads.Test_V1TopLevelSpans object at 0x7fa002daf8c0&gt;

    def test_root_span_is_top_level(self):
...
Testing the test | System Tests (php, dev) / End-to-end #1 / apache-mod-7.1 1 — ❌ 3 tests failed · 🔧 Needs a code fix, caused by this PR

View more details · View in GitHub Actions

❌ tests.test_v1_payloads.Test_V1Payloads.test_field_changes[apache-mod-7.1] from system_tests_suite
AssertionError: assert False
 &#43;  where False = isinstance([{&#39;duration&#39;: 3770230, &#39;error&#39;: 1, &#39;meta&#39;: {&#39;_dd.appsec.event_rules.version&#39;: &#39;1.18.0&#39;, &#39;_dd.appsec.fp.http.endpoint&#39;:...abled&#39;: 1.0, &#39;_dd.appsec.waf.duration&#39;: 682.0, &#39;_dd.appsec.waf.duration_ext&#39;: 951.553, &#39;_dd.rule_psr&#39;: 1.0, ...}, ...}], dict)
 &#43;    where [{&#39;duration&#39;: 3770230, &#39;error&#39;: 1, &#39;meta&#39;: {&#39;_dd.appsec.event_rules.version&#39;: &#39;1.18.0&#39;, &#39;_dd.appsec.fp.http.endpoint&#39;:...abled&#39;: 1.0, &#39;_dd.appsec.waf.duration&#39;: 682.0, &#39;_dd.appsec.waf.duration_ext&#39;: 951.553, &#39;_dd.rule_psr&#39;: 1.0, ...}, ...}] = &lt;utils.dd_types._datadog_library_trace.DataDogLibraryTraceLegacy object at 0x7f7a0127e5a0&gt;.raw_trace

self = &lt;tests.test_v1_payloads.Test_V1Payloads object at 0x7f7a294ad4c0&gt;

    def test_field_changes(self):
        library_traces = list(interfaces.library.get_traces(self.r))
        agent_traces = list(interfaces.agent.get_traces(self.r))
        assert len(library_traces) == 1
...
❌ tests.test_v1_payloads.Test_V1SpanEvents.test_span_event_present[apache-mod-7.1] from system_tests_suite
AssertionError: Expected at least one span event
assert 0 &gt;= 1
 &#43;  where 0 = len([])

self = &lt;tests.test_v1_payloads.Test_V1SpanEvents object at 0x7f7a294ae3c0&gt;

    def test_span_event_present(self):
        &#34;&#34;&#34;Root span carries at least one span event in V1 format&#34;&#34;&#34;
        span = interfaces.library.get_root_span(self.r)
        assert span is not None
...
❌ tests.test_v1_payloads.Test_V1TopLevelSpans.test_root_span_is_top_level[apache-mod-7.1] from system_tests_suite
AssertionError: Root span must have _dd.top_level=1 in attributes, got: None
assert (None == 1 or None == 1.0)
 &#43;  where None = &lt;built-in method get of dict object at 0x7f7a01e282c0&gt;(&#39;_dd.top_level&#39;)
 &#43;    where &lt;built-in method get of dict object at 0x7f7a01e282c0&gt; = {}.get
 &#43;  and   None = &lt;built-in method get of dict object at 0x7f7a01e282c0&gt;(&#39;_dd.top_level&#39;)
 &#43;    where &lt;built-in method get of dict object at 0x7f7a01e282c0&gt; = {}.get

self = &lt;tests.test_v1_payloads.Test_V1TopLevelSpans object at 0x7f7a294ae750&gt;

    def test_root_span_is_top_level(self):
...

View all 67 failed jobs.

ℹ️ Info

No other issues found (see more)

❄️ No new flaky tests detected

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 934eb96 | Docs | View more details | Give us feedback!

Leiyks added a commit to DataDog/dd-trace-php that referenced this pull request Sep 28, 2026
…merge

Clone system-tests at SYSTEM_TESTS_REF (default leiyks/php-v1-payload,
DataDog/system-tests#7843) from SYSTEM_TESTS_REPO, and add
APM_TRACING_EFFICIENT_PAYLOAD to the System Tests matrix.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant