From 82b8aaf5d198ecb539e2753a2f5a14df49e14546 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Tue, 24 Feb 2026 16:36:07 -0500 Subject: [PATCH 01/20] 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) --- .../datadog_checks/base/utils/http_testing.py | 27 +++++++++++++++++-- datadog_checks_base/tests/conftest.py | 1 + 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/datadog_checks_base/datadog_checks/base/utils/http_testing.py b/datadog_checks_base/datadog_checks/base/utils/http_testing.py index c5419c46bff37..58312ca50a468 100644 --- a/datadog_checks_base/datadog_checks/base/utils/http_testing.py +++ b/datadog_checks_base/datadog_checks/base/utils/http_testing.py @@ -6,7 +6,30 @@ from typing import Any, Iterator from unittest.mock import MagicMock -__all__ = ['MockHTTPResponse'] +import pytest + +__all__ = ['MockHTTPResponse', 'mock_http'] + + +@pytest.fixture +def mock_http(mocker): + """Intercept HTTP calls made through RequestsWrapper; import into integration conftest.py to use. + + Patches get/post/put/delete/head/patch at the RequestsWrapper class level so all three + HTTP paths are intercepted (AgentCheck.http, OpenMetrics V2 scraper, and health-check + handlers that create their own wrappers). Real RequestsWrapper instances are still + created, so check.http.options is populated and available for config assertions. + """ + from datadog_checks.base.utils.http import RequestsWrapper + + container = MagicMock() + mocker.patch.object(RequestsWrapper, 'get', container.get) + mocker.patch.object(RequestsWrapper, 'post', container.post) + mocker.patch.object(RequestsWrapper, 'put', container.put) + mocker.patch.object(RequestsWrapper, 'delete', container.delete) + mocker.patch.object(RequestsWrapper, 'head', container.head) + mocker.patch.object(RequestsWrapper, 'patch', container.patch) + return container class MockHTTPResponse: @@ -17,7 +40,7 @@ def __init__( content: str | bytes = '', status_code: int = 200, headers: dict[str, str] | None = None, - json_data: dict[str, Any] | None = None, + json_data: Any = None, file_path: str | None = None, cookies: dict[str, str] | None = None, elapsed_seconds: float = 0.1, diff --git a/datadog_checks_base/tests/conftest.py b/datadog_checks_base/tests/conftest.py index d9936327da8c2..d26875073a484 100644 --- a/datadog_checks_base/tests/conftest.py +++ b/datadog_checks_base/tests/conftest.py @@ -3,6 +3,7 @@ import pytest import requests +from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.base.utils.platform import Platform from datadog_checks.dev import TempDir, docker_run, get_here from datadog_checks.dev.conditions import CheckDockerLogs, WaitFor From f4e689f3658982a369e39146cd5b132321d6962c Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Tue, 24 Feb 2026 16:36:13 -0500 Subject: [PATCH 02/20] 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) --- falco/tests/conftest.py | 2 ++ falco/tests/test_unit.py | 14 +++++--------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/falco/tests/conftest.py b/falco/tests/conftest.py index 28ca090908e04..79f5cd009c1ab 100644 --- a/falco/tests/conftest.py +++ b/falco/tests/conftest.py @@ -8,6 +8,8 @@ from datadog_checks.dev import docker_run from datadog_checks.dev.conditions import CheckEndpoints +pytest_plugins = ['datadog_checks.base.utils.http_testing'] + from .common import COMPOSE_FILE, INSTANCE # Needed to mount volume for logging diff --git a/falco/tests/test_unit.py b/falco/tests/test_unit.py index c2a544b1f780a..fdb03f05bbc30 100644 --- a/falco/tests/test_unit.py +++ b/falco/tests/test_unit.py @@ -1,12 +1,10 @@ # (C) Datadog, Inc. 2025-present # All rights reserved # Licensed under a 3-clause BSD style license (see LICENSE) -from unittest import mock - import pytest from datadog_checks.base.constants import ServiceCheck -from datadog_checks.dev.http import MockResponse +from datadog_checks.base.utils.http_testing import MockHTTPResponse from datadog_checks.dev.utils import get_metadata_metrics from datadog_checks.falco import FalcoCheck @@ -22,13 +20,11 @@ def test_empty_instance(dd_run_check): dd_run_check(check) -def test_check_falco(dd_run_check, aggregator, instance): - mock_responses = [ - MockResponse(file_path=get_fixture_path("falco_metrics.txt")), +def test_check_falco(dd_run_check, aggregator, instance, mock_http): + mock_http.get.side_effect = [ + MockHTTPResponse(file_path=get_fixture_path("falco_metrics.txt")), ] - - with mock.patch('requests.Session.get', side_effect=mock_responses): - dd_run_check(FalcoCheck('falco', {}, [instance])) + dd_run_check(FalcoCheck('falco', {}, [instance])) for metric in METRICS: aggregator.assert_metric(metric) From e67204f39d2e0aa303c8661bd773ee2d3df7a5ec Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Tue, 24 Feb 2026 16:40:45 -0500 Subject: [PATCH 03/20] 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) --- strimzi/tests/conftest.py | 6 ++++-- strimzi/tests/test_unit.py | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/strimzi/tests/conftest.py b/strimzi/tests/conftest.py index 0499c622ed9bb..98b4eaea453e6 100644 --- a/strimzi/tests/conftest.py +++ b/strimzi/tests/conftest.py @@ -8,12 +8,14 @@ import pytest +from datadog_checks.base.utils.http_testing import MockHTTPResponse from datadog_checks.dev import run_command -from datadog_checks.dev.http import MockResponse from datadog_checks.dev.kind import kind_run from datadog_checks.dev.kube_port_forward import port_forward from datadog_checks.strimzi import StrimziCheck +pytest_plugins = ['datadog_checks.base.utils.http_testing'] + from .common import HERE, KUBERNETES_VERSION, STRIMZI_VERSION @@ -103,4 +105,4 @@ def mock_http_responses(url, **_params): pytest.fail(f"url `{url}` not registered") with open(os.path.join(HERE, 'fixtures', STRIMZI_VERSION, metrics_file)) as f: - return MockResponse(content=f.read()) + return MockHTTPResponse(content=f.read()) diff --git a/strimzi/tests/test_unit.py b/strimzi/tests/test_unit.py index 0c9475cefab1a..1cfb28a5478c1 100644 --- a/strimzi/tests/test_unit.py +++ b/strimzi/tests/test_unit.py @@ -54,9 +54,9 @@ def test_check_unique_operator( instance, metrics, tag, - mocker, + mock_http, ): - mocker.patch("requests.Session.get", wraps=mock_http_responses) + mock_http.get.side_effect = mock_http_responses dd_run_check(check(instance)) for expected_metric in metrics: @@ -75,8 +75,8 @@ def test_check_unique_operator( assert len(aggregator.service_check_names) == 1 -def test_check_all_operators(dd_run_check, aggregator, check, mocker): - mocker.patch("requests.Session.get", wraps=mock_http_responses) +def test_check_all_operators(dd_run_check, aggregator, check, mock_http): + mock_http.get.side_effect = mock_http_responses dd_run_check( check( { From 56475b300c167004235c0d101144f1c45b5c57dc Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Tue, 24 Feb 2026 16:43:45 -0500 Subject: [PATCH 04/20] Fix E402: move pytest_plugins after all imports Co-Authored-By: Claude Opus 4.6 (1M context) --- falco/tests/conftest.py | 4 ++-- strimzi/tests/conftest.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/falco/tests/conftest.py b/falco/tests/conftest.py index 79f5cd009c1ab..ecf4c36fcca5c 100644 --- a/falco/tests/conftest.py +++ b/falco/tests/conftest.py @@ -8,10 +8,10 @@ from datadog_checks.dev import docker_run from datadog_checks.dev.conditions import CheckEndpoints -pytest_plugins = ['datadog_checks.base.utils.http_testing'] - from .common import COMPOSE_FILE, INSTANCE +pytest_plugins = ['datadog_checks.base.utils.http_testing'] + # Needed to mount volume for logging E2E_METADATA = {'docker_volumes': ['/var/run/docker.sock:/var/run/docker.sock:ro']} diff --git a/strimzi/tests/conftest.py b/strimzi/tests/conftest.py index 98b4eaea453e6..be6ce9ac47747 100644 --- a/strimzi/tests/conftest.py +++ b/strimzi/tests/conftest.py @@ -14,10 +14,10 @@ from datadog_checks.dev.kube_port_forward import port_forward from datadog_checks.strimzi import StrimziCheck -pytest_plugins = ['datadog_checks.base.utils.http_testing'] - from .common import HERE, KUBERNETES_VERSION, STRIMZI_VERSION +pytest_plugins = ['datadog_checks.base.utils.http_testing'] + def setup_strimzi(): run_command(["kubectl", "create", "namespace", "kafka"]) From fad8557bb11667fcc576d39379af50fff4cc31fc Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Tue, 24 Feb 2026 16:52:38 -0500 Subject: [PATCH 05/20] 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) --- couchbase/tests/conftest.py | 6 ++++-- couchbase/tests/test_unit.py | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/couchbase/tests/conftest.py b/couchbase/tests/conftest.py index 5d5136982e14c..1f1195763955d 100644 --- a/couchbase/tests/conftest.py +++ b/couchbase/tests/conftest.py @@ -10,10 +10,10 @@ import pytest import requests +from datadog_checks.base.utils.http_testing import MockHTTPResponse from datadog_checks.couchbase import Couchbase from datadog_checks.dev import WaitFor, docker_run from datadog_checks.dev.docker import get_container_ip -from datadog_checks.dev.http import MockResponse from .common import ( BUCKET_NAME, @@ -33,6 +33,8 @@ USER, ) +pytest_plugins = ['datadog_checks.base.utils.http_testing'] + @pytest.fixture def instance(): @@ -301,4 +303,4 @@ def mock_http_responses(url, **_params): pytest.fail("url `{url}` not registered".format(url=url)) with open(os.path.join(HERE, 'fixtures', metrics_file)) as f: - return MockResponse(content=f.read()) + return MockHTTPResponse(content=f.read()) diff --git a/couchbase/tests/test_unit.py b/couchbase/tests/test_unit.py index 25a437c02f842..1836ea77f1e6e 100644 --- a/couchbase/tests/test_unit.py +++ b/couchbase/tests/test_unit.py @@ -124,8 +124,8 @@ def test_extract_index_tags(instance, test_input, expected_tags): assert eval(str(test_output)) == expected_tags -def test_unit(dd_run_check, check, instance, mocker, aggregator): - mocker.patch("requests.Session.get", wraps=mock_http_responses) +def test_unit(dd_run_check, check, instance, mock_http, aggregator): + mock_http.get.side_effect = mock_http_responses dd_run_check(check(instance)) @@ -140,8 +140,8 @@ def test_unit(dd_run_check, check, instance, mocker, aggregator): aggregator.assert_metrics_using_metadata(get_metadata_metrics()) -def test_unit_query_metrics(dd_run_check, check, instance_query, mocker, aggregator): - mocker.patch("requests.Session.get", wraps=mock_http_responses) +def test_unit_query_metrics(dd_run_check, check, instance_query, mock_http, aggregator): + mock_http.get.side_effect = mock_http_responses dd_run_check(check(instance_query)) From 40b1e59f8d36b6df150dd49774dfff8d93c4a237 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Tue, 24 Feb 2026 17:10:19 -0500 Subject: [PATCH 06/20] 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) --- couchbase/tests/test_unit.py | 8 ++++---- .../datadog_checks/base/utils/http_testing.py | 4 ++-- datadog_checks_base/tests/conftest.py | 2 +- falco/tests/test_unit.py | 4 ++-- strimzi/tests/test_unit.py | 8 ++++---- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/couchbase/tests/test_unit.py b/couchbase/tests/test_unit.py index 1836ea77f1e6e..4ea0e2fcbe0dc 100644 --- a/couchbase/tests/test_unit.py +++ b/couchbase/tests/test_unit.py @@ -124,8 +124,8 @@ def test_extract_index_tags(instance, test_input, expected_tags): assert eval(str(test_output)) == expected_tags -def test_unit(dd_run_check, check, instance, mock_http, aggregator): - mock_http.get.side_effect = mock_http_responses +def test_unit(dd_run_check, check, instance, mock_http_client, aggregator): + mock_http_client.get.side_effect = mock_http_responses dd_run_check(check(instance)) @@ -140,8 +140,8 @@ def test_unit(dd_run_check, check, instance, mock_http, aggregator): aggregator.assert_metrics_using_metadata(get_metadata_metrics()) -def test_unit_query_metrics(dd_run_check, check, instance_query, mock_http, aggregator): - mock_http.get.side_effect = mock_http_responses +def test_unit_query_metrics(dd_run_check, check, instance_query, mock_http_client, aggregator): + mock_http_client.get.side_effect = mock_http_responses dd_run_check(check(instance_query)) diff --git a/datadog_checks_base/datadog_checks/base/utils/http_testing.py b/datadog_checks_base/datadog_checks/base/utils/http_testing.py index 58312ca50a468..6156bcc440da7 100644 --- a/datadog_checks_base/datadog_checks/base/utils/http_testing.py +++ b/datadog_checks_base/datadog_checks/base/utils/http_testing.py @@ -8,11 +8,11 @@ import pytest -__all__ = ['MockHTTPResponse', 'mock_http'] +__all__ = ['MockHTTPResponse', 'mock_http_client'] @pytest.fixture -def mock_http(mocker): +def mock_http_client(mocker): """Intercept HTTP calls made through RequestsWrapper; import into integration conftest.py to use. Patches get/post/put/delete/head/patch at the RequestsWrapper class level so all three diff --git a/datadog_checks_base/tests/conftest.py b/datadog_checks_base/tests/conftest.py index d26875073a484..1f2d2675cc545 100644 --- a/datadog_checks_base/tests/conftest.py +++ b/datadog_checks_base/tests/conftest.py @@ -3,7 +3,7 @@ import pytest import requests -from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 +from datadog_checks.base.utils.http_testing import mock_http_client # noqa: F401 from datadog_checks.base.utils.platform import Platform from datadog_checks.dev import TempDir, docker_run, get_here from datadog_checks.dev.conditions import CheckDockerLogs, WaitFor diff --git a/falco/tests/test_unit.py b/falco/tests/test_unit.py index fdb03f05bbc30..40b538a4116fa 100644 --- a/falco/tests/test_unit.py +++ b/falco/tests/test_unit.py @@ -20,8 +20,8 @@ def test_empty_instance(dd_run_check): dd_run_check(check) -def test_check_falco(dd_run_check, aggregator, instance, mock_http): - mock_http.get.side_effect = [ +def test_check_falco(dd_run_check, aggregator, instance, mock_http_client): + mock_http_client.get.side_effect = [ MockHTTPResponse(file_path=get_fixture_path("falco_metrics.txt")), ] dd_run_check(FalcoCheck('falco', {}, [instance])) diff --git a/strimzi/tests/test_unit.py b/strimzi/tests/test_unit.py index 1cfb28a5478c1..16c5756c2ec37 100644 --- a/strimzi/tests/test_unit.py +++ b/strimzi/tests/test_unit.py @@ -54,9 +54,9 @@ def test_check_unique_operator( instance, metrics, tag, - mock_http, + mock_http_client, ): - mock_http.get.side_effect = mock_http_responses + mock_http_client.get.side_effect = mock_http_responses dd_run_check(check(instance)) for expected_metric in metrics: @@ -75,8 +75,8 @@ def test_check_unique_operator( assert len(aggregator.service_check_names) == 1 -def test_check_all_operators(dd_run_check, aggregator, check, mock_http): - mock_http.get.side_effect = mock_http_responses +def test_check_all_operators(dd_run_check, aggregator, check, mock_http_client): + mock_http_client.get.side_effect = mock_http_responses dd_run_check( check( { From 8be2a72ca02f9275a802a16a328909daf750be3b Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Tue, 24 Feb 2026 17:21:22 -0500 Subject: [PATCH 07/20] 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) --- ray/tests/common.py | 4 ++-- ray/tests/conftest.py | 2 ++ ray/tests/test_unit.py | 8 ++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/ray/tests/common.py b/ray/tests/common.py index 19b0c9f911678..d51a4faaf0061 100644 --- a/ray/tests/common.py +++ b/ray/tests/common.py @@ -4,8 +4,8 @@ import os +from datadog_checks.base.utils.http_testing import MockHTTPResponse from datadog_checks.dev import get_docker_hostname, get_here -from datadog_checks.dev.http import MockResponse HERE = get_here() @@ -333,4 +333,4 @@ def mock_http_responses(url, **_params): raise Exception(f"url `{url}` not registered") with open(os.path.join(HERE, 'fixtures', metrics_file)) as f: - return MockResponse(content=f.read()) + return MockHTTPResponse(content=f.read()) diff --git a/ray/tests/conftest.py b/ray/tests/conftest.py index 0a43fe058c810..7304ce8e8ccce 100644 --- a/ray/tests/conftest.py +++ b/ray/tests/conftest.py @@ -38,6 +38,8 @@ WORKER3_OPENMETRICS_ENDPOINT, ) +pytest_plugins = ['datadog_checks.base.utils.http_testing'] + @pytest.fixture(scope='session') def dd_environment(): diff --git a/ray/tests/test_unit.py b/ray/tests/test_unit.py index f2e7725b5287f..2ca40a2997005 100644 --- a/ray/tests/test_unit.py +++ b/ray/tests/test_unit.py @@ -16,8 +16,8 @@ pytest.param(MOCKED_WORKER_INSTANCE, WORKER_METRICS, id='worker'), ], ) -def test_check(dd_run_check, aggregator, mocker, check, instance, metrics): - mocker.patch("requests.Session.get", wraps=mock_http_responses) +def test_check(dd_run_check, aggregator, mock_http_client, check, instance, metrics): + mock_http_client.get.side_effect = mock_http_responses dd_run_check(check(instance)) for expected_metric in metrics: @@ -30,10 +30,10 @@ def test_check(dd_run_check, aggregator, mocker, check, instance, metrics): assert len(aggregator.service_check_names) == 1 -def test_invalid_url(dd_run_check, aggregator, check, mocked_head_instance, mocker): +def test_invalid_url(dd_run_check, aggregator, check, mocked_head_instance, mock_http_client): mocked_head_instance["openmetrics_endpoint"] = "http://unknowwn" - mocker.patch("requests.Session.get", wraps=mock_http_responses) + mock_http_client.get.side_effect = mock_http_responses with pytest.raises(Exception): dd_run_check(check(mocked_head_instance)) From 9d6a7b7e344a5241930bf87cb76b39db52005842 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Tue, 24 Feb 2026 17:28:04 -0500 Subject: [PATCH 08/20] 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) --- tekton/tests/common.py | 4 ++-- tekton/tests/conftest.py | 2 ++ tekton/tests/test_unit.py | 8 ++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tekton/tests/common.py b/tekton/tests/common.py index 0203124213c86..a1d36404d371a 100644 --- a/tekton/tests/common.py +++ b/tekton/tests/common.py @@ -3,8 +3,8 @@ # Licensed under a 3-clause BSD style license (see LICENSE) import os +from datadog_checks.base.utils.http_testing import MockHTTPResponse from datadog_checks.dev import get_here -from datadog_checks.dev.http import MockResponse from datadog_checks.tekton import TektonCheck HERE = get_here() @@ -152,4 +152,4 @@ def mock_http_responses(url, **_params): raise Exception(f"url `{url}` not registered") with open(os.path.join(HERE, 'fixtures', metrics_file)) as f: - return MockResponse(content=f.read()) + return MockHTTPResponse(content=f.read()) diff --git a/tekton/tests/conftest.py b/tekton/tests/conftest.py index 86d7acb3fecb4..1cf055b0bfafd 100644 --- a/tekton/tests/conftest.py +++ b/tekton/tests/conftest.py @@ -10,6 +10,8 @@ from datadog_checks.dev.kind import kind_run from datadog_checks.dev.kube_port_forward import port_forward +pytest_plugins = ['datadog_checks.base.utils.http_testing'] + HERE = get_here() diff --git a/tekton/tests/test_unit.py b/tekton/tests/test_unit.py index 0010a2eae466d..21af093e5f393 100644 --- a/tekton/tests/test_unit.py +++ b/tekton/tests/test_unit.py @@ -16,8 +16,8 @@ pytest.param('triggers_instance', TRIGGERS_METRICS, 'triggers_controller', id='triggers'), ], ) -def test_check(dd_run_check, aggregator, mocker, instance, metrics, request, namespace): - mocker.patch("requests.Session.get", wraps=mock_http_responses) +def test_check(dd_run_check, aggregator, mock_http_client, instance, metrics, request, namespace): + mock_http_client.get.side_effect = mock_http_responses dd_run_check(check(request.getfixturevalue(instance))) for expected_metric in metrics: @@ -30,10 +30,10 @@ def test_check(dd_run_check, aggregator, mocker, instance, metrics, request, nam assert len(aggregator.service_check_names) == 1 -def test_invalid_url(dd_run_check, aggregator, pipelines_instance, mocker): +def test_invalid_url(dd_run_check, aggregator, pipelines_instance, mock_http_client): pipelines_instance["pipelines_controller_endpoint"] = "http://unknowwn" - mocker.patch("requests.Session.get", wraps=mock_http_responses) + mock_http_client.get.side_effect = mock_http_responses with pytest.raises(Exception): dd_run_check(check(pipelines_instance)) From 5ab95476b6b2a96c4dc2071fac3ea361d9c78ee9 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Tue, 24 Feb 2026 18:27:00 -0500 Subject: [PATCH 09/20] 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) --- couchbase/tests/conftest.py | 4 +--- falco/tests/conftest.py | 3 +-- ray/tests/conftest.py | 3 +-- strimzi/tests/conftest.py | 4 +--- tekton/tests/conftest.py | 3 +-- 5 files changed, 5 insertions(+), 12 deletions(-) diff --git a/couchbase/tests/conftest.py b/couchbase/tests/conftest.py index 1f1195763955d..2a0e4074dab73 100644 --- a/couchbase/tests/conftest.py +++ b/couchbase/tests/conftest.py @@ -10,7 +10,7 @@ import pytest import requests -from datadog_checks.base.utils.http_testing import MockHTTPResponse +from datadog_checks.base.utils.http_testing import MockHTTPResponse, mock_http_client # noqa: F401 from datadog_checks.couchbase import Couchbase from datadog_checks.dev import WaitFor, docker_run from datadog_checks.dev.docker import get_container_ip @@ -33,8 +33,6 @@ USER, ) -pytest_plugins = ['datadog_checks.base.utils.http_testing'] - @pytest.fixture def instance(): diff --git a/falco/tests/conftest.py b/falco/tests/conftest.py index ecf4c36fcca5c..a8a090566b568 100644 --- a/falco/tests/conftest.py +++ b/falco/tests/conftest.py @@ -5,13 +5,12 @@ import pytest +from datadog_checks.base.utils.http_testing import mock_http_client # noqa: F401 from datadog_checks.dev import docker_run from datadog_checks.dev.conditions import CheckEndpoints from .common import COMPOSE_FILE, INSTANCE -pytest_plugins = ['datadog_checks.base.utils.http_testing'] - # Needed to mount volume for logging E2E_METADATA = {'docker_volumes': ['/var/run/docker.sock:/var/run/docker.sock:ro']} diff --git a/ray/tests/conftest.py b/ray/tests/conftest.py index 7304ce8e8ccce..3b73af37332a8 100644 --- a/ray/tests/conftest.py +++ b/ray/tests/conftest.py @@ -10,6 +10,7 @@ import pytest import requests +from datadog_checks.base.utils.http_testing import mock_http_client # noqa: F401 from datadog_checks.dev import EnvVars, TempDir, docker_run from datadog_checks.dev._env import get_state, save_state from datadog_checks.dev.conditions import CheckEndpoints, WaitFor @@ -38,8 +39,6 @@ WORKER3_OPENMETRICS_ENDPOINT, ) -pytest_plugins = ['datadog_checks.base.utils.http_testing'] - @pytest.fixture(scope='session') def dd_environment(): diff --git a/strimzi/tests/conftest.py b/strimzi/tests/conftest.py index be6ce9ac47747..dd6e5fd47d416 100644 --- a/strimzi/tests/conftest.py +++ b/strimzi/tests/conftest.py @@ -8,7 +8,7 @@ import pytest -from datadog_checks.base.utils.http_testing import MockHTTPResponse +from datadog_checks.base.utils.http_testing import MockHTTPResponse, mock_http_client # noqa: F401 from datadog_checks.dev import run_command from datadog_checks.dev.kind import kind_run from datadog_checks.dev.kube_port_forward import port_forward @@ -16,8 +16,6 @@ from .common import HERE, KUBERNETES_VERSION, STRIMZI_VERSION -pytest_plugins = ['datadog_checks.base.utils.http_testing'] - def setup_strimzi(): run_command(["kubectl", "create", "namespace", "kafka"]) diff --git a/tekton/tests/conftest.py b/tekton/tests/conftest.py index 1cf055b0bfafd..8ed609aab31f2 100644 --- a/tekton/tests/conftest.py +++ b/tekton/tests/conftest.py @@ -6,12 +6,11 @@ import pytest +from datadog_checks.base.utils.http_testing import mock_http_client # noqa: F401 from datadog_checks.dev import get_here, run_command from datadog_checks.dev.kind import kind_run from datadog_checks.dev.kube_port_forward import port_forward -pytest_plugins = ['datadog_checks.base.utils.http_testing'] - HERE = get_here() From 693faee51ef85f3605cf19b1d093750445877853 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Tue, 24 Feb 2026 21:26:42 -0500 Subject: [PATCH 10/20] =?UTF-8?q?Revert=20rename:=20mock=5Fhttp=5Fclient?= =?UTF-8?q?=20=E2=86=92=20mock=5Fhttp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- couchbase/tests/conftest.py | 2 +- couchbase/tests/test_unit.py | 8 ++++---- .../datadog_checks/base/utils/http_testing.py | 4 ++-- datadog_checks_base/tests/conftest.py | 2 +- falco/tests/conftest.py | 2 +- falco/tests/test_unit.py | 4 ++-- ray/tests/conftest.py | 2 +- ray/tests/test_unit.py | 8 ++++---- strimzi/tests/conftest.py | 2 +- strimzi/tests/test_unit.py | 8 ++++---- tekton/tests/conftest.py | 2 +- tekton/tests/test_unit.py | 8 ++++---- 12 files changed, 26 insertions(+), 26 deletions(-) diff --git a/couchbase/tests/conftest.py b/couchbase/tests/conftest.py index 2a0e4074dab73..ed2ca27acada9 100644 --- a/couchbase/tests/conftest.py +++ b/couchbase/tests/conftest.py @@ -10,7 +10,7 @@ import pytest import requests -from datadog_checks.base.utils.http_testing import MockHTTPResponse, mock_http_client # noqa: F401 +from datadog_checks.base.utils.http_testing import MockHTTPResponse, mock_http # noqa: F401 from datadog_checks.couchbase import Couchbase from datadog_checks.dev import WaitFor, docker_run from datadog_checks.dev.docker import get_container_ip diff --git a/couchbase/tests/test_unit.py b/couchbase/tests/test_unit.py index 4ea0e2fcbe0dc..1836ea77f1e6e 100644 --- a/couchbase/tests/test_unit.py +++ b/couchbase/tests/test_unit.py @@ -124,8 +124,8 @@ def test_extract_index_tags(instance, test_input, expected_tags): assert eval(str(test_output)) == expected_tags -def test_unit(dd_run_check, check, instance, mock_http_client, aggregator): - mock_http_client.get.side_effect = mock_http_responses +def test_unit(dd_run_check, check, instance, mock_http, aggregator): + mock_http.get.side_effect = mock_http_responses dd_run_check(check(instance)) @@ -140,8 +140,8 @@ def test_unit(dd_run_check, check, instance, mock_http_client, aggregator): aggregator.assert_metrics_using_metadata(get_metadata_metrics()) -def test_unit_query_metrics(dd_run_check, check, instance_query, mock_http_client, aggregator): - mock_http_client.get.side_effect = mock_http_responses +def test_unit_query_metrics(dd_run_check, check, instance_query, mock_http, aggregator): + mock_http.get.side_effect = mock_http_responses dd_run_check(check(instance_query)) diff --git a/datadog_checks_base/datadog_checks/base/utils/http_testing.py b/datadog_checks_base/datadog_checks/base/utils/http_testing.py index 6156bcc440da7..58312ca50a468 100644 --- a/datadog_checks_base/datadog_checks/base/utils/http_testing.py +++ b/datadog_checks_base/datadog_checks/base/utils/http_testing.py @@ -8,11 +8,11 @@ import pytest -__all__ = ['MockHTTPResponse', 'mock_http_client'] +__all__ = ['MockHTTPResponse', 'mock_http'] @pytest.fixture -def mock_http_client(mocker): +def mock_http(mocker): """Intercept HTTP calls made through RequestsWrapper; import into integration conftest.py to use. Patches get/post/put/delete/head/patch at the RequestsWrapper class level so all three diff --git a/datadog_checks_base/tests/conftest.py b/datadog_checks_base/tests/conftest.py index 1f2d2675cc545..d26875073a484 100644 --- a/datadog_checks_base/tests/conftest.py +++ b/datadog_checks_base/tests/conftest.py @@ -3,7 +3,7 @@ import pytest import requests -from datadog_checks.base.utils.http_testing import mock_http_client # noqa: F401 +from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.base.utils.platform import Platform from datadog_checks.dev import TempDir, docker_run, get_here from datadog_checks.dev.conditions import CheckDockerLogs, WaitFor diff --git a/falco/tests/conftest.py b/falco/tests/conftest.py index a8a090566b568..0f2dc010223d7 100644 --- a/falco/tests/conftest.py +++ b/falco/tests/conftest.py @@ -5,7 +5,7 @@ import pytest -from datadog_checks.base.utils.http_testing import mock_http_client # noqa: F401 +from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.dev import docker_run from datadog_checks.dev.conditions import CheckEndpoints diff --git a/falco/tests/test_unit.py b/falco/tests/test_unit.py index 40b538a4116fa..fdb03f05bbc30 100644 --- a/falco/tests/test_unit.py +++ b/falco/tests/test_unit.py @@ -20,8 +20,8 @@ def test_empty_instance(dd_run_check): dd_run_check(check) -def test_check_falco(dd_run_check, aggregator, instance, mock_http_client): - mock_http_client.get.side_effect = [ +def test_check_falco(dd_run_check, aggregator, instance, mock_http): + mock_http.get.side_effect = [ MockHTTPResponse(file_path=get_fixture_path("falco_metrics.txt")), ] dd_run_check(FalcoCheck('falco', {}, [instance])) diff --git a/ray/tests/conftest.py b/ray/tests/conftest.py index 3b73af37332a8..f3fffd26aa216 100644 --- a/ray/tests/conftest.py +++ b/ray/tests/conftest.py @@ -10,7 +10,7 @@ import pytest import requests -from datadog_checks.base.utils.http_testing import mock_http_client # noqa: F401 +from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.dev import EnvVars, TempDir, docker_run from datadog_checks.dev._env import get_state, save_state from datadog_checks.dev.conditions import CheckEndpoints, WaitFor diff --git a/ray/tests/test_unit.py b/ray/tests/test_unit.py index 2ca40a2997005..4be5c8aa13ba9 100644 --- a/ray/tests/test_unit.py +++ b/ray/tests/test_unit.py @@ -16,8 +16,8 @@ pytest.param(MOCKED_WORKER_INSTANCE, WORKER_METRICS, id='worker'), ], ) -def test_check(dd_run_check, aggregator, mock_http_client, check, instance, metrics): - mock_http_client.get.side_effect = mock_http_responses +def test_check(dd_run_check, aggregator, mock_http, check, instance, metrics): + mock_http.get.side_effect = mock_http_responses dd_run_check(check(instance)) for expected_metric in metrics: @@ -30,10 +30,10 @@ def test_check(dd_run_check, aggregator, mock_http_client, check, instance, metr assert len(aggregator.service_check_names) == 1 -def test_invalid_url(dd_run_check, aggregator, check, mocked_head_instance, mock_http_client): +def test_invalid_url(dd_run_check, aggregator, check, mocked_head_instance, mock_http): mocked_head_instance["openmetrics_endpoint"] = "http://unknowwn" - mock_http_client.get.side_effect = mock_http_responses + mock_http.get.side_effect = mock_http_responses with pytest.raises(Exception): dd_run_check(check(mocked_head_instance)) diff --git a/strimzi/tests/conftest.py b/strimzi/tests/conftest.py index dd6e5fd47d416..afcb9c9b41076 100644 --- a/strimzi/tests/conftest.py +++ b/strimzi/tests/conftest.py @@ -8,7 +8,7 @@ import pytest -from datadog_checks.base.utils.http_testing import MockHTTPResponse, mock_http_client # noqa: F401 +from datadog_checks.base.utils.http_testing import MockHTTPResponse, mock_http # noqa: F401 from datadog_checks.dev import run_command from datadog_checks.dev.kind import kind_run from datadog_checks.dev.kube_port_forward import port_forward diff --git a/strimzi/tests/test_unit.py b/strimzi/tests/test_unit.py index 16c5756c2ec37..1cfb28a5478c1 100644 --- a/strimzi/tests/test_unit.py +++ b/strimzi/tests/test_unit.py @@ -54,9 +54,9 @@ def test_check_unique_operator( instance, metrics, tag, - mock_http_client, + mock_http, ): - mock_http_client.get.side_effect = mock_http_responses + mock_http.get.side_effect = mock_http_responses dd_run_check(check(instance)) for expected_metric in metrics: @@ -75,8 +75,8 @@ def test_check_unique_operator( assert len(aggregator.service_check_names) == 1 -def test_check_all_operators(dd_run_check, aggregator, check, mock_http_client): - mock_http_client.get.side_effect = mock_http_responses +def test_check_all_operators(dd_run_check, aggregator, check, mock_http): + mock_http.get.side_effect = mock_http_responses dd_run_check( check( { diff --git a/tekton/tests/conftest.py b/tekton/tests/conftest.py index 8ed609aab31f2..e2ef0879cfe6b 100644 --- a/tekton/tests/conftest.py +++ b/tekton/tests/conftest.py @@ -6,7 +6,7 @@ import pytest -from datadog_checks.base.utils.http_testing import mock_http_client # noqa: F401 +from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.dev import get_here, run_command from datadog_checks.dev.kind import kind_run from datadog_checks.dev.kube_port_forward import port_forward diff --git a/tekton/tests/test_unit.py b/tekton/tests/test_unit.py index 21af093e5f393..de85f1b0857fb 100644 --- a/tekton/tests/test_unit.py +++ b/tekton/tests/test_unit.py @@ -16,8 +16,8 @@ pytest.param('triggers_instance', TRIGGERS_METRICS, 'triggers_controller', id='triggers'), ], ) -def test_check(dd_run_check, aggregator, mock_http_client, instance, metrics, request, namespace): - mock_http_client.get.side_effect = mock_http_responses +def test_check(dd_run_check, aggregator, mock_http, instance, metrics, request, namespace): + mock_http.get.side_effect = mock_http_responses dd_run_check(check(request.getfixturevalue(instance))) for expected_metric in metrics: @@ -30,10 +30,10 @@ def test_check(dd_run_check, aggregator, mock_http_client, instance, metrics, re assert len(aggregator.service_check_names) == 1 -def test_invalid_url(dd_run_check, aggregator, pipelines_instance, mock_http_client): +def test_invalid_url(dd_run_check, aggregator, pipelines_instance, mock_http): pipelines_instance["pipelines_controller_endpoint"] = "http://unknowwn" - mock_http_client.get.side_effect = mock_http_responses + mock_http.get.side_effect = mock_http_responses with pytest.raises(Exception): dd_run_check(check(pipelines_instance)) From 0549839e40ab4b3de8b84f05d7f07b50b287477f Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Wed, 25 Feb 2026 12:18:26 -0500 Subject: [PATCH 11/20] 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 --- .../datadog_checks/base/checks/base.py | 4 +-- .../openmetrics/v2/scraper/base_scraper.py | 5 ++-- .../datadog_checks/base/utils/http_testing.py | 30 ++++++++----------- 3 files changed, 17 insertions(+), 22 deletions(-) diff --git a/datadog_checks_base/datadog_checks/base/checks/base.py b/datadog_checks_base/datadog_checks/base/checks/base.py index c059586cd2e40..67ca4e97f8dd4 100644 --- a/datadog_checks_base/datadog_checks/base/checks/base.py +++ b/datadog_checks_base/datadog_checks/base/checks/base.py @@ -63,7 +63,7 @@ import unicodedata as _module_unicodedata from datadog_checks.base.utils.diagnose import Diagnosis - from datadog_checks.base.utils.http import RequestsWrapper + from datadog_checks.base.utils.http_protocol import HTTPClientProtocol from datadog_checks.base.utils.metadata import MetadataManager inspect: _module_inspect = lazy_loader.load('inspect') @@ -376,7 +376,7 @@ def _get_metric_limit(self, instance=None): return limit @property - def http(self) -> RequestsWrapper: + def http(self) -> HTTPClientProtocol: """ Provides logic to yield consistent network behavior based on user configuration. diff --git a/datadog_checks_base/datadog_checks/base/checks/openmetrics/v2/scraper/base_scraper.py b/datadog_checks_base/datadog_checks/base/checks/openmetrics/v2/scraper/base_scraper.py index 65be700d603b6..d898b1ce8076c 100644 --- a/datadog_checks_base/datadog_checks/base/checks/openmetrics/v2/scraper/base_scraper.py +++ b/datadog_checks_base/datadog_checks/base/checks/openmetrics/v2/scraper/base_scraper.py @@ -23,7 +23,6 @@ from datadog_checks.base.constants import ServiceCheck from datadog_checks.base.errors import ConfigurationError from datadog_checks.base.utils.functions import no_op, return_true -from datadog_checks.base.utils.http import RequestsWrapper class OpenMetricsScraper: @@ -215,7 +214,7 @@ def __init__(self, check, config): self.raw_line_filter = re.compile('|'.join(raw_line_filters)) - self.http = RequestsWrapper(config, self.check.init_config, self.check.HTTP_CONFIG_REMAPPER, self.check.log) + self.http = check.http self._content_type = '' self._use_latest_spec = is_affirmative(config.get('use_latest_spec', False)) @@ -225,7 +224,7 @@ def __init__(self, check, config): accept_header = 'text/plain' # Request the appropriate exposition format - if self.http.options['headers'].get('Accept') == '*/*': + if hasattr(self.http, 'options') and self.http.options['headers'].get('Accept') == '*/*': self.http.options['headers']['Accept'] = accept_header self.use_process_start_time = is_affirmative(config.get('use_process_start_time')) diff --git a/datadog_checks_base/datadog_checks/base/utils/http_testing.py b/datadog_checks_base/datadog_checks/base/utils/http_testing.py index 58312ca50a468..45914f2c375b0 100644 --- a/datadog_checks_base/datadog_checks/base/utils/http_testing.py +++ b/datadog_checks_base/datadog_checks/base/utils/http_testing.py @@ -4,7 +4,7 @@ import json from io import BytesIO from typing import Any, Iterator -from unittest.mock import MagicMock +from unittest.mock import MagicMock, PropertyMock, create_autospec import pytest @@ -12,24 +12,20 @@ @pytest.fixture -def mock_http(mocker): - """Intercept HTTP calls made through RequestsWrapper; import into integration conftest.py to use. +def mock_http(mocker: Any) -> Any: + """Intercept HTTP calls made through AgentCheck.http; import into integration conftest.py to use. - Patches get/post/put/delete/head/patch at the RequestsWrapper class level so all three - HTTP paths are intercepted (AgentCheck.http, OpenMetrics V2 scraper, and health-check - handlers that create their own wrappers). Real RequestsWrapper instances are still - created, so check.http.options is populated and available for config assertions. + Patches AgentCheck.http with a create_autospec(HTTPClientProtocol) mock, constraining it + to the protocol interface and enforcing call signatures. Because the OM V2 scraper is + changed to use check.http directly, this single patch covers both AgentCheck.http and + the scraper HTTP path. """ - from datadog_checks.base.utils.http import RequestsWrapper - - container = MagicMock() - mocker.patch.object(RequestsWrapper, 'get', container.get) - mocker.patch.object(RequestsWrapper, 'post', container.post) - mocker.patch.object(RequestsWrapper, 'put', container.put) - mocker.patch.object(RequestsWrapper, 'delete', container.delete) - mocker.patch.object(RequestsWrapper, 'head', container.head) - mocker.patch.object(RequestsWrapper, 'patch', container.patch) - return container + from datadog_checks.base.checks.base import AgentCheck + from datadog_checks.base.utils.http_protocol import HTTPClientProtocol + + client = create_autospec(HTTPClientProtocol) + mocker.patch.object(AgentCheck, 'http', new_callable=PropertyMock, return_value=client) + return client class MockHTTPResponse: From 3321b99fe6b4b427b4005eb9028a545ca451bfa3 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Wed, 25 Feb 2026 12:22:14 -0500 Subject: [PATCH 12/20] Shorten docstring --- .../datadog_checks/base/utils/http_testing.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/datadog_checks_base/datadog_checks/base/utils/http_testing.py b/datadog_checks_base/datadog_checks/base/utils/http_testing.py index 45914f2c375b0..ce81e7eb33455 100644 --- a/datadog_checks_base/datadog_checks/base/utils/http_testing.py +++ b/datadog_checks_base/datadog_checks/base/utils/http_testing.py @@ -13,13 +13,7 @@ @pytest.fixture def mock_http(mocker: Any) -> Any: - """Intercept HTTP calls made through AgentCheck.http; import into integration conftest.py to use. - - Patches AgentCheck.http with a create_autospec(HTTPClientProtocol) mock, constraining it - to the protocol interface and enforcing call signatures. Because the OM V2 scraper is - changed to use check.http directly, this single patch covers both AgentCheck.http and - the scraper HTTP path. - """ + # Intercept HTTP calls made through AgentCheck.http, import into integration conftest.py to use from datadog_checks.base.checks.base import AgentCheck from datadog_checks.base.utils.http_protocol import HTTPClientProtocol From 8d3945391d9a842715a0e6a6b946e18adf0e30cd Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Wed, 25 Feb 2026 12:53:48 -0500 Subject: [PATCH 13/20] Migrate kubevirt_api, kubevirt_controller, kubevirt_handler tests to mock_http fixture Co-Authored-By: Claude Sonnet 4.6 --- kubevirt_api/tests/conftest.py | 4 ++-- kubevirt_api/tests/test_unit.py | 28 +++++++++++++------------- kubevirt_controller/tests/conftest.py | 4 ++-- kubevirt_controller/tests/test_unit.py | 8 ++++---- kubevirt_handler/tests/conftest.py | 4 ++-- kubevirt_handler/tests/test_unit.py | 16 +++++++-------- 6 files changed, 32 insertions(+), 32 deletions(-) diff --git a/kubevirt_api/tests/conftest.py b/kubevirt_api/tests/conftest.py index 8556cf4d3956d..330446da218d6 100644 --- a/kubevirt_api/tests/conftest.py +++ b/kubevirt_api/tests/conftest.py @@ -7,8 +7,8 @@ import pytest import yaml +from datadog_checks.base.utils.http_testing import MockHTTPResponse, mock_http # noqa: F401 from datadog_checks.dev import get_here, run_command -from datadog_checks.dev.http import MockResponse from datadog_checks.dev.kind import kind_run from datadog_checks.dev.kube_port_forward import port_forward @@ -105,4 +105,4 @@ def mock_http_responses(url, **_params): raise Exception(f"url `{url}` not registered") with open(os.path.join(HERE, "fixtures", fixtures_file)) as f: - return MockResponse(content=f.read()) + return MockHTTPResponse(content=f.read()) diff --git a/kubevirt_api/tests/test_unit.py b/kubevirt_api/tests/test_unit.py index 1a4b040e86d05..0179b6c93586b 100644 --- a/kubevirt_api/tests/test_unit.py +++ b/kubevirt_api/tests/test_unit.py @@ -17,8 +17,8 @@ pytestmark = [pytest.mark.unit] -def test_check_collects_all_metrics(dd_run_check, aggregator, instance, mocker): - mocker.patch("requests.Session.get", wraps=mock_http_responses) +def test_check_collects_all_metrics(dd_run_check, aggregator, instance, mock_http): + mock_http.get.side_effect = mock_http_responses check = KubeVirtApiCheck("kubevirt_api", {}, [instance]) @@ -94,8 +94,8 @@ def test_check_collects_all_metrics(dd_run_check, aggregator, instance, mocker): aggregator.assert_metrics_using_metadata(get_metadata_metrics()) -def test_check_sends_zero_count_for_vms(dd_run_check, aggregator, instance, mocker): - mocker.patch("requests.Session.get", wraps=mock_http_responses) +def test_check_sends_zero_count_for_vms(dd_run_check, aggregator, instance, mock_http): + mock_http.get.side_effect = mock_http_responses check = KubeVirtApiCheck("kubevirt_api", {}, [instance]) @@ -115,8 +115,8 @@ def test_check_sends_zero_count_for_vms(dd_run_check, aggregator, instance, mock aggregator.assert_metric("kubevirt_api.vm.count", value=0) -def test_check_sends_zero_count_for_vmis(dd_run_check, aggregator, instance, mocker): - mocker.patch("requests.Session.get", wraps=mock_http_responses) +def test_check_sends_zero_count_for_vmis(dd_run_check, aggregator, instance, mock_http): + mock_http.get.side_effect = mock_http_responses check = KubeVirtApiCheck("kubevirt_api", {}, [instance]) @@ -153,8 +153,8 @@ def test_emits_zero_can_connect_when_service_is_down(dd_run_check, aggregator, i ) -def test_emits_one_can_connect_when_service_is_up(dd_run_check, aggregator, instance, mocker): - mocker.patch("requests.Session.get", wraps=mock_http_responses) +def test_emits_one_can_connect_when_service_is_up(dd_run_check, aggregator, instance, mock_http): + mock_http.get.side_effect = mock_http_responses check = KubeVirtApiCheck("kubevirt_api", {}, [instance]) check._setup_kube_client = lambda: None @@ -170,8 +170,8 @@ def test_emits_one_can_connect_when_service_is_up(dd_run_check, aggregator, inst ) -def test_raise_exception_when_metrics_endpoint_is_bad(dd_run_check, aggregator, instance, mocker): - mocker.patch("requests.Session.get", wraps=mock_http_responses) +def test_raise_exception_when_metrics_endpoint_is_bad(dd_run_check, aggregator, instance, mock_http): + mock_http.get.side_effect = mock_http_responses check = KubeVirtApiCheck("kubevirt_api", {}, [BAD_METRICS_HOSTNAME_INSTANCE]) check._setup_kube_client = lambda: None @@ -189,8 +189,8 @@ def test_raise_exception_when_metrics_endpoint_is_bad(dd_run_check, aggregator, ) -def test_raise_exception_cannot_connect_to_kubernetes_api(dd_run_check, aggregator, instance, mocker, caplog): - mocker.patch("requests.Session.get", wraps=mock_http_responses) +def test_raise_exception_cannot_connect_to_kubernetes_api(dd_run_check, aggregator, instance, mock_http, caplog): + mock_http.get.side_effect = mock_http_responses check = KubeVirtApiCheck("kubevirt_api", {}, [instance]) with pytest.raises( @@ -201,8 +201,8 @@ def test_raise_exception_cannot_connect_to_kubernetes_api(dd_run_check, aggregat assert "Cannot connect to Kubernetes API:" in caplog.text -def test_log_warning_healthz_endpoint_not_provided(dd_run_check, aggregator, instance, mocker, caplog): - mocker.patch("requests.Session.get", wraps=mock_http_responses) +def test_log_warning_healthz_endpoint_not_provided(dd_run_check, aggregator, instance, mock_http, caplog): + mock_http.get.side_effect = mock_http_responses new_instance = deepcopy(instance) new_instance.pop("kubevirt_api_healthz_endpoint") diff --git a/kubevirt_controller/tests/conftest.py b/kubevirt_controller/tests/conftest.py index e0e0174775b60..a89153907018f 100644 --- a/kubevirt_controller/tests/conftest.py +++ b/kubevirt_controller/tests/conftest.py @@ -7,8 +7,8 @@ import pytest import yaml +from datadog_checks.base.utils.http_testing import MockHTTPResponse, mock_http # noqa: F401 from datadog_checks.dev import get_here, run_command -from datadog_checks.dev.http import MockResponse from datadog_checks.dev.kind import kind_run from datadog_checks.dev.kube_port_forward import port_forward @@ -101,4 +101,4 @@ def mock_http_responses(url, **_params): raise Exception(f"url `{url}` not registered") with open(os.path.join(HERE, "fixtures", fixtures_file)) as f: - return MockResponse(content=f.read()) + return MockHTTPResponse(content=f.read()) diff --git a/kubevirt_controller/tests/test_unit.py b/kubevirt_controller/tests/test_unit.py index 0a6bcb988a40c..1b4aa53fe488a 100644 --- a/kubevirt_controller/tests/test_unit.py +++ b/kubevirt_controller/tests/test_unit.py @@ -15,8 +15,8 @@ ] -def test_emits_can_connect_one_when_service_is_up(dd_run_check, aggregator, instance, mocker): - mocker.patch("requests.Session.get", wraps=mock_http_responses) +def test_emits_can_connect_one_when_service_is_up(dd_run_check, aggregator, instance, mock_http): + mock_http.get.side_effect = mock_http_responses check = KubeVirtControllerCheck("kubevirt_controller", {}, [instance]) dd_run_check(check) aggregator.assert_metric( @@ -35,8 +35,8 @@ def test_emits_can_connect_zero_when_service_is_down(dd_run_check, aggregator, i ) -def test_check_collects_all_metrics(dd_run_check, aggregator, instance, mocker): - mocker.patch("requests.Session.get", wraps=mock_http_responses) +def test_check_collects_all_metrics(dd_run_check, aggregator, instance, mock_http): + mock_http.get.side_effect = mock_http_responses check = KubeVirtControllerCheck("kubevirt_controller", {}, [instance]) diff --git a/kubevirt_handler/tests/conftest.py b/kubevirt_handler/tests/conftest.py index 7bc0bc1bad6d3..dfc6d8208a92d 100644 --- a/kubevirt_handler/tests/conftest.py +++ b/kubevirt_handler/tests/conftest.py @@ -6,8 +6,8 @@ import pytest +from datadog_checks.base.utils.http_testing import MockHTTPResponse, mock_http # noqa: F401 from datadog_checks.dev import get_here, run_command -from datadog_checks.dev.http import MockResponse from datadog_checks.dev.kind import kind_run from datadog_checks.dev.kube_port_forward import port_forward @@ -89,4 +89,4 @@ def mock_http_responses(url, **_params): raise Exception(f"url `{url}` not registered") with open(os.path.join(HERE, "fixtures", fixtures_file)) as f: - return MockResponse(content=f.read()) + return MockHTTPResponse(content=f.read()) diff --git a/kubevirt_handler/tests/test_unit.py b/kubevirt_handler/tests/test_unit.py index 01e8e42c4a9ba..28561e3e5a327 100644 --- a/kubevirt_handler/tests/test_unit.py +++ b/kubevirt_handler/tests/test_unit.py @@ -16,8 +16,8 @@ ] -def test_check_collects_metrics(dd_run_check, aggregator, instance, mocker): - mocker.patch("requests.Session.get", wraps=mock_http_responses) +def test_check_collects_metrics(dd_run_check, aggregator, instance, mock_http): + mock_http.get.side_effect = mock_http_responses check = KubeVirtHandlerCheck("kubevirt_handler", {}, [instance]) dd_run_check(check) @@ -121,8 +121,8 @@ def test_check_collects_metrics(dd_run_check, aggregator, instance, mocker): aggregator.assert_metrics_using_metadata(get_metadata_metrics()) -def test_logs_warning_when_healthz_endpoint_is_missing(dd_run_check, aggregator, instance, mocker, caplog): - mocker.patch("requests.Session.get", wraps=mock_http_responses) +def test_logs_warning_when_healthz_endpoint_is_missing(dd_run_check, aggregator, instance, mock_http, caplog): + mock_http.get.side_effect = mock_http_responses del instance["kubevirt_handler_healthz_endpoint"] check = KubeVirtHandlerCheck("kubevirt_handler", {}, [instance]) dd_run_check(check) @@ -133,8 +133,8 @@ def test_logs_warning_when_healthz_endpoint_is_missing(dd_run_check, aggregator, ) -def test_emits_can_connect_one_when_service_is_up(dd_run_check, aggregator, instance, mocker): - mocker.patch("requests.Session.get", wraps=mock_http_responses) +def test_emits_can_connect_one_when_service_is_up(dd_run_check, aggregator, instance, mock_http): + mock_http.get.side_effect = mock_http_responses check = KubeVirtHandlerCheck("kubevirt_handler", {}, [instance]) dd_run_check(check) aggregator.assert_metric( @@ -156,8 +156,8 @@ def test_emits_can_connect_zero_when_service_is_down(dd_run_check, aggregator, i ) -def test_version_metadata(instance, dd_run_check, datadog_agent, aggregator, mocker): - mocker.patch("requests.Session.get", wraps=mock_http_responses) +def test_version_metadata(instance, dd_run_check, datadog_agent, aggregator, mock_http): + mock_http.get.side_effect = mock_http_responses check = KubeVirtHandlerCheck("kubevirt_handler", {}, [instance]) check.check_id = "test:123" dd_run_check(check) From c4faf9ae44027c90fb44a04205682df2f92d22b9 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Thu, 26 Feb 2026 15:26:27 -0500 Subject: [PATCH 14/20] Fix Accept header mutation side-effect in OM V2 scraper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../checks/openmetrics/v2/scraper/base_scraper.py | 13 +++++++------ .../base/checks/openmetrics/test_v2/test_config.py | 4 ++-- openmetrics/tests/test_openmetrics.py | 4 ++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/datadog_checks_base/datadog_checks/base/checks/openmetrics/v2/scraper/base_scraper.py b/datadog_checks_base/datadog_checks/base/checks/openmetrics/v2/scraper/base_scraper.py index d898b1ce8076c..a290beba400ab 100644 --- a/datadog_checks_base/datadog_checks/base/checks/openmetrics/v2/scraper/base_scraper.py +++ b/datadog_checks_base/datadog_checks/base/checks/openmetrics/v2/scraper/base_scraper.py @@ -219,13 +219,11 @@ def __init__(self, check, config): self._content_type = '' self._use_latest_spec = is_affirmative(config.get('use_latest_spec', False)) if self._use_latest_spec: - accept_header = 'application/openmetrics-text;version=1.0.0,application/openmetrics-text;version=0.0.1' + self._accept_header = ( + 'application/openmetrics-text;version=1.0.0,application/openmetrics-text;version=0.0.1' + ) else: - accept_header = 'text/plain' - - # Request the appropriate exposition format - if hasattr(self.http, 'options') and self.http.options['headers'].get('Accept') == '*/*': - self.http.options['headers']['Accept'] = accept_header + self._accept_header = 'text/plain' self.use_process_start_time = is_affirmative(config.get('use_process_start_time')) @@ -462,6 +460,9 @@ def send_request(self, **kwargs): """ kwargs['stream'] = True + extra_headers = kwargs.get('extra_headers', {}) + extra_headers['Accept'] = self._accept_header + kwargs['extra_headers'] = extra_headers return self.http.get(self.endpoint, **kwargs) def set_dynamic_tags(self, *tags): diff --git a/datadog_checks_base/tests/base/checks/openmetrics/test_v2/test_config.py b/datadog_checks_base/tests/base/checks/openmetrics/test_v2/test_config.py index 0f3f6b7812e68..6ac0c5fe15880 100644 --- a/datadog_checks_base/tests/base/checks/openmetrics/test_v2/test_config.py +++ b/datadog_checks_base/tests/base/checks/openmetrics/test_v2/test_config.py @@ -417,7 +417,7 @@ def test_strict_latest_spec(self, dd_run_check): check = get_check({'use_latest_spec': True}) check.configure_scrapers() scraper = check.scrapers['test'] - assert scraper.http.options['headers']['Accept'] == ( + assert scraper._accept_header == ( 'application/openmetrics-text;version=1.0.0,application/openmetrics-text;version=0.0.1' ) @@ -425,4 +425,4 @@ def test_dynamic_spec(self, dd_run_check): check = get_check({'use_latest_spec': False}) check.configure_scrapers() scraper = check.scrapers['test'] - assert scraper.http.options['headers']['Accept'] == 'text/plain' + assert scraper._accept_header == 'text/plain' diff --git a/openmetrics/tests/test_openmetrics.py b/openmetrics/tests/test_openmetrics.py index f0212951b1bde..39e7da3383ba3 100644 --- a/openmetrics/tests/test_openmetrics.py +++ b/openmetrics/tests/test_openmetrics.py @@ -64,7 +64,7 @@ def test_openmetrics(aggregator, dd_run_check, request, poll_mock_fixture): aggregator.assert_all_metrics_covered() assert check.http.options['headers']['Accept'] == '*/*' - assert scraper.http.options['headers']['Accept'] == 'text/plain' + assert scraper._accept_header == 'text/plain' def test_openmetrics_use_latest_spec(aggregator, dd_run_check, mock_http_response, openmetrics_payload, caplog): @@ -97,7 +97,7 @@ def test_openmetrics_use_latest_spec(aggregator, dd_run_check, mock_http_respons assert check.http.options['headers']['Accept'] == '*/*' assert caplog.text == '' - assert scraper.http.options['headers']['Accept'] == ( + assert scraper._accept_header == ( 'application/openmetrics-text;version=1.0.0,application/openmetrics-text;version=0.0.1' ) From 504040280e0537efe82f0b26bf14f561760e217b Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Thu, 26 Feb 2026 16:07:53 -0500 Subject: [PATCH 15/20] 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 --- bentoml/tests/test_unit.py | 54 +++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/bentoml/tests/test_unit.py b/bentoml/tests/test_unit.py index 3ec90e358d026..edf95d6c58922 100644 --- a/bentoml/tests/test_unit.py +++ b/bentoml/tests/test_unit.py @@ -1,7 +1,7 @@ # (C) Datadog, Inc. 2025-present # All rights reserved # Licensed under a 3-clause BSD style license (see LICENSE) -from unittest.mock import Mock, patch +from unittest.mock import Mock import pytest import requests @@ -19,28 +19,23 @@ def test_bentoml_mock_metrics(dd_run_check, aggregator, mock_http_response): - mock_http_response(file_path=get_fixture_path('metrics.txt')) + get_mock = mock_http_response(file_path=get_fixture_path('metrics.txt')) - with patch('datadog_checks.bentoml.check.BentomlCheck.http') as mock_http: - mock_response = type('MockResponse', (), {'status_code': 200})() - mock_http.get.return_value = mock_response - mock_http.get.return_value.raise_for_status = lambda: None - - check = BentomlCheck('bentoml', {}, [OM_MOCKED_INSTANCE]) - dd_run_check(check) + check = BentomlCheck('bentoml', {}, [OM_MOCKED_INSTANCE]) + dd_run_check(check) - for metric in METRICS: - aggregator.assert_metric(metric) + for metric in METRICS: + aggregator.assert_metric(metric) - for metric in ENDPOINT_METRICS: - aggregator.assert_metric(metric, value=1, tags=['test:tag', 'status_code:200']) + for metric in ENDPOINT_METRICS: + aggregator.assert_metric(metric, value=1, tags=['test:tag', 'status_code:200']) - aggregator.assert_all_metrics_covered() - assert mock_http.get.call_count == 2 - aggregator.assert_metrics_using_metadata(get_metadata_metrics()) - aggregator.assert_all_metrics_covered() - aggregator.assert_metric_has_tag('bentoml.service.request.count', 'bentoml_endpoint:/summarize') - aggregator.assert_service_check('bentoml.openmetrics.health', ServiceCheck.OK) + aggregator.assert_all_metrics_covered() + assert get_mock.call_count == 3 # 1 metrics scrape + 2 health endpoints (/livez, /readyz) + aggregator.assert_metrics_using_metadata(get_metadata_metrics()) + aggregator.assert_all_metrics_covered() + aggregator.assert_metric_has_tag('bentoml.service.request.count', 'bentoml_endpoint:/summarize') + aggregator.assert_service_check('bentoml.openmetrics.health', ServiceCheck.OK) def test_bentoml_mock_invalid_endpoint(dd_run_check, aggregator, mock_http_response): @@ -53,7 +48,8 @@ def test_bentoml_mock_invalid_endpoint(dd_run_check, aggregator, mock_http_respo def test_bentoml_mock_valid_endpoint_invalid_health(dd_run_check, aggregator, mock_http_response): - mock_http_response(file_path=get_fixture_path('metrics.txt')) + session_get_mock = mock_http_response(file_path=get_fixture_path('metrics.txt')) + metrics_response = session_get_mock.return_value _err = Mock() _err.status_code = 500 @@ -61,13 +57,17 @@ def test_bentoml_mock_valid_endpoint_invalid_health(dd_run_check, aggregator, mo _http_err.response = _err _err.raise_for_status.side_effect = _http_err - with patch('datadog_checks.bentoml.check.BentomlCheck.http') as mock_http: - mock_http.get.return_value = _err + def dispatch(url, **_): + if '/livez' in url or '/readyz' in url: + return _err + return metrics_response - check = BentomlCheck('bentoml', {}, [OM_MOCKED_INSTANCE]) - dd_run_check(check) + session_get_mock.side_effect = dispatch + + check = BentomlCheck('bentoml', {}, [OM_MOCKED_INSTANCE]) + dd_run_check(check) - for metric in ENDPOINT_METRICS: - aggregator.assert_metric(metric, value=0, tags=['test:tag', 'status_code:500']) + for metric in ENDPOINT_METRICS: + aggregator.assert_metric(metric, value=0, tags=['test:tag', 'status_code:500']) - aggregator.assert_service_check('bentoml.openmetrics.health', ServiceCheck.OK) + aggregator.assert_service_check('bentoml.openmetrics.health', ServiceCheck.OK) From 05152e75a0097f0efd083321cd05a9babdac1296 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Thu, 26 Feb 2026 16:33:16 -0500 Subject: [PATCH 16/20] Fix Vault auth headers lost when OM V2 scraper reuses check.http Co-Authored-By: Claude Sonnet 4.6 --- vault/datadog_checks/vault/check.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vault/datadog_checks/vault/check.py b/vault/datadog_checks/vault/check.py index 5726d1eb4bc35..3661256185999 100644 --- a/vault/datadog_checks/vault/check.py +++ b/vault/datadog_checks/vault/check.py @@ -238,8 +238,12 @@ def configure_scrapers(self): }, } } + if hasattr(self, '_http'): + del self._http + self.http.options['headers']['X-Vault-Request'] = 'true' if self.config.client_token: config['headers']['X-Vault-Token'] = self.config.client_token + self.http.options['headers']['X-Vault-Token'] = self.config.client_token self.scraper_configs.clear() self.scraper_configs.append(config) From a12f3ee117ddc3b767346f2085a0669e772f4f1e Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Thu, 26 Feb 2026 16:52:04 -0500 Subject: [PATCH 17/20] Raise NotImplementedError for options_method in mock_http fixture Co-Authored-By: Claude Sonnet 4.6 --- datadog_checks_base/datadog_checks/base/utils/http_testing.py | 1 + 1 file changed, 1 insertion(+) diff --git a/datadog_checks_base/datadog_checks/base/utils/http_testing.py b/datadog_checks_base/datadog_checks/base/utils/http_testing.py index ce81e7eb33455..62102e4848f30 100644 --- a/datadog_checks_base/datadog_checks/base/utils/http_testing.py +++ b/datadog_checks_base/datadog_checks/base/utils/http_testing.py @@ -18,6 +18,7 @@ def mock_http(mocker: Any) -> Any: from datadog_checks.base.utils.http_protocol import HTTPClientProtocol client = create_autospec(HTTPClientProtocol) + client.options_method.side_effect = NotImplementedError('HTTP OPTIONS not yet supported in mock_http') mocker.patch.object(AgentCheck, 'http', new_callable=PropertyMock, return_value=client) return client From 8db2b4f297263d8f4724cfeeae6b8609013fc7fc Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Thu, 26 Feb 2026 16:59:22 -0500 Subject: [PATCH 18/20] Move mock_http fixture to datadog_checks_dev pytest plugin Co-Authored-By: Claude Sonnet 4.6 --- couchbase/tests/conftest.py | 2 +- .../datadog_checks/base/utils/http_testing.py | 18 ++---------------- datadog_checks_base/tests/conftest.py | 1 - .../datadog_checks/dev/plugin/pytest.py | 13 +++++++++++++ falco/tests/conftest.py | 1 - kubevirt_api/tests/conftest.py | 2 +- kubevirt_controller/tests/conftest.py | 2 +- kubevirt_handler/tests/conftest.py | 2 +- ray/tests/conftest.py | 1 - strimzi/tests/conftest.py | 2 +- tekton/tests/conftest.py | 1 - 11 files changed, 20 insertions(+), 25 deletions(-) diff --git a/couchbase/tests/conftest.py b/couchbase/tests/conftest.py index ed2ca27acada9..dfda5ee73fbb5 100644 --- a/couchbase/tests/conftest.py +++ b/couchbase/tests/conftest.py @@ -10,7 +10,7 @@ import pytest import requests -from datadog_checks.base.utils.http_testing import MockHTTPResponse, mock_http # noqa: F401 +from datadog_checks.base.utils.http_testing import MockHTTPResponse # noqa: F401 from datadog_checks.couchbase import Couchbase from datadog_checks.dev import WaitFor, docker_run from datadog_checks.dev.docker import get_container_ip diff --git a/datadog_checks_base/datadog_checks/base/utils/http_testing.py b/datadog_checks_base/datadog_checks/base/utils/http_testing.py index 62102e4848f30..8930187a49856 100644 --- a/datadog_checks_base/datadog_checks/base/utils/http_testing.py +++ b/datadog_checks_base/datadog_checks/base/utils/http_testing.py @@ -4,23 +4,9 @@ import json from io import BytesIO from typing import Any, Iterator -from unittest.mock import MagicMock, PropertyMock, create_autospec +from unittest.mock import MagicMock -import pytest - -__all__ = ['MockHTTPResponse', 'mock_http'] - - -@pytest.fixture -def mock_http(mocker: Any) -> Any: - # Intercept HTTP calls made through AgentCheck.http, import into integration conftest.py to use - from datadog_checks.base.checks.base import AgentCheck - from datadog_checks.base.utils.http_protocol import HTTPClientProtocol - - client = create_autospec(HTTPClientProtocol) - client.options_method.side_effect = NotImplementedError('HTTP OPTIONS not yet supported in mock_http') - mocker.patch.object(AgentCheck, 'http', new_callable=PropertyMock, return_value=client) - return client +__all__ = ['MockHTTPResponse'] class MockHTTPResponse: diff --git a/datadog_checks_base/tests/conftest.py b/datadog_checks_base/tests/conftest.py index d26875073a484..d9936327da8c2 100644 --- a/datadog_checks_base/tests/conftest.py +++ b/datadog_checks_base/tests/conftest.py @@ -3,7 +3,6 @@ import pytest import requests -from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.base.utils.platform import Platform from datadog_checks.dev import TempDir, docker_run, get_here from datadog_checks.dev.conditions import CheckDockerLogs, WaitFor diff --git a/datadog_checks_dev/datadog_checks/dev/plugin/pytest.py b/datadog_checks_dev/datadog_checks/dev/plugin/pytest.py index e9f9c80a513f0..16317857ad87c 100644 --- a/datadog_checks_dev/datadog_checks/dev/plugin/pytest.py +++ b/datadog_checks_dev/datadog_checks/dev/plugin/pytest.py @@ -301,6 +301,19 @@ def mock_http_response(mocker, mock_response): ) +@pytest.fixture +def mock_http(mocker): + from unittest.mock import PropertyMock, create_autospec + + from datadog_checks.base.checks.base import AgentCheck + from datadog_checks.base.utils.http_protocol import HTTPClientProtocol + + client = create_autospec(HTTPClientProtocol) + client.options_method.side_effect = NotImplementedError('HTTP OPTIONS not yet supported in mock_http') + mocker.patch.object(AgentCheck, 'http', new_callable=PropertyMock, return_value=client) + return client + + @pytest.fixture def mock_http_response_per_endpoint(mocker, mock_response): @overload diff --git a/falco/tests/conftest.py b/falco/tests/conftest.py index 0f2dc010223d7..28ca090908e04 100644 --- a/falco/tests/conftest.py +++ b/falco/tests/conftest.py @@ -5,7 +5,6 @@ import pytest -from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.dev import docker_run from datadog_checks.dev.conditions import CheckEndpoints diff --git a/kubevirt_api/tests/conftest.py b/kubevirt_api/tests/conftest.py index 330446da218d6..81af61164d28d 100644 --- a/kubevirt_api/tests/conftest.py +++ b/kubevirt_api/tests/conftest.py @@ -7,7 +7,7 @@ import pytest import yaml -from datadog_checks.base.utils.http_testing import MockHTTPResponse, mock_http # noqa: F401 +from datadog_checks.base.utils.http_testing import MockHTTPResponse # noqa: F401 from datadog_checks.dev import get_here, run_command from datadog_checks.dev.kind import kind_run from datadog_checks.dev.kube_port_forward import port_forward diff --git a/kubevirt_controller/tests/conftest.py b/kubevirt_controller/tests/conftest.py index a89153907018f..b2512fba1a7b4 100644 --- a/kubevirt_controller/tests/conftest.py +++ b/kubevirt_controller/tests/conftest.py @@ -7,7 +7,7 @@ import pytest import yaml -from datadog_checks.base.utils.http_testing import MockHTTPResponse, mock_http # noqa: F401 +from datadog_checks.base.utils.http_testing import MockHTTPResponse # noqa: F401 from datadog_checks.dev import get_here, run_command from datadog_checks.dev.kind import kind_run from datadog_checks.dev.kube_port_forward import port_forward diff --git a/kubevirt_handler/tests/conftest.py b/kubevirt_handler/tests/conftest.py index dfc6d8208a92d..294abc17ab1e9 100644 --- a/kubevirt_handler/tests/conftest.py +++ b/kubevirt_handler/tests/conftest.py @@ -6,7 +6,7 @@ import pytest -from datadog_checks.base.utils.http_testing import MockHTTPResponse, mock_http # noqa: F401 +from datadog_checks.base.utils.http_testing import MockHTTPResponse # noqa: F401 from datadog_checks.dev import get_here, run_command from datadog_checks.dev.kind import kind_run from datadog_checks.dev.kube_port_forward import port_forward diff --git a/ray/tests/conftest.py b/ray/tests/conftest.py index f3fffd26aa216..0a43fe058c810 100644 --- a/ray/tests/conftest.py +++ b/ray/tests/conftest.py @@ -10,7 +10,6 @@ import pytest import requests -from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.dev import EnvVars, TempDir, docker_run from datadog_checks.dev._env import get_state, save_state from datadog_checks.dev.conditions import CheckEndpoints, WaitFor diff --git a/strimzi/tests/conftest.py b/strimzi/tests/conftest.py index afcb9c9b41076..16ce3da9f2b10 100644 --- a/strimzi/tests/conftest.py +++ b/strimzi/tests/conftest.py @@ -8,7 +8,7 @@ import pytest -from datadog_checks.base.utils.http_testing import MockHTTPResponse, mock_http # noqa: F401 +from datadog_checks.base.utils.http_testing import MockHTTPResponse # noqa: F401 from datadog_checks.dev import run_command from datadog_checks.dev.kind import kind_run from datadog_checks.dev.kube_port_forward import port_forward diff --git a/tekton/tests/conftest.py b/tekton/tests/conftest.py index e2ef0879cfe6b..86d7acb3fecb4 100644 --- a/tekton/tests/conftest.py +++ b/tekton/tests/conftest.py @@ -6,7 +6,6 @@ import pytest -from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.dev import get_here, run_command from datadog_checks.dev.kind import kind_run from datadog_checks.dev.kube_port_forward import port_forward From 93c6cd251fee088123868546f18a16d461c07089 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Fri, 27 Feb 2026 11:26:16 -0500 Subject: [PATCH 19/20] 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 --- bentoml/tests/test_unit.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bentoml/tests/test_unit.py b/bentoml/tests/test_unit.py index edf95d6c58922..70fa4f1ab842c 100644 --- a/bentoml/tests/test_unit.py +++ b/bentoml/tests/test_unit.py @@ -31,7 +31,6 @@ def test_bentoml_mock_metrics(dd_run_check, aggregator, mock_http_response): aggregator.assert_metric(metric, value=1, tags=['test:tag', 'status_code:200']) aggregator.assert_all_metrics_covered() - assert get_mock.call_count == 3 # 1 metrics scrape + 2 health endpoints (/livez, /readyz) aggregator.assert_metrics_using_metadata(get_metadata_metrics()) aggregator.assert_all_metrics_covered() aggregator.assert_metric_has_tag('bentoml.service.request.count', 'bentoml_endpoint:/summarize') From ea5790da65646a6f7e5486006a5b6ba469a53ffd Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Fri, 27 Feb 2026 11:26:59 -0500 Subject: [PATCH 20/20] Drop unused get_mock variable in bentoml test Co-Authored-By: Claude Sonnet 4.6 --- bentoml/tests/test_unit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bentoml/tests/test_unit.py b/bentoml/tests/test_unit.py index 70fa4f1ab842c..0843e4ab750ba 100644 --- a/bentoml/tests/test_unit.py +++ b/bentoml/tests/test_unit.py @@ -19,7 +19,7 @@ def test_bentoml_mock_metrics(dd_run_check, aggregator, mock_http_response): - get_mock = mock_http_response(file_path=get_fixture_path('metrics.txt')) + mock_http_response(file_path=get_fixture_path('metrics.txt')) check = BentomlCheck('bentoml', {}, [OM_MOCKED_INSTANCE]) dd_run_check(check)