ddapm-test-agent 1.34.0__tar.gz → 1.35.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/.github/workflows/main.yml +15 -7
  2. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/PKG-INFO +30 -2
  3. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/README.md +27 -1
  4. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/agent.py +391 -1
  5. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/trace_snapshot.py +29 -4
  6. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/vcr_proxy.py +27 -7
  7. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent.egg-info/PKG-INFO +30 -2
  8. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent.egg-info/SOURCES.txt +3 -0
  9. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent.egg-info/requires.txt +4 -0
  10. ddapm_test_agent-1.35.0/releasenotes/notes/named-pipe-ded0ebbbeee2e7fa.yaml +4 -0
  11. ddapm_test_agent-1.35.0/releasenotes/notes/vcr-custom-providers-map-a43b7e2d62d02015.yaml +6 -0
  12. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/riotfile.py +1 -0
  13. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/setup.py +1 -0
  14. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/test_deps.txt +1 -0
  15. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/conftest.py +38 -17
  16. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_agent.py +70 -0
  17. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_container.py +18 -0
  18. ddapm_test_agent-1.35.0/tests/test_vcr_proxy.py +197 -0
  19. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/.dockerignore +0 -0
  20. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/.github/workflows/docker.yml +0 -0
  21. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/.github/workflows/publish_pypi.yml +0 -0
  22. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/.github/workflows/releasenote.yml +0 -0
  23. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/.gitignore +0 -0
  24. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/Dockerfile +0 -0
  25. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/Dockerfile.windows +0 -0
  26. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/LICENSE.BSD3 +0 -0
  27. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/LICENSE.apache2 +0 -0
  28. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/__init__.py +0 -0
  29. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/apmtelemetry.py +0 -0
  30. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/checks.py +0 -0
  31. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/client.py +0 -0
  32. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/cmd.py +0 -0
  33. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/context.py +0 -0
  34. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/fmt.py +0 -0
  35. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/integration.py +0 -0
  36. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/logs.py +0 -0
  37. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/metrics.py +0 -0
  38. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/remoteconfig.py +0 -0
  39. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/trace.py +0 -0
  40. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/trace_checks.py +0 -0
  41. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/tracerflare.py +0 -0
  42. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/tracestats.py +0 -0
  43. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/tracestats_snapshot.py +0 -0
  44. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent.egg-info/dependency_links.txt +0 -0
  45. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent.egg-info/entry_points.txt +0 -0
  46. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent.egg-info/not-zip-safe +0 -0
  47. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent.egg-info/top_level.txt +0 -0
  48. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/pyproject.toml +0 -0
  49. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/check-releasenotes +0 -0
  50. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/config.yaml +0 -0
  51. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/1.0-e192f5064e917083.yaml +0 -0
  52. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/Add-metrics.process_id-to-ignored-attributes-62b264f0ea591326.yaml +0 -0
  53. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/Add-values-handling-to-span_event-array_value-to-mirror-agent-ee7483c90c263ff4.yaml +0 -0
  54. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/Checks-changed-to-opt-in-8716cac4ecdbb1c2.yaml +0 -0
  55. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/SNAPSHOT_REGEX_PLACEHOLDERS-1d2c5e2711d1953b.yaml +0 -0
  56. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/SNAPSHOT_REGEX_PLACEHOLDERS-compare-c829e7a4df4fa1f4.yaml +0 -0
  57. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/Settings-endpoint-928ae5b6e8ddc625.yaml +0 -0
  58. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/Telemetry-requests-delay-2586180b286ce393.yaml +0 -0
  59. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/Use-default-value-for-null-fields-in-tracestats-55d465f489efb2ba.yaml +0 -0
  60. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/acceptV1TracePayloads-5435cff37cfb6a85.yaml +0 -0
  61. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-datadog-proxy-7e2e608c101a564b.yaml +0 -0
  62. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-distributed-trace-c35a314698a3b966.yaml +0 -0
  63. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-fmt-command-cc31769942a5fec3.yaml +0 -0
  64. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-nix-build-support-29dc8a347e3bd7c1.yaml +0 -0
  65. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-optional-json-parser-10aac54bd1cbe322.yaml +0 -0
  66. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-otel-metrics-support-a2ebeb28cae2f0ba.yaml +0 -0
  67. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-python-3.13-support-ae7b96f4a10f20f4.yaml +0 -0
  68. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-rcm-endpoints-7e1f949e83e21039.yaml +0 -0
  69. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-request-forwarding-middleware-d3f325166b0f8e9e.yaml +0 -0
  70. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-service-naming-checks-2b68ff51d1b5496d.yaml +0 -0
  71. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-session-to-rcm-endpoints-d97e925a04a99a65.yaml +0 -0
  72. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-span-events-306e697168373899.yaml +0 -0
  73. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-support-for-plain-text-responses-00d20bf7b335e75b.yaml +0 -0
  74. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-support-telemetry-requests-10737cd3da802ca6.yaml +0 -0
  75. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-tracer_flare-endpoint-b2c81510920974d7.yaml +0 -0
  76. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/addAgentStateToInfo-f9a179ce88f2ab9e.yaml +0 -0
  77. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/addPeerTagsToInfo-4ccc2539d22c2993.yaml +0 -0
  78. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/allow-attribute-removal-snapshots-314b744b043b97c5.yaml +0 -0
  79. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/args-88f664c83a96075d.yaml +0 -0
  80. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/change-trace-proxy-headers-f9fcbb4efc4fcb95.yaml +0 -0
  81. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/check-http-header-sensitivity-daaa9d9595ae86d6.yaml +0 -0
  82. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/clearing-sessions-now-only-removes-6b0311673d8b37aa.yaml +0 -0
  83. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/client-173dbc6655e42337.yaml +0 -0
  84. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/content_length-e1bab75580aa1dcb.yaml +0 -0
  85. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/disable-error-responses-and-collect-trace-failures-in-memory-4a199bc7be416709.yaml +0 -0
  86. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/docker-arm64-images-a4b6b2cc527327d6.yaml +0 -0
  87. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/evp-proxy-on-info-d65cd077575306ca.yaml +0 -0
  88. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/exception-messages-21ee64461020edd1.yaml +0 -0
  89. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/fix-docker-image-tags-785d40f5bfdb8003.yaml +0 -0
  90. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/fix-fmt-logging-6a323fd8d5d4eb28.yaml +0 -0
  91. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/fix-getting-tested-integrations-multiple-session-tokens-4ee41d545754f87f.yaml +0 -0
  92. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/fix-matching-319744b82d2514c1.yaml +0 -0
  93. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/fix-missing-slim-deps-fa3b0fc0292a09b3.yaml +0 -0
  94. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/fix-partial-chunks-0db14ce3017e6173.yaml +0 -0
  95. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/fix-racecondition-9bd0ef15b7da60fa.yaml +0 -0
  96. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/fix-tracerflare-request-parsing-fae18ff9997c216d.yaml +0 -0
  97. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/genai-vcr-support-b499ec54df84eaa3.yaml +0 -0
  98. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/ignore-dsm-pathway-hash-during-trace-snapshots-f0b99ea267fbad48.yaml +0 -0
  99. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/image-optimization-d614eccb59441217.yaml +0 -0
  100. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/improve-test-agent-debugging-5759413f1fc5f7fa.yaml +0 -0
  101. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/improve-test-agent-proxying-a207f0fc81b3ab2d.yaml +0 -0
  102. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/improve-trace-check-results-endpoints-6ab4132628520793.yaml +0 -0
  103. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/info-34dcd9cbcc382487.yaml +0 -0
  104. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/info-drop-p0s-c207889f590340fb.yaml +0 -0
  105. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/llmobs-eval-metric-endpoint-8b5222491969ab4f.yaml +0 -0
  106. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/llmobs-evp-proxy-1383f4b4962ac7c9.yaml +0 -0
  107. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/meta-struct-2cce08475cb05470.yaml +0 -0
  108. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/more-oai-cass-908eb5ea46bd2985.yaml +0 -0
  109. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/new-process-id-tag-f0ab0daf652e05cc.yaml +0 -0
  110. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/oai-incomplete-cass-795ad19b6a226c1f.yaml +0 -0
  111. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/otlp-logs-grpc-45365879c22969aa.yaml +0 -0
  112. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/otlp-logs-support-d5a150d9f5304d7c.yaml +0 -0
  113. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/pipeline_stats_endpoint-e8ad6da735dc2647.yaml +0 -0
  114. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/profiling-endpoint-0cd209e4e5b6cfc0.yaml +0 -0
  115. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/provider-snapshot-server-f6a307acbf11d214.yaml +0 -0
  116. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/proxy-37c94e2fb428c6fc.yaml +0 -0
  117. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/python-3.12-952e06c6158af67d.yaml +0 -0
  118. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/python-support-1c447acc4607abc7.yaml +0 -0
  119. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/python310-025fbc190363de98.yaml +0 -0
  120. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/python310-docker-image-d4e329cfecf6510e.yaml +0 -0
  121. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/rc-encoding-length-fix-cc011edea7f8f5b2.yaml +0 -0
  122. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/rc-get-endpoint-e502f55b7df544e2.yaml +0 -0
  123. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/remoteconfig-requests-1af7abb99c61c069.yaml +0 -0
  124. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/remove-agent-state-header-from-info-87f920bf4ce5785c.yaml +0 -0
  125. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/remove-nix-ec1c4aca7dc002c4.yaml +0 -0
  126. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/remove-old-pythons-4667b182aacf0ce6.yaml +0 -0
  127. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/reuse-session-1670aa569907cf68.yaml +0 -0
  128. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/sample-rate-1e06ae4cdc933b14.yaml +0 -0
  129. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/session-requests-b8057811f976220e.yaml +0 -0
  130. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/session-tracerflares-400ce9b3d3838b40.yaml +0 -0
  131. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/snapshot-cmds-de4a561911afee11.yaml +0 -0
  132. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/snapshot-empty-maps-2cbe8cea3e7112fa.yaml +0 -0
  133. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/snapshot-error-messages-de41d9e3207fa30a.yaml +0 -0
  134. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/snapshot-filename-c068de1bc3e50c04.yaml +0 -0
  135. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/snapshot-order-type-2d6424e380b2c88f.yaml +0 -0
  136. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/snapshot-parent-id-7abb860008702e70.yaml +0 -0
  137. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/span-links-1ec76bd2b47a3880.yaml +0 -0
  138. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/span-ordering-1a7b383aa015bddc.yaml +0 -0
  139. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/span-parent-id-a4d7d63fa623361c.yaml +0 -0
  140. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/support-ant-vcr-1eff9a40caa0aba0.yaml +0 -0
  141. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/support-tracking-of-tested-integrations-ac19ccd1f8333c00.yaml +0 -0
  142. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/throttling-590bf58ecb3cc4a5.yaml +0 -0
  143. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/trace-stats-97da3a478dabfa99.yaml +0 -0
  144. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/trace-stats-snapshot-718ca37385c93e1e.yaml +0 -0
  145. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/traces-endpoint-f4f9c1d94d6ceda2.yaml +0 -0
  146. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/tracestats-fixes-07152c708e73ef96.yaml +0 -0
  147. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/tracestats-post-65ce788f81862532.yaml +0 -0
  148. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/tracestats-service-2a0a178cbd21b07d.yaml +0 -0
  149. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/uds-64b11960931d8b77.yaml +0 -0
  150. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/uds-c99ea5d099e67156.yaml +0 -0
  151. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/uds-container-8138f8b1438b1a0a.yaml +0 -0
  152. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/uds-permissions-903266ac6445b873.yaml +0 -0
  153. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/v0.5-traces-cf469b0b71398d97.yaml +0 -0
  154. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/v0.7-traces-7ea3ebbed7502d01.yaml +0 -0
  155. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/vcr-aws-bedrock-proxy-3bf018b1712d5105.yaml +0 -0
  156. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/vcr-cassette-name-middleware-fix-9e47c395892a9fe7.yaml +0 -0
  157. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/vcr-cassettes-for-openai-v5-6e9d78091de1f0c2.yaml +0 -0
  158. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/vcr-cassettes-for-vercel-ai-7a8275f9c2b48bc7.yaml +0 -0
  159. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/vcr-ci-mode-99dbd2940fff8d7a.yaml +0 -0
  160. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/vcr-prefix-instead-of-suffix-4c56dcb5038d222e.yaml +0 -0
  161. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/vcr-proxy-aws-recalculation-fix-2184c10270a7bca5.yaml +0 -0
  162. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/vcr-proxy-use-test-name-bugfix-be758294ba30ac78.yaml +0 -0
  163. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/vcr-proxy-use-test-name-e47891994c961c52.yaml +0 -0
  164. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/vcr-support-querystring-b06555fb9a7c90ae.yaml +0 -0
  165. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/version-0c32d2752f154eb9.yaml +0 -0
  166. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/wheels-68a7dc2f4b00e0c4.yaml +0 -0
  167. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/windows-docker-image-1f5d5e894558bb4b.yaml +0 -0
  168. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/setup.cfg +0 -0
  169. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/__init__.py +0 -0
  170. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/integration_snapshots/test_multi_trace.json +0 -0
  171. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/integration_snapshots/test_single_trace.json +0 -0
  172. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/integration_snapshots/test_trace_distributed_propagated.json +0 -0
  173. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/integration_snapshots/test_trace_distributed_same_payload.json +0 -0
  174. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/integration_snapshots/test_trace_missing_received.json +0 -0
  175. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/integration_snapshots/test_trace_stats_tracestats.json +0 -0
  176. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_apmtelemetry.py +0 -0
  177. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_checks.py +0 -0
  178. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_client.py +0 -0
  179. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_logs.py +0 -0
  180. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_metrics.py +0 -0
  181. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_remoteconfig.py +0 -0
  182. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_session.py +0 -0
  183. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_snapshot.py +0 -0
  184. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_snapshot_integration.py +0 -0
  185. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_trace.py +0 -0
  186. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_tracerflare.py +0 -0
  187. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_tracestats.py +0 -0
  188. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/trace_utils.py +0 -0
  189. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/anthropic/anthropic_v1_messages_post_26d618ee.yaml +0 -0
  190. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/anthropic/anthropic_v1_messages_post_595f439c.yaml +0 -0
  191. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/anthropic/anthropic_v1_messages_post_717ba0b4.yaml +0 -0
  192. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/anthropic/anthropic_v1_messages_post_a1af2c12.yaml +0 -0
  193. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/deepseek/deepseek_chat_completions_post_afb6ccab.yaml +0 -0
  194. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_audio_transcriptions_post_173af3e5.yaml +0 -0
  195. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_audio_transcriptions_post_71305a25.yaml +0 -0
  196. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_audio_translations_post_d5b5b8d6.yaml +0 -0
  197. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_audio_translations_post_dd92a18a.yaml +0 -0
  198. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_0f1514e1.yaml +0 -0
  199. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_172294b4.yaml +0 -0
  200. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_193ae44a.yaml +0 -0
  201. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_23558eed.yaml +0 -0
  202. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_2edb59ae.yaml +0 -0
  203. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_3517e44e.yaml +0 -0
  204. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_36bdc0cb.yaml +0 -0
  205. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_3c045664.yaml +0 -0
  206. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_432a8e46.yaml +0 -0
  207. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_4749eff9.yaml +0 -0
  208. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_4dce8db6.yaml +0 -0
  209. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_57612363.yaml +0 -0
  210. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_649d8162.yaml +0 -0
  211. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_655a8ef2.yaml +0 -0
  212. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_66dfc80e.yaml +0 -0
  213. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_67e8e833.yaml +0 -0
  214. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_6df851cc.yaml +0 -0
  215. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_7c2d1ac5.yaml +0 -0
  216. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_82a4bb3c.yaml +0 -0
  217. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_9122b1ae.yaml +0 -0
  218. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_917478d0.yaml +0 -0
  219. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_a73ecd7a.yaml +0 -0
  220. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_a925b737.yaml +0 -0
  221. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_ae4728c2.yaml +0 -0
  222. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_b29f1a87.yaml +0 -0
  223. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_ce69ed91.yaml +0 -0
  224. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_d8fb132a.yaml +0 -0
  225. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_d94d5844.yaml +0 -0
  226. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_d98ce00d.yaml +0 -0
  227. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_ebff79da.yaml +0 -0
  228. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_completions_post_33681ea4.yaml +0 -0
  229. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_completions_post_5d2418d4.yaml +0 -0
  230. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_completions_post_619dee1c.yaml +0 -0
  231. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_completions_post_6224acff.yaml +0 -0
  232. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_completions_post_87f617af.yaml +0 -0
  233. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_completions_post_98c30019.yaml +0 -0
  234. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_completions_post_9bb49464.yaml +0 -0
  235. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_completions_post_b24dbf7d.yaml +0 -0
  236. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_embeddings_post_0381abe4.yaml +0 -0
  237. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_embeddings_post_48694087.yaml +0 -0
  238. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_embeddings_post_541bd4d0.yaml +0 -0
  239. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_files_file-RpTpuvRVtnKpdKZb7DDGto_content_get_60bd10ef.yaml +0 -0
  240. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_files_file-RpTpuvRVtnKpdKZb7DDGto_delete_3ee48409.yaml +0 -0
  241. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_files_file-RpTpuvRVtnKpdKZb7DDGto_get_1afefb93.yaml +0 -0
  242. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_files_get_68efa25d.yaml +0 -0
  243. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_files_post_2fcf9545.yaml +0 -0
  244. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_files_post_957d63ba.yaml +0 -0
  245. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_fine_tuning_jobs_ftjob-q9CUUUsHJemGUVQ1Ecc01zcf_cancel_post_d7c16b38.yaml +0 -0
  246. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_fine_tuning_jobs_ftjob-q9CUUUsHJemGUVQ1Ecc01zcf_events_get_557d820e.yaml +0 -0
  247. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_fine_tuning_jobs_ftjob-q9CUUUsHJemGUVQ1Ecc01zcf_get_265489e7.yaml +0 -0
  248. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_fine_tuning_jobs_get_ebc57c6f.yaml +0 -0
  249. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_fine_tuning_jobs_post_c3b6e4a9.yaml +0 -0
  250. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_edits_post_075386c4.yaml +0 -0
  251. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_edits_post_57b4f4da.yaml +0 -0
  252. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_edits_post_660e9dd7.yaml +0 -0
  253. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_edits_post_993e0192.yaml +0 -0
  254. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_edits_post_a2f1eb43.yaml +0 -0
  255. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_edits_post_ae72c45f.yaml +0 -0
  256. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_edits_post_cf5af376.yaml +0 -0
  257. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_edits_post_dbefb624.yaml +0 -0
  258. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_generations_post_48272841.yaml +0 -0
  259. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_generations_post_736070ea.yaml +0 -0
  260. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_variations_post_5971e285.yaml +0 -0
  261. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_variations_post_f2f62f6c.yaml +0 -0
  262. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_models_ft_gpt-4.1-mini-2025-04-14_datadog-staging__BkaILRSh_delete_c70f2992.yaml +0 -0
  263. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_models_get_e04cf04b.yaml +0 -0
  264. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_models_gpt-4_get_b13c5b23.yaml +0 -0
  265. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_moderations_post_532b3315.yaml +0 -0
  266. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_responses_post_33fb1f66.yaml +0 -0
  267. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_responses_post_5ca556ec.yaml +0 -0
  268. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_responses_post_c05c936e.yaml +0 -0
  269. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_responses_post_c61e3067.yaml +0 -0
  270. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_responses_post_ee2423e6.yaml +0 -0
