diff --git a/ddtrace/contrib/internal/pytest/_plugin_v2.py b/ddtrace/contrib/internal/pytest/_plugin_v2.py index eb415d08667..a22ea5dff5b 100644 --- a/ddtrace/contrib/internal/pytest/_plugin_v2.py +++ b/ddtrace/contrib/internal/pytest/_plugin_v2.py @@ -679,7 +679,10 @@ def _pytest_sessionfinish(session: pytest.Session, exitstatus: int) -> None: InternalTestSession.finish(force_finish_children=True) +@pytest.hookimpl(hookwrapper=True, tryfirst=True) def pytest_sessionfinish(session: pytest.Session, exitstatus: int) -> None: + yield + if not is_test_visibility_enabled(): return diff --git a/ddtrace/internal/ci_visibility/api/_base.py b/ddtrace/internal/ci_visibility/api/_base.py index 64ea5586e82..fe2390b9159 100644 --- a/ddtrace/internal/ci_visibility/api/_base.py +++ b/ddtrace/internal/ci_visibility/api/_base.py @@ -90,6 +90,7 @@ def __post_init__(self): class SPECIAL_STATUS(Enum): UNFINISHED = 1 + NONSTARTED = 2 CIDT = TypeVar("CIDT", TestModuleId, TestSuiteId, TestId) # Child item ID types @@ -415,6 +416,8 @@ def get_span_id(self) -> Optional[int]: def get_status(self) -> Union[TestStatus, SPECIAL_STATUS]: if self.is_finished(): return self._status + if not self.is_started(): + return SPECIAL_STATUS.NONSTARTED return SPECIAL_STATUS.UNFINISHED def get_raw_status(self) -> TestStatus: @@ -562,7 +565,10 @@ def get_status(self) -> Union[TestStatus, SPECIAL_STATUS]: for child in self._children.values(): child_status = child.get_status() - if child_status == SPECIAL_STATUS.UNFINISHED: + if child_status == SPECIAL_STATUS.NONSTARTED: + # This means that the child was never started, so we don't count it + continue + elif child_status == SPECIAL_STATUS.UNFINISHED: # There's no point in continuing to count if we care about unfinished children log.debug("Item %s has unfinished children", self) return SPECIAL_STATUS.UNFINISHED diff --git a/tests/contrib/pytest/test_pytest_xdist_snapshot.py b/tests/contrib/pytest/test_pytest_xdist_snapshot.py new file mode 100644 index 00000000000..dc42ef90114 --- /dev/null +++ b/tests/contrib/pytest/test_pytest_xdist_snapshot.py @@ -0,0 +1,179 @@ +import os +import subprocess +from unittest import mock + +import pytest + +from ddtrace.contrib.internal.pytest._utils import _USE_PLUGIN_V2 +from ddtrace.internal.ci_visibility._api_client import TestVisibilityAPISettings +from tests.ci_visibility.util import _get_default_ci_env_vars +from tests.utils import TracerTestCase +from tests.utils import snapshot + +###### +# Skip these tests if they are not running under riot +riot_env_value = os.getenv("RIOT", None) +if not riot_env_value: + pytest.importorskip("xdist", reason="Pytest xdist tests, not running under riot") +###### + + + +pytestmark = pytest.mark.skipif(not _USE_PLUGIN_V2, reason="Tests in this module are for v2 of the pytest plugin") + +SNAPSHOT_IGNORES = [ + "meta.ci.workspace_path", + "meta.error.stack", + "meta.library_version", + "meta.os.architecture", + "meta.os.platform", + "meta.os.version", + "meta.runtime-id", + "meta.runtime.version", + "meta.test.framework_version", + "meta.test_module_id", + "meta.test_session_id", + "meta.test_suite_id", + "metrics._dd.top_level", + "metrics._dd.tracer_kr", + "metrics._sampling_priority_v1", + "metrics.process_id", + "duration", + "start", +] +SNAPSHOT_IGNORES_PATCH_ALL = SNAPSHOT_IGNORES + ["meta.http.useragent"] + +SNAPSHOT_IGNORES_ITR_COVERAGE = ["metrics.test.source.start", "metrics.test.source.end", "meta.test.source.file"] + + +class PytestXdistSnapshotTestCase(TracerTestCase): + @pytest.fixture(autouse=True) + def fixtures(self, testdir, monkeypatch, git_repo): + self.testdir = testdir + self.monkeypatch = monkeypatch + self.git_repo = git_repo + + @snapshot(ignores=SNAPSHOT_IGNORES) + def test_pytest_xdist_will_include_lines_pct(self): + tools = """ + def add_two_number_list(list_1, list_2): + output_list = [] + for number_a, number_b in zip(list_1, list_2): + output_list.append(number_a + number_b) + return output_list + + def multiply_two_number_list(list_1, list_2): + output_list = [] + for number_a, number_b in zip(list_1, list_2): + output_list.append(number_a * number_b) + return output_list + """ + self.testdir.makepyfile(tools=tools) + test_tools = """ + from tools import add_two_number_list + + def test_add_two_number_list(): + a_list = [1,2,3,4,5,6,7,8] + b_list = [2,3,4,5,6,7,8,9] + actual_output = add_two_number_list(a_list, b_list) + + assert actual_output == [3,5,7,9,11,13,15,17] + """ + self.testdir.makepyfile(test_tools=test_tools) + self.testdir.chdir() + with mock.patch( + "ddtrace.internal.ci_visibility._api_client._TestVisibilityAPIClientBase.fetch_settings", + return_value=TestVisibilityAPISettings(False, False, False, False), + ): + subprocess.run( + ["ddtrace-run", "coverage", "run", "--include=tools.py", "-m", "pytest", "--ddtrace", "-n", "2"], + env=_get_default_ci_env_vars( + dict( + DD_API_KEY="foobar.baz", + DD_CIVISIBILITY_ITR_ENABLED="false", + DD_PATCH_MODULES="sqlite3:false", + CI_PROJECT_DIR=str(self.testdir.tmpdir), + DD_CIVISIBILITY_AGENTLESS_ENABLED="false", + ) + ), + ) + + @snapshot(ignores=SNAPSHOT_IGNORES) + def test_pytest_xdist_wont_include_lines_pct_if_report_empty(self): + tools = """ + def add_two_number_list(list_1, list_2): + output_list = [] + for number_a, number_b in zip(list_1, list_2): + output_list.append(number_a + number_b) + return output_list + + def multiply_two_number_list(list_1, list_2): + output_list = [] + for number_a, number_b in zip(list_1, list_2): + output_list.append(number_a * number_b) + return output_list + """ + self.testdir.makepyfile(tools=tools) + test_tools = """ + from tools import add_two_number_list + + def test_add_two_number_list(): + a_list = [1,2,3,4,5,6,7,8] + b_list = [2,3,4,5,6,7,8,9] + actual_output = add_two_number_list(a_list, b_list) + + assert actual_output == [3,5,7,9,11,13,15,17] + """ + self.testdir.makepyfile(test_tools=test_tools) + self.testdir.chdir() + with mock.patch( + "ddtrace.internal.ci_visibility._api_client._TestVisibilityAPIClientBase.fetch_settings", + return_value=TestVisibilityAPISettings(False, False, False, False), + ): + subprocess.run( + ["ddtrace-run", "coverage", "run", "--include=nothing.py", "-m", "pytest", "--ddtrace", "-n", "2"], + env=_get_default_ci_env_vars( + dict( + DD_API_KEY="foobar.baz", + DD_CIVISIBILITY_ITR_ENABLED="false", + DD_PATCH_MODULES="sqlite3:false", + CI_PROJECT_DIR=str(self.testdir.tmpdir), + DD_CIVISIBILITY_AGENTLESS_ENABLED="false", + ) + ), + ) + + @snapshot(ignores=SNAPSHOT_IGNORES_PATCH_ALL) + def test_pytest_xdist_with_ddtrace_patch_all(self): + call_httpx = """ + import httpx + + def call_httpx(): + return httpx.get("http://localhost:9126/bad_path.cgi") + """ + self.testdir.makepyfile(call_httpx=call_httpx) + test_call_httpx = """ + from call_httpx import call_httpx + + def test_call_urllib(): + r = call_httpx() + assert r.status_code == 404 + """ + self.testdir.makepyfile(test_call_httpx=test_call_httpx) + self.testdir.chdir() + with mock.patch( + "ddtrace.internal.ci_visibility._api_client._TestVisibilityAPIClientBase.fetch_settings", + return_value=TestVisibilityAPISettings(False, False, False, False), + ): + subprocess.run( + ["pytest", "--ddtrace", "--ddtrace-patch-all", "-n", "2"], + env=_get_default_ci_env_vars( + dict( + DD_API_KEY="foobar.baz", + DD_CIVISIBILITY_ITR_ENABLED="false", + CI_PROJECT_DIR=str(self.testdir.tmpdir), + DD_CIVISIBILITY_AGENTLESS_ENABLED="false", + DD_PATCH_MODULES="httpx:true", + ) + ), + ) diff --git a/tests/snapshots/tests.contrib.pytest.test_pytest_xdist_snapshot.test_pytest_xdist_will_include_lines_pct.json b/tests/snapshots/tests.contrib.pytest.test_pytest_xdist_snapshot.test_pytest_xdist_will_include_lines_pct.json new file mode 100644 index 00000000000..8d35f3defe3 --- /dev/null +++ b/tests/snapshots/tests.contrib.pytest.test_pytest_xdist_snapshot.test_pytest_xdist_will_include_lines_pct.json @@ -0,0 +1,269 @@ +[[ + { + "name": "pytest.test_session", + "service": "pytest", + "resource": "pytest.test_session", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "test", + "error": 0, + "meta": { + "_dd.origin": "ciapp-test", + "_dd.p.dm": "-0", + "_dd.p.tid": "6824a47000000000", + "component": "pytest", + "language": "python", + "library_version": "3.8.0.dev42+g5ece7dca1.d20250514", + "os.architecture": "aarch64", + "os.platform": "Linux", + "os.version": "6.10.14-linuxkit", + "runtime-id": "31d4f2e2c93347f9a55867a6779d4117", + "runtime.name": "CPython", + "runtime.version": "3.12.8", + "span.kind": "test", + "test.code_coverage.enabled": "false", + "test.command": "pytest --ddtrace -n 2", + "test.framework": "pytest", + "test.framework_version": "6.2.5", + "test.itr.tests_skipping.enabled": "false", + "test.status": "skip", + "test_session_id": "1917611093305268474", + "type": "test_session_end" + }, + "metrics": { + "_dd.py.partial_flush": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "process_id": 577 + }, + "duration": 4871841529, + "start": 1747231856394911722 + }], +[ + { + "name": "pytest.test", + "service": "pytest", + "resource": "test_add_two_number_list", + "trace_id": 1, + "span_id": 1, + "parent_id": 0, + "type": "test", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.origin": "ciapp-test", + "_dd.p.dm": "-0", + "_dd.p.tid": "6824a47100000000", + "component": "pytest", + "language": "python", + "library_version": "3.8.0.dev42+g5ece7dca1.d20250514", + "os.architecture": "aarch64", + "os.platform": "Linux", + "os.version": "6.10.14-linuxkit", + "runtime-id": "636051554bde43c3aeeb80b202cdbd26", + "runtime.name": "CPython", + "runtime.version": "3.12.8", + "span.kind": "test", + "test.command": "pytest --ddtrace -n 2", + "test.framework": "pytest", + "test.framework_version": "6.2.5", + "test.module": "", + "test.module_path": "", + "test.name": "test_add_two_number_list", + "test.source.file": "test_tools.py", + "test.status": "pass", + "test.suite": "test_tools.py", + "test.type": "test", + "test_module_id": "13274413685374338856", + "test_session_id": "13887040111267361680", + "test_suite_id": "4357464865339177957", + "type": "test" + }, + "metrics": { + "_dd.py.partial_flush": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "process_id": 590, + "test.source.end": 9, + "test.source.start": 3 + }, + "duration": 1480083, + "start": 1747231857413431583 + }], +[ + { + "name": "pytest.test_session", + "service": "pytest", + "resource": "pytest.test_session", + "trace_id": 2, + "span_id": 1, + "parent_id": 0, + "type": "test", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.origin": "ciapp-test", + "_dd.p.dm": "-0", + "_dd.p.tid": "6824a47100000000", + "component": "pytest", + "language": "python", + "library_version": "3.8.0.dev42+g5ece7dca1.d20250514", + "os.architecture": "aarch64", + "os.platform": "Linux", + "os.version": "6.10.14-linuxkit", + "runtime-id": "636051554bde43c3aeeb80b202cdbd26", + "runtime.name": "CPython", + "runtime.version": "3.12.8", + "span.kind": "test", + "test.code_coverage.enabled": "false", + "test.command": "pytest --ddtrace -n 2", + "test.framework": "pytest", + "test.framework_version": "6.2.5", + "test.itr.tests_skipping.enabled": "false", + "test.status": "pass", + "test_session_id": "13887040111267361680", + "type": "test_session_end" + }, + "metrics": { + "_dd.py.partial_flush": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "process_id": 590 + }, + "duration": 307537986, + "start": 1747231857109905014 + }, + { + "name": "pytest.test_module", + "service": "pytest", + "resource": "pytest.test_module", + "trace_id": 2, + "span_id": 2, + "parent_id": 1, + "type": "test", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.origin": "ciapp-test", + "_dd.p.dm": "-0", + "_dd.p.tid": "6824a47100000000", + "component": "pytest", + "language": "python", + "library_version": "3.8.0.dev42+g5ece7dca1.d20250514", + "os.architecture": "aarch64", + "os.platform": "Linux", + "os.version": "6.10.14-linuxkit", + "runtime.name": "CPython", + "runtime.version": "3.12.8", + "span.kind": "test", + "test.code_coverage.enabled": "false", + "test.command": "pytest --ddtrace -n 2", + "test.framework": "pytest", + "test.framework_version": "6.2.5", + "test.itr.tests_skipping.enabled": "false", + "test.module": "", + "test.module_path": "", + "test.status": "pass", + "test_module_id": "13274413685374338856", + "test_session_id": "13887040111267361680", + "type": "test_module_end" + }, + "metrics": { + "_dd.py.partial_flush": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1 + }, + "duration": 2213250, + "start": 1747231857413339750 + }, + { + "name": "pytest.test_suite", + "service": "pytest", + "resource": "pytest.test_suite", + "trace_id": 2, + "span_id": 3, + "parent_id": 2, + "type": "test", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.origin": "ciapp-test", + "_dd.p.dm": "-0", + "_dd.p.tid": "6824a47100000000", + "component": "pytest", + "language": "python", + "library_version": "3.8.0.dev42+g5ece7dca1.d20250514", + "os.architecture": "aarch64", + "os.platform": "Linux", + "os.version": "6.10.14-linuxkit", + "runtime.name": "CPython", + "runtime.version": "3.12.8", + "span.kind": "test", + "test.command": "pytest --ddtrace -n 2", + "test.framework": "pytest", + "test.framework_version": "6.2.5", + "test.module": "", + "test.module_path": "", + "test.status": "pass", + "test.suite": "test_tools.py", + "test_module_id": "13274413685374338856", + "test_session_id": "13887040111267361680", + "test_suite_id": "4357464865339177957", + "type": "test_suite_end" + }, + "metrics": { + "_dd.py.partial_flush": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1 + }, + "duration": 2063333, + "start": 1747231857413390958 + }], +[ + { + "name": "pytest.test_session", + "service": "pytest", + "resource": "pytest.test_session", + "trace_id": 3, + "span_id": 1, + "parent_id": 0, + "type": "test", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.origin": "ciapp-test", + "_dd.p.dm": "-0", + "_dd.p.tid": "6824a47100000000", + "component": "pytest", + "language": "python", + "library_version": "3.8.0.dev42+g5ece7dca1.d20250514", + "os.architecture": "aarch64", + "os.platform": "Linux", + "os.version": "6.10.14-linuxkit", + "runtime-id": "dc0c8ee6f2bb4170bed621638fcd7c3b", + "runtime.name": "CPython", + "runtime.version": "3.12.8", + "span.kind": "test", + "test.code_coverage.enabled": "false", + "test.command": "pytest --ddtrace -n 2", + "test.framework": "pytest", + "test.framework_version": "6.2.5", + "test.itr.tests_skipping.enabled": "false", + "test.status": "pass", + "test_session_id": "361878570529835958", + "type": "test_session_end" + }, + "metrics": { + "_dd.py.partial_flush": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "process_id": 599 + }, + "duration": 19397375, + "start": 1747231857394667166 + }]] diff --git a/tests/snapshots/tests.contrib.pytest.test_pytest_xdist_snapshot.test_pytest_xdist_with_ddtrace_patch_all.json b/tests/snapshots/tests.contrib.pytest.test_pytest_xdist_snapshot.test_pytest_xdist_with_ddtrace_patch_all.json new file mode 100644 index 00000000000..43ef4cd3bf8 --- /dev/null +++ b/tests/snapshots/tests.contrib.pytest.test_pytest_xdist_snapshot.test_pytest_xdist_with_ddtrace_patch_all.json @@ -0,0 +1,308 @@ +[[ + { + "name": "pytest.test_session", + "service": "pytest", + "resource": "pytest.test_session", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "test", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.origin": "ciapp-test", + "_dd.p.dm": "-0", + "_dd.p.tid": "6824a48300000000", + "component": "pytest", + "language": "python", + "library_version": "3.8.0.dev42+g5ece7dca1.d20250514", + "os.architecture": "aarch64", + "os.platform": "Linux", + "os.version": "6.10.14-linuxkit", + "runtime-id": "2e721ff133c044159ab0b079033db24a", + "runtime.name": "CPython", + "runtime.version": "3.12.8", + "span.kind": "test", + "test.code_coverage.enabled": "false", + "test.command": "pytest --ddtrace --ddtrace-patch-all -n 2", + "test.framework": "pytest", + "test.framework_version": "6.2.5", + "test.itr.tests_skipping.enabled": "false", + "test.status": "skip", + "test_session_id": "7421398664347405606", + "type": "test_session_end" + }, + "metrics": { + "_dd.py.partial_flush": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "process_id": 715 + }, + "duration": 4878562627, + "start": 1747231875177681175 + }], +[ + { + "name": "pytest.test", + "service": "pytest", + "resource": "test_call_urllib", + "trace_id": 1, + "span_id": 1, + "parent_id": 0, + "type": "test", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.origin": "ciapp-test", + "_dd.p.dm": "-0", + "_dd.p.tid": "6824a48400000000", + "component": "pytest", + "language": "python", + "library_version": "3.8.0.dev42+g5ece7dca1.d20250514", + "os.architecture": "aarch64", + "os.platform": "Linux", + "os.version": "6.10.14-linuxkit", + "runtime-id": "a953d9bcd8c4452791dbf3309345801c", + "runtime.name": "CPython", + "runtime.version": "3.12.8", + "span.kind": "test", + "test.command": "pytest --ddtrace --ddtrace-patch-all -n 2", + "test.framework": "pytest", + "test.framework_version": "6.2.5", + "test.module": "", + "test.module_path": "", + "test.name": "test_call_urllib", + "test.source.file": "test_call_httpx.py", + "test.status": "pass", + "test.suite": "test_call_httpx.py", + "test.type": "test", + "test_module_id": "16502366615175320937", + "test_session_id": "3303449708150025418", + "test_suite_id": "17112779979893924224", + "type": "test" + }, + "metrics": { + "_dd.py.partial_flush": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "process_id": 722, + "test.source.end": 6, + "test.source.start": 3 + }, + "duration": 100027792, + "start": 1747231876174150467 + }, + { + "name": "http.request", + "service": "pytest", + "resource": "http.request", + "trace_id": 1, + "span_id": 2, + "parent_id": 1, + "type": "http", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.origin": "ciapp-test", + "_dd.p.dm": "-0", + "_dd.p.tid": "6824a48400000000", + "component": "httpx", + "http.method": "GET", + "http.status_code": "404", + "http.url": "http://localhost:9126/bad_path.cgi", + "http.useragent": "python-httpx/0.28.1", + "language": "python", + "library_version": "3.8.0.dev42+g5ece7dca1.d20250514", + "os.architecture": "aarch64", + "os.platform": "Linux", + "os.version": "6.10.14-linuxkit", + "out.host": "localhost", + "runtime.name": "CPython", + "runtime.version": "3.12.8", + "span.kind": "client" + }, + "metrics": { + "_dd.measured": 1, + "_dd.py.partial_flush": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1 + }, + "duration": 1634333, + "start": 1747231876255991217 + }], +[ + { + "name": "pytest.test_session", + "service": "pytest", + "resource": "pytest.test_session", + "trace_id": 2, + "span_id": 1, + "parent_id": 0, + "type": "test", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.origin": "ciapp-test", + "_dd.p.dm": "-0", + "_dd.p.tid": "6824a48400000000", + "component": "pytest", + "language": "python", + "library_version": "3.8.0.dev42+g5ece7dca1.d20250514", + "os.architecture": "aarch64", + "os.platform": "Linux", + "os.version": "6.10.14-linuxkit", + "runtime-id": "a953d9bcd8c4452791dbf3309345801c", + "runtime.name": "CPython", + "runtime.version": "3.12.8", + "span.kind": "test", + "test.code_coverage.enabled": "false", + "test.command": "pytest --ddtrace --ddtrace-patch-all -n 2", + "test.framework": "pytest", + "test.framework_version": "6.2.5", + "test.itr.tests_skipping.enabled": "false", + "test.status": "pass", + "test_session_id": "3303449708150025418", + "type": "test_session_end" + }, + "metrics": { + "_dd.py.partial_flush": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "process_id": 722 + }, + "duration": 240454583, + "start": 1747231876035830467 + }, + { + "name": "pytest.test_module", + "service": "pytest", + "resource": "pytest.test_module", + "trace_id": 2, + "span_id": 2, + "parent_id": 1, + "type": "test", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.origin": "ciapp-test", + "_dd.p.dm": "-0", + "_dd.p.tid": "6824a48400000000", + "component": "pytest", + "language": "python", + "library_version": "3.8.0.dev42+g5ece7dca1.d20250514", + "os.architecture": "aarch64", + "os.platform": "Linux", + "os.version": "6.10.14-linuxkit", + "runtime.name": "CPython", + "runtime.version": "3.12.8", + "span.kind": "test", + "test.code_coverage.enabled": "false", + "test.command": "pytest --ddtrace --ddtrace-patch-all -n 2", + "test.framework": "pytest", + "test.framework_version": "6.2.5", + "test.itr.tests_skipping.enabled": "false", + "test.module": "", + "test.module_path": "", + "test.status": "pass", + "test_module_id": "16502366615175320937", + "test_session_id": "3303449708150025418", + "type": "test_module_end" + }, + "metrics": { + "_dd.py.partial_flush": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1 + }, + "duration": 100542750, + "start": 1747231876174053217 + }, + { + "name": "pytest.test_suite", + "service": "pytest", + "resource": "pytest.test_suite", + "trace_id": 2, + "span_id": 3, + "parent_id": 2, + "type": "test", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.origin": "ciapp-test", + "_dd.p.dm": "-0", + "_dd.p.tid": "6824a48400000000", + "component": "pytest", + "language": "python", + "library_version": "3.8.0.dev42+g5ece7dca1.d20250514", + "os.architecture": "aarch64", + "os.platform": "Linux", + "os.version": "6.10.14-linuxkit", + "runtime.name": "CPython", + "runtime.version": "3.12.8", + "span.kind": "test", + "test.command": "pytest --ddtrace --ddtrace-patch-all -n 2", + "test.framework": "pytest", + "test.framework_version": "6.2.5", + "test.module": "", + "test.module_path": "", + "test.status": "pass", + "test.suite": "test_call_httpx.py", + "test_module_id": "16502366615175320937", + "test_session_id": "3303449708150025418", + "test_suite_id": "17112779979893924224", + "type": "test_suite_end" + }, + "metrics": { + "_dd.py.partial_flush": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1 + }, + "duration": 100415167, + "start": 1747231876174104633 + }], +[ + { + "name": "pytest.test_session", + "service": "pytest", + "resource": "pytest.test_session", + "trace_id": 3, + "span_id": 1, + "parent_id": 0, + "type": "test", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.origin": "ciapp-test", + "_dd.p.dm": "-0", + "_dd.p.tid": "6824a48400000000", + "component": "pytest", + "language": "python", + "library_version": "3.8.0.dev42+g5ece7dca1.d20250514", + "os.architecture": "aarch64", + "os.platform": "Linux", + "os.version": "6.10.14-linuxkit", + "runtime-id": "72746598484b426fa129807ee7def316", + "runtime.name": "CPython", + "runtime.version": "3.12.8", + "span.kind": "test", + "test.code_coverage.enabled": "false", + "test.command": "pytest --ddtrace --ddtrace-patch-all -n 2", + "test.framework": "pytest", + "test.framework_version": "6.2.5", + "test.itr.tests_skipping.enabled": "false", + "test.status": "pass", + "test_session_id": "10575653905102725390", + "type": "test_session_end" + }, + "metrics": { + "_dd.py.partial_flush": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "process_id": 725 + }, + "duration": 49427250, + "start": 1747231876125310092 + }]] diff --git a/tests/snapshots/tests.contrib.pytest.test_pytest_xdist_snapshot.test_pytest_xdist_wont_include_lines_pct_if_report_empty.json b/tests/snapshots/tests.contrib.pytest.test_pytest_xdist_snapshot.test_pytest_xdist_wont_include_lines_pct_if_report_empty.json new file mode 100644 index 00000000000..99cab4e54b0 --- /dev/null +++ b/tests/snapshots/tests.contrib.pytest.test_pytest_xdist_snapshot.test_pytest_xdist_wont_include_lines_pct_if_report_empty.json @@ -0,0 +1,269 @@ +[[ + { + "name": "pytest.test_session", + "service": "pytest", + "resource": "pytest.test_session", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "test", + "error": 0, + "meta": { + "_dd.origin": "ciapp-test", + "_dd.p.dm": "-0", + "_dd.p.tid": "6824a47a00000000", + "component": "pytest", + "language": "python", + "library_version": "3.8.0.dev42+g5ece7dca1.d20250514", + "os.architecture": "aarch64", + "os.platform": "Linux", + "os.version": "6.10.14-linuxkit", + "runtime-id": "43751da0a2634bf7b8381af506319cc0", + "runtime.name": "CPython", + "runtime.version": "3.12.8", + "span.kind": "test", + "test.code_coverage.enabled": "false", + "test.command": "pytest --ddtrace -n 2", + "test.framework": "pytest", + "test.framework_version": "6.2.5", + "test.itr.tests_skipping.enabled": "false", + "test.status": "skip", + "test_session_id": "13401683197192035257", + "type": "test_session_end" + }, + "metrics": { + "_dd.py.partial_flush": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "process_id": 646 + }, + "duration": 4834358002, + "start": 1747231866091026712 + }], +[ + { + "name": "pytest.test", + "service": "pytest", + "resource": "test_add_two_number_list", + "trace_id": 1, + "span_id": 1, + "parent_id": 0, + "type": "test", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.origin": "ciapp-test", + "_dd.p.dm": "-0", + "_dd.p.tid": "6824a47b00000000", + "component": "pytest", + "language": "python", + "library_version": "3.8.0.dev42+g5ece7dca1.d20250514", + "os.architecture": "aarch64", + "os.platform": "Linux", + "os.version": "6.10.14-linuxkit", + "runtime-id": "34861b29cfba40b19e2c92781cbc4e80", + "runtime.name": "CPython", + "runtime.version": "3.12.8", + "span.kind": "test", + "test.command": "pytest --ddtrace -n 2", + "test.framework": "pytest", + "test.framework_version": "6.2.5", + "test.module": "", + "test.module_path": "", + "test.name": "test_add_two_number_list", + "test.source.file": "test_tools.py", + "test.status": "pass", + "test.suite": "test_tools.py", + "test.type": "test", + "test_module_id": "5470148288796704589", + "test_session_id": "931371332892065214", + "test_suite_id": "17788908745303008972", + "type": "test" + }, + "metrics": { + "_dd.py.partial_flush": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "process_id": 659, + "test.source.end": 9, + "test.source.start": 3 + }, + "duration": 1429500, + "start": 1747231867121508754 + }], +[ + { + "name": "pytest.test_session", + "service": "pytest", + "resource": "pytest.test_session", + "trace_id": 2, + "span_id": 1, + "parent_id": 0, + "type": "test", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.origin": "ciapp-test", + "_dd.p.dm": "-0", + "_dd.p.tid": "6824a47a00000000", + "component": "pytest", + "language": "python", + "library_version": "3.8.0.dev42+g5ece7dca1.d20250514", + "os.architecture": "aarch64", + "os.platform": "Linux", + "os.version": "6.10.14-linuxkit", + "runtime-id": "34861b29cfba40b19e2c92781cbc4e80", + "runtime.name": "CPython", + "runtime.version": "3.12.8", + "span.kind": "test", + "test.code_coverage.enabled": "false", + "test.command": "pytest --ddtrace -n 2", + "test.framework": "pytest", + "test.framework_version": "6.2.5", + "test.itr.tests_skipping.enabled": "false", + "test.status": "pass", + "test_session_id": "931371332892065214", + "type": "test_session_end" + }, + "metrics": { + "_dd.py.partial_flush": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "process_id": 659 + }, + "duration": 304213625, + "start": 1747231866821064087 + }, + { + "name": "pytest.test_module", + "service": "pytest", + "resource": "pytest.test_module", + "trace_id": 2, + "span_id": 2, + "parent_id": 1, + "type": "test", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.origin": "ciapp-test", + "_dd.p.dm": "-0", + "_dd.p.tid": "6824a47a00000000", + "component": "pytest", + "language": "python", + "library_version": "3.8.0.dev42+g5ece7dca1.d20250514", + "os.architecture": "aarch64", + "os.platform": "Linux", + "os.version": "6.10.14-linuxkit", + "runtime.name": "CPython", + "runtime.version": "3.12.8", + "span.kind": "test", + "test.code_coverage.enabled": "false", + "test.command": "pytest --ddtrace -n 2", + "test.framework": "pytest", + "test.framework_version": "6.2.5", + "test.itr.tests_skipping.enabled": "false", + "test.module": "", + "test.module_path": "", + "test.status": "pass", + "test_module_id": "5470148288796704589", + "test_session_id": "931371332892065214", + "type": "test_module_end" + }, + "metrics": { + "_dd.py.partial_flush": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1 + }, + "duration": 2070834, + "start": 1747231867121418837 + }, + { + "name": "pytest.test_suite", + "service": "pytest", + "resource": "pytest.test_suite", + "trace_id": 2, + "span_id": 3, + "parent_id": 2, + "type": "test", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.origin": "ciapp-test", + "_dd.p.dm": "-0", + "_dd.p.tid": "6824a47a00000000", + "component": "pytest", + "language": "python", + "library_version": "3.8.0.dev42+g5ece7dca1.d20250514", + "os.architecture": "aarch64", + "os.platform": "Linux", + "os.version": "6.10.14-linuxkit", + "runtime.name": "CPython", + "runtime.version": "3.12.8", + "span.kind": "test", + "test.command": "pytest --ddtrace -n 2", + "test.framework": "pytest", + "test.framework_version": "6.2.5", + "test.module": "", + "test.module_path": "", + "test.status": "pass", + "test.suite": "test_tools.py", + "test_module_id": "5470148288796704589", + "test_session_id": "931371332892065214", + "test_suite_id": "17788908745303008972", + "type": "test_suite_end" + }, + "metrics": { + "_dd.py.partial_flush": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1 + }, + "duration": 1937917, + "start": 1747231867121467504 + }], +[ + { + "name": "pytest.test_session", + "service": "pytest", + "resource": "pytest.test_session", + "trace_id": 3, + "span_id": 1, + "parent_id": 0, + "type": "test", + "error": 0, + "meta": { + "_dd.base_service": "", + "_dd.origin": "ciapp-test", + "_dd.p.dm": "-0", + "_dd.p.tid": "6824a47b00000000", + "component": "pytest", + "language": "python", + "library_version": "3.8.0.dev42+g5ece7dca1.d20250514", + "os.architecture": "aarch64", + "os.platform": "Linux", + "os.version": "6.10.14-linuxkit", + "runtime-id": "4d6ec9a69ec941ae931527dc2aa8da12", + "runtime.name": "CPython", + "runtime.version": "3.12.8", + "span.kind": "test", + "test.code_coverage.enabled": "false", + "test.command": "pytest --ddtrace -n 2", + "test.framework": "pytest", + "test.framework_version": "6.2.5", + "test.itr.tests_skipping.enabled": "false", + "test.status": "pass", + "test_session_id": "15492075490523613270", + "type": "test_session_end" + }, + "metrics": { + "_dd.py.partial_flush": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "process_id": 668 + }, + "duration": 18553292, + "start": 1747231867103547129 + }]]