Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 11 additions & 3 deletions tests/appsec/test_asm_standalone.py
Original file line number Diff line number Diff line change
Expand Up @@ -737,9 +737,17 @@ def test_telemetry_sca_enabled_propagated(self):
payload.sort(key=lambda item: item["seq_id"], reverse=True)
assert configuration_by_name

dd_appsec_sca_enabled = TelemetryUtils.get_dd_appsec_sca_enabled_str(context.library)

cfg_appsec_enabled = configuration_by_name.get(dd_appsec_sca_enabled)
dd_appsec_sca_enabled_names = TelemetryUtils.get_dd_appsec_sca_enabled_names(context.library)
dd_appsec_sca_enabled = " or ".join(dd_appsec_sca_enabled_names)

cfg_appsec_enabled = next(
(
configuration_by_name.get(config_name)
for config_name in dd_appsec_sca_enabled_names
if config_name in configuration_by_name
),
None,
)
assert cfg_appsec_enabled is not None, f"Missing telemetry config item for '{dd_appsec_sca_enabled}'"

outcome_value: bool | str = True
Expand Down
4 changes: 2 additions & 2 deletions tests/docker_ssi/test_docker_ssi_appsec.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ def test_telemetry_source_ssi(self):

# Check that instrumentation source is ssi
injection_source = (
configurations.get("DD_APPSEC_ENABLED") # Python
or configurations.get("appsec.enabled") # Node.js & PHP
configurations.get("DD_APPSEC_ENABLED") # Node.js & Python
or configurations.get("appsec.enabled") # PHP
or configurations.get("appsec_enabled") # Java
)
assert injection_source, f"instrumentation_source not found in configuration {configurations}"
Expand Down
119 changes: 88 additions & 31 deletions tests/parametric/test_telemetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,20 @@
telemetry_name_mapping: dict[str, dict[str, str | list[str]]] = {
"instrumentation_source": {
"java": "DD_INSTRUMENTATION_SOURCE",
"nodejs": ["instrumentationSource", "instrumentation_source"],
},
"ssi_injection_enabled": {
"python": "DD_INJECTION_ENABLED",
"java": "DD_INJECTION_ENABLED",
"ruby": "DD_INJECTION_ENABLED",
"nodejs": ["DD_INJECTION_ENABLED", "injectionEnabled", "ssi_injection_enabled"],
"golang": ["DD_INJECTION_ENABLED", "injection_enabled"],
},
"ssi_forced_injection_enabled": {
"python": "DD_INJECT_FORCE",
"ruby": "DD_INJECT_FORCE",
"java": "DD_INJECT_FORCE",
"nodejs": ["DD_INJECT_FORCE", "injectForce", "ssi_forced_injection_enabled"],
"golang": ["DD_INJECT_FORCE", "inject_force"],
},
"trace_sample_rate": {
Expand All @@ -41,7 +44,7 @@
},
"logs_injection_enabled": {
"dotnet": "DD_LOGS_INJECTION",
"nodejs": "DD_LOG_INJECTION", # TODO: rename to DD_LOGS_INJECTION in subsequent PR
"nodejs": ["DD_LOGS_INJECTION", "DD_LOG_INJECTION"],
"python": "DD_LOGS_INJECTION",
"php": "trace.logs_enabled",
"ruby": "DD_LOGS_INJECTION",
Expand All @@ -67,30 +70,30 @@
"trace_enabled": {
"dotnet": "DD_TRACE_ENABLED",
"java": "DD_TRACE_ENABLED",
"nodejs": "tracing",
"nodejs": ["DD_TRACE_ENABLED", "tracing"],
"python": "DD_TRACE_ENABLED",
"ruby": "DD_TRACE_ENABLED",
"golang": ["DD_TRACE_ENABLED", "trace_enabled"],
},
"profiling_enabled": {
"dotnet": "DD_PROFILING_ENABLED",
"nodejs": "profiling.enabled",
"nodejs": ["DD_PROFILING_ENABLED", "profiling.enabled"],
"python": "DD_PROFILING_ENABLED",
"ruby": "DD_PROFILING_ENABLED",
"golang": ["DD_PROFILING_ENABLED", "profiling_enabled"],
"java": "DD_PROFILING_ENABLED",
},
"appsec_enabled": {
"dotnet": "DD_APPSEC_ENABLED",
"nodejs": "appsec.enabled",
"nodejs": ["DD_APPSEC_ENABLED", "appsec.enabled"],
"python": "DD_APPSEC_ENABLED",
"ruby": "DD_APPSEC_ENABLED",
"golang": ["DD_APPSEC_ENABLED", "appsec_enabled"],
"java": "DD_APPSEC_ENABLED",
},
"data_streams_enabled": {
"dotnet": "DD_DATA_STREAMS_ENABLED",
"nodejs": "dsmEnabled",
"nodejs": ["DD_DATA_STREAMS_ENABLED", "dsmEnabled"],
"python": "DD_DATA_STREAMS_ENABLED",
"java": "DD_DATA_STREAMS_ENABLED",
"golang": ["DD_DATA_STREAMS_ENABLED", "data_streams_enabled"],
Expand All @@ -99,15 +102,15 @@
"runtime_metrics_enabled": {
"java": "DD_RUNTIME_METRICS_ENABLED",
"dotnet": "DD_RUNTIME_METRICS_ENABLED",
"nodejs": "runtime.metrics.enabled",
"nodejs": ["DD_RUNTIME_METRICS_ENABLED", "runtime.metrics.enabled"],
"python": "DD_RUNTIME_METRICS_ENABLED",
"ruby": "DD_RUNTIME_METRICS_ENABLED",
"golang": ["DD_RUNTIME_METRICS_ENABLED", "runtime_metrics_enabled"],
},
"dynamic_instrumentation_enabled": {
"java": "DD_DYNAMIC_INSTRUMENTATION_ENABLED",
"dotnet": "DD_DYNAMIC_INSTRUMENTATION_ENABLED",
"nodejs": "dynamicInstrumentation.enabled",
"nodejs": ["DD_DYNAMIC_INSTRUMENTATION_ENABLED", "dynamicInstrumentation.enabled"],
"python": "DD_DYNAMIC_INSTRUMENTATION_ENABLED",
"php": "dynamic_instrumentation.enabled",
"ruby": "DD_DYNAMIC_INSTRUMENTATION_ENABLED",
Expand Down Expand Up @@ -162,16 +165,22 @@ def _check_propagation_style_with_inject_and_extract(
"""
# Define the inject and extract key names for each language
if library_name in ("python", "ruby"):
inject_key = "DD_TRACE_PROPAGATION_STYLE_INJECT"
extract_key = "DD_TRACE_PROPAGATION_STYLE_EXTRACT"
inject_keys = ["DD_TRACE_PROPAGATION_STYLE_INJECT"]
extract_keys = ["DD_TRACE_PROPAGATION_STYLE_EXTRACT"]
elif library_name == "nodejs":
inject_key = "tracePropagationStyle.inject"
extract_key = "tracePropagationStyle.extract"
inject_keys = ["DD_TRACE_PROPAGATION_STYLE_INJECT", "tracePropagationStyle.inject"]
extract_keys = ["DD_TRACE_PROPAGATION_STYLE_EXTRACT", "tracePropagationStyle.extract"]
else:
raise ValueError(f"Unsupported library for inject/extract propagation style: {library_name}")

# Check inject key
inject_item = test_agent.get_telemetry_config_by_origin(configuration_by_name, inject_key, expected_origin)
inject_item = None
inject_key = inject_keys[0]
for candidate in inject_keys:
inject_item = test_agent.get_telemetry_config_by_origin(configuration_by_name, candidate, expected_origin)
if inject_item is not None:
inject_key = candidate
break
assert inject_item is not None, (
f"No configuration found for '{inject_key}' with origin '{expected_origin}'. Full configuration_by_name: {configuration_by_name}"
)
Expand All @@ -182,7 +191,13 @@ def _check_propagation_style_with_inject_and_extract(
assert inject_item["value"], f"Expected non-empty value for '{inject_key}'"

# Check extract key
extract_item = test_agent.get_telemetry_config_by_origin(configuration_by_name, extract_key, expected_origin)
extract_item = None
extract_key = extract_keys[0]
for candidate in extract_keys:
extract_item = test_agent.get_telemetry_config_by_origin(configuration_by_name, candidate, expected_origin)
if extract_item is not None:
extract_key = candidate
break
assert extract_item is not None, (
f"No configuration found for '{extract_key}' with origin '{expected_origin}'. Full configuration_by_name: {configuration_by_name}"
)
Expand Down Expand Up @@ -320,12 +335,9 @@ def test_library_settings(self, test_agent: TestAgentAPI, test_library: APMLibra
)
== "5.2.0"
)
assert (
test_agent.get_telemetry_config_by_origin(
configuration_by_name, "DD_TRACE_RATE_LIMIT", "env_var", return_value_only=True
)
== "10"
)
assert test_agent.get_telemetry_config_by_origin(
configuration_by_name, "DD_TRACE_RATE_LIMIT", "env_var", return_value_only=True
) in ("10", 10)
assert (
test_agent.get_telemetry_config_by_origin(
configuration_by_name, "DD_TRACE_HEADER_TAGS", "env_var", return_value_only=True
Expand Down Expand Up @@ -1084,17 +1096,27 @@ def test_injection_enabled(
ssi_enabled_telemetry_names = _mapped_telemetry_name("ssi_injection_enabled")
inject_enabled = None
for ssi_name in ssi_enabled_telemetry_names:
inject_enabled = test_agent.get_telemetry_config_by_origin(
configuration_by_name, ssi_name, "env_var", fallback_to_first=(expected_value is None)
)
inject_enabled = test_agent.get_telemetry_config_by_origin(configuration_by_name, ssi_name, "env_var")
if inject_enabled is not None:
break
if inject_enabled is None and context.library == "nodejs":
for ssi_name in ssi_enabled_telemetry_names:
inject_enabled = test_agent.get_telemetry_config_by_origin(
configuration_by_name, ssi_name, "calculated", fallback_to_first=True
)
if inject_enabled is not None:
break
assert inject_enabled is not None, (
f"No configuration found for any of {' or '.join(ssi_enabled_telemetry_names)}"
)
assert isinstance(inject_enabled, dict)
assert inject_enabled.get("value") == expected_value
if expected_value is not None:
expected_values: tuple[object, ...] = (expected_value,)
if context.library == "nodejs":
expected_values += ([item.strip() for item in expected_value.split(",")],)
assert inject_enabled.get("value") in expected_values
# Node.js now derives the SSI source config from canonical config entries. Once PR #7734
# is fully rolled out, restore the strict env_var origin assertion here.
if expected_value is not None and context.library != "nodejs":
assert inject_enabled.get("origin") == "env_var"

@pytest.mark.parametrize(
Expand Down Expand Up @@ -1132,16 +1154,26 @@ def test_inject_force(self, expected_value: str, test_agent: TestAgentAPI, test_
inject_force = None
for inject_force_name in inject_force_telemetry_names:
inject_force = test_agent.get_telemetry_config_by_origin(
configuration_by_name, inject_force_name, "env_var", fallback_to_first=(expected_value == "none")
configuration_by_name, inject_force_name, "env_var"
)
if inject_force is not None:
break
if inject_force is None and context.library == "nodejs":
for inject_force_name in inject_force_telemetry_names:
inject_force = test_agent.get_telemetry_config_by_origin(
configuration_by_name, inject_force_name, "calculated", fallback_to_first=True
)
if inject_force is not None:
break
assert inject_force is not None, (
f"No configuration found for any of {' or '.join(inject_force_telemetry_names)}"
)
assert isinstance(inject_force, dict)
assert str(inject_force.get("value")).lower() == expected_value
assert inject_force.get("origin") == "env_var"
# Node.js now derives the SSI source config from canonical config entries. Once PR #7734
# is fully rolled out, restore the strict env_var origin assertion here.
if context.library != "nodejs":
assert inject_force.get("origin") == "env_var"

@pytest.mark.parametrize("library_env", [{**DEFAULT_ENVVARS, "DD_SERVICE": "service_test"}])
def test_instrumentation_source_non_ssi(self, test_agent: TestAgentAPI, test_library: APMLibrary):
Expand All @@ -1161,6 +1193,15 @@ def test_instrumentation_source_non_ssi(self, test_agent: TestAgentAPI, test_lib
)
if instrumentation_source is not None:
break
# Node.js reports instrumentationSource as a calculated value with the new config pipeline.
# Remove this fallback after PR #7734 lands and older values no longer need coverage.
if instrumentation_source is None and context.library == "nodejs":
for instrumentation_source_name in instrumentation_source_telemetry_names:
instrumentation_source = test_agent.get_telemetry_config_by_origin(
configuration_by_name, instrumentation_source_name, "calculated", fallback_to_first=True
)
if instrumentation_source is not None:
break
assert instrumentation_source is not None, (
f"No configuration found for any of {' or '.join(instrumentation_source_telemetry_names)}"
)
Expand Down Expand Up @@ -1217,15 +1258,23 @@ def _assert_telemetry_sca_enabled_propagated(
):
assert test_library.is_alive(), "Library container is not running"
configuration_by_name = test_agent.wait_for_telemetry_configurations()
dd_appsec_sca_enabled = TelemetryUtils.get_dd_appsec_sca_enabled_str(context.library)
dd_appsec_sca_enabled_names = TelemetryUtils.get_dd_appsec_sca_enabled_names(context.library)
dd_appsec_sca_enabled = " or ".join(dd_appsec_sca_enabled_names)

logger.info(f"""Check that:
* the env var DD_APPSEC_SCA_ENABLED={library_env["DD_APPSEC_SCA_ENABLED"]}
* is reported in telemetry configuration {dd_appsec_sca_enabled} as value={outcome_value}""")

assert configuration_by_name is not None, "Missing telemetry configuration"

cfg_appsec_enabled = configuration_by_name.get(dd_appsec_sca_enabled)
cfg_appsec_enabled = next(
(
configuration_by_name.get(config_name)
for config_name in dd_appsec_sca_enabled_names
if config_name in configuration_by_name
),
None,
)
logger.info(f"Oberved {dd_appsec_sca_enabled}: {cfg_appsec_enabled}")
assert cfg_appsec_enabled is not None, f"Missing telemetry config item for '{dd_appsec_sca_enabled}'"

Expand All @@ -1239,11 +1288,19 @@ def test_telemetry_sca_enabled_not_propagated(self, test_agent: TestAgentAPI, te

assert configuration_by_name is not None, "Missing telemetry configuration"

dd_appsec_sca_enabled = TelemetryUtils.get_dd_appsec_sca_enabled_str(context.library)
dd_appsec_sca_enabled_names = TelemetryUtils.get_dd_appsec_sca_enabled_names(context.library)
dd_appsec_sca_enabled = " or ".join(dd_appsec_sca_enabled_names)

if context.library in ("java", "nodejs", "python", "ruby"):
cfg_appsec_enabled = configuration_by_name.get(dd_appsec_sca_enabled)
cfg_appsec_enabled = next(
(
configuration_by_name.get(config_name)
for config_name in dd_appsec_sca_enabled_names
if config_name in configuration_by_name
),
None,
)
assert cfg_appsec_enabled is not None, f"Missing telemetry config item for '{dd_appsec_sca_enabled}'"
assert cfg_appsec_enabled[0].get("value") is None
else:
assert dd_appsec_sca_enabled not in configuration_by_name
assert all(config_name not in configuration_by_name for config_name in dd_appsec_sca_enabled_names)
Loading
Loading