@@ -22,17 +22,25 @@ jobs:
22
22
  test:
23
23
  strategy:
24
24
  matrix:
25
- os: [ubuntu-latest, macos-latest]
25
+ os: [ubuntu-latest, macos-latest, windows-latest]
26
26
  python-version: ["3.11", "3.12", "3.13"]
27
27
  runs-on: ${{ matrix.os }}
28
28
  steps:
29
29
  - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
30
- - uses: actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c # v4.9.1
30
+ - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
31
31
  with:
32
32
  python-version: ${{ matrix.python-version }}
33
33
  - name: install deps
34
34
  run: pip install .[testing]
35
- - run: |
35
+ # Windows: Use vanilla pytest (riot doesn't support Windows - see https://github.com/DataDog/riot/issues/74)
36
+ - name: Run tests (Windows - direct pytest)
37
+ if: runner.os == 'Windows'
38
+ run: |
39
+ echo "Using pytest directly due to riot Windows limitation (https://github.com/DataDog/riot/issues/74)"
40
+ python -m pytest -v --basetemp=$env:TEMP\pytest tests/ --ignore=tests/test_container.py
41
+ - name: Run tests (Unix - riot)
42
+ if: runner.os != 'Windows'
43
+ run: |
36
44
  riot run --pass-env -p ${{ matrix.python-version}} test
