Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
e01336e
Add HTTP protocol definitions for httpx migration (#22662)
mwdd146980 Feb 18, 2026
e237047
Add library-agnostic HTTP exception hierarchy
mwdd146980 Feb 19, 2026
3c6d79a
Update PR changelog
mwdd146980 Feb 20, 2026
de1e85c
Rename changelog
mwdd146980 Feb 20, 2026
09ba979
Fix iter_content/iter_lines return type and document the decode_unico…
mwdd146980 Feb 20, 2026
00a38e5
Address Noueman's comments
mwdd146980 Feb 20, 2026
f92a1c7
Remove docstring on http_exceptions.py
mwdd146980 Feb 20, 2026
ec98927
Add mock HTTP response (#22677)
mwdd146980 Feb 20, 2026
e81884f
Update changelog: consolidate into 22676.added, drop 22677.added
mwdd146980 Feb 20, 2026
3237476
Remove module docstrings from http_testing.py and test_http_testing.py
mwdd146980 Feb 20, 2026
dc82419
Re-export HTTP exceptions and protocol types from http.py
mwdd146980 Feb 20, 2026
7ddf84f
Use unittest.mock.MagicMock for raw socket mock in MockHTTPResponse
mwdd146980 Feb 23, 2026
76d0c3e
Replace _CaseInsensitiveDict with plain lowercased dict in MockHTTPRe…
mwdd146980 Feb 23, 2026
72981a5
Add mock_http fixture; migrate 9 intg to mock_http (#22710)
mwdd146980 Feb 28, 2026
5534ed6
Address Noueman's review comments on PR #22676
mwdd146980 Mar 2, 2026
553d5c9
Fix ruff lint: remove unnecessary parens around single-line string
mwdd146980 Mar 2, 2026
f8fc5de
Add changelog entries for datadog_checks_base and datadog_checks_dev
mwdd146980 Mar 2, 2026
4f36d9a
Fix TestUseLatestSpec: assert on _use_latest_spec instead of removed …
mwdd146980 Mar 2, 2026
11f5db1
Add changelog entry for vault intg
mwdd146980 Mar 2, 2026
381950d
Revise message for vault intg changelog entry
mwdd146980 Mar 2, 2026
a04adc8
Clean up MockHTTPResponse: top-level imports, flatten test classes, t…
mwdd146980 Mar 13, 2026
ac94f5d
Migrate config assertion tests away from requests
mwdd146980 Mar 19, 2026
697ad3b
Widen except clauses and align MockHTTPResponse for fixture swap (#22…
mwdd146980 Apr 4, 2026
2ba7a3a
Swap mock_http_response to MockHTTPResponse (#22935)
mwdd146980 Apr 5, 2026
b8257ea
Widen production except clauses for httpx migration (#23046)
mwdd146980 Apr 17, 2026
84ff3d3
Batch migrate integration tests from MockResponse to MockHTTPResponse…
mwdd146980 Apr 20, 2026
ead2f66
Migrate conftest.py MockResponse fixture chains to MockHTTPResponse (…
mwdd146980 Apr 20, 2026
b773da5
Revert sonatype_nexus test to master: preserve PR #23448 design decis…
mwdd146980 Apr 24, 2026
9f799e1
Revert bentoml test to master: no test behavior changes in migration …
mwdd146980 Apr 24, 2026
03f40f5
Drop bentoml duplicate assert_all_metrics_covered() (sync with #23470)
mwdd146980 Apr 28, 2026
7e8968a
Update dependency resolution
Apr 28, 2026
242c4ad
Remove requests.Session test patches from conftest.py files (#23314)
mwdd146980 May 1, 2026
610bb2b
Merge remote-tracking branch 'origin/master' into mwdd146980/httpx-mi…
mwdd146980 May 1, 2026
faddc6c
Migrate squid tests to mock_http fixture (#23555)
mwdd146980 May 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion airflow/datadog_checks/airflow/airflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import requests

from datadog_checks.base import AgentCheck, ConfigurationError
from datadog_checks.base.utils.http_exceptions import HTTPTimeoutError
from datadog_checks.base.utils.time import get_timestamp

AIRFLOW_STATUS_OK = "OK"
Expand Down Expand Up @@ -141,6 +142,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
109 changes: 50 additions & 59 deletions airflow/tests/test_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,16 @@ def test_service_checks_cannot_connect(aggregator):
'json_resp, expected_healthy_status, expected_healthy_value',
[({'status': 'OK'}, AgentCheck.OK, 1), ({'status': 'KO'}, AgentCheck.CRITICAL, 0), ({}, AgentCheck.CRITICAL, 0)],
)
def test_service_checks_healthy_exp(aggregator, json_resp, expected_healthy_status, expected_healthy_value):
def test_service_checks_healthy_exp(aggregator, mock_http, json_resp, expected_healthy_status, expected_healthy_value):
instance = common.FULL_CONFIG['instances'][0]
check = AirflowCheck('airflow', common.FULL_CONFIG, [instance])

with mock.patch('datadog_checks.airflow.airflow.AirflowCheck._get_version', return_value=None):
mock_session = mock.MagicMock()
with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=mock_session):
mock_resp = mock.MagicMock(status_code=200)
mock_resp.json.side_effect = [json_resp]
mock_session.get.return_value = mock_resp
mock_resp = mock.MagicMock(status_code=200)
mock_resp.json.side_effect = [json_resp]
mock_http.get.return_value = mock_resp

check.check(None)
with mock.patch('datadog_checks.airflow.airflow.AirflowCheck._get_version', return_value=None):
check.check(None)

tags = ['key:my-tag', 'url:http://localhost:8080']

Expand All @@ -54,65 +52,60 @@ def test_service_checks_healthy_exp(aggregator, json_resp, expected_healthy_stat
],
)
def test_service_checks_healthy_stable(
aggregator, metadb_status, scheduler_status, expected_healthy_status, expected_healthy_value
aggregator, mock_http, metadb_status, scheduler_status, expected_healthy_status, expected_healthy_value
): # Stable is only defined in the context of Airflow 2
instance = common.FULL_CONFIG['instances'][0]
check = AirflowCheck('airflow', common.FULL_CONFIG, [instance])

with mock.patch('datadog_checks.airflow.airflow.AirflowCheck._get_version', return_value='2.6.2'):
mock_session = mock.MagicMock()
with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=mock_session):
mock_resp = mock.MagicMock(status_code=200)
mock_resp.json.side_effect = [
{'metadatabase': {'status': metadb_status}, 'scheduler': {'status': scheduler_status}},
{'status': 'OK'},
]
mock_session.get.return_value = mock_resp
mock_resp = mock.MagicMock(status_code=200)
mock_resp.json.side_effect = [
{'metadatabase': {'status': metadb_status}, 'scheduler': {'status': scheduler_status}},
{'status': 'OK'},
]
mock_http.get.return_value = mock_resp

check.check(None)
with mock.patch('datadog_checks.airflow.airflow.AirflowCheck._get_version', return_value='2.6.2'):
check.check(None)

tags = ['key:my-tag', 'url:http://localhost:8080']

aggregator.assert_service_check('airflow.healthy', expected_healthy_status, tags=tags, count=1)
aggregator.assert_metric('airflow.healthy', expected_healthy_value, tags=tags, count=1)


def test_dag_total_tasks(aggregator, task_instance):
def test_dag_total_tasks(aggregator, mock_http, task_instance):
instance = common.FULL_CONFIG['instances'][0]
check = AirflowCheck('airflow', common.FULL_CONFIG, [instance])

with mock.patch('datadog_checks.airflow.airflow.AirflowCheck._get_version', return_value='2.6.2'):
req = mock.MagicMock()
with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=req):
mock_resp = mock.MagicMock(status_code=200)
mock_resp.json.side_effect = [
{'metadatabase': {'status': 'healthy'}, 'scheduler': {'status': 'healthy'}},
task_instance,
]
req.get.return_value = mock_resp
mock_resp = mock.MagicMock(status_code=200)
mock_resp.json.side_effect = [
{'metadatabase': {'status': 'healthy'}, 'scheduler': {'status': 'healthy'}},
task_instance,
]
mock_http.get.return_value = mock_resp

check.check(None)
with mock.patch('datadog_checks.airflow.airflow.AirflowCheck._get_version', return_value='2.6.2'):
check.check(None)

aggregator.assert_metric('airflow.dag.task.total_running', value=1, count=1)


def test_dag_task_ongoing_duration(aggregator, task_instance):
def test_dag_task_ongoing_duration(aggregator, mock_http, task_instance):
instance = common.FULL_CONFIG['instances'][0]
check = AirflowCheck('airflow', common.FULL_CONFIG, [instance])

mock_resp = mock.MagicMock(status_code=200)
mock_resp.json.side_effect = [
{'metadatabase': {'status': 'healthy'}, 'scheduler': {'status': 'healthy'}},
]
mock_http.get.return_value = mock_resp

with mock.patch('datadog_checks.airflow.airflow.AirflowCheck._get_version', return_value='2.6.2'):
req = mock.MagicMock()
with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=req):
mock_resp = mock.MagicMock(status_code=200)
mock_resp.json.side_effect = [
{'metadatabase': {'status': 'healthy'}, 'scheduler': {'status': 'healthy'}},
]
req.get.return_value = mock_resp
with mock.patch(
'datadog_checks.airflow.airflow.AirflowCheck._get_all_task_instances',
return_value=task_instance.get('task_instances'),
):
check.check(None)
with mock.patch(
'datadog_checks.airflow.airflow.AirflowCheck._get_all_task_instances',
return_value=task_instance.get('task_instances'),
):
check.check(None)

aggregator.assert_metric(
'airflow.dag.task.ongoing_duration',
Expand Down Expand Up @@ -141,23 +134,21 @@ def test_dag_task_ongoing_duration(aggregator, task_instance):
),
],
)
def test_config_collect_ongoing_duration(collect_ongoing_duration, should_call_method):
def test_config_collect_ongoing_duration(mock_http, collect_ongoing_duration, should_call_method):
instance = {**common.FULL_CONFIG['instances'][0], 'collect_ongoing_duration': collect_ongoing_duration}
check = AirflowCheck('airflow', common.FULL_CONFIG, [instance])

mock_resp = mock.MagicMock(status_code=200)
mock_resp.json.side_effect = [
{'metadatabase': {'status': 'healthy'}, 'scheduler': {'status': 'healthy'}},
]
mock_http.get.return_value = mock_resp

with mock.patch('datadog_checks.airflow.airflow.AirflowCheck._get_version', return_value='2.6.2'):
req = mock.MagicMock()
with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=req):
mock_resp = mock.MagicMock(status_code=200)
mock_resp.json.side_effect = [
{'metadatabase': {'status': 'healthy'}, 'scheduler': {'status': 'healthy'}},
]
req.get.return_value = mock_resp

with mock.patch(
'datadog_checks.airflow.airflow.AirflowCheck._get_all_task_instances'
) as mock_get_all_task_instances:
check.check(None)

# Assert method calls
mock_get_all_task_instances.assert_has_calls(should_call_method, any_order=False)
with mock.patch(
'datadog_checks.airflow.airflow.AirflowCheck._get_all_task_instances'
) as mock_get_all_task_instances:
check.check(None)

# Assert method calls
mock_get_all_task_instances.assert_has_calls(should_call_method, any_order=False)
2 changes: 1 addition & 1 deletion appgate_sdp/tests/test_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def test_check_appgate_sdp(dd_run_check, aggregator, instance, mock_http_respons
def test_emits_critical_service_check_when_service_is_down(dd_run_check, aggregator, instance, mock_http_response):
mock_http_response(status_code=404)
check = AppgateSDPCheck('appgate_sdp', {}, [instance])
with pytest.raises(Exception, match='requests.exceptions.HTTPError'):
with pytest.raises(Exception, match='HTTPStatusError'):
dd_run_check(check)
aggregator.assert_service_check('appgate_sdp.openmetrics.health', AppgateSDPCheck.CRITICAL)

Expand Down
4 changes: 2 additions & 2 deletions arangodb/tests/test_arangodb.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from requests import HTTPError

from datadog_checks.arangodb import ArangodbCheck
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 .common import METRICS
Expand Down Expand Up @@ -54,7 +54,7 @@ def test_check(instance, dd_run_check, aggregator, tag_condition, base_tags):

def mock_requests_get(session, url, *args, **kwargs):
fixture = url.rsplit('/', 1)[-1]
return MockResponse(file_path=os.path.join(os.path.dirname(__file__), 'fixtures', tag_condition, fixture))
return MockHTTPResponse(file_path=os.path.join(os.path.dirname(__file__), 'fixtures', tag_condition, fixture))

with mock.patch('requests.Session.get', side_effect=mock_requests_get, autospec=True):
dd_run_check(check)
Expand Down
2 changes: 1 addition & 1 deletion argo_workflows/tests/test_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,6 @@ def test_check_with_fixtures(dd_run_check, aggregator, instance, mock_http_respo
def test_emits_critical_service_check_when_service_is_down(dd_run_check, aggregator, instance, mock_http_response):
mock_http_response(status_code=404)
check = ArgoWorkflowsCheck('argo_workflows', {}, [instance])
with pytest.raises(Exception, match='requests.exceptions.HTTPError'):
with pytest.raises(Exception, match='HTTPStatusError'):
dd_run_check(check)
aggregator.assert_service_check('argo_workflows.openmetrics.health', ArgoWorkflowsCheck.CRITICAL)
19 changes: 10 additions & 9 deletions avi_vantage/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
import json
import os
from typing import Any, AnyStr
from unittest.mock import MagicMock
from urllib.parse import urlparse

import mock
import pytest

from datadog_checks.base.utils.http_testing import MockHTTPResponse
from datadog_checks.dev import docker_run, get_docker_hostname, get_here
from datadog_checks.dev.conditions import CheckDockerLogs
from datadog_checks.dev.http import MockResponse

HERE = get_here()

Expand Down Expand Up @@ -57,7 +57,7 @@ def _get_metrics(metrics_folder=NO_TENANT_METRICS_FOLDER, endpoint=None):


@pytest.fixture
def mock_client():
def mock_client(mock_http):
def mock_get(url: AnyStr, *__: Any, **___: Any):
parsed = urlparse(url)
resource = [part for part in parsed.path.split('/') if len(part) > 0][-1]
Expand All @@ -69,20 +69,21 @@ def mock_get(url: AnyStr, *__: Any, **___: Any):
path['tenant=admin%2Ctenant_a%2Ctenant_b'] = MULTIPLE_TENANTS_METRICS_FOLDER

if query_params:
return MockResponse(
return MockHTTPResponse(
file_path=os.path.join(HERE, 'compose', 'fixtures', path[query_params], f'{resource}_metrics')
)

return MockResponse(
return MockHTTPResponse(
file_path=os.path.join(HERE, 'compose', 'fixtures', NO_TENANT_METRICS_FOLDER, f'{resource}_metrics')
)

def mock_post(url: AnyStr, *__: Any, **___: Any):
return mock.MagicMock(status_code=200, content=b'{"results": []}')
return MockHTTPResponse(json_data={"results": []})

with mock.patch('datadog_checks.base.utils.http.RequestsWrapper.get', side_effect=mock_get):
with mock.patch('datadog_checks.base.utils.http.RequestsWrapper.post', new=mock_post):
yield
mock_http.session = MagicMock(cookies={})
mock_http.get.side_effect = mock_get
mock_http.post.side_effect = mock_post
yield


@pytest.fixture(scope='session')
Expand Down
2 changes: 1 addition & 1 deletion celery/tests/test_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def test_emits_critical_openemtrics_service_check_when_service_is_down(
"""
mock_http_response(status_code=404)
check = CeleryCheck("celery", {}, [instance])
with pytest.raises(Exception, match="requests.exceptions.HTTPError"):
with pytest.raises(Exception, match="HTTPStatusError"):
dd_run_check(check)

aggregator.assert_all_metrics_covered()
Expand Down
4 changes: 2 additions & 2 deletions cert_manager/tests/test_cert_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
import mock
import pytest

from datadog_checks.base.utils.http_testing import MockHTTPResponse
from datadog_checks.cert_manager import CertManagerCheck
from datadog_checks.dev.http import MockResponse

from .common import ACME_METRICS, CERT_METRICS, CONTROLLER_METRICS, MOCK_INSTANCE

Expand All @@ -32,7 +32,7 @@ def test_check(aggregator, dd_run_check):
check = CertManagerCheck('cert_manager', {}, [MOCK_INSTANCE])

def mock_requests_get(url, *args, **kwargs):
return MockResponse(file_path=os.path.join(os.path.dirname(__file__), 'fixtures', 'cert_manager.txt'))
return MockHTTPResponse(file_path=os.path.join(os.path.dirname(__file__), 'fixtures', 'cert_manager.txt'))

with mock.patch('requests.Session.get', side_effect=mock_requests_get, autospec=True):
dd_run_check(check)
Expand Down
24 changes: 7 additions & 17 deletions cilium/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
# Licensed under a 3-clause BSD style license (see LICENSE)
import os

import mock
import pytest

from datadog_checks.base.utils.common import get_docker_hostname
from datadog_checks.base.utils.http_testing import MockHTTPResponse
from datadog_checks.cilium import CiliumCheck
from datadog_checks.dev import run_command
from datadog_checks.dev.kind import kind_run
Expand Down Expand Up @@ -198,28 +198,18 @@ def operator_instance_use_openmetrics():


@pytest.fixture()
def mock_agent_data():
def mock_agent_data(mock_openmetrics_http):
f_name = os.path.join(os.path.dirname(__file__), "fixtures", "agent_metrics.txt")
with open(f_name, "r") as f:
text_data = f.read()
with mock.patch(
'requests.Session.get',
return_value=mock.MagicMock(
status_code=200, iter_lines=lambda **kwargs: text_data.split("\n"), headers={"Content-Type": "text/plain"}
),
):
yield
mock_openmetrics_http.get.return_value = MockHTTPResponse(content=text_data, headers={"Content-Type": "text/plain"})
yield


@pytest.fixture()
def mock_operator_data():
def mock_operator_data(mock_openmetrics_http):
f_name = os.path.join(os.path.dirname(__file__), "fixtures", "operator_metrics.txt")
with open(f_name, "r") as f:
text_data = f.read()
with mock.patch(
'requests.Session.get',
return_value=mock.MagicMock(
status_code=200, iter_lines=lambda **kwargs: text_data.split("\n"), headers={"Content-Type": "text/plain"}
),
):
yield
mock_openmetrics_http.get.return_value = MockHTTPResponse(content=text_data, headers={"Content-Type": "text/plain"})
yield
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# Licensed under a 3-clause BSD style license (see LICENSE)
from __future__ import annotations

from json import JSONDecodeError as StdJSONDecodeError
from typing import TYPE_CHECKING, Any, Dict, List # noqa: F401
from xmlrpc.client import ServerProxy

Expand All @@ -25,7 +26,7 @@ def _safely_process_metrics_response(data: ResponseWrapper) -> dict[str, dict]:
# See https://github.com/yaml/pyyaml/issues/443
try:
return data.json()
except requests.exceptions.JSONDecodeError:
except (requests.exceptions.JSONDecodeError, StdJSONDecodeError):
return yaml.load(data.content, Loader=yaml.SafeLoader)


Expand Down
15 changes: 7 additions & 8 deletions citrix_hypervisor/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
# Licensed under a 3-clause BSD style license (see LICENSE)
import os

import mock
import pytest

from datadog_checks.base.utils.http_testing import MockHTTPResponse
from datadog_checks.dev import docker_run
from datadog_checks.dev.http import MockResponse

from . import common

Expand Down Expand Up @@ -38,17 +37,17 @@ def mock_requests_get(url, *args, **kwargs):
print(url_parts)

if url_parts[0] == 'wrong':
return MockResponse(status_code=404)
return MockHTTPResponse(status_code=404)

json_file = f"rrd_updates_{url_parts[0]}.json" if url_parts[1] == "rrd_updates" else f"{url_parts[1]}.json"
path = os.path.join(common.HERE, 'fixtures', 'standalone', json_file)
if not os.path.exists(path):
return MockResponse(status_code=404)
return MockHTTPResponse(status_code=404)

return MockResponse(file_path=path)
return MockHTTPResponse(file_path=path)


@pytest.fixture
def mock_responses():
with mock.patch('requests.Session.get', side_effect=mock_requests_get):
yield
def mock_responses(mock_http):
mock_http.get.side_effect = mock_requests_get
yield
Loading
Loading