Skip to content

Feature branch for httpx migration#22676

Draft
mwdd146980 wants to merge 34 commits intomasterfrom
mwdd146980/httpx-migration-base
Draft

Feature branch for httpx migration#22676
mwdd146980 wants to merge 34 commits intomasterfrom
mwdd146980/httpx-migration-base

Conversation

@mwdd146980
Copy link
Copy Markdown
Contributor

@mwdd146980 mwdd146980 commented Feb 18, 2026

What does this PR do?

Feature branch for the requestshttpx migration. Introduces library-agnostic HTTP infrastructure and decouples integration tests from requests internals. See the RFC for full context.

Approach

Infrastructure — New modules in datadog_checks_base provide a library-agnostic HTTP layer:

  • http_protocolHTTPClientProtocol and HTTPResponseProtocol define the contract that tests and production code program to
  • http_exceptions — Exception hierarchy decoupled from requests
  • http_testingMockHTTPResponse, replacing the requests-coupled MockResponse
  • get_header()/set_header() added to RequestsWrapper so production code and tests can manipulate headers without reaching into requests internals
  • mock_http pytest fixture patches AgentCheck.http at the property level. The OM V2 scraper was changed to reuse check.http, so a single patch covers both scraper and check.

Test migrations — 36 integration test suites migrated to the new layer. Tests that patched requests.Session or matched against requests.exceptions now use mock_http and HTTPStatusError, so they'll work unchanged when the underlying client switches to httpx.

Status

Work in progress. Subsequent steps are stacked PRs that merge here after review.

Step PR Status
Infrastructure (protocol, exceptions, MockHTTPResponse) #22676, #22680 ✅ On feature branch
mock_http fixture + 9 integrations #22710 ✅ Merged
Config assertions + get/set_header (19 intg) #22722 ✅ Merged
Widen except clauses + align MockHTTPResponse #22864 ✅ Merged
Swap mock_http_response to MockHTTPResponse #22935 ✅ Merged
Widen production except clauses #23046 ✅ Merged
Batch migrate MockResponse → MockHTTPResponse #23207 ✅ Merged
Migrate conftest.py fixture chains #23226 ✅ Merged

Verification

  • All existing unit tests pass with the new fixtures
  • MockHTTPResponse covered by dedicated tests
  • Formatting validated with ddev test -fs

@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 18, 2026

Codecov Report

❌ Patch coverage is 92.94872% with 77 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.81%. Comparing base (3fb0c5c) to head (faddc6c).
⚠️ Report is 6 commits behind head on master.