37
45
  cassettes-size:
38
46
  runs-on: ubuntu-latest
@@ -41,12 +49,12 @@ jobs:
41
49
  - name: Check VCR cassettes size
42
50
  run: |
43
51
  CASSETTES_SIZE=$(du -sb vcr-cassettes/ 2>/dev/null | cut -f1 || echo "0")
44
-
52
+
45
53
  MAX_SIZE=2097152
46
-
54
+
47
55
  echo "VCR cassettes size: ${CASSETTES_SIZE} bytes ($((CASSETTES_SIZE / 1024 / 1024))MB)"
48
56
  echo "Maximum allowed size: ${MAX_SIZE} bytes (2MB)"
49
-
57
+
50
58
  if [ "$CASSETTES_SIZE" -gt "$MAX_SIZE" ]; then
51
59
  echo "❌ VCR cassettes directory is larger than 2MB!"
52
60
  echo "Current size: $((CASSETTES_SIZE / 1024 / 1024))MB"
@@ -55,4 +63,4 @@ jobs:
55
63
  else
56
64
  echo "✅ VCR cassettes directory size is within limits"
57
65
  fi
58
-
66
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ddapm-test-agent
3
- Version: 1.34.0
3
+ Version: 1.35.0
4
4
  Summary: Test agent for Datadog APM client libraries
