diff --git a/.github/workflows/run-end-to-end.yml b/.github/workflows/run-end-to-end.yml index a7e94af1863..928551f0f2f 100644 --- a/.github/workflows/run-end-to-end.yml +++ b/.github/workflows/run-end-to-end.yml @@ -386,6 +386,9 @@ jobs: - name: Run TELEMETRY_ENHANCED_CONFIG_REPORTING scenario if: steps.build.outcome == 'success' && !cancelled() && contains(inputs.scenarios, '"TELEMETRY_ENHANCED_CONFIG_REPORTING"') run: ./run.sh TELEMETRY_ENHANCED_CONFIG_REPORTING + - name: Run TELEMETRY_EXTENDED_HEARTBEAT scenario + if: steps.build.outcome == 'success' && !cancelled() && contains(inputs.scenarios, '"TELEMETRY_EXTENDED_HEARTBEAT"') + run: ./run.sh TELEMETRY_EXTENDED_HEARTBEAT - name: Run TELEMETRY_LOG_GENERATION_DISABLED scenario if: steps.build.outcome == 'success' && !cancelled() && contains(inputs.scenarios, '"TELEMETRY_LOG_GENERATION_DISABLED"') run: ./run.sh TELEMETRY_LOG_GENERATION_DISABLED diff --git a/manifests/cpp_httpd.yml b/manifests/cpp_httpd.yml index c9e124ccae9..6abaa4526f0 100644 --- a/manifests/cpp_httpd.yml +++ b/manifests/cpp_httpd.yml @@ -188,6 +188,7 @@ manifest: tests/test_smoke.py::Test_Library::test_receive_request_trace: missing_feature (For some reason, span type is server i/o web) tests/test_span_events.py: incomplete_test_app (Weblog `/add_event` not implemented) tests/test_standard_tags.py: irrelevant + tests/test_telemetry.py::Test_ExtendedHeartbeat: '>1.0.4' tests/test_telemetry.py::Test_Log_Generation: '>=1.0.3' # Modified by easy win activation script tests/test_telemetry.py::Test_Log_Generation::test_log_generation_enabled: missing_feature # Created by easy win activation script tests/test_telemetry.py::Test_MessageBatch: '>=1.0.3' # Modified by easy win activation script diff --git a/manifests/cpp_nginx.yml b/manifests/cpp_nginx.yml index 3d7b45098c6..e452475dfa8 100644 --- a/manifests/cpp_nginx.yml +++ b/manifests/cpp_nginx.yml @@ -434,6 +434,7 @@ manifest: tests/test_standard_tags.py: irrelevant tests/test_telemetry.py::Test_APMOnboardingInstallID: '>=1.12.0' # Modified by easy win activation script tests/test_telemetry.py::Test_DependencyEnable: '>=1.12.0' # Modified by easy win activation script + tests/test_telemetry.py::Test_ExtendedHeartbeat: '>=1.16.1' tests/test_telemetry.py::Test_Log_Generation: '>=1.12.0' # Modified by easy win activation script tests/test_telemetry.py::Test_Log_Generation::test_log_generation_enabled: missing_feature # Created by easy win activation script tests/test_telemetry.py::Test_MessageBatch: '>=1.12.0' # Modified by easy win activation script diff --git a/manifests/dotnet.yml b/manifests/dotnet.yml index df00b4ff8bf..dff706e1ac5 100644 --- a/manifests/dotnet.yml +++ b/manifests/dotnet.yml @@ -1201,6 +1201,7 @@ manifest: component_version: '>=2.41' tests/test_standard_tags.py::Test_StandardTagsUserAgent: v2.13.0 tests/test_telemetry.py::Test_DependencyEnable: v2.35.0 + tests/test_telemetry.py::Test_ExtendedHeartbeat: v3.39.0 tests/test_telemetry.py::Test_Log_Generation: # Modified by easy win activation script - weblog_declaration: '*': missing_feature diff --git a/manifests/golang.yml b/manifests/golang.yml index ff3a0a5f5e7..240716ba670 100644 --- a/manifests/golang.yml +++ b/manifests/golang.yml @@ -1456,6 +1456,7 @@ manifest: tests/test_standard_tags.py::Test_StandardTagsUrl::test_url_with_sensitive_query_string: missing_feature (tracer did not yet implemented the new version of query parameters obfuscation regex) tests/test_standard_tags.py::Test_StandardTagsUserAgent: v1.39.0 tests/test_telemetry.py::Test_DependencyEnable: v1.73.0-dev + tests/test_telemetry.py::Test_ExtendedHeartbeat: '>=2.8.0' tests/test_telemetry.py::Test_Log_Generation: v1.73.0-dev tests/test_telemetry.py::Test_MessageBatch: v1.73.0-dev tests/test_telemetry.py::Test_Metric_Generation_Disabled: v1.73.0-dev diff --git a/manifests/java.yml b/manifests/java.yml index 29ef1a462e5..ca629928155 100644 --- a/manifests/java.yml +++ b/manifests/java.yml @@ -4357,6 +4357,10 @@ manifest: component_version: '>=1.21.0' tests/test_standard_tags.py::Test_StandardTagsUserAgent: v0.107.1 tests/test_telemetry.py::Test_DependencyEnable: v1.7.0 + tests/test_telemetry.py::Test_ExtendedHeartbeat: + - weblog_declaration: + '*': missing_feature + spring-boot: v1.23.0 tests/test_telemetry.py::Test_Log_Generation: # Modified by easy win activation script - weblog_declaration: '*': missing_feature diff --git a/manifests/nodejs.yml b/manifests/nodejs.yml index 43b9643e991..9b467225667 100644 --- a/manifests/nodejs.yml +++ b/manifests/nodejs.yml @@ -88,6 +88,8 @@ refs: - &ref_5_88_0 '>=5.88.0' - &ref_5_89_0 '>=5.89.0' - &ref_5_90_0 '>=5.90.0' + - &ref_5_94_0 '>=5.94.0' + - &ref_5_97_0 '>=5.97.0' - &ref_5_98_0 '>=5.98.0' - &ref_5_99_0 '>=5.99.0' - &ref_6_0_0 '>=6.0.0-pre' @@ -2429,6 +2431,7 @@ manifest: tests/test_standard_tags.py::Test_StandardTagsUrl::test_url_with_sensitive_query_string: missing_feature (tracer did not yet implemented the new version of query parameters obfuscation regex) tests/test_standard_tags.py::Test_StandardTagsUserAgent: v2.9.0 tests/test_telemetry.py::Test_DependencyEnable: missing_feature + tests/test_telemetry.py::Test_ExtendedHeartbeat: *ref_5_97_0 tests/test_telemetry.py::Test_Log_Generation: # TODO: a lower version might be supported - weblog_declaration: '*': missing_feature diff --git a/manifests/php.yml b/manifests/php.yml index 3ac5cff5276..06928d6405b 100644 --- a/manifests/php.yml +++ b/manifests/php.yml @@ -1119,6 +1119,7 @@ manifest: component_version: '>=0.93.0' tests/test_standard_tags.py::Test_StandardTagsUserAgent: v0.75.0 tests/test_telemetry.py::Test_DependencyEnable: missing_feature + tests/test_telemetry.py::Test_ExtendedHeartbeat: missing_feature (PHP v1.20.0 emits null for dependencies[].version in app-extended-heartbeat, failing schema validation) tests/test_telemetry.py::Test_Log_Generation: # TODO: a lower version might be supported - weblog_declaration: '*': missing_feature diff --git a/manifests/python.yml b/manifests/python.yml index 3efde1b87d2..7ae0a487aaa 100644 --- a/manifests/python.yml +++ b/manifests/python.yml @@ -2247,6 +2247,7 @@ manifest: component_version: '>=1.18.0-rc1' tests/test_standard_tags.py::Test_StandardTagsUserAgent: v1.5.0-rc1 tests/test_telemetry.py::Test_DependencyEnable: v2.8.0 + tests/test_telemetry.py::Test_ExtendedHeartbeat: v4.6.5 tests/test_telemetry.py::Test_Log_Generation: # Modified by easy win activation script - weblog_declaration: '*': missing_feature diff --git a/manifests/ruby.yml b/manifests/ruby.yml index d096841f822..01ed19fbdfe 100644 --- a/manifests/ruby.yml +++ b/manifests/ruby.yml @@ -2143,6 +2143,7 @@ manifest: uds-sinatra: missing_feature tests/test_standard_tags.py::Test_StandardTagsUserAgent: v1.8.0 tests/test_telemetry.py::Test_DependencyEnable: v1.4.0 + tests/test_telemetry.py::Test_ExtendedHeartbeat: ">2.30.0" tests/test_telemetry.py::Test_Log_Generation: # Modified by easy win activation script - weblog_declaration: '*': missing_feature diff --git a/tests/schemas/test_schemas.py b/tests/schemas/test_schemas.py index 96e61a0aae3..379f3b87303 100644 --- a/tests/schemas/test_schemas.py +++ b/tests/schemas/test_schemas.py @@ -37,12 +37,6 @@ def test_library(self): condition=context.library < "python@v2.9.0.dev", ticket="APPSEC-52845", ), - SchemaBug( - endpoint="/telemetry/proxy/api/v2/apmtelemetry", - data_path="$.payload.configuration[].value", - condition=context.library == "golang", - ticket="APMS-12697", - ), SchemaBug( endpoint="/debugger/v1/diagnostics", data_path="$[].content", @@ -146,12 +140,6 @@ def test_agent(self): SchemaBug( endpoint="/api/v2/apmtelemetry", data_path="$", condition=True, ticket="???" ), # the main payload sent by the agent may be an array i/o an object - SchemaBug( - endpoint="/api/v2/apmtelemetry", - data_path="$.payload.configuration[].value", - condition=context.library == "golang", - ticket="APMS-12697", - ), SchemaBug( endpoint="/api/v2/debugger", data_path="$[].content", diff --git a/tests/schemas/utils/miscs/telemetry/v2/objects/configuration.json b/tests/schemas/utils/miscs/telemetry/v2/objects/configuration.json index 7a7ca884e2b..fa769513b37 100644 --- a/tests/schemas/utils/miscs/telemetry/v2/objects/configuration.json +++ b/tests/schemas/utils/miscs/telemetry/v2/objects/configuration.json @@ -29,7 +29,6 @@ }, "required": [ "name", - "value", "origin" ] } diff --git a/tests/test_telemetry.py b/tests/test_telemetry.py index 41a6771e3ee..9f752300ec5 100644 --- a/tests/test_telemetry.py +++ b/tests/test_telemetry.py @@ -1004,3 +1004,53 @@ def test_telemetry_sca_propagated(self): f"No telemetry found for {target_service_name} on {target_request_type} with configuration in " f"{' or '.join(dd_appsec_sca_enabled_names)}" ) + + +@scenarios.telemetry_extended_heartbeat +@features.app_extended_heartbeat_event +class Test_ExtendedHeartbeat: + """Test app-extended-heartbeat telemetry event in end-to-end scenario""" + + def setup_extended_heartbeat_config_matches(self): + weblog.get("/") + + def test_extended_heartbeat_config_matches(self): + """Test that every config reported in app-started or app-client-configuration-change + was eventually reported by at least one app-extended-heartbeat event. + """ + telemetry_data = list(interfaces.library.get_telemetry_data()) + + # Collect all config names reported in app-started and config-change events + expected_config_names: set[str] = set() + found_app_started = False + + for data in telemetry_data: + request_type = get_request_type(data) + if request_type in ("app-started", "app-client-configuration-change"): + if request_type == "app-started": + found_app_started = True + for c in get_configurations(data) or []: + expected_config_names.add(c["name"]) + + assert found_app_started, "app-started event not found" + + # Collect all config names ever reported across all extended heartbeats + heartbeat_config_names: set[str] = set() + found_extended_hb = False + + for data in telemetry_data: + if get_request_type(data) == "app-extended-heartbeat": + found_extended_hb = True + for c in get_configurations(data) or []: + heartbeat_config_names.add(c["name"]) + + assert found_extended_hb, "app-extended-heartbeat event not found" + + # For each expected config, verify it was reported by at least one extended heartbeat. + # Configs may appear in heartbeats before or after they are (re-)reported in + # config-change events (e.g. remote config updates re-report existing configs). + missing = sorted(expected_config_names - heartbeat_config_names) + assert not missing, ( + f"{len(missing)} config(s) reported in app-started or config-change but never " + f"included in any app-extended-heartbeat event: {missing}" + ) diff --git a/utils/_context/_scenarios/__init__.py b/utils/_context/_scenarios/__init__.py index 1f237720823..77a292977e6 100644 --- a/utils/_context/_scenarios/__init__.py +++ b/utils/_context/_scenarios/__init__.py @@ -186,6 +186,16 @@ class _Scenarios: doc="Test env var `DD_TELEMETRY_METRICS_ENABLED=false`", scenario_groups=[scenario_groups.telemetry], ) + telemetry_extended_heartbeat = EndToEndScenario( + "TELEMETRY_EXTENDED_HEARTBEAT", + weblog_env={ + "DD_TELEMETRY_HEARTBEAT_INTERVAL": "1", + "DD_TELEMETRY_EXTENDED_HEARTBEAT_INTERVAL": "2", + "_DD_TELEMETRY_EXTENDED_HEARTBEAT_INTERVAL": "2", + }, + doc="Test app-extended-heartbeat telemetry event with a shortened interval", + scenario_groups=[scenario_groups.telemetry], + ) # ASM scenarios appsec_missing_rules = EndToEndScenario(