Additional details and impacted files
Flag Coverage Δ
active_directory ?
activemq_xml ?
aerospike ?
airflow ?
amazon_msk ?
ambari ?
apache ?
appgate_sdp ?
arangodb ?
argo_rollouts ?
argo_workflows ?
argocd ?
aspdotnet ?
avi_vantage ?
aws_neuron ?
azure_iot_edge ?
boundary ?
btrfs ?
cacti ?
calico ?
cassandra_nodetool ?
celery ?
ceph ?
cert_manager ?
cilium ?
cisco_aci ?
citrix_hypervisor ?
clickhouse ?
cloud_foundry_api ?
cloudera ?
cockroachdb ?
consul ?
coredns ?
couch ?
couchbase ?
crio ?
datadog_checks_base ?
datadog_checks_dev ?
datadog_checks_downloader ?
datadog_cluster_agent ?
dcgm ?
ddev ?
directory ?
disk ?
dns_check ?
dotnetclr ?
druid ?
duckdb ?
ecs_fargate ?
eks_fargate ?
elastic ?
envoy ?
esxi ?
etcd ?
exchange_server ?
external_dns ?
falco ?
fluentd ?
fluxcd ?
fly_io ?
foundationdb ?
gearmand ?
gitlab ?
gitlab_runner ?
glusterfs ?
go_expvar ?
gunicorn ?
haproxy ?
harbor ?
hazelcast ?
hdfs_datanode ?
hdfs_namenode ?
http_check ?
ibm_ace ?
ibm_db2 ?
ibm_i ?
ibm_mq ?
ibm_was ?
iis ?
impala ?
infiniband ?
istio ?
kafka_consumer ?
karpenter ?
keda ?
kong ?
krakend ?
kube_apiserver_metrics ?
kube_controller_manager ?
kube_dns ?
kube_metrics_server ?
kube_proxy ?
kube_scheduler ?
kubeflow ?
kubelet ?
kubernetes_cluster_autoscaler ?
kubernetes_state ?
kubevirt_api ?
kubevirt_controller ?
kubevirt_handler ?
kuma ?
kyototycoon ?
kyverno ?
lighttpd ?
linkerd ?
linux_proc_extras ?
litellm ?
lustre ?
mac_audit_logs ?
mapr ?
mapreduce ?
marathon ?
marklogic ?
mcache ?
mesos_master ?
milvus ?
mongo ?
mysql ?
nagios ?
network ?
nfsstat ?
nginx ?
nginx_ingress_controller ?
nvidia_nim ?
nvidia_triton ?
octopus_deploy ?
openldap ?
openmetrics ?
openstack ?
openstack_controller ?
pdh_check ?
pgbouncer ?
php_fpm ?
postfix ?
postgres ?
powerdns_recursor ?
process ?
prometheus ?
proxmox ?
proxysql ?
pulsar ?
quarkus ?
rabbitmq ?
ray ?
redisdb ?
rethinkdb ?
riak ?
riakcs ?
sap_hana ?
scylla ?
silk ?
silverstripe_cms ?
singlestore ?
slurm ?
snmp ?
sonarqube ?
sonatype_nexus ?
spark ?
sqlserver ?
squid ?
ssh_check ?
statsd ?
strimzi ?
supabase ?
supervisord ?
system_core ?
system_swap ?
tcp_check ?
teamcity ?
tekton ?
teleport ?
temporal ?
teradata ?
tibco_ems ?
tls ?
torchserve ?
traefik_mesh ?
traffic_server ?
twemproxy ?
twistlock ?
varnish ?
vault ?
velero ?
vertica ?
vllm ?
voltdb ?
vsphere ?
weaviate ?
win32_event_log ?
windows_performance_counters ?
windows_service ?
wmi_check ?
yarn ?
zk ?

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread datadog_checks_base/changelog.d/22676.added Outdated
Comment thread datadog_checks_base/datadog_checks/base/utils/http_protocol.py
Comment thread datadog_checks_base/datadog_checks/base/utils/http_exceptions.py Outdated
@mwdd146980 mwdd146980 force-pushed the mwdd146980/httpx-migration-base branch from beb72ad to 07a9003 Compare February 20, 2026 19:16
Copy link
Copy Markdown
Contributor Author

mwdd146980 commented Feb 20, 2026

This stack of pull requests is managed by Graphite. Learn more about stacking.

mwdd146980 and others added 29 commits April 29, 2026 18:02
* Add MockHTTPResponse for library-agnostic HTTP response mocking

MockHTTPResponse implements HTTPResponseProtocol without depending on
requests or httpx. It supports the full response API (.json(), .text,
.content, .status_code, .headers, .cookies, .elapsed), streaming via
iter_content() and iter_lines(), raise_for_status() using HTTPStatusError,
and context manager usage.

Demonstrates usage by migrating test_authtoken.py from MockResponse to
MockHTTPResponse — a drop-in replacement with protocol compliance.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Expand MockHTTPResponse usage to test_openmetrics.py and test_kerberos_unit.py

Also adds three missing API surface members discovered during migration:
- encoding attribute (accessed by openmetrics mixin before iter_lines)
- close() no-op (called by openmetrics mixin after response processing)
- Removes _stream_consumed guard so the same instance can be reused
  across repeated mock.MagicMock(return_value=...) calls

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Reformat with ddev test --fmt

* Fix headers mutation and add case-insensitive header dict

Two correctness fixes in MockHTTPResponse:

1. When json_data and headers are both provided, the caller's headers dict
   was mutated in-place via setdefault(). Now copies before modifying.

2. self.headers was a plain dict (case-sensitive). HTTP headers are
   case-insensitive per RFC 7230 §3.2. Replace with _CaseInsensitiveDict
   that stores keys lowercased, matching requests.Response behaviour.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
No other file in the codebase uses module-level docstrings.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds convenience re-exports so integrations can import HTTP exceptions
from the existing datadog_checks.base.utils.http import path rather
than a new module, supporting a phased migration to httpx.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…sponse

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Redesign mock_http fixture to patch RequestsWrapper at class level