5
5
  Home-page: https://github.com/Datadog/dd-apm-test-agent
6
6
  Author: Kyle Verhoog
@@ -25,10 +25,12 @@ Requires-Dist: requests-aws4auth
25
25
  Requires-Dist: opentelemetry-proto<1.37.0,>1.33.0
26
26
  Requires-Dist: protobuf>=3.19.0
27
27
  Requires-Dist: grpcio<2.0,>=1.66.2
28
+ Requires-Dist: pywin32; sys_platform == "win32"
28
29
  Provides-Extra: testing
29
30
  Requires-Dist: ddtrace==3.11.0; extra == "testing"
30
31
  Requires-Dist: pytest; extra == "testing"
31
32
  Requires-Dist: riot==0.20.1; extra == "testing"
33
+ Requires-Dist: PyYAML==6.0.3; extra == "testing"
32
34
  Dynamic: author
33
35
  Dynamic: author-email
34
36
  Dynamic: classifier
@@ -183,7 +185,33 @@ The cassettes are matched based on the path, method, and body of the request. To
183
185
  -v $PWD/vcr-cassettes:/vcr-cassettes
184
186
  ghcr.io/datadog/dd-apm-test-agent/ddapm-test-agent:latest
185
187
 
186
- Optionally specifying whatever mounted path is used for the cassettes directory. The test agent comes with a default set of cassettes for OpenAI, Azure OpenAI, and DeepSeek.
188
+ Optionally specifying whatever mounted path is used for the cassettes directory. The test agent comes with a default set of cassettes for OpenAI, Azure OpenAI, DeepSeek, Anthropic, Google GenAI, and AWS Bedrock Runtime.
189
+
190
+ #### Custom 3rd Party Providers
191
+
192
+ The test agent can be configured to also register custom 3rd party providers. This is done by setting the `VCR_PROVIDER_MAP` environment variable or the `--vcr-provider-map` command-line option to a comma-separated list of provider names and their corresponding base URLs.
193
+
194
+ ```shell
195
+ VCR_PROVIDER_MAP="provider1=http://provider1.com/,provider2=http://provider2.com/"
196
+ ```
197
+
198
+ or
199
+
200
+ ```shell
201
+ --vcr-provider-map="provider1=http://provider1.com/,provider2=http://provider2.com/"
202
+ ```
203
+
204
+ The provider names are used to match the provider name in the request path, and the base URLs are used to proxy the request to the corresponding provider API endpoint.
205
+
206
+ With this configuration set, you can make the following request to the test agent without error:
207
+
208
+ ```shell
209
+ curl -X POST 'http://127.0.0.1:9126/vcr/provider1/some/path'
210
+ ```
211
+
212
+ #### Ignoring Headers in Recorded Cassettes
213
+
214
+ To ignore headers in recorded cassettes, you can use the `--vcr-ignore-headers` flag or `VCR_IGNORE_HEADERS` environment variable. The list should take the form of `header1,header2,header3`, and will be omitted from the recorded cassettes.
187
215
 
188
216
  #### AWS Services
189
217
  AWS service proxying, specifically recording cassettes for the first time, requires a `AWS_SECRET_ACCESS_KEY` environment variable to be set for the container running the test agent. This is used to recalculate the AWS signature for the request, as the one generated client-side likely used `{test-agent-host}:{test-agent-port}/vcr/{aws-service}` as the host, and the signature will mismatch that on the actual AWS service.
@@ -139,7 +139,33 @@ The cassettes are matched based on the path, method, and body of the request. To
139
139
  -v $PWD/vcr-cassettes:/vcr-cassettes
140
140
  ghcr.io/datadog/dd-apm-test-agent/ddapm-test-agent:latest
141
141
 
142
- Optionally specifying whatever mounted path is used for the cassettes directory. The test agent comes with a default set of cassettes for OpenAI, Azure OpenAI, and DeepSeek.
142
+ Optionally specifying whatever mounted path is used for the cassettes directory. The test agent comes with a default set of cassettes for OpenAI, Azure OpenAI, DeepSeek, Anthropic, Google GenAI, and AWS Bedrock Runtime.
143
+
144
+ #### Custom 3rd Party Providers
145
+
146
+ The test agent can be configured to also register custom 3rd party providers. This is done by setting the `VCR_PROVIDER_MAP` environment variable or the `--vcr-provider-map` command-line option to a comma-separated list of provider names and their corresponding base URLs.
147
+
148
+ ```shell
149
+ VCR_PROVIDER_MAP="provider1=http://provider1.com/,provider2=http://provider2.com/"
150
+ ```
151
+
152
+ or
153
+
154
+ ```shell
155
+ --vcr-provider-map="provider1=http://provider1.com/,provider2=http://provider2.com/"
156
+ ```
157
+
158
+ The provider names are used to match the provider name in the request path, and the base URLs are used to proxy the request to the corresponding provider API endpoint.
159
+
160
+ With this configuration set, you can make the following request to the test agent without error:
161
+
162
+ ```shell
163
+ curl -X POST 'http://127.0.0.1:9126/vcr/provider1/some/path'
164
+ ```
165
+
166
+ #### Ignoring Headers in Recorded Cassettes
167
+
168
+ To ignore headers in recorded cassettes, you can use the `--vcr-ignore-headers` flag or `VCR_IGNORE_HEADERS` environment variable. The list should take the form of `header1,header2,header3`, and will be omitted from the recorded cassettes.
143
169
 
144
170
  #### AWS Services
145
171
  AWS service proxying, specifically recording cassettes for the first time, requires a `AWS_SECRET_ACCESS_KEY` environment variable to be set for the container running the test agent. This is used to recalculate the AWS signature for the request, as the one generated client-side likely used `{test-agent-host}:{test-agent-port}/vcr/{aws-service}` as the host, and the signature will mismatch that on the actual AWS service.
@@ -9,10 +9,12 @@ from dataclasses import field
9
9
  import json
10
10
  import logging
11
11
  import os
12
+ import platform
12
13
  import pprint
13
14
  import re
14
15
  import socket
15
16
  import sys
17
+ import threading
16
18
  from typing import Any
17
19
  from typing import Awaitable
18
20
  from typing import Callable
@@ -240,6 +242,59 @@ def default_value_trace_results_summary():
240
242
  }
241
243
 
242
244
 
245
+ class MockQuery:
246
+ """Mock query object that behaves like a dict."""
247
+
248
+ def __init__(self):
249
+ self._data = {} # Empty query params for named pipe processing
250
+
251
+ def get(self, key, default=None):
252
+ return self._data.get(key, default)
253
+
254
+ def __getitem__(self, key):
255
+ return self._data[key]
256
+
257
+ def __contains__(self, key):
258
+ return key in self._data
259
+
260
+
261
+ class MockURL:
262
+ """Mock URL object for named pipe processing."""
263
+
264
+ def __init__(self, path: str):
265
+ self.path = path
266
+ self.query = MockQuery()
267
+
268
+
269
+ class MockRequest:
270
+ """Mock Request object for named pipe processing."""
271
+
272
+ def __init__(
273
+ self, method: str, path: str, headers: Dict[str, str], body: bytes, agent: "Agent", app: web.Application
274
+ ):
275
+ self.method = method
276
+ self.path = path
277
+ self.headers = headers
278
+ self._body = body
279
+ self._data: Dict[str, Any] = {}
280
+ self.url = MockURL(path)
281
+ self.content_type = headers.get("Content-Type", "application/msgpack")
282
+ self.app = app
283
+
284
+ async def read(self) -> bytes:
285
+ """Mock read() method that returns the body data."""
286
+ return self._body
287
+
288
+ def __getitem__(self, key):
289
+ return self._data.get(key)
290
+
291
+ def __setitem__(self, key, value):
292
+ self._data[key] = value
293
+
294
+ def get(self, key, default=None):
295
+ return self._data.get(key, default)
296
+
297
+
243
298
  @dataclass
244
299
  class _AgentSession:
245
300
  """Maintain Agent state across requests."""
@@ -1287,6 +1342,174 @@ class Agent:
1287
1342
  raise web.HTTPBadRequest(body=msg)
1288
1343
  return response
1289
1344
 
1345
+ def _parse_http_request(self, data: bytes) -> tuple[str, str, Dict[str, str], bytes]:
1346
+ """Parse HTTP request from raw bytes.
1347
+
1348
+ Returns:
1349
+ tuple: (method, path, headers_dict, body)
1350
+ """
1351
+ try:
1352
+ # Split request into headers and body
1353
+ if b"\r\n\r\n" in data:
1354
+ header_data, body = data.split(b"\r\n\r\n", 1)
1355
+ else:
1356
+ header_data, body = data, b""
1357
+
1358
+ # Parse headers
1359
+ header_lines = header_data.decode("utf-8", errors="ignore").split("\r\n")
1360
+ if not header_lines:
1361
+ raise ValueError("No request line found")
1362
+
1363
+ # Parse request line (e.g., "POST /v0.4/traces HTTP/1.1")
1364
+ request_line = header_lines[0]
1365
+ parts = request_line.split(" ")
1366
+ if len(parts) < 2:
1367
+ raise ValueError(f"Invalid request line: {request_line}")
1368
+
1369
+ method = parts[0]
1370
+ path = parts[1]
1371
+
1372
+ # Parse headers
1373
+ headers: Dict[str, str] = {}
1374
+ for line in header_lines[1:]:
1375
+ if ":" in line:
1376
+ key, value = line.split(":", 1)
1377
+ headers[key.strip()] = value.strip()
1378
+
1379
+ return method, path, headers, body
1380
+
1381
+ except Exception as e:
1382
+ log.error(f"Error parsing HTTP request: {e}")
1383
+ raise ValueError(f"Failed to parse HTTP request: {e}") from e
1384
+
1385
+ def _process_named_pipe_request(self, data: bytes, app: web.Application) -> bytes:
1386
+ """Process a request using the existing Agent infrastructure."""
1387
+ try:
1388
+ # Parse the HTTP request
1389
+ method, path, headers, body = self._parse_http_request(data)
1390
+
1391
+ log.info(f"Processing Named Pipe request: {method} {path}")
1392
+
1393
+ # Create a mock Request object
1394
+ mock_request = MockRequest(method, path, headers, body, self, app)
1395
+
1396
+ # Extract session token like the middleware does
1397
+ token = None
1398
+ if "X-Datadog-Test-Session-Token" in headers:
1399
+ token = headers["X-Datadog-Test-Session-Token"]
1400
+ mock_request["session_token"] = token
1401
+
1402
+ # Store request data for agent processing
1403
+ mock_request["_testagent_data"] = body
1404
+
1405
+ # Route to appropriate handler based on path using dictionary lookup
1406
+ path_handlers = {
1407
+ "/v0.4/traces": self.handle_v04_traces,
1408
+ "/v0.5/traces": self.handle_v05_traces,
1409
+ "/v0.7/traces": self.handle_v07_traces,
1410
+ "/v1.0/traces": self.handle_v1_traces,
1411
+ "/v0.6/stats": self.handle_v06_tracestats,
1412
+ "/v0.1/pipeline_stats": self.handle_v01_pipelinestats,
1413
+ "/v0.7/config": self.handle_v07_remoteconfig,
1414
+ "/telemetry/proxy/api/v2/apmtelemetry": self.handle_v2_apmtelemetry,
1415
+ "/profiling/v1/input": self.handle_v1_profiling,
1416
+ "/tracer_flare/v1": self.handle_v1_tracer_flare,
1417
+ "/evp_proxy/v2/api/v2/llmobs": self.handle_evp_proxy_v2_api_v2_llmobs,
1418
+ "/evp_proxy/v2/api/intake/llm-obs/v1/eval-metric": self.handle_evp_proxy_v2_llmobs_eval_metric,
1419
+ "/evp_proxy/v2/api/intake/llm-obs/v2/eval-metric": self.handle_evp_proxy_v2_llmobs_eval_metric,
1420
+ "/info": self.handle_info,
1421
+ # Test endpoints
1422
+ "/test/session/start": self.handle_session_start,
1423
+ "/test/session/clear": self.handle_session_clear,
1424
+ "/test/session/snapshot": self.handle_snapshot,
1425
+ "/test/session/traces": self.handle_session_traces,
1426
+ "/test/session/apmtelemetry": self.handle_session_apmtelemetry,
1427
+ "/test/session/tracerflares": self.handle_session_tracerflares,
1428
+ "/test/session/stats": self.handle_session_tracestats,
1429
+ "/test/session/requests": self.handle_session_requests,
1430
+ "/test/session/responses/config": self.handle_v07_remoteconfig_create,
1431
+ "/test/session/responses/config/path": self.handle_v07_remoteconfig_path_create,
1432
+ "/test/traces": self.handle_test_traces,
1433
+ "/test/apmtelemetry": self.handle_test_apmtelemetry,
1434
+ "/test/trace/analyze": self.handle_trace_analyze,
1435
+ "/test/trace_check/failures": self.get_trace_check_failures,
1436
+ "/test/trace_check/clear": self.clear_trace_check_failures,
1437
+ "/test/trace_check/summary": self.get_trace_check_summary,
1438
+ "/test/integrations/tested_versions": self.handle_get_tested_integrations,
1439
+ "/test/settings": self.handle_settings,
1440
+ }
1441
+
1442
+ # Get handler from dictionary lookup
1443
+ handler = path_handlers.get(path)
1444
+ if not handler:
1445
+ return self._create_error_response(404, "Not Found")
1446
+
1447
+ try:
1448
+ # Create a new event loop for this thread if one doesn't exist
1449
+ loop = asyncio.get_event_loop()
1450
+ except RuntimeError:
1451
+ loop = asyncio.new_event_loop()
1452
+ asyncio.set_event_loop(loop)
1453
+
1454
+ # Initialize the CheckTrace context like middleware does
1455
+ start_trace("named_pipe_request %s %s" % (method, path))
1456
+
1457
+ # Run the handler
1458
+ response = loop.run_until_complete(handler(mock_request)) # type: ignore[arg-type]
1459
+
1460
+ # Convert aiohttp response to HTTP bytes
1461
+ return self._convert_response_to_http(response)
1462
+
1463
+ except Exception as e:
1464
+ log.error(f"Error processing Named Pipe request: {e}", exc_info=True)
1465
+ return self._create_error_response(500, "Internal Server Error")
1466
+
1467
+ def _convert_response_to_http(self, response: web.Response) -> bytes:
1468
+ """Convert aiohttp Response to HTTP response bytes."""
1469
+ try:
1470
+ # Build HTTP response
1471
+ status_line = f"HTTP/1.1 {response.status} {response.reason}\r\n"
1472
+
1473
+ # Build headers
1474
+ headers_lines = []
1475
+ for key, value in response.headers.items():
1476
+ headers_lines.append(f"{key}: {value}\r\n")
1477
+
1478
+ # Get response body
1479
+ body_data: bytes
1480
+ if hasattr(response, "body") and response.body:
1481
+ if isinstance(response.body, bytes):
1482
+ body_data = response.body
1483
+ elif isinstance(response.body, str):
1484
+ body_data = response.body.encode()
1485
+ else:
1486
+ # Handle Payload or other types by converting to string first
1487
+ body_data = str(response.body).encode()
1488
+ else:
1489
+ body_data = b""
1490
+
1491
+ # Add Content-Length header if not present
1492
+ if "Content-Length" not in response.headers:
1493
+ headers_lines.append(f"Content-Length: {len(body_data)}\r\n")
1494
+
1495
+ # Combine all parts
1496
+ headers_str = "".join(headers_lines)
1497
+ http_response = status_line + headers_str + "\r\n"
1498
+ return http_response.encode("utf-8") + body_data
1499
+
1500
+ except Exception as e:
1501
+ log.error(f"Error converting response to HTTP: {e}")
1502
+ return self._create_error_response(500, "Internal Server Error")
1503
+
1504
+ def _create_error_response(self, status_code: int, reason: str) -> bytes:
1505
+ """Create an HTTP error response."""
1506
+ body = f"{status_code} {reason}".encode("utf-8")
1507
+ response = f"HTTP/1.1 {status_code} {reason}\r\n"
1508
+ response += f"Content-Length: {len(body)}\r\n"
1509
+ response += "Content-Type: text/plain\r\n"
1510
+ response += "\r\n"
1511
+ return response.encode("utf-8") + body
1512
+
1290
1513
 
1291
1514
  def make_otlp_http_app(agent: Agent) -> web.Application:
1292
1515
  """Create a separate HTTP application for OTLP endpoints using the shared agent instance."""
@@ -1356,6 +1579,8 @@ def make_app(
1356
1579
  snapshot_regex_placeholders: Dict[str, str],
1357
1580
  vcr_cassettes_directory: str,
1358
1581
  vcr_ci_mode: bool,
1582
+ vcr_provider_map: str,
1583
+ vcr_ignore_headers: str,
1359
1584
  ) -> web.Application:
1360
1585
  agent = Agent()
1361
1586
  app = web.Application(
@@ -1417,7 +1642,9 @@ def make_app(
1417
1642
  web.route(
1418
1643
  "*",
1419
1644
  "/vcr/{path:.*}",
1420
- lambda request: proxy_request(request, vcr_cassettes_directory, vcr_ci_mode),
1645
+ lambda request: proxy_request(
1646
+ request, vcr_cassettes_directory, vcr_ci_mode, vcr_provider_map, vcr_ignore_headers
1647
+ ),
1421
1648
  ),
1422
1649
  ]
1423
1650
  )
@@ -1449,6 +1676,137 @@ def make_app(
1449
1676
  return app
1450
1677
 
1451
1678
 
1679
+ def _start_named_pipe_server(pipe_path: str, agent: "Agent", app: web.Application) -> None:
1680
+ """Start Windows named pipe server."""
1681
+ if platform.system() != "Windows":
1682
+ log.warning("Named pipes are only supported on Windows, ignoring --trace-named-pipe")
1683
+ return
1684
+
1685
+ # Import Windows-specific modules here to avoid import errors on other platforms
1686
+ try:
1687
+ import win32file
1688
+ import win32pipe
1689
+ except ImportError as e:
1690
+ log.error(f"Failed to import Windows modules for named pipes: {e}")
1691
+ return
1692
+
1693
+ _start_windows_named_pipe_server(pipe_path, agent, app, win32pipe, win32file)
1694
+
1695
+
1696
+ def _create_and_wait_for_client(
1697
+ pipe_path: str, agent: "Agent", app: web.Application, win32pipe: Any, win32file: Any
1698
+ ) -> None:
1699
+ """Create a single pipe instance and wait for a client connection."""
1700
+ while True:
1701
+ try:
1702
+ # Create named pipe instance
1703
+ pipe_handle = win32pipe.CreateNamedPipe(
1704
+ pipe_path,
1705
+ win32pipe.PIPE_ACCESS_DUPLEX,
1706
+ win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_READMODE_MESSAGE | win32pipe.PIPE_WAIT,
1707
+ win32pipe.PIPE_UNLIMITED_INSTANCES, # allow multiple concurrent connections
1708
+ 65536, # output buffer size
1709
+ 65536, # input buffer size
1710
+ 0, # default timeout
1711
+ None, # security attributes
1712
+ )
1713
+
1714
+ if pipe_handle == win32file.INVALID_HANDLE_VALUE:
1715
+ log.error("Failed to create named pipe instance")
1716
+ import time
1717
+
1718
+ time.sleep(1) # Wait before retrying
1719
+ continue
1720
+
1721
+ log.debug("Named pipe instance created, waiting for client...")
1722
+
1723
+ # Wait for client connection
1724
+ win32pipe.ConnectNamedPipe(pipe_handle, None)
1725
+ log.info("Client connected to named pipe instance")
1726
+
1727
+ # Handle the client request
1728
+ _handle_windows_named_pipe_client(pipe_handle, agent, app, win32pipe, win32file)
1729
+
1730
+ except Exception as e:
1731
+ log.error(f"Error in named pipe instance: {e}")
1732
+ import time
1733
+
1734
+ time.sleep(1) # Wait before retrying
1735
+
1736
+
1737
+ def _start_windows_named_pipe_server(
1738
+ pipe_path: str, agent: "Agent", app: web.Application, win32pipe: Any, win32file: Any
1739
+ ) -> None:
1740
+ """Start a Windows named pipe server with multiple instances."""
1741
+ if win32pipe is None:
1742
+ log.error("Windows named pipe support not available (pywin32 not installed)")
1743
+ return
1744
+
1745
+ log.info(f"Starting Windows named pipe server on: {pipe_path}")
1746
+
1747
+ # Create multiple pipe instances for better concurrency
1748
+ num_instances = 10 # Support up to 10 concurrent connections
1749
+ threads = []
1750
+
1751
+ for _ in range(num_instances):
1752
+ thread = threading.Thread(
1753
+ target=_create_and_wait_for_client, args=(pipe_path, agent, app, win32pipe, win32file), daemon=True
1754
+ )
1755
+ thread.start()
1756
+ threads.append(thread)
1757
+
1758
+ log.info(f"Started {num_instances} named pipe instances")
1759
+
1760
+ # Keep the main thread alive and monitor instance threads
1761
+ try:
1762
+ while True:
1763
+ import time
1764
+
1765
+ time.sleep(5)
1766
+
1767
+ # Check if any threads have died and restart them
1768
+ for i, thread in enumerate(threads):
1769
+ if not thread.is_alive():
1770
+ log.warning(f"Restarting named pipe instance {i}")
1771
+ new_thread = threading.Thread(
1772
+ target=_create_and_wait_for_client,
1773
+ args=(pipe_path, agent, app, win32pipe, win32file),
1774
+ daemon=True,
1775
+ )
1776
+ new_thread.start()
1777
+ threads[i] = new_thread
1778
+
1779
+ except KeyboardInterrupt:
1780
+ log.info("Named pipe server shutting down")
1781
+
1782
+
1783
+ def _handle_windows_named_pipe_client(
1784
+ pipe_handle: Any, agent: "Agent", app: web.Application, win32pipe: Any, win32file: Any
1785
+ ) -> None:
1786
+ """Handle a Windows named pipe client connection."""
1787
+ try:
1788
+ # Read request data
1789
+ result, data = win32file.ReadFile(pipe_handle, 65536)
1790
+ if result == 0: # SUCCESS
1791
+ log.info(f"Received {len(data)} bytes from named pipe client")
1792
+
1793
+ # Process request
1794
+ response = agent._process_named_pipe_request(data, app)
1795
+
1796
+ # Write response
1797
+ win32file.WriteFile(pipe_handle, response)
1798
+ log.info(f"Sent {len(response)} bytes response to named pipe client")
1799
+
1800
+ except Exception as e:
1801
+ log.error(f"Error handling Windows named pipe client: {e}")
1802
+ finally:
1803
+ try:
1804
+ win32pipe.DisconnectNamedPipe(pipe_handle)
1805
+ win32file.CloseHandle(pipe_handle)
1806
+ except Exception:
1807
+ pass
1808
+
1809
+
1452
1810
  def main(args: Optional[List[str]] = None) -> None:
1453
1811
  if args is None:
1454
1812
  args = sys.argv[1:]
@@ -1550,6 +1908,12 @@ def main(args: Optional[List[str]] = None) -> None:
1550
1908
  default=os.environ.get("DD_APM_RECEIVER_SOCKET", None),
1551
1909
  help=("Will listen for traces on the specified socket path"),
1552
1910
  )
1911
+ parser.add_argument(
1912
+ "--trace-named-pipe",
1913
+ type=str,
1914
+ default=os.environ.get("DD_APM_RECEIVER_NAMED_PIPE", None),
1915
+ help=("Will listen for traces on the specified named pipe path"),
1916
+ )
1553
1917
  parser.add_argument(
1554
1918
  "--trace-request-delay",
1555
1919
  type=float,
@@ -1588,6 +1952,18 @@ def main(args: Optional[List[str]] = None) -> None:
1588
1952
  default=os.environ.get("VCR_CI_MODE", False),
1589
1953
  help="Will change the test agent to record VCR cassettes in CI mode, throwing an error if a cassette is not found on /vcr/{provider}",
1590
1954
  )
1955
+ parser.add_argument(
1956
+ "--vcr-provider-map",
1957
+ type=str,
1958
+ default=os.environ.get("VCR_PROVIDER_MAP", ""),
1959
+ help="Comma-separated list of provider=base_url tuples to map providers to paths. Used in addition to the default provider paths.",
1960
+ )
1961
+ parser.add_argument(
1962
+ "--vcr-ignore-headers",
1963
+ type=str,
1964
+ default=os.environ.get("VCR_IGNORE_HEADERS", ""),
1965
+ help="Comma-separated list of headers to ignore when recording VCR cassettes.",
1966
+ )
1591
1967
  parsed_args = parser.parse_args(args=args)
1592
1968
  logging.basicConfig(level=parsed_args.log_level)
1593
1969
 
@@ -1632,6 +2008,8 @@ def main(args: Optional[List[str]] = None) -> None:
1632
2008
  snapshot_regex_placeholders=parsed_args.snapshot_regex_placeholders,
1633
2009
  vcr_cassettes_directory=parsed_args.vcr_cassettes_directory,
1634
2010
  vcr_ci_mode=parsed_args.vcr_ci_mode,
2011
+ vcr_provider_map=parsed_args.vcr_provider_map,
2012
+ vcr_ignore_headers=parsed_args.vcr_ignore_headers,
1635
2013
  )
1636
2014
 
1637
2015
  # Validate port configuration
@@ -1644,6 +2022,18 @@ def main(args: Optional[List[str]] = None) -> None:
1644
2022
 
1645
2023
  # Get the shared agent instance from the main app
1646
2024
  agent = app["agent"]
2025
+
2026
+ # Named pipe setup (after agent is available)
2027
+ named_pipe_thread = None
2028
+ if parsed_args.trace_named_pipe is not None:
2029
+
2030
+ def start_named_pipe_server():
2031
+ _start_named_pipe_server(parsed_args.trace_named_pipe, agent, app)
2032
+
2033
+ named_pipe_thread = threading.Thread(target=start_named_pipe_server, daemon=True)
2034
+ named_pipe_thread.start()
2035
+ log.info(f"Started named pipe server on: {parsed_args.trace_named_pipe}")
2036
+
1647
2037
  otlp_http_app = make_otlp_http_app(agent)
1648
2038
 
1649
2039
  async def run_servers():
@@ -34,6 +34,27 @@ log = logging.getLogger(__name__)
34
34
  DEFAULT_SNAPSHOT_IGNORES = "span_id,trace_id,parent_id,duration,start,metrics.system.pid,metrics.system.process_id,metrics.process_id,metrics._dd.tracer_kr,meta.runtime-id,span_links.trace_id_high,span_events.time_unix_nano,meta.pathway.hash,meta._dd.p.tid"
35
35
 
36
36
 
37
+ def _normalize_span_for_comparison(span: Span) -> Span:
38
+ """Normalize span for cross-platform comparison (Windows vs Unix).
39
+
40
+ Handles differences in how ddtrace creates spans on different platforms:
41
+ - Windows may omit fields with default values (error, type)
42
+ - Windows may use None instead of empty string for service
43
+ """
44
+ normalized = dict(span)
45
+
46
+ if "error" not in normalized:
47
+ normalized["error"] = 0
48
+
49
+ if "type" not in normalized:
50
+ normalized["type"] = ""
51
+
52
+ if normalized.get("service") is None:
53
+ normalized["service"] = ""
54
+
55
+ return cast(Span, normalized)
56
+
57
+
37
58
  def _key_match(d1: Dict[str, Any], d2: Dict[str, Any], key: str) -> bool:
38
59
  """
39
60
  >>> _key_match({"a": 1}, {"a": 2}, "a")
@@ -347,6 +368,10 @@ def _compare_traces(expected: Trace, received: Trace, ignored: Set[str]) -> None
347
368
  )
348
369
 
349
370
  for s_exp, s_rec in zip(expected, received):
371
+ # Normalize spans for cross-platform comparison (Windows vs Unix)
372
+ s_exp_norm = _normalize_span_for_comparison(s_exp)
373
+ s_rec_norm = _normalize_span_for_comparison(s_rec)
374
+
350
375
  with CheckTrace.add_frame(
351
376
  f"snapshot compare of span '{s_exp['name']}' at position {s_exp['span_id']} in trace"
352
377
  ) as frame:
@@ -358,12 +383,12 @@ def _compare_traces(expected: Trace, received: Trace, ignored: Set[str]) -> None
358
383
  metrics_diffs,
359
384
  span_link_diffs,
360
385
  span_event_diffs,
361
- ) = _diff_spans(s_exp, s_rec, ignored)
386
+ ) = _diff_spans(s_exp_norm, s_rec_norm, ignored)
362
387
 
363
388
  for diffs, diff_type, d_exp, d_rec in [
364
- (top_level_diffs, "span", s_exp, s_rec),
365
- (meta_diffs, "meta", s_exp["meta"], s_rec["meta"]),
366
- (metrics_diffs, "metrics", s_exp["metrics"], s_rec["metrics"]),
389
+ (top_level_diffs, "span", s_exp_norm, s_rec_norm),
390
+ (meta_diffs, "meta", s_exp_norm["meta"], s_rec_norm["meta"]),
391
+ (metrics_diffs, "metrics", s_exp_norm["metrics"], s_rec_norm["metrics"]),
367
392
  ]:
368
393
  for diff_key in diffs:
369
394
  if diff_key not in d_exp: