From f843a3a8870447d360aebadfe35b9943df37dcfd Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Tue, 24 Feb 2026 20:53:30 -0500 Subject: [PATCH 01/25] 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) --- couch/tests/conftest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/couch/tests/conftest.py b/couch/tests/conftest.py index 8e407331a251c..2906b79035a93 100644 --- a/couch/tests/conftest.py +++ b/couch/tests/conftest.py @@ -8,6 +8,7 @@ import pytest import requests +from datadog_checks.base.utils.http_testing import mock_http_client # noqa: F401 from datadog_checks.couch import CouchDb from datadog_checks.dev import docker_run from datadog_checks.dev.conditions import CheckDockerLogs, CheckEndpoints, WaitFor From 1e845f92d270f5a1cb93300b556d9de28f10fbf2 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Tue, 24 Feb 2026 21:48:40 -0500 Subject: [PATCH 02/25] 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 --- couch/tests/conftest.py | 2 +- couch/tests/test_unit.py | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/couch/tests/conftest.py b/couch/tests/conftest.py index 2906b79035a93..fa1c43ab57bea 100644 --- a/couch/tests/conftest.py +++ b/couch/tests/conftest.py @@ -8,7 +8,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 http_client_session # noqa: F401 from datadog_checks.couch import CouchDb from datadog_checks.dev import docker_run from datadog_checks.dev.conditions import CheckDockerLogs, CheckEndpoints, WaitFor diff --git a/couch/tests/test_unit.py b/couch/tests/test_unit.py index d1bf4b49af3e9..f87c80269b3f2 100644 --- a/couch/tests/test_unit.py +++ b/couch/tests/test_unit.py @@ -2,7 +2,7 @@ # All rights reserved # Licensed under a 3-clause BSD style license (see LICENSE) from copy import deepcopy -from unittest.mock import MagicMock +from unittest.mock import ANY, MagicMock import pytest @@ -24,13 +24,25 @@ ("timeout", {'timeout': 17}, {'timeout': (17, 17)}), ], ) -def test_config(test_case, extra_config, expected_http_kwargs): +def test_config(test_case, extra_config, expected_http_kwargs, http_client_session): instance = deepcopy(common.BASIC_CONFIG) instance.update(extra_config) check = CouchDb(common.CHECK_NAME, {}, instances=[instance]) - for key, value in expected_http_kwargs.items(): - assert check.http.options[key] == value + http_client_session.get.return_value = MagicMock(status_code=200, content='{}') + check.check(instance) + + http_wargs = { + 'auth': ANY, + 'cert': ANY, + 'headers': ANY, + 'proxies': ANY, + 'timeout': ANY, + 'verify': ANY, + 'allow_redirects': ANY, + } + http_wargs.update(expected_http_kwargs) + http_client_session.get.assert_called_with('http://{}:5984/_all_dbs/'.format(common.HOST), **http_wargs) def test_new_version_system_metrics(load_test_data): From b007cb742f16ed699e8e480859c4e36db767fd24 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Tue, 24 Feb 2026 21:53:44 -0500 Subject: [PATCH 03/25] 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 --- gitlab_runner/tests/conftest.py | 2 ++ gitlab_runner/tests/test_unit.py | 17 +++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/gitlab_runner/tests/conftest.py b/gitlab_runner/tests/conftest.py index ec93ffbd16807..642d7c57065b0 100644 --- a/gitlab_runner/tests/conftest.py +++ b/gitlab_runner/tests/conftest.py @@ -7,6 +7,8 @@ import mock import pytest +from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 + from datadog_checks.dev import docker_run from datadog_checks.dev.conditions import CheckDockerLogs, CheckEndpoints diff --git a/gitlab_runner/tests/test_unit.py b/gitlab_runner/tests/test_unit.py index 35b89bc2109d2..02f86991de13d 100644 --- a/gitlab_runner/tests/test_unit.py +++ b/gitlab_runner/tests/test_unit.py @@ -3,6 +3,7 @@ # Licensed under a 3-clause BSD style license (see LICENSE) from copy import deepcopy +from unittest.mock import ANY, MagicMock import pytest @@ -21,14 +22,26 @@ ("default timeout", {}, (5, 15)), ], ) -def test_timeout(test_case, timeout_config, expected_timeout): +def test_timeout(test_case, timeout_config, expected_timeout, http_client_session): config = deepcopy(common.CONFIG) config['instances'][0].update(timeout_config) gitlab_runner = GitlabRunnerCheck('gitlab_runner', common.CONFIG['init_config'], instances=config['instances']) - assert gitlab_runner.http.options['timeout'] == expected_timeout + http_client_session.get.return_value = MagicMock(status_code=200) + gitlab_runner.check(config['instances'][0]) + + http_client_session.get.assert_called_with( + '{}/ci'.format(common.GITLAB_MASTER_URL), + auth=ANY, + cert=ANY, + headers=ANY, + proxies=ANY, + timeout=expected_timeout, + verify=ANY, + allow_redirects=ANY, + ) @pytest.mark.unit From 95607c38a25684dfe3d02da835cf7d82862473b3 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Tue, 24 Feb 2026 21:54:41 -0500 Subject: [PATCH 04/25] Reformat with ddev test --fmt --- gitlab_runner/tests/conftest.py | 1 - 1 file changed, 1 deletion(-) diff --git a/gitlab_runner/tests/conftest.py b/gitlab_runner/tests/conftest.py index 642d7c57065b0..c809884b2599c 100644 --- a/gitlab_runner/tests/conftest.py +++ b/gitlab_runner/tests/conftest.py @@ -8,7 +8,6 @@ import pytest from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 - from datadog_checks.dev import docker_run from datadog_checks.dev.conditions import CheckDockerLogs, CheckEndpoints From 0328063d8f11507fee4e2de53532139ad4f1eea4 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Tue, 24 Feb 2026 23:39:53 -0500 Subject: [PATCH 05/25] 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 --- marathon/tests/conftest.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/marathon/tests/conftest.py b/marathon/tests/conftest.py index a6f450a449b92..b44e3441364b6 100644 --- a/marathon/tests/conftest.py +++ b/marathon/tests/conftest.py @@ -7,6 +7,8 @@ import pytest +from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 + from datadog_checks.dev import docker_run from datadog_checks.marathon import Marathon From edb97269a0811f5278fdf3410c8a09f5ae9d09a9 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Tue, 24 Feb 2026 23:43:16 -0500 Subject: [PATCH 06/25] 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 --- rabbitmq/tests/conftest.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rabbitmq/tests/conftest.py b/rabbitmq/tests/conftest.py index 1ae63672e802d..cd954cf23d6f4 100644 --- a/rabbitmq/tests/conftest.py +++ b/rabbitmq/tests/conftest.py @@ -6,6 +6,8 @@ import subprocess import pytest + +from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 import requests from datadog_checks.dev import docker_run, temp_dir From 0906d216c1f76a8d18c2226d36cc776eb6d79b5f Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Tue, 24 Feb 2026 23:53:46 -0500 Subject: [PATCH 07/25] 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 --- consul/tests/conftest.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/consul/tests/conftest.py b/consul/tests/conftest.py index 1106920ab4ffa..083c5e559129b 100644 --- a/consul/tests/conftest.py +++ b/consul/tests/conftest.py @@ -4,6 +4,8 @@ import os import pytest + +from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 import requests from datadog_checks.dev import WaitFor, docker_run From 553378951db1cb30c211ed45fe2a4305654512bf Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Tue, 24 Feb 2026 23:58:22 -0500 Subject: [PATCH 08/25] 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 --- torchserve/tests/conftest.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/torchserve/tests/conftest.py b/torchserve/tests/conftest.py index b02a64195e086..012fb15b1c698 100644 --- a/torchserve/tests/conftest.py +++ b/torchserve/tests/conftest.py @@ -7,6 +7,8 @@ import pytest +from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 + from datadog_checks.dev import EnvVars, TempDir, docker_run, get_here from datadog_checks.dev._env import get_state, save_state from datadog_checks.dev.conditions import CheckEndpoints, WaitFor From 5f4cb724bd69d3cf244fbb1a873f2f50ab8f394b Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Wed, 25 Feb 2026 00:09:54 -0500 Subject: [PATCH 09/25] Migrate etcd, ecs_fargate, mesos_master session-patch tests to http_client_session Co-Authored-By: Claude Sonnet 4.6 --- ecs_fargate/tests/conftest.py | 1 + etcd/tests/conftest.py | 1 + mesos_master/tests/conftest.py | 1 + 3 files changed, 3 insertions(+) diff --git a/ecs_fargate/tests/conftest.py b/ecs_fargate/tests/conftest.py index 8c092686f9825..3cd03d9264cd8 100644 --- a/ecs_fargate/tests/conftest.py +++ b/ecs_fargate/tests/conftest.py @@ -6,6 +6,7 @@ import pytest +from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 from datadog_checks.dev import get_here from datadog_checks.dev.http import MockResponse from datadog_checks.ecs_fargate import FargateCheck diff --git a/etcd/tests/conftest.py b/etcd/tests/conftest.py index 53ddf375fc121..4626d61259620 100644 --- a/etcd/tests/conftest.py +++ b/etcd/tests/conftest.py @@ -3,6 +3,7 @@ # Licensed under a 3-clause BSD style license (see LICENSE) import pytest +from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 from datadog_checks.dev import docker_run from datadog_checks.dev.conditions import CheckEndpoints from datadog_checks.etcd.metrics import METRIC_MAP diff --git a/mesos_master/tests/conftest.py b/mesos_master/tests/conftest.py index 7bfb2e65c0115..dbffa29aafd52 100644 --- a/mesos_master/tests/conftest.py +++ b/mesos_master/tests/conftest.py @@ -7,6 +7,7 @@ import pytest +from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 from datadog_checks.dev import docker_run from datadog_checks.mesos_master import MesosMaster From a5b3bdac41e9d1d72709d391a95bb9548dea381a Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Wed, 25 Feb 2026 00:19:02 -0500 Subject: [PATCH 10/25] Reformat with ddev test --fmt --- consul/tests/conftest.py | 3 +-- marathon/tests/conftest.py | 1 - rabbitmq/tests/conftest.py | 3 +-- torchserve/tests/conftest.py | 1 - 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/consul/tests/conftest.py b/consul/tests/conftest.py index 083c5e559129b..39390d94da124 100644 --- a/consul/tests/conftest.py +++ b/consul/tests/conftest.py @@ -4,10 +4,9 @@ import os import pytest - -from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 import requests +from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 from datadog_checks.dev import WaitFor, docker_run from . import common diff --git a/marathon/tests/conftest.py b/marathon/tests/conftest.py index b44e3441364b6..b1725b207947d 100644 --- a/marathon/tests/conftest.py +++ b/marathon/tests/conftest.py @@ -8,7 +8,6 @@ import pytest from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 - from datadog_checks.dev import docker_run from datadog_checks.marathon import Marathon diff --git a/rabbitmq/tests/conftest.py b/rabbitmq/tests/conftest.py index cd954cf23d6f4..03d4cc49d1931 100644 --- a/rabbitmq/tests/conftest.py +++ b/rabbitmq/tests/conftest.py @@ -6,10 +6,9 @@ import subprocess import pytest - -from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 import requests +from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 from datadog_checks.dev import docker_run, temp_dir from datadog_checks.rabbitmq import RabbitMQ diff --git a/torchserve/tests/conftest.py b/torchserve/tests/conftest.py index 012fb15b1c698..dd7b11f61dec7 100644 --- a/torchserve/tests/conftest.py +++ b/torchserve/tests/conftest.py @@ -8,7 +8,6 @@ import pytest from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 - from datadog_checks.dev import EnvVars, TempDir, docker_run, get_here from datadog_checks.dev._env import get_state, save_state from datadog_checks.dev.conditions import CheckEndpoints, WaitFor From c360c29e6452e6e6a824f8d3eb048d122474c4f8 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Wed, 25 Feb 2026 13:46:04 -0500 Subject: [PATCH 11/25] Scrap http_client_session; migrate Step 2 tests to check.http.options and mock_http MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- consul/tests/conftest.py | 2 +- couch/tests/conftest.py | 1 - couch/tests/test_unit.py | 20 ++++---------------- ecs_fargate/tests/conftest.py | 1 - etcd/tests/conftest.py | 1 - gitlab_runner/tests/conftest.py | 1 - gitlab_runner/tests/test_unit.py | 17 ++--------------- marathon/tests/conftest.py | 1 - mesos_master/tests/conftest.py | 2 +- mesos_master/tests/test_check.py | 1 + rabbitmq/tests/conftest.py | 2 +- torchserve/tests/conftest.py | 2 +- 12 files changed, 11 insertions(+), 40 deletions(-) diff --git a/consul/tests/conftest.py b/consul/tests/conftest.py index 39390d94da124..189230f5487ea 100644 --- a/consul/tests/conftest.py +++ b/consul/tests/conftest.py @@ -6,7 +6,7 @@ import pytest import requests -from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 +from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.dev import WaitFor, docker_run from . import common diff --git a/couch/tests/conftest.py b/couch/tests/conftest.py index fa1c43ab57bea..8e407331a251c 100644 --- a/couch/tests/conftest.py +++ b/couch/tests/conftest.py @@ -8,7 +8,6 @@ import pytest import requests -from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 from datadog_checks.couch import CouchDb from datadog_checks.dev import docker_run from datadog_checks.dev.conditions import CheckDockerLogs, CheckEndpoints, WaitFor diff --git a/couch/tests/test_unit.py b/couch/tests/test_unit.py index f87c80269b3f2..d1bf4b49af3e9 100644 --- a/couch/tests/test_unit.py +++ b/couch/tests/test_unit.py @@ -2,7 +2,7 @@ # All rights reserved # Licensed under a 3-clause BSD style license (see LICENSE) from copy import deepcopy -from unittest.mock import ANY, MagicMock +from unittest.mock import MagicMock import pytest @@ -24,25 +24,13 @@ ("timeout", {'timeout': 17}, {'timeout': (17, 17)}), ], ) -def test_config(test_case, extra_config, expected_http_kwargs, http_client_session): +def test_config(test_case, extra_config, expected_http_kwargs): instance = deepcopy(common.BASIC_CONFIG) instance.update(extra_config) check = CouchDb(common.CHECK_NAME, {}, instances=[instance]) - http_client_session.get.return_value = MagicMock(status_code=200, content='{}') - check.check(instance) - - http_wargs = { - 'auth': ANY, - 'cert': ANY, - 'headers': ANY, - 'proxies': ANY, - 'timeout': ANY, - 'verify': ANY, - 'allow_redirects': ANY, - } - http_wargs.update(expected_http_kwargs) - http_client_session.get.assert_called_with('http://{}:5984/_all_dbs/'.format(common.HOST), **http_wargs) + for key, value in expected_http_kwargs.items(): + assert check.http.options[key] == value def test_new_version_system_metrics(load_test_data): diff --git a/ecs_fargate/tests/conftest.py b/ecs_fargate/tests/conftest.py index 3cd03d9264cd8..8c092686f9825 100644 --- a/ecs_fargate/tests/conftest.py +++ b/ecs_fargate/tests/conftest.py @@ -6,7 +6,6 @@ import pytest -from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 from datadog_checks.dev import get_here from datadog_checks.dev.http import MockResponse from datadog_checks.ecs_fargate import FargateCheck diff --git a/etcd/tests/conftest.py b/etcd/tests/conftest.py index 4626d61259620..53ddf375fc121 100644 --- a/etcd/tests/conftest.py +++ b/etcd/tests/conftest.py @@ -3,7 +3,6 @@ # Licensed under a 3-clause BSD style license (see LICENSE) import pytest -from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 from datadog_checks.dev import docker_run from datadog_checks.dev.conditions import CheckEndpoints from datadog_checks.etcd.metrics import METRIC_MAP diff --git a/gitlab_runner/tests/conftest.py b/gitlab_runner/tests/conftest.py index c809884b2599c..ec93ffbd16807 100644 --- a/gitlab_runner/tests/conftest.py +++ b/gitlab_runner/tests/conftest.py @@ -7,7 +7,6 @@ import mock import pytest -from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 from datadog_checks.dev import docker_run from datadog_checks.dev.conditions import CheckDockerLogs, CheckEndpoints diff --git a/gitlab_runner/tests/test_unit.py b/gitlab_runner/tests/test_unit.py index 02f86991de13d..35b89bc2109d2 100644 --- a/gitlab_runner/tests/test_unit.py +++ b/gitlab_runner/tests/test_unit.py @@ -3,7 +3,6 @@ # Licensed under a 3-clause BSD style license (see LICENSE) from copy import deepcopy -from unittest.mock import ANY, MagicMock import pytest @@ -22,26 +21,14 @@ ("default timeout", {}, (5, 15)), ], ) -def test_timeout(test_case, timeout_config, expected_timeout, http_client_session): +def test_timeout(test_case, timeout_config, expected_timeout): config = deepcopy(common.CONFIG) config['instances'][0].update(timeout_config) gitlab_runner = GitlabRunnerCheck('gitlab_runner', common.CONFIG['init_config'], instances=config['instances']) - http_client_session.get.return_value = MagicMock(status_code=200) - gitlab_runner.check(config['instances'][0]) - - http_client_session.get.assert_called_with( - '{}/ci'.format(common.GITLAB_MASTER_URL), - auth=ANY, - cert=ANY, - headers=ANY, - proxies=ANY, - timeout=expected_timeout, - verify=ANY, - allow_redirects=ANY, - ) + assert gitlab_runner.http.options['timeout'] == expected_timeout @pytest.mark.unit diff --git a/marathon/tests/conftest.py b/marathon/tests/conftest.py index b1725b207947d..a6f450a449b92 100644 --- a/marathon/tests/conftest.py +++ b/marathon/tests/conftest.py @@ -7,7 +7,6 @@ import pytest -from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 from datadog_checks.dev import docker_run from datadog_checks.marathon import Marathon diff --git a/mesos_master/tests/conftest.py b/mesos_master/tests/conftest.py index dbffa29aafd52..6136a17cff5e5 100644 --- a/mesos_master/tests/conftest.py +++ b/mesos_master/tests/conftest.py @@ -7,7 +7,7 @@ import pytest -from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 +from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.dev import docker_run from datadog_checks.mesos_master import MesosMaster diff --git a/mesos_master/tests/test_check.py b/mesos_master/tests/test_check.py index daff6b4033480..228811bff1012 100644 --- a/mesos_master/tests/test_check.py +++ b/mesos_master/tests/test_check.py @@ -158,6 +158,7 @@ def test_can_connect_service_check( expected_tags, expect_exception, ): + mock_http.options = {'verify': True} check = MesosMaster('mesos_master', {}, [instance]) mock_http.get.side_effect = request_mock_side_effects diff --git a/rabbitmq/tests/conftest.py b/rabbitmq/tests/conftest.py index 03d4cc49d1931..0c06c26fe3031 100644 --- a/rabbitmq/tests/conftest.py +++ b/rabbitmq/tests/conftest.py @@ -8,7 +8,7 @@ import pytest import requests -from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 +from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.dev import docker_run, temp_dir from datadog_checks.rabbitmq import RabbitMQ diff --git a/torchserve/tests/conftest.py b/torchserve/tests/conftest.py index dd7b11f61dec7..3612bc47b2575 100644 --- a/torchserve/tests/conftest.py +++ b/torchserve/tests/conftest.py @@ -7,7 +7,7 @@ import pytest -from datadog_checks.base.utils.http_testing import http_client_session # noqa: F401 +from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.dev import EnvVars, TempDir, docker_run, get_here from datadog_checks.dev._env import get_state, save_state from datadog_checks.dev.conditions import CheckEndpoints, WaitFor From 8f684e195f7ed07b37cf5e21fc560eaf935a7bbf Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Wed, 25 Feb 2026 14:22:33 -0500 Subject: [PATCH 12/25] Migrate airflow session-patch tests to mock_http Co-Authored-By: Claude Sonnet 4.6 --- airflow/tests/conftest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/airflow/tests/conftest.py b/airflow/tests/conftest.py index a209063f01ae6..ddca0520840e8 100644 --- a/airflow/tests/conftest.py +++ b/airflow/tests/conftest.py @@ -7,6 +7,7 @@ import pytest +from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.dev import TempDir, docker_run from datadog_checks.dev.conditions import CheckEndpoints From 0ee2b7eb97e66b73702941d28cd190f21303637f Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Wed, 25 Feb 2026 14:43:28 -0500 Subject: [PATCH 13/25] Migrate druid session-patch tests to mock_http Co-Authored-By: Claude Sonnet 4.6 --- druid/tests/conftest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/druid/tests/conftest.py b/druid/tests/conftest.py index fa947beaecb20..f8f2a4e0b4952 100644 --- a/druid/tests/conftest.py +++ b/druid/tests/conftest.py @@ -5,6 +5,7 @@ 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 From 1d11b9e4b4aff18f58648fa965c4832dd1ada766 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Wed, 25 Feb 2026 14:49:31 -0500 Subject: [PATCH 14/25] Migrate mesos_slave session-patch tests to mock_http Co-Authored-By: Claude Sonnet 4.6 --- mesos_slave/tests/conftest.py | 1 + mesos_slave/tests/test_unit.py | 3 +++ 2 files changed, 4 insertions(+) diff --git a/mesos_slave/tests/conftest.py b/mesos_slave/tests/conftest.py index 8b97177e8de4d..7afff7a994813 100644 --- a/mesos_slave/tests/conftest.py +++ b/mesos_slave/tests/conftest.py @@ -6,6 +6,7 @@ import pytest +from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.dev import docker_run from datadog_checks.mesos_slave import MesosSlave diff --git a/mesos_slave/tests/test_unit.py b/mesos_slave/tests/test_unit.py index e04738108caed..45c30d0beeaa1 100644 --- a/mesos_slave/tests/test_unit.py +++ b/mesos_slave/tests/test_unit.py @@ -186,6 +186,7 @@ def test_can_connect_service_check_state( expect_exception, expected_status, ): + mock_http.options = {'verify': True} check = MesosSlave('mesos_slave', {}, [instance]) mock_http.get.side_effect = request_mock_effects try: @@ -203,6 +204,7 @@ def test_can_connect_service_with_instance_cluster_name(instance, aggregator, mo instance['cluster_name'] = 'test-cluster' expected_tags = ['url:http://hello.com/state'] + cluster_name_tag + additional_tags expected_status = AgentCheck.OK + mock_http.options = {'verify': True} check = MesosSlave('mesos_slave', {}, [instance]) mock_http.get.side_effect = [mock.MagicMock(status_code=200, content='{}')] try: @@ -227,6 +229,7 @@ def test_can_connect_service_check_stats( expect_exception, expected_status, ): + mock_http.options = {'verify': True} check = MesosSlave('mesos_slave', {}, [instance]) mock_http.get.side_effect = request_mock_effects try: From 66b43842653d9c8603d29e67ab16a86056075e0b Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Wed, 25 Feb 2026 14:50:57 -0500 Subject: [PATCH 15/25] Migrate nginx session-patch tests to check.http.options and mock_http Co-Authored-By: Claude Sonnet 4.6 --- nginx/tests/conftest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nginx/tests/conftest.py b/nginx/tests/conftest.py index 30493bdab1937..ff07d61f70e44 100644 --- a/nginx/tests/conftest.py +++ b/nginx/tests/conftest.py @@ -6,6 +6,7 @@ import pytest +from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.dev import docker_run from datadog_checks.nginx import Nginx From bf636e50d0a3ca62f21dfa77e91181661670457a Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Wed, 25 Feb 2026 14:54:29 -0500 Subject: [PATCH 16/25] Migrate php_fpm session-patch tests to check.http.options and mock_http Co-Authored-By: Claude Sonnet 4.6 --- php_fpm/tests/conftest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/php_fpm/tests/conftest.py b/php_fpm/tests/conftest.py index 4a8330a0529f1..fc43a0ed48fc0 100644 --- a/php_fpm/tests/conftest.py +++ b/php_fpm/tests/conftest.py @@ -7,6 +7,7 @@ import pytest +from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.dev import docker_run, get_docker_hostname from datadog_checks.php_fpm import PHPFPMCheck From 9ab6ceac40985f0add5414572f3f315b43f560f4 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Wed, 25 Feb 2026 15:51:44 -0500 Subject: [PATCH 17/25] 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 --- mesos_master/tests/test_check.py | 1 - mesos_slave/tests/test_unit.py | 3 --- 2 files changed, 4 deletions(-) diff --git a/mesos_master/tests/test_check.py b/mesos_master/tests/test_check.py index 228811bff1012..daff6b4033480 100644 --- a/mesos_master/tests/test_check.py +++ b/mesos_master/tests/test_check.py @@ -158,7 +158,6 @@ def test_can_connect_service_check( expected_tags, expect_exception, ): - mock_http.options = {'verify': True} check = MesosMaster('mesos_master', {}, [instance]) mock_http.get.side_effect = request_mock_side_effects diff --git a/mesos_slave/tests/test_unit.py b/mesos_slave/tests/test_unit.py index 45c30d0beeaa1..e04738108caed 100644 --- a/mesos_slave/tests/test_unit.py +++ b/mesos_slave/tests/test_unit.py @@ -186,7 +186,6 @@ def test_can_connect_service_check_state( expect_exception, expected_status, ): - mock_http.options = {'verify': True} check = MesosSlave('mesos_slave', {}, [instance]) mock_http.get.side_effect = request_mock_effects try: @@ -204,7 +203,6 @@ def test_can_connect_service_with_instance_cluster_name(instance, aggregator, mo instance['cluster_name'] = 'test-cluster' expected_tags = ['url:http://hello.com/state'] + cluster_name_tag + additional_tags expected_status = AgentCheck.OK - mock_http.options = {'verify': True} check = MesosSlave('mesos_slave', {}, [instance]) mock_http.get.side_effect = [mock.MagicMock(status_code=200, content='{}')] try: @@ -229,7 +227,6 @@ def test_can_connect_service_check_stats( expect_exception, expected_status, ): - mock_http.options = {'verify': True} check = MesosSlave('mesos_slave', {}, [instance]) mock_http.get.side_effect = request_mock_effects try: From 78e7612ee029314c18754ab22399f2876bf8c436 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Fri, 27 Feb 2026 01:04:33 -0500 Subject: [PATCH 18/25] 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 --- airflow/tests/conftest.py | 1 - consul/tests/conftest.py | 1 - druid/tests/conftest.py | 1 - mesos_master/tests/conftest.py | 1 - mesos_slave/tests/conftest.py | 1 - nginx/tests/conftest.py | 1 - php_fpm/tests/conftest.py | 1 - rabbitmq/tests/conftest.py | 1 - torchserve/tests/conftest.py | 1 - 9 files changed, 9 deletions(-) diff --git a/airflow/tests/conftest.py b/airflow/tests/conftest.py index ddca0520840e8..a209063f01ae6 100644 --- a/airflow/tests/conftest.py +++ b/airflow/tests/conftest.py @@ -7,7 +7,6 @@ import pytest -from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.dev import TempDir, docker_run from datadog_checks.dev.conditions import CheckEndpoints diff --git a/consul/tests/conftest.py b/consul/tests/conftest.py index 189230f5487ea..1106920ab4ffa 100644 --- a/consul/tests/conftest.py +++ b/consul/tests/conftest.py @@ -6,7 +6,6 @@ import pytest import requests -from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.dev import WaitFor, docker_run from . import common diff --git a/druid/tests/conftest.py b/druid/tests/conftest.py index f8f2a4e0b4952..fa947beaecb20 100644 --- a/druid/tests/conftest.py +++ b/druid/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/mesos_master/tests/conftest.py b/mesos_master/tests/conftest.py index 6136a17cff5e5..7bfb2e65c0115 100644 --- a/mesos_master/tests/conftest.py +++ b/mesos_master/tests/conftest.py @@ -7,7 +7,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.mesos_master import MesosMaster diff --git a/mesos_slave/tests/conftest.py b/mesos_slave/tests/conftest.py index 7afff7a994813..8b97177e8de4d 100644 --- a/mesos_slave/tests/conftest.py +++ b/mesos_slave/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 docker_run from datadog_checks.mesos_slave import MesosSlave diff --git a/nginx/tests/conftest.py b/nginx/tests/conftest.py index ff07d61f70e44..30493bdab1937 100644 --- a/nginx/tests/conftest.py +++ b/nginx/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 docker_run from datadog_checks.nginx import Nginx diff --git a/php_fpm/tests/conftest.py b/php_fpm/tests/conftest.py index fc43a0ed48fc0..4a8330a0529f1 100644 --- a/php_fpm/tests/conftest.py +++ b/php_fpm/tests/conftest.py @@ -7,7 +7,6 @@ import pytest -from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.dev import docker_run, get_docker_hostname from datadog_checks.php_fpm import PHPFPMCheck diff --git a/rabbitmq/tests/conftest.py b/rabbitmq/tests/conftest.py index 0c06c26fe3031..1ae63672e802d 100644 --- a/rabbitmq/tests/conftest.py +++ b/rabbitmq/tests/conftest.py @@ -8,7 +8,6 @@ import pytest import requests -from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.dev import docker_run, temp_dir from datadog_checks.rabbitmq import RabbitMQ diff --git a/torchserve/tests/conftest.py b/torchserve/tests/conftest.py index 3612bc47b2575..b02a64195e086 100644 --- a/torchserve/tests/conftest.py +++ b/torchserve/tests/conftest.py @@ -7,7 +7,6 @@ import pytest -from datadog_checks.base.utils.http_testing import mock_http # noqa: F401 from datadog_checks.dev import EnvVars, TempDir, docker_run, get_here from datadog_checks.dev._env import get_state, save_state from datadog_checks.dev.conditions import CheckEndpoints, WaitFor From 541a33c5ec295b4865f6885852c4a3a8d7fb07d5 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Fri, 27 Feb 2026 01:17:03 -0500 Subject: [PATCH 19/25] 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 --- datadog_checks_dev/datadog_checks/dev/plugin/pytest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datadog_checks_dev/datadog_checks/dev/plugin/pytest.py b/datadog_checks_dev/datadog_checks/dev/plugin/pytest.py index 2e549004fec28..e2731673a52b4 100644 --- a/datadog_checks_dev/datadog_checks/dev/plugin/pytest.py +++ b/datadog_checks_dev/datadog_checks/dev/plugin/pytest.py @@ -303,7 +303,7 @@ def mock_http_response(mocker, mock_response): @pytest.fixture def mock_http(mocker): - from unittest.mock import PropertyMock, create_autospec + from unittest.mock import MagicMock, PropertyMock, create_autospec from datadog_checks.base.checks.base import AgentCheck from datadog_checks.base.utils.http_protocol import HTTPClientProtocol From 041ceb803fdbe36e0be731ed2b68128463a2ca63 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Thu, 5 Mar 2026 15:06:55 -0800 Subject: [PATCH 20/25] 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 --- datadog_checks_dev/datadog_checks/dev/plugin/pytest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datadog_checks_dev/datadog_checks/dev/plugin/pytest.py b/datadog_checks_dev/datadog_checks/dev/plugin/pytest.py index e2731673a52b4..2e549004fec28 100644 --- a/datadog_checks_dev/datadog_checks/dev/plugin/pytest.py +++ b/datadog_checks_dev/datadog_checks/dev/plugin/pytest.py @@ -303,7 +303,7 @@ def mock_http_response(mocker, mock_response): @pytest.fixture def mock_http(mocker): - from unittest.mock import MagicMock, PropertyMock, create_autospec + from unittest.mock import PropertyMock, create_autospec from datadog_checks.base.checks.base import AgentCheck from datadog_checks.base.utils.http_protocol import HTTPClientProtocol From dce0290ae7202bced4061ed321bfbe8832e984e5 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Tue, 10 Mar 2026 13:50:37 -0400 Subject: [PATCH 21/25] 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 --- datadog_checks_base/tests/base/utils/http/test_headers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/datadog_checks_base/tests/base/utils/http/test_headers.py b/datadog_checks_base/tests/base/utils/http/test_headers.py index dd3bca5d4b46a..485188722899d 100644 --- a/datadog_checks_base/tests/base/utils/http/test_headers.py +++ b/datadog_checks_base/tests/base/utils/http/test_headers.py @@ -120,6 +120,7 @@ def test_set_header(): assert http.get_header('Accept') == 'application/json' + def test_set_header_case_insensitive(): http = RequestsWrapper({}, {}) http.set_header('accept', 'application/json') From fad98d61eb504418616995950a7c450308cddb97 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Mon, 16 Mar 2026 16:20:08 -0400 Subject: [PATCH 22/25] 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 --- datadog_checks_base/tests/base/utils/http/test_headers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/datadog_checks_base/tests/base/utils/http/test_headers.py b/datadog_checks_base/tests/base/utils/http/test_headers.py index 485188722899d..dd3bca5d4b46a 100644 --- a/datadog_checks_base/tests/base/utils/http/test_headers.py +++ b/datadog_checks_base/tests/base/utils/http/test_headers.py @@ -120,7 +120,6 @@ def test_set_header(): assert http.get_header('Accept') == 'application/json' - def test_set_header_case_insensitive(): http = RequestsWrapper({}, {}) http.set_header('accept', 'application/json') From 560d9f340f7792e272ac7ec3317a0e3e4f29d073 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Mon, 16 Mar 2026 22:05:06 -0400 Subject: [PATCH 23/25] 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 --- .../base/checks/openmetrics/v2/base.py | 3 ++- .../datadog_checks/base/utils/http_testing.py | 12 +++++++++++- traefik_mesh/datadog_checks/traefik_mesh/check.py | 9 ++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/datadog_checks_base/datadog_checks/base/checks/openmetrics/v2/base.py b/datadog_checks_base/datadog_checks/base/checks/openmetrics/v2/base.py index 1a476138157de..ab77ff8c25a7e 100644 --- a/datadog_checks_base/datadog_checks/base/checks/openmetrics/v2/base.py +++ b/datadog_checks_base/datadog_checks/base/checks/openmetrics/v2/base.py @@ -8,6 +8,7 @@ from datadog_checks.base.checks import AgentCheck from datadog_checks.base.errors import ConfigurationError +from datadog_checks.base.utils.http_exceptions import HTTPRequestError, HTTPStatusError from datadog_checks.base.utils.tracing import traced_class from .scraper import OpenMetricsScraper @@ -71,7 +72,7 @@ def check(self, _): with self.adopt_namespace(scraper.namespace): try: scraper.scrape() - except (ConnectionError, RequestException) as e: + except (ConnectionError, RequestException, HTTPRequestError, HTTPStatusError) as e: self.log.error("There was an error scraping endpoint %s: %s", endpoint, str(e)) raise type(e)("There was an error scraping endpoint {}: {}".format(endpoint, e)) from None 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 3a509f2673f3f..f954359120185 100644 --- a/datadog_checks_base/datadog_checks/base/utils/http_testing.py +++ b/datadog_checks_base/datadog_checks/base/utils/http_testing.py @@ -3,7 +3,9 @@ # Licensed under a 3-clause BSD style license (see LICENSE) import json from datetime import timedelta +from http.client import responses as http_responses from io import BytesIO +from textwrap import dedent from typing import Any, Iterator from unittest.mock import MagicMock @@ -41,7 +43,7 @@ def __init__( (isinstance(content, str) and content.startswith('\n')) or (isinstance(content, bytes) and content.startswith(b'\n')) ): - content = content[1:] + content = dedent(content[1:]) if isinstance(content, str) else content[1:] self._content = content.encode('utf-8') if isinstance(content, str) else content self.status_code = status_code @@ -62,6 +64,14 @@ def content(self) -> bytes: def text(self) -> str: return self._content.decode('utf-8') + @property + def ok(self) -> bool: + return self.status_code < 400 + + @property + def reason(self) -> str: + return http_responses.get(self.status_code, '') + def json(self, **kwargs: Any) -> Any: return json.loads(self.text, **kwargs) diff --git a/traefik_mesh/datadog_checks/traefik_mesh/check.py b/traefik_mesh/datadog_checks/traefik_mesh/check.py index a1e1549f9c566..e270bf4d943cf 100644 --- a/traefik_mesh/datadog_checks/traefik_mesh/check.py +++ b/traefik_mesh/datadog_checks/traefik_mesh/check.py @@ -8,6 +8,8 @@ import requests from datadog_checks.base import AgentCheck, OpenMetricsBaseCheckV2 +from datadog_checks.base.utils.http_exceptions import HTTPConnectionError as _HTTPConnectionError +from datadog_checks.base.utils.http_exceptions import HTTPStatusError from datadog_checks.traefik_mesh.config_models import ConfigMixin from datadog_checks.traefik_mesh.metrics import METRIC_MAP, RENAME_LABELS @@ -112,7 +114,12 @@ def _get_json(self, url): resp = self.http.get(url) resp.raise_for_status() return resp.json() - except (requests.exceptions.HTTPError, requests.exceptions.ConnectionError) as e: + except ( + requests.exceptions.HTTPError, + requests.exceptions.ConnectionError, + HTTPStatusError, + _HTTPConnectionError, + ) as e: self.warning( "Couldn't connect to URL: %s with exception: %s. Please verify the address is reachable", url, e ) From 14a6b7e9d640325fce7bc5df20cf6c85e18a8306 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Tue, 17 Mar 2026 14:28:40 -0400 Subject: [PATCH 24/25] 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) --- .../base/checks/openmetrics/v2/base.py | 1 + .../datadog_checks/base/utils/http_protocol.py | 5 +++++ .../tests/base/utils/http/test_http_testing.py | 13 +++++++++++++ traefik_mesh/datadog_checks/traefik_mesh/check.py | 3 ++- 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/datadog_checks_base/datadog_checks/base/checks/openmetrics/v2/base.py b/datadog_checks_base/datadog_checks/base/checks/openmetrics/v2/base.py index ab77ff8c25a7e..6552a1723c4d1 100644 --- a/datadog_checks_base/datadog_checks/base/checks/openmetrics/v2/base.py +++ b/datadog_checks_base/datadog_checks/base/checks/openmetrics/v2/base.py @@ -72,6 +72,7 @@ def check(self, _): with self.adopt_namespace(scraper.namespace): try: scraper.scrape() + # Pairs requests-native + library-agnostic exceptions; simplify to HTTPError after migration. except (ConnectionError, RequestException, HTTPRequestError, HTTPStatusError) as e: self.log.error("There was an error scraping endpoint %s: %s", endpoint, str(e)) raise type(e)("There was an error scraping endpoint {}: {}".format(endpoint, e)) from None diff --git a/datadog_checks_base/datadog_checks/base/utils/http_protocol.py b/datadog_checks_base/datadog_checks/base/utils/http_protocol.py index f6fb97ca5c849..4d103de5930c3 100644 --- a/datadog_checks_base/datadog_checks/base/utils/http_protocol.py +++ b/datadog_checks_base/datadog_checks/base/utils/http_protocol.py @@ -13,6 +13,11 @@ class HTTPResponseProtocol(Protocol): text: str headers: Mapping[str, str] + @property + def ok(self) -> bool: ... + @property + def reason(self) -> str: ... + def json(self, **kwargs: Any) -> Any: ... def raise_for_status(self) -> None: ... def close(self) -> None: ... diff --git a/datadog_checks_base/tests/base/utils/http/test_http_testing.py b/datadog_checks_base/tests/base/utils/http/test_http_testing.py index 81d49bc17b653..6574b81896fce 100644 --- a/datadog_checks_base/tests/base/utils/http/test_http_testing.py +++ b/datadog_checks_base/tests/base/utils/http/test_http_testing.py @@ -70,3 +70,16 @@ def test_mock_response_normalize_leading_newline(): response = MockHTTPResponse(content=content) assert response.text == 'Actual content' + + +def test_mock_response_ok_property(): + assert MockHTTPResponse(status_code=200).ok is True + assert MockHTTPResponse(status_code=399).ok is True + assert MockHTTPResponse(status_code=400).ok is False + assert MockHTTPResponse(status_code=500).ok is False + + +def test_mock_response_reason_property(): + assert MockHTTPResponse(status_code=200).reason == 'OK' + assert MockHTTPResponse(status_code=404).reason == 'Not Found' + assert MockHTTPResponse(status_code=999).reason == '' diff --git a/traefik_mesh/datadog_checks/traefik_mesh/check.py b/traefik_mesh/datadog_checks/traefik_mesh/check.py index e270bf4d943cf..ab49a566a0ffb 100644 --- a/traefik_mesh/datadog_checks/traefik_mesh/check.py +++ b/traefik_mesh/datadog_checks/traefik_mesh/check.py @@ -10,6 +10,7 @@ from datadog_checks.base import AgentCheck, OpenMetricsBaseCheckV2 from datadog_checks.base.utils.http_exceptions import HTTPConnectionError as _HTTPConnectionError from datadog_checks.base.utils.http_exceptions import HTTPStatusError +from datadog_checks.base.utils.http_exceptions import HTTPTimeoutError as _HTTPTimeoutError from datadog_checks.traefik_mesh.config_models import ConfigMixin from datadog_checks.traefik_mesh.metrics import METRIC_MAP, RENAME_LABELS @@ -123,6 +124,6 @@ def _get_json(self, url): self.warning( "Couldn't connect to URL: %s with exception: %s. Please verify the address is reachable", url, e ) - except requests.exceptions.Timeout as e: + except (requests.exceptions.Timeout, _HTTPTimeoutError) as e: self.warning("Connection timeout when connecting to %s: %s", url, e) return None From 08e03be2ca1b160210eb0896233f4cd6d9e99174 Mon Sep 17 00:00:00 2001 From: mwdd146980 Date: Tue, 24 Mar 2026 15:53:56 -0400 Subject: [PATCH 25/25] 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) --- .../datadog_checks/base/utils/http_testing.py | 2 ++ .../base/utils/http/test_http_testing.py | 9 ++++++++ traefik_mesh/changelog.d/22676.changed | 1 + .../datadog_checks/traefik_mesh/check.py | 2 +- traefik_mesh/tests/test_unit.py | 21 +++++++++++++++++++ 5 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 traefik_mesh/changelog.d/22676.changed 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 f954359120185..83b6a85c263d2 100644 --- a/datadog_checks_base/datadog_checks/base/utils/http_testing.py +++ b/datadog_checks_base/datadog_checks/base/utils/http_testing.py @@ -66,6 +66,8 @@ def text(self) -> str: @property def ok(self) -> bool: + # Transitional: mirrors requests.Response.ok for current production code. + # httpx uses is_success/is_client_error/is_server_error instead. return self.status_code < 400 @property diff --git a/datadog_checks_base/tests/base/utils/http/test_http_testing.py b/datadog_checks_base/tests/base/utils/http/test_http_testing.py index 6574b81896fce..32a9036db7080 100644 --- a/datadog_checks_base/tests/base/utils/http/test_http_testing.py +++ b/datadog_checks_base/tests/base/utils/http/test_http_testing.py @@ -72,6 +72,15 @@ def test_mock_response_normalize_leading_newline(): assert response.text == 'Actual content' +def test_mock_response_normalize_leading_newline_with_indent(): + content = """ + line one + line two + """ + response = MockHTTPResponse(content=content) + assert response.text == "line one\nline two\n" + + def test_mock_response_ok_property(): assert MockHTTPResponse(status_code=200).ok is True assert MockHTTPResponse(status_code=399).ok is True diff --git a/traefik_mesh/changelog.d/22676.changed b/traefik_mesh/changelog.d/22676.changed new file mode 100644 index 0000000000000..f39347eb80c40 --- /dev/null +++ b/traefik_mesh/changelog.d/22676.changed @@ -0,0 +1 @@ +Remove unused ``url`` parameter from ``get_version``. \ No newline at end of file diff --git a/traefik_mesh/datadog_checks/traefik_mesh/check.py b/traefik_mesh/datadog_checks/traefik_mesh/check.py index ab49a566a0ffb..ad1394c8a9aca 100644 --- a/traefik_mesh/datadog_checks/traefik_mesh/check.py +++ b/traefik_mesh/datadog_checks/traefik_mesh/check.py @@ -87,7 +87,7 @@ def get_mesh_ready_status(self): return node_status - def get_version(self, url): + def get_version(self): """Fetches Traefik Proxy version from the Proxy API""" version_url = urljoin(self.traefik_proxy_api_endpoint, PROXY_VERSION) diff --git a/traefik_mesh/tests/test_unit.py b/traefik_mesh/tests/test_unit.py index 6a7cb29d2507f..c6c3acbc697df 100644 --- a/traefik_mesh/tests/test_unit.py +++ b/traefik_mesh/tests/test_unit.py @@ -5,6 +5,9 @@ import pytest from datadog_checks.base.constants import ServiceCheck +from datadog_checks.base.utils.http_exceptions import HTTPConnectionError as _HTTPConnectionError +from datadog_checks.base.utils.http_exceptions import HTTPStatusError +from datadog_checks.base.utils.http_exceptions import HTTPTimeoutError as _HTTPTimeoutError from datadog_checks.dev.utils import assert_service_checks, get_metadata_metrics from datadog_checks.traefik_mesh import TraefikMeshCheck @@ -125,3 +128,21 @@ def test_submit_version(datadog_agent, dd_run_check, mock_http_response): } datadog_agent.assert_metadata('test:123', version_metadata) + + +def test_get_json_handles_http_status_error(): + check = TraefikMeshCheck('traefik_mesh', {}, [OM_MOCKED_INSTANCE]) + with mock.patch('requests.Session.get', side_effect=HTTPStatusError('404 Client Error')): + assert check._get_json('http://example.com/api') is None + + +def test_get_json_handles_http_connection_error(): + check = TraefikMeshCheck('traefik_mesh', {}, [OM_MOCKED_INSTANCE]) + with mock.patch('requests.Session.get', side_effect=_HTTPConnectionError('Connection refused')): + assert check._get_json('http://example.com/api') is None + + +def test_get_json_handles_http_timeout_error(): + check = TraefikMeshCheck('traefik_mesh', {}, [OM_MOCKED_INSTANCE]) + with mock.patch('requests.Session.get', side_effect=_HTTPTimeoutError('Read timed out')): + assert check._get_json('http://example.com/api') is None