Patches get/post/put/delete/head/patch on RequestsWrapper so all three
HTTP paths are intercepted: AgentCheck.http, OpenMetrics V2 scraper,
and kube* health check handlers. Real RequestsWrapper instances are
still created, so check.http.options remains accessible.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Migrate falco tests from requests.Session.get patch to mock_http fixture

Replace direct mock.patch('requests.Session.get') with the library-agnostic
mock_http fixture and MockHTTPResponse from http_testing.py.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Migrate strimzi tests from requests.Session.get patch to mock_http fixture

Replace direct mocker.patch('requests.Session.get') with the library-agnostic
mock_http fixture and MockHTTPResponse from http_testing.py.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix E402: move pytest_plugins after all imports

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Migrate couchbase tests from requests.Session.get patch to mock_http fixture

Replace direct mocker.patch('requests.Session.get') with the library-agnostic
mock_http fixture and MockHTTPResponse from http_testing.py.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Rename mock_http fixture to mock_http_client

The fixture mocks the HTTP client (RequestsWrapper), not responses.
mock_http_client is more precise and avoids confusion with the existing
mock_http_response fixture from datadog_checks.dev.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Migrate ray tests from requests.Session.get patch to mock_http_client fixture

Replace direct mocker.patch('requests.Session.get') with the library-agnostic
mock_http_client fixture and MockHTTPResponse from http_testing.py.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Migrate tekton tests from requests.Session.get patch to mock_http_client fixture

Replace direct mocker.patch('requests.Session.get') with the library-agnostic
mock_http_client fixture and MockHTTPResponse from http_testing.py.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Switch from pytest_plugins to direct import for fixture registration

Use direct import with noqa: F401 to match the existing codebase pattern.
No other integration uses pytest_plugins for fixture registration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Revert rename: mock_http_client → mock_http

The fixture name mock_http_client was added in the previous commit, but the
team prefers the shorter mock_http name. Revert all usages across integrations
and the fixture definition in http_testing.py.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Redesign mock_http: use create_autospec(HTTPClientProtocol) + PropertyMock on AgentCheck.http

- mock_http now patches AgentCheck.http via PropertyMock with a create_autospec(HTTPClientProtocol)
  client, constraining the mock to the protocol interface and enforcing call signatures
- AgentCheck.http return type updated from RequestsWrapper to HTTPClientProtocol
- OM V2 scraper reuses check.http directly instead of constructing its own RequestsWrapper;
  options access guarded with hasattr for mock compatibility

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Shorten docstring

* Migrate kubevirt_api, kubevirt_controller, kubevirt_handler tests to mock_http fixture

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix Accept header mutation side-effect in OM V2 scraper

base_scraper.py shares check.http via `self.http = check.http`. The
previous code mutated `self.http.options['headers']['Accept']` which
bled through to check.http since they are the same object, breaking
tests that assert check.http.options['headers']['Accept'] == '*/*'.

Fix: store the accept header as self._accept_header and inject it
per-request via extra_headers in send_request. Using extra_headers
(not headers=) is required because RequestsWrapper._request uses
ChainMap — passing headers= directly would shadow the entire session
headers dict rather than merging a single key.

Update test assertions in three files to check scraper._accept_header
instead of scraper.http.options['headers']['Accept'].

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix bentoml tests broken by scraper sharing check.http

After self.http = check.http in the OM V2 scraper, patching
BentomlCheck.http at the class level intercepted scraper HTTP calls too,
causing AttributeError on the minimal mock response. Replace both
patch('BentomlCheck.http') blocks with URL-based dispatch on the
already-patched requests.Session.get mock.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix Vault auth headers lost when OM V2 scraper reuses check.http

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Raise NotImplementedError for options_method in mock_http fixture

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Move mock_http fixture to datadog_checks_dev pytest plugin

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Remove call_count assertion from bentoml test

Asserting on the number of HTTP calls ties the test to implementation
details rather than observable behavior (metrics, service checks).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Drop unused get_mock variable in bentoml test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- base_scraper: use self.check.http instead of local check.http parameter
- base_scraper: move accept_header from instance variable to local in send_request
- openmetrics tests: replace scraper._accept_header assertion with call_args header inspection
- bentoml tests: remove duplicate assert_all_metrics_covered call
- bentoml tests: replace requests.HTTPError with HTTPStatusError from http_exceptions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…_accept_header

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rim comments

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add get_header/set_header (case-insensitive) to RequestsWrapper and
HTTPClientProtocol, then migrate 16 integration test suites from patching
requests.Session internals to asserting against check.http.options and
using the mock_http fixture.

