diff --git a/manifests/cpp.yml b/manifests/cpp.yml index 9193180aca2..d833d6becf5 100644 --- a/manifests/cpp.yml +++ b/manifests/cpp.yml @@ -198,6 +198,7 @@ manifest: : missing_feature (_dd.p.dm does not change when a sampling priority was extracted) ? tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_dd_propagate_propagatedtags_change_sampling_same_dm : missing_feature (_dd.p.dm is never dropped) + tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_ows_between_list_members: bug (APMAPI-2297) tests/parametric/test_library_tracestats.py::Test_Library_Tracestats::test_agent_populated_fields_empty_TS013: missing_feature (cpp has not implemented stats computation yet) tests/parametric/test_library_tracestats.py::Test_Library_Tracestats::test_cardinality_overflow_sentinel_TS017: missing_feature (cpp has not implemented stats computation yet) tests/parametric/test_library_tracestats.py::Test_Library_Tracestats::test_distinct_aggregationkeys_TS003: missing_feature (cpp has not implemented stats computation yet) diff --git a/manifests/dotnet.yml b/manifests/dotnet.yml index 43afb01eaa6..709a7cc8a48 100644 --- a/manifests/dotnet.yml +++ b/manifests/dotnet.yml @@ -940,6 +940,7 @@ manifest: component_version: <2.51.0 ? tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_dd_evicts_32_or_greater_list_members : bug (APMAPI-914) + tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_ows_between_list_members: bug (APMAPI-2296) tests/parametric/test_library_tracestats.py::Test_Library_Tracestats::test_agent_populated_fields_empty_TS013: - declaration: missing_feature component_version: '<3.43.0' diff --git a/manifests/java.yml b/manifests/java.yml index 9d8c9130bcf..39e4127d2e8 100644 --- a/manifests/java.yml +++ b/manifests/java.yml @@ -3931,9 +3931,21 @@ manifest: tests/parametric/test_headers_tracecontext.py::Test_Headers_Tracecontext::test_tracestate_w3c_p_inject: - declaration: missing_feature (Not implemented) component_version: <1.35.0 + tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_dd_empty_elements: + - declaration: bug (APMAPI-2293) + component_version: <1.66.0-SNAPSHOT ? tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_dd_evicts_32_or_greater_list_members : - declaration: missing_feature (Implemented in 1.24.0) component_version: <1.24.0 + ? tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_dd_known_elements_not_duplicated + : - declaration: bug (APMAPI-2293) + component_version: <1.66.0-SNAPSHOT + tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_dd_skips_malformed_elements: + - declaration: bug (APMAPI-2293) + component_version: <1.66.0-SNAPSHOT + tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_dd_trailing_separator: + - declaration: bug (APMAPI-2293) + component_version: <1.66.0-SNAPSHOT tests/parametric/test_library_tracestats.py::Test_Library_Tracestats::test_cardinality_overflow_sentinel_TS017: "missing_feature (CSS v1.2.0 Cardinality Limits: dd-trace-java does not honor DD_TRACE_STATS_CARDINALITY_LIMIT for client-side stats, so its default limit is not lowered and no overflow collapsing to the tracer_blocked_value sentinel occurs)" tests/parametric/test_library_tracestats.py::Test_Library_Tracestats::test_partial_version_excluded_TS014: irrelevant (dd-trace-java excludes partial snapshots via its internal longRunningVersion field) tests/parametric/test_library_tracestats.py::Test_Library_Tracestats::test_sample_rate_0_TS007: # Modified by easy win activation script diff --git a/manifests/php.yml b/manifests/php.yml index ac069f7adbd..e88b8c86464 100644 --- a/manifests/php.yml +++ b/manifests/php.yml @@ -1492,13 +1492,19 @@ manifest: - declaration: missing_feature (Not implemented) component_version: <0.99.0 tests/parametric/test_headers_tracecontext.py::Test_Headers_Tracecontext::test_tracestate_w3c_p_phase_3_extract_first: missing_feature (Not implemented) + tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_dd_empty_elements: bug (APMAPI-2295) ? tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_dd_evicts_32_or_greater_list_members : bug (APMAPI-916) ? tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_dd_keeps_32_or_fewer_list_members : bug (APMAPI-916) + ? tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_dd_known_elements_not_duplicated + : bug (APMAPI-2295) tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_dd_propagate_propagatedtags: - declaration: bug (APMAPI-1539) component_version: '>=1.11.0' + tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_dd_skips_malformed_elements: bug (APMAPI-2295) + tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_dd_trailing_separator: bug (APMAPI-2295) + tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_ows_between_list_members: bug (APMAPI-2295) tests/parametric/test_library_tracestats.py::Test_Library_Tracestats: # Easy win for all weblogs and version 1.23.3 - declaration: "missing_feature (CSS v1.2.0: dd-trace-php ships CSS since v1.19.0, but the sidecar stats exporter retains buckets younger than ~20s (buffer_len=2 * bucket_size=10s) and dd_trace_synchronous_flush passes force=false, so short-lived parametric tests never observe a /v0.6/stats request)" component_version: '>=1.19.0' diff --git a/manifests/python.yml b/manifests/python.yml index c53766b0c71..99690732938 100644 --- a/manifests/python.yml +++ b/manifests/python.yml @@ -2002,12 +2002,15 @@ manifest: - declaration: missing_feature (Not implemented) component_version: <2.7.0 tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD: v2.8.0 + tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_dd_empty_elements: bug (APMAPI-2294) ? tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_dd_evicts_32_or_greater_list_members : bug (APMAPI-914) ? tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_dd_propagate_propagatedtags_change_sampling_reset_dm : "missing_feature (\"Issue: Does not reset dm to DEFAULT\")" ? tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_dd_propagate_propagatedtags_change_sampling_same_dm : "missing_feature (\"Issue: Does not drop dm\")" + tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_dd_skips_malformed_elements: bug (APMAPI-2294) + tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_dd_trailing_separator: bug (APMAPI-2294) tests/parametric/test_library_tracestats.py::Test_Library_Tracestats: # Modified by easy win activation script - declaration: missing_feature (failure 2.8.0) component_version: <4.3.1 diff --git a/manifests/rust.yml b/manifests/rust.yml index 839f3b99fd0..b1c0d030d38 100644 --- a/manifests/rust.yml +++ b/manifests/rust.yml @@ -188,6 +188,7 @@ manifest: tests/parametric/test_headers_tracecontext.py::Test_Headers_Tracecontext::test_tracestate_ows_handling: missing_feature (Invalid tracestate keys for OpenTelemetry's implementation) tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD: v0.0.1 tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_dd_propagate_propagatedtags: missing_feature (can't guarantee the order of strings in the tracestate since they came from the map.) + tests/parametric/test_headers_tracestate_dd.py::Test_Headers_Tracestate_DD::test_headers_tracestate_ows_between_list_members: bug (APMSP-3974) tests/parametric/test_library_tracestats.py::Test_Library_Tracestats: '>=0.2.1' # Modified by easy win activation script tests/parametric/test_library_tracestats.py::Test_Library_Tracestats::test_agent_populated_fields_empty_TS013: "missing_feature (CSS v1.2.0: dd-trace-rs has no client-side stats implementation)" tests/parametric/test_library_tracestats.py::Test_Library_Tracestats::test_cardinality_overflow_sentinel_TS017: "missing_feature (CSS v1.2.0: dd-trace-rs has no client-side stats implementation)" diff --git a/tests/parametric/test_headers_tracestate_dd.py b/tests/parametric/test_headers_tracestate_dd.py index 22542689d7a..d1801bf82cb 100644 --- a/tests/parametric/test_headers_tracestate_dd.py +++ b/tests/parametric/test_headers_tracestate_dd.py @@ -619,3 +619,309 @@ def test_headers_tracestate_dd_evicts_32_or_greater_list_members(self, test_libr assert len(tracestate_1_string.split(",")) == 32 assert "key32=value32" not in tracestate_1_string assert tracestate_1_string.startswith("dd=") + + @temporary_enable_propagationstyle_default() + def test_headers_tracestate_dd_trailing_separator(self, test_library: APMLibrary): + """A trailing element separator (optionally followed by OWS, optionally right before + the next list-member's comma) in the tracestate 'dd' value must not invalidate the + rest of the 'dd' member: known sub-keys (s, o) are still extracted, and any other + list-member is still preserved. + """ + with test_library: + # 1) Trailing separator + headers1 = test_library.dd_make_child_span_and_get_headers( + [ + ("traceparent", "00-12345678901234567890123456789012-1234567890123456-01"), + ("tracestate", "dd=s:2;o:some;"), + ], + ) + + # 2) Trailing separator followed by OWS + headers2 = test_library.dd_make_child_span_and_get_headers( + [ + ("traceparent", "00-12345678901234567890123456789012-1234567890123456-01"), + ("tracestate", "dd=s:2;o:some; \t"), + ], + ) + + # 3) Double trailing separator + headers3 = test_library.dd_make_child_span_and_get_headers( + [ + ("traceparent", "00-12345678901234567890123456789012-1234567890123456-01"), + ("tracestate", "dd=s:2;o:some;;"), + ], + ) + + # 4) Trailing separator immediately before the next list-member's comma + headers4 = test_library.dd_make_child_span_and_get_headers( + [ + ("traceparent", "00-12345678901234567890123456789012-1234567890123456-01"), + ("tracestate", "dd=s:2;o:some;,other=x"), + ], + ) + + # 1) Trailing separator + _, tracestate1 = get_tracecontext(headers1) + dd_items1 = tracestate1["dd"].split(";") + assert "s:2" in dd_items1 + assert "o:some" in dd_items1 + + # 2) Trailing separator followed by OWS + _, tracestate2 = get_tracecontext(headers2) + dd_items2 = tracestate2["dd"].split(";") + assert "s:2" in dd_items2 + assert "o:some" in dd_items2 + + # 3) Double trailing separator + _, tracestate3 = get_tracecontext(headers3) + dd_items3 = tracestate3["dd"].split(";") + assert "s:2" in dd_items3 + assert "o:some" in dd_items3 + + # 4) Trailing separator immediately before the next list-member's comma + _, tracestate4 = get_tracecontext(headers4) + dd_items4 = tracestate4["dd"].split(";") + assert "s:2" in dd_items4 + assert "o:some" in dd_items4 + assert "other" in tracestate4 + assert tracestate4["other"] == "x" + + @temporary_enable_propagationstyle_default() + def test_headers_tracestate_dd_empty_elements(self, test_library: APMLibrary): + """Bare element separators (empty elements) anywhere in the tracestate 'dd' value + must be ignored rather than invalidating the rest of the 'dd' member. + """ + with test_library: + # 1) Leading empty element + headers1 = test_library.dd_make_child_span_and_get_headers( + [ + ("traceparent", "00-12345678901234567890123456789012-1234567890123456-01"), + ("tracestate", "dd=;s:2;o:some"), + ], + ) + + # 2) Interior double separator + headers2 = test_library.dd_make_child_span_and_get_headers( + [ + ("traceparent", "00-12345678901234567890123456789012-1234567890123456-01"), + ("tracestate", "dd=s:2;;o:some"), + ], + ) + + # 3) Interior triple separator + headers3 = test_library.dd_make_child_span_and_get_headers( + [ + ("traceparent", "00-12345678901234567890123456789012-1234567890123456-01"), + ("tracestate", "dd=s:2;;;o:some"), + ], + ) + + # 1) Leading empty element + _, tracestate1 = get_tracecontext(headers1) + dd_items1 = tracestate1["dd"].split(";") + assert "s:2" in dd_items1 + assert "o:some" in dd_items1 + + # 2) Interior double separator + _, tracestate2 = get_tracecontext(headers2) + dd_items2 = tracestate2["dd"].split(";") + assert "s:2" in dd_items2 + assert "o:some" in dd_items2 + + # 3) Interior triple separator + _, tracestate3 = get_tracecontext(headers3) + dd_items3 = tracestate3["dd"].split(";") + assert "s:2" in dd_items3 + assert "o:some" in dd_items3 + + @temporary_enable_propagationstyle_default() + def test_headers_tracestate_dd_skips_malformed_elements(self, test_library: APMLibrary): + """A malformed element (no ':' separator, or invalid characters abutting a + neighboring separator) inside the tracestate 'dd' value must be skipped rather + than invalidating the entire 'dd' member. + """ + with test_library: + # 1) Bare colonless element in the middle + headers1 = test_library.dd_make_child_span_and_get_headers( + [ + ("traceparent", "00-12345678901234567890123456789012-1234567890123456-01"), + ("tracestate", "dd=s:2;flag;o:some"), + ], + ) + + # 2) Bare element leading + headers2 = test_library.dd_make_child_span_and_get_headers( + [ + ("traceparent", "00-12345678901234567890123456789012-1234567890123456-01"), + ("tracestate", "dd=flag;s:2;o:some"), + ], + ) + + # 3) Bare element trailing, no separator after it + headers3 = test_library.dd_make_child_span_and_get_headers( + [ + ("traceparent", "00-12345678901234567890123456789012-1234567890123456-01"), + ("tracestate", "dd=s:2;o:some;flag"), + ], + ) + + # 4) Interior-OWS-abutting malformed element + headers4 = test_library.dd_make_child_span_and_get_headers( + [ + ("traceparent", "00-12345678901234567890123456789012-1234567890123456-01"), + ("tracestate", "dd=s:2; z:w;o:some"), + ], + ) + + # 1) Bare colonless element in the middle + _, tracestate1 = get_tracecontext(headers1) + dd_items1 = tracestate1["dd"].split(";") + assert "s:2" in dd_items1 + assert "o:some" in dd_items1 + + # 2) Bare element leading + _, tracestate2 = get_tracecontext(headers2) + dd_items2 = tracestate2["dd"].split(";") + assert "s:2" in dd_items2 + assert "o:some" in dd_items2 + + # 3) Bare element trailing, no separator after it + _, tracestate3 = get_tracecontext(headers3) + dd_items3 = tracestate3["dd"].split(";") + assert "s:2" in dd_items3 + assert "o:some" in dd_items3 + + # 4) Interior-OWS-abutting malformed element + _, tracestate4 = get_tracecontext(headers4) + dd_items4 = tracestate4["dd"].split(";") + assert "s:2" in dd_items4 + assert "o:some" in dd_items4 + + @temporary_enable_propagationstyle_default() + def test_headers_tracestate_dd_known_elements_not_duplicated(self, test_library: APMLibrary): + """When an unknown element coexists with a known sub-key (p, o, or s) in the + tracestate 'dd' value, the known sub-key must not be duplicated when the 'dd' + value is re-serialized for propagation. + """ + with test_library: + # 1) Last parent id alongside an unknown element + headers1 = test_library.dd_make_child_span_and_get_headers( + [ + ("traceparent", "00-12345678901234567890123456789012-1234567890123456-01"), + ("tracestate", "dd=p:b6241412414a;x:y"), + ], + ) + + # 2) Origin alongside an unknown element + headers2 = test_library.dd_make_child_span_and_get_headers( + [ + ("traceparent", "00-12345678901234567890123456789012-1234567890123456-01"), + ("tracestate", "dd=o:rum;x:y"), + ], + ) + + # 3) Sampling priority alongside an unknown element + headers3 = test_library.dd_make_child_span_and_get_headers( + [ + ("traceparent", "00-12345678901234567890123456789012-1234567890123456-01"), + ("tracestate", "dd=s:1;x:y"), + ], + ) + + # 1) Last parent id alongside an unknown element + _, tracestate1 = get_tracecontext(headers1) + dd_items1 = tracestate1["dd"].split(";") + assert sum(1 for item in dd_items1 if item.startswith("p:")) == 1 + + # 2) Origin alongside an unknown element + _, tracestate2 = get_tracecontext(headers2) + dd_items2 = tracestate2["dd"].split(";") + assert sum(1 for item in dd_items2 if item.startswith("o:")) == 1 + + # 3) Sampling priority alongside an unknown element + _, tracestate3 = get_tracecontext(headers3) + dd_items3 = tracestate3["dd"].split(";") + assert sum(1 for item in dd_items3 if item.startswith("s:")) == 1 + + @temporary_enable_propagationstyle_default() + def test_headers_tracestate_ows_between_list_members(self, test_library: APMLibrary): + """Empty list-members (consecutive commas) and OWS around the outer list's commas + are both explicitly allowed by the W3C tracestate grammar and must not invalidate + the 'dd' member or any other list-member. + """ + with test_library: + # 1) Leading empty outer list-member + headers1 = test_library.dd_make_child_span_and_get_headers( + [ + ("traceparent", "00-12345678901234567890123456789012-1234567890123456-01"), + ("tracestate", ",dd=s:2;o:some"), + ], + ) + + # 2) Trailing empty outer list-members + headers2 = test_library.dd_make_child_span_and_get_headers( + [ + ("traceparent", "00-12345678901234567890123456789012-1234567890123456-01"), + ("tracestate", "dd=s:2;o:some,,"), + ], + ) + + # 3) Interior empty outer list-member between two list-members + headers3 = test_library.dd_make_child_span_and_get_headers( + [ + ("traceparent", "00-12345678901234567890123456789012-1234567890123456-01"), + ("tracestate", "dd=s:2;o:some,,other=x"), + ], + ) + + # 4) OWS around the outer list's commas + headers4 = test_library.dd_make_child_span_and_get_headers( + [ + ("traceparent", "00-12345678901234567890123456789012-1234567890123456-01"), + ("tracestate", "dd=s:2;o:some , other=x"), + ], + ) + + # 5) OWS before and after the comma that precedes the 'dd' member + headers5 = test_library.dd_make_child_span_and_get_headers( + [ + ("traceparent", "00-12345678901234567890123456789012-1234567890123456-01"), + ("tracestate", "other=x , dd=s:2;o:some"), + ], + ) + + # 1) Leading empty outer list-member + _, tracestate1 = get_tracecontext(headers1) + dd_items1 = tracestate1["dd"].split(";") + assert "s:2" in dd_items1 + assert "o:some" in dd_items1 + + # 2) Trailing empty outer list-members + _, tracestate2 = get_tracecontext(headers2) + dd_items2 = tracestate2["dd"].split(";") + assert "s:2" in dd_items2 + assert "o:some" in dd_items2 + + # 3) Interior empty outer list-member between two list-members + _, tracestate3 = get_tracecontext(headers3) + dd_items3 = tracestate3["dd"].split(";") + assert "s:2" in dd_items3 + assert "o:some" in dd_items3 + assert "other" in tracestate3 + assert tracestate3["other"] == "x" + + # 4) OWS around the outer list's commas + _, tracestate4 = get_tracecontext(headers4) + dd_items4 = tracestate4["dd"].split(";") + assert "s:2" in dd_items4 + assert "o:some" in dd_items4 + assert "other" in tracestate4 + assert tracestate4["other"] == "x" + + # 5) OWS before and after the comma that precedes the 'dd' member + _, tracestate5 = get_tracecontext(headers5) + dd_items5 = tracestate5["dd"].split(";") + assert "s:2" in dd_items5 + assert "o:some" in dd_items5 + assert "other" in tracestate5 + assert tracestate5["other"] == "x"