Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
84adf1b
Migrate couch config assertion test to check.http.options
mwdd146980 Feb 25, 2026
270399b
Migrate couch config assertion test to http_client_session
mwdd146980 Feb 25, 2026
0487a47
Migrate gitlab_runner timeout test to http_client_session
mwdd146980 Feb 25, 2026
bbdb5c2
Reformat with ddev test --fmt
mwdd146980 Feb 25, 2026
70bf198
Migrate marathon config assertion test to http_client_session
mwdd146980 Feb 25, 2026
a86d301
Migrate rabbitmq session-patch tests to http_client_session
mwdd146980 Feb 25, 2026
ffc056c
Migrate consul session-patch tests to http_client_session
mwdd146980 Feb 25, 2026
aa74f49
Migrate torchserve session-patch test to http_client_session
mwdd146980 Feb 25, 2026
78bdf3b
Migrate etcd, ecs_fargate, mesos_master session-patch tests to http_c…
mwdd146980 Feb 25, 2026
d386336
Reformat with ddev test --fmt
mwdd146980 Feb 25, 2026
ffebac2
Scrap http_client_session; migrate Step 2 tests to check.http.options…
mwdd146980 Feb 25, 2026
84bded7
Migrate airflow session-patch tests to mock_http
mwdd146980 Feb 25, 2026
e522ca0
Migrate druid session-patch tests to mock_http
mwdd146980 Feb 25, 2026
66c6df3
Migrate mesos_slave session-patch tests to mock_http
mwdd146980 Feb 25, 2026
7bfaf2b
Migrate nginx session-patch tests to check.http.options and mock_http
mwdd146980 Feb 25, 2026
05a25f1
Migrate php_fpm session-patch tests to check.http.options and mock_http
mwdd146980 Feb 25, 2026
5c31b82
Add options to HTTPClientProtocol; initialize in mock_http fixture
mwdd146980 Feb 25, 2026
13af852
Remove mock_http from http_testing.py; use datadog_checks_dev plugin …
mwdd146980 Feb 27, 2026
9df0547
Fix mock_http fixture: initialize client.options as MagicMock
mwdd146980 Feb 27, 2026
44b71bc
Fix mock_http fixture: use real dict for client.options
mwdd146980 Mar 5, 2026
a3ba255
Flatten test classes to top-level functions in test_headers.py and te…
mwdd146980 Mar 10, 2026
4392635
Make get_header/set_header case-insensitive
mwdd146980 Mar 16, 2026
ad32264
Align MockHTTPResponse + widen production except clauses (PR 3a)
mwdd146980 Mar 17, 2026
731cea9
Address PR 3a review: protocol gaps, transitional comment, timeout ha…
mwdd146980 Mar 17, 2026
fd558c5
Address agint-review follow-ups: dedent test, exception tests, get_ve…
mwdd146980 Mar 24, 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
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -71,7 +72,8 @@ def check(self, _):
with self.adopt_namespace(scraper.namespace):
try:
scraper.scrape()
except (ConnectionError, RequestException) as e:
# 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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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: ...
Expand Down
14 changes: 13 additions & 1 deletion datadog_checks_base/datadog_checks/base/utils/http_testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand All @@ -62,6 +64,16 @@ def content(self) -> bytes:
def text(self) -> str:
return self._content.decode('utf-8')

@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
def reason(self) -> str:
return http_responses.get(self.status_code, '')

def json(self, **kwargs: Any) -> Any:
return json.loads(self.text, **kwargs)

Expand Down
22 changes: 22 additions & 0 deletions datadog_checks_base/tests/base/utils/http/test_http_testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,25 @@ def test_mock_response_normalize_leading_newline():
response = MockHTTPResponse(content=content)

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
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 == ''
1 change: 1 addition & 0 deletions traefik_mesh/changelog.d/22676.changed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove unused ``url`` parameter from ``get_version``.
14 changes: 11 additions & 3 deletions traefik_mesh/datadog_checks/traefik_mesh/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
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.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

Expand Down Expand Up @@ -84,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)
Expand Down Expand Up @@ -112,10 +115,15 @@ 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
)
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
21 changes: 21 additions & 0 deletions traefik_mesh/tests/test_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -106,3 +109,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
Loading