- Add get_header/set_header to RequestsWrapper with case-insensitive
  key lookup; use set_header in Vault's __init__ auth header setup
- Extend HTTPClientProtocol with options property and get/set_header
- Migrate config assertion tests: airflow, consul, couch, druid,
  ecs_fargate, envoy, etcd, gitlab_runner, marathon, mesos_master,
  mesos_slave, nginx, openmetrics, php_fpm, squid, teamcity
- Update mock_http fixture to expose client.options as a real dict
- Flatten test classes to top-level functions in test_headers.py
- Remove dead assertions in rabbitmq and torchserve tests
)

* Migrate couch config assertion test to check.http.options

Replace mock.patch('...requests.Session') + assert_called_with pattern
with direct check.http.options assertions. Config parsing is verified
without needing to mock HTTP calls or run the check.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Migrate couch config assertion test to http_client_session

Replace mock.patch('...requests.Session') + assert_called_with pattern
with the new http_client_session fixture. The full _request() option-merging
flow now runs, and assertions verify the kwargs forwarded to session.get().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Migrate gitlab_runner timeout test to http_client_session

Replace mock.patch('...requests.Session') + assert_called_with pattern
with the new http_client_session fixture. The full _request() option-merging
flow now runs, and the assertion verifies the timeout kwarg forwarded to
session.get().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Reformat with ddev test --fmt

* Migrate marathon config assertion test to http_client_session

Replace mock.patch('...requests.Session') + assert_called_with pattern
with the new http_client_session fixture. Also replace third-party mock
import with unittest.mock throughout the file.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Migrate rabbitmq session-patch tests to http_client_session

Replace mock.patch('...requests.Session') with the http_client_session
fixture in test__get_data (error-handling) and test_config (config
assertion).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Migrate consul session-patch tests to http_client_session

Replace mock.patch('...requests.Session') patterns with the
http_client_session fixture in test_consul_request (error-handling)
and test_config (config assertion).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Migrate torchserve session-patch test to http_client_session

Extend _CanonicalMock with call_count, call_args, and call_args_list
properties to support tests that introspect individual calls beyond
assert_called_with. Then migrate test_get_models to use the fixture
instead of patching requests.Session directly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Migrate etcd, ecs_fargate, mesos_master session-patch tests to http_client_session

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Reformat with ddev test --fmt

* Scrap http_client_session; migrate Step 2 tests to check.http.options and mock_http

- Remove http_client_session fixture, _CanonicalMock, and supporting code from
  http_testing.py; update __all__ to ['MockHTTPResponse', 'mock_http']
- Config tests (couch, gitlab_runner, marathon, rabbitmq, consul, etcd,
  ecs_fargate): drop http_client_session + check.check() + URL assertion;
  assert check.http.options[key] == value directly — no HTTP call needed
- Functional tests (rabbitmq test__get_data, consul test_consul_request,
  mesos_master test_can_connect_service_check, torchserve test_get_models):
  replace http_client_session with mock_http
- mesos_master: set mock_http.options = {'verify': True} before check
  instantiation since MesosMaster.__init__ reads self.http.options['verify']

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Migrate airflow session-patch tests to mock_http

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Migrate druid session-patch tests to mock_http

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Migrate mesos_slave session-patch tests to mock_http

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Migrate nginx session-patch tests to check.http.options and mock_http

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Migrate php_fpm session-patch tests to check.http.options and mock_http

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add options to HTTPClientProtocol; initialize in mock_http fixture

create_autospec does not expose Protocol class-variable annotations at
runtime, so mock_http now explicitly sets client.options = MagicMock(spec=dict).
This provides a proper dict-like mock for any check that reads http.options
in __init__ (mesos_slave, mesos_master), removing the per-test workaround
of assigning mock_http.options = {'verify': True} before instantiation.

With options always present on the mock, the hasattr guard in
base_scraper.py is also removed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Remove mock_http from http_testing.py; use datadog_checks_dev plugin fixture

mock_http was moved to datadog_checks_dev/plugin/pytest.py in PR #22710 and is
auto-available to all tests via the plugin. Remove the duplicate definition from
http_testing.py and drop the now-unnecessary noqa: F401 conftest imports.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix mock_http fixture: initialize client.options as MagicMock

Protocol annotation-only attributes (options: dict[str, Any]) are not
included in dir() and thus not auto-mocked by create_autospec. Checks
like mesos_master that access self.http.options in __init__ raised
AttributeError when using the mock_http fixture.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix mock_http fixture: use real dict for client.options

MagicMock does not preserve dict item assignment, so any check that
writes to self.http.options in __init__ would silently discard the
mutation when tested with mock_http. Use a real dict with the standard
RequestsWrapper keys so item assignment and retrieval work correctly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Flatten test classes to top-level functions in test_headers.py and test_http_testing.py

Match the dominant repo convention of top-level test functions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Make get_header/set_header case-insensitive

Both requests and httpx treat headers case-insensitively, so the API
should too. Case folding happens inside the methods; options['headers']
remains a plain dict. set_header preserves the original key casing when
overwriting an existing entry.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Align MockHTTPResponse + widen production except clauses (PR 3a)

MockHTTPResponse alignment (http_testing.py):
- Add textwrap.dedent() to string content normalization
- Add .ok and .reason properties

Production except clause widening (only clauses exercised by
mock_http_response error tests):
- openmetrics/v2/base.py: add HTTPRequestError, HTTPStatusError
- traefik_mesh/check.py: add HTTPStatusError, HTTPConnectionError

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Address PR 3a review: protocol gaps, transitional comment, timeout handling

Add ok/reason properties to HTTPResponseProtocol to match production usage,
widen traefik_mesh timeout handler with HTTPTimeoutError, add transitional
comment to OM V2 except clause, and add tests for ok/reason on MockHTTPResponse.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Address agint-review follow-ups: dedent test, exception tests, get_version fix

- Add test exercising dedent with indented multi-line content (item 2)
- Add transitional comment to MockHTTPResponse.ok property (item 3)
- Add tests for library-agnostic exception handling in _get_json (item 7)
- Remove unused url parameter from traefik_mesh get_version (item 9)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Update dependency resolution (#23159)

Co-authored-by: Kyle-Neale <37895372+Kyle-Neale@users.noreply.github.com>

* Swap mock_http_response fixture from MockResponse to MockHTTPResponse

Replace the requests-coupled MockResponse with the library-agnostic
MockHTTPResponse in the mock_response fixture, decoupling ~102 test
files from the requests library without touching individual test code.

- Swap mock_response fixture to yield MockHTTPResponse
- Fix mock_http_response_per_endpoint fallback to use fixture parameter
- Remove sonatype_nexus local fixture override (now redundant)
- Update match strings in 9 integrations from requests.exceptions.HTTPError
  to HTTPStatusError (our own shared exception class)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add parameter order comment + fix sonatype_nexus test bug

Document that MockHTTPResponse has a different parameter order than
MockResponse (all callers use keyword args, so not a compatibility
concern).

Fix test_successful_metrics_collection which was passing vacuously:
dict.update() returns None so json_data was always None, the check's
json decode failed silently, no metrics were submitted, and
assert_all_metrics_covered() trivially passed. Provide complete mock
data for both API calls and add individual metric assertions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Re-add _CaseInsensitiveDict to MockHTTPResponse for step3b fixture swap

Step3b will make MockHTTPResponse the backing for all mock_http_response
fixture users (~102 test files). Production code accesses headers with
original-case keys (e.g. response.headers['Content-Type']), which would
KeyError or silently return wrong values with the plain lowered-key dict.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Address PR 3b review: harden _CaseInsensitiveDict, fix test redundancy

- Add missing dict methods (__delitem__, pop, update, setdefault) to
  _CaseInsensitiveDict so tests won't silently break if production code
  uses them on response headers
- Make isinstance guards consistent across all methods
- Replace redundant `assert in` checks with mixed-case .get() per
  reviewer suggestion; add tests for new dict methods
- Add TODO(httpx-migration) comment on per-endpoint fixture default

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix response.raw and response.url on MockHTTPResponse

Make raw.read delegate to BytesIO stream so json.load(r.raw) works
(fixes kubelet_base test regression). Add url attribute with default ''
(fixes sonatype_nexus test_timeout_error accessing response.url).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Address agint-review nits: fix iterable update, add url test, remove dead args

- Fix _CaseInsensitiveDict.update() to lowercase keys from iterable-of-pairs
- Add test_mock_response_url() for MockHTTPResponse url parameter
- Remove dead URL positional args from 7 sonatype_nexus test calls

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Address review round 2: revert test churn, extract mock method constant

- Revert unnecessary Content-Type → content-type case change in test
- Extract _DEFAULT_MOCK_METHOD constant for requests.Session.get default

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: datadog-agent-integrations-bot[bot] <159767151+datadog-agent-integrations-bot[bot]@users.noreply.github.com>
Co-authored-by: Kyle-Neale <37895372+Kyle-Neale@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Widen per-integration except clauses for library-agnostic HTTP exceptions

Add library-agnostic exception types alongside existing requests-specific
exceptions in 7 integrations, preparing for Step 3d's MockHTTPResponse
migration. Also add HTTPInvalidURLError to the http_exceptions module.

Integrations: elastic, fly_io, harbor, octopus_deploy,
openstack_controller, proxmox, spark.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Include AgentHTTPConnectionError in spark connection suppression check

Widen the isinstance guard so that connection errors from the
library-agnostic HTTP layer also go through _should_suppress_connection_error,
keeping debouncing behavior consistent across backends.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add None guard for e.response in harbor except clauses

HTTPStatusError allows response=None by default. Guard against
AttributeError when accessing e.response.status_code, matching
the pattern already used in elastic.py.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix _CaseInsensitiveDict.update for non-dict Mapping inputs

isinstance(other, dict) misses Mapping subclasses that don't inherit
from dict (e.g. httpx.Headers). Iterating a Mapping yields keys only,
causing ValueError on the (k, v) unpack. Use isinstance(other, Mapping)
so .items() is called for any mapping type.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Widen Timeout/ReadTimeout except clauses to catch HTTPTimeoutError

Add HTTPTimeoutError from the library-agnostic exception hierarchy
alongside requests.Timeout/ReadTimeout in 27 except clauses across
15 integrations. This ensures timeout handling will continue to work
when the HTTP backend switches from requests to httpx.

Integrations: airflow, consul, couch, druid, ecs_fargate, elastic,
envoy, gitlab, gitlab_runner, marathon, mesos_master, openstack,
openstack_controller, sonatype_nexus, vault

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* reformat with ddev test --fmt

* Widen except clauses in proxmox, elastic, citrix_hypervisor for httpx compat

- proxmox: Add StdJSONDecodeError to 2 except clauses (json.JSONDecodeError
  is not a subclass of requests.exceptions.JSONDecodeError)
- elastic: Add AgentHTTPError to _get_template_metrics except clause
  (HTTPStatusError is not a subclass of requests.exceptions.RequestException)
- citrix_hypervisor: Add StdJSONDecodeError to _safely_process_metrics_response
  except clause

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…#23207)

* Batch-migrate direct MockResponse usages to MockHTTPResponse

Migrate 31 test files from `MockResponse` (requests-coupled) to
`MockHTTPResponse` (library-agnostic) as part of the requests→httpx
decoupling. Also widen JSONDecodeError except clauses in spark and
proxmox production code, add `links` property to MockHTTPResponse
for pagination support, and update test assertions that referenced
requests-specific exception class names.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix elastic CI failures and harden MockHTTPResponse.links parser

- Fix links property to split on ", <" instead of bare commas,
  matching requests.Response.links behavior (avoids breaking URLs
  containing commas)
- Update elastic test assertions to remove requests-specific
  ": None for url: None" error suffix
- Widen elastic _get_template_metrics except clause to catch
  AgentHTTPError alongside requests.RequestException

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* reformat with ddev test --fmt

* Add links unit tests and fix rel fallback in MockHTTPResponse

- Fix links property to fall back to keying by URL when rel is
  absent (matching requests.Response.links behavior)
- Add 6 dedicated unit tests for the links property: standard
  rel, multiple links, empty header, no-rel fallback, commas in
  URLs, and header pop clearing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Remove redundant MockHTTPResponse tests

Drop 5 tests that tested Python internals or trivial one-liners
rather than MockHTTPResponse behavior: ok property (status < 400),
reason property (stdlib dict lookup), headers delete/pop (dict ops),
headers update with custom Mapping (unused code path), url attribute
(attribute assignment).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…23226)

* Batch-migrate direct MockResponse usages to MockHTTPResponse

Migrate 31 test files from `MockResponse` (requests-coupled) to
`MockHTTPResponse` (library-agnostic) as part of the requests→httpx
decoupling. Also widen JSONDecodeError except clauses in spark and
proxmox production code, add `links` property to MockHTTPResponse
for pagination support, and update test assertions that referenced
requests-specific exception class names.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix elastic CI failures and harden MockHTTPResponse.links parser

- Fix links property to split on ", <" instead of bare commas,
  matching requests.Response.links behavior (avoids breaking URLs
  containing commas)
- Update elastic test assertions to remove requests-specific
  ": None for url: None" error suffix
- Widen elastic _get_template_metrics except clause to catch
  AgentHTTPError alongside requests.RequestException

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* reformat with ddev test --fmt

* Add links unit tests and fix rel fallback in MockHTTPResponse

- Fix links property to fall back to keying by URL when rel is
  absent (matching requests.Response.links behavior)
- Add 6 dedicated unit tests for the links property: standard
  rel, multiple links, empty header, no-rel fallback, commas in
  URLs, and header pop clearing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Remove redundant MockHTTPResponse tests

Drop 5 tests that tested Python internals or trivial one-liners
rather than MockHTTPResponse behavior: ok property (status < 400),
reason property (stdlib dict lookup), headers delete/pop (dict ops),
headers update with custom Mapping (unused code path), url attribute
(attribute assignment).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Migrate conftest.py MockResponse fixture chains to MockHTTPResponse

Replace MockResponse with MockHTTPResponse in 13 conftest.py files.
For 10 integrations, also migrate requests.Session.* patches to use
the mock_http fixture with configured side_effect, making tests
backend-agnostic. openstack_controller keeps Session patches due to
keystoneauth1 SDK coupling. Widen citrix_hypervisor JSONDecodeError
except clause for stdlib compatibility.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Remove changelog entry (merging to feature branch, not master)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Update dependency resolution

* Migrate temporal, fluxcd, dcgm, impala conftest.py to mock_http

Replace requests.Session.get patches with mock_http fixture for 4
OpenMetricsBaseCheckV2 integrations. MockHTTPResponse natively supports
iter_lines() and content, removing the need for MagicMock wrappers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Migrate nutanix conftest.py to mock_http

Replace mocker.patch('requests.Session.get') with mock_http fixture.
Replace all mocker.Mock() responses with MockHTTPResponse(json_data=...).
107 unit tests pass; 10+ URL handlers with pagination and time-based
filtering preserved unchanged.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Migrate yarn mocked_bad_cert_request to config assertion

Remove the requests.Session.get patch from yarn conftest.py.
Convert test_ssl_verification from an end-to-end SSL behavior test
to a config assertion test that verifies ssl_verify propagates to
http.options['verify']. Remove unused mock/patch/SSLError imports.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix OM v1 mixin to use self.http + migrate 8 conftest.py files

Change get_http_handler() in both openmetrics/mixins.py and
prometheus/mixins.py to return self.http instead of constructing
a new RequestsWrapper, allowing mock_http to intercept v1 mixin
HTTP calls. Migrate 8 conftest.py files from requests.Session
patches to mock_http + MockHTTPResponse.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Revert mixin change, patch get_http_handler in conftest fixtures instead

The production mixin change (returning self.http from get_http_handler)
broke kubelet's per-endpoint TLS isolation and prometheus E2E tests.
Revert to RequestsWrapper construction in production. Instead, patch
get_http_handler directly in each conftest fixture via mocker.patch
to return mock_http — same decoupling result, zero production risk.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Extract shared mock_openmetrics_http/mock_prometheus_http fixtures

- Add mock_openmetrics_http and mock_prometheus_http to pytest plugin,
  centralizing the get_http_handler patch in one place
- Update 7 conftest files to use mock_openmetrics_http, 1 to use
  mock_prometheus_http (eliminates repeated magic string)
- Remove unnecessary get_http_handler patch from 3 haproxy fixtures
  (legacy check uses self.http.get directly, not the OM mixin)
- Fix gitlab version endpoint: json_data=json.loads(text_data) so
  .json() returns a dict instead of a string (pre-existing bug)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Address review findings: nutanix retry tests, changelog, gitlab nit

- Rewrite 8 nutanix test_retry.py tests to use mock_http_get instead of
  dead requests.Session.get patches (MockHTTPResponse + HTTPStatusError)
- Update changelog to include mock_openmetrics_http/mock_prometheus_http
- Remove unreachable /-/health duplicate in gitlab conftest

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix nutanix conftest: restore mocker fixture + comments stripped during migration

* Set ignore_tls_warning on mock_prometheus_http to handle future https URLs

* Document mock_openmetrics_http dual interception (v1 patch + v2 PropertyMock)

* Use MockHTTPResponse(status_code=404) for nutanix conftest fall-through

* Rename yarn test_ssl_verification to test_tls_verify_config_propagates

* Restore yarn SSL catch-translate coverage via mock_http.get.side_effect

Replaces test_tls_verify_config_propagates with test_ssl_verification.
Two-phase test mirrors original shape: SSLError -> CRITICAL service
check, then verify=False -> 4 OK service checks. Uses mock_http instead
of patching requests.Session.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Minimize test_ssl_verification diff vs pre-migration shape

Restore original try/except/else body. Only diff vs pre-migration:
fixture arg (mocked_bad_cert_request -> mock_http) and side_effect
setup lines. No pytest.raises rewrite.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Restore original comments in test_ssl_verification

Comment removal was out of scope for this PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: dd-agent-integrations-bot[bot] <dd-agent-integrations-bot[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…gration-base

# Conflicts:
#	.deps/resolved/linux-aarch64_3.13.txt
#	.deps/resolved/linux-x86_64_3.13.txt
#	.deps/resolved/macos-aarch64_3.13.txt
#	.deps/resolved/macos-x86_64_3.13.txt
#	.deps/resolved/windows-x86_64_3.13.txt
@dd-octo-sts
Copy link
Copy Markdown
Contributor

dd-octo-sts Bot commented May 1, 2026

Validation Report

All 20 validations passed.

Show details
Validation Description Status
agent-reqs Verify check versions match the Agent requirements file
ci Validate CI configuration and Codecov settings
codeowners Validate every integration has a CODEOWNERS entry
config Validate default configuration files against spec.yaml
dep Verify dependency pins are consistent and Agent-compatible
http Validate integrations use the HTTP wrapper correctly
imports Validate check imports do not use deprecated modules
integration-style Validate check code style conventions
jmx-metrics Validate JMX metrics definition files and config
labeler Validate PR labeler config matches integration directories
legacy-signature Validate no integration uses the legacy Agent check signature
license-headers Validate Python files have proper license headers
licenses Validate third-party license attribution list
metadata Validate metadata.csv metric definitions
models Validate configuration data models match spec.yaml
openmetrics Validate OpenMetrics integrations disable the metric limit
package Validate Python package metadata and naming
readmes Validate README files have required sections
saved-views Validate saved view JSON file structure and fields
version Validate version consistency between package and changelog

View full run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent/review-requested base_package dev_package ecosystems/review-requested integration/airflow integration/appgate_sdp integration/arangodb integration/argo_workflows integration/avi_vantage integration/celery integration/cert_manager integration/cilium integration/citrix_hypervisor integration/consul integration/couch integration/couchbase integration/datadog_cluster_agent integration/dcgm  integration/druid integration/ecs_fargate integration/elastic integration/envoy integration/etcd integration/external_dns integration/falco integration/fluxcd integration/fly_io integration/gitlab_runner integration/gitlab integration/haproxy integration/harbor integration/hdfs_datanode integration/hdfs_namenode integration/impala integration/kubelet integration/kubevirt_api integration/kubevirt_controller integration/kubevirt_handler integration/mapreduce integration/marathon integration/mesos_master integration/mesos_slave integration/nginx integration/nutanix integration/nvidia_nim integration/nvidia_triton integration/octopus_deploy integration/openmetrics integration/openstack_controller integration/openstack integration/php_fpm integration/powerdns_recursor integration/prometheus integration/proxmox integration/quarkus integration/rabbitmq integration/ray integration/scylla integration/sonarqube integration/sonatype_nexus integration/spark integration/squid integration/strimzi integration/teamcity integration/tekton integration/temporal integration/torchserve integration/traefik_mesh integration/twistlock integration/vault integration/vllm integration/vsphere integration/yarn product/review-requested

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants