diff --git a/airflow/tests/test_unit.py b/airflow/tests/test_unit.py index cbdef5dc22efd..d8d70878c741e 100644 --- a/airflow/tests/test_unit.py +++ b/airflow/tests/test_unit.py @@ -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'] @@ -54,22 +52,20 @@ 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'] @@ -77,42 +73,39 @@ def test_service_checks_healthy_stable( 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', @@ -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) diff --git a/consul/tests/test_unit.py b/consul/tests/test_unit.py index 2b844e3601da8..0d3ecb460631e 100644 --- a/consul/tests/test_unit.py +++ b/consul/tests/test_unit.py @@ -3,7 +3,6 @@ # Licensed under a 3-clause BSD style license (see LICENSE) import logging -import mock import pytest from datadog_checks.consul import ConsulCheck @@ -155,25 +154,25 @@ def test_get_nodes_with_service_critical(aggregator): aggregator.assert_metric('consul.catalog.services_count', value=1, tags=expected_tags) -def test_consul_request(aggregator, instance, mocker): +def test_consul_request(aggregator, instance, mocker, mock_http): consul_check = ConsulCheck(common.CHECK_NAME, {}, [consul_mocks.MOCK_CONFIG]) mocker.patch("datadog_checks.base.utils.serialization.json.loads") - with mock.patch("datadog_checks.consul.consul.requests.Session.get") as mock_requests_get: + + consul_check.consul_request("foo") + url = "{}/{}".format(instance["url"], "foo") + aggregator.assert_service_check("consul.can_connect", ConsulCheck.OK, tags=["url:{}".format(url)], count=1) + + aggregator.reset() + mock_http.get.side_effect = Exception("message") + with pytest.raises(Exception): consul_check.consul_request("foo") - url = "{}/{}".format(instance["url"], "foo") - aggregator.assert_service_check("consul.can_connect", ConsulCheck.OK, tags=["url:{}".format(url)], count=1) - - aggregator.reset() - mock_requests_get.side_effect = Exception("message") - with pytest.raises(Exception): - consul_check.consul_request("foo") - aggregator.assert_service_check( - "consul.can_connect", - ConsulCheck.CRITICAL, - tags=["url:{}".format(url)], - count=1, - message="Consul request to {} failed: message".format(url), - ) + aggregator.assert_service_check( + "consul.can_connect", + ConsulCheck.CRITICAL, + tags=["url:{}".format(url)], + count=1, + message="Consul request to {} failed: message".format(url), + ) def test_service_checks(aggregator): @@ -648,26 +647,13 @@ def test_network_latency_node_name( ), ], ) -def test_config(test_case, extra_config, expected_http_kwargs, mocker): +def test_config(test_case, extra_config, expected_http_kwargs): instance = extra_config check = ConsulCheck(common.CHECK_NAME, {}, instances=[instance]) - mocker.patch("datadog_checks.base.utils.serialization.json.loads") - with mock.patch('datadog_checks.base.utils.http.requests.Session') as session: - mock_session = mock.MagicMock() - session.return_value = mock_session - mock_session.get.return_value = mock.MagicMock(status_code=200) - - check.check(None) - - http_wargs = { - 'auth': mock.ANY, - 'cert': mock.ANY, - 'headers': mock.ANY, - 'proxies': mock.ANY, - 'timeout': mock.ANY, - 'verify': mock.ANY, - 'allow_redirects': mock.ANY, - } - http_wargs.update(expected_http_kwargs) - mock_session.get.assert_called_with('/v1/status/leader', **http_wargs) + for key, value in expected_http_kwargs.items(): + if key == 'headers': + for h_key, h_value in value.items(): + assert check.http.get_header(h_key) == h_value + else: + assert check.http.options[key] == value diff --git a/couch/tests/test_unit.py b/couch/tests/test_unit.py index 7f2ad8678ae2d..d1bf4b49af3e9 100644 --- a/couch/tests/test_unit.py +++ b/couch/tests/test_unit.py @@ -4,7 +4,6 @@ from copy import deepcopy from unittest.mock import MagicMock -import mock import pytest from datadog_checks.couch import CouchDb @@ -30,24 +29,8 @@ def test_config(test_case, extra_config, expected_http_kwargs): instance.update(extra_config) check = CouchDb(common.CHECK_NAME, {}, instances=[instance]) - r = mock.MagicMock() - with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=r): - r.get.return_value = mock.MagicMock(status_code=200, content='{}') - - check.check(instance) - - http_wargs = { - 'auth': mock.ANY, - 'cert': mock.ANY, - 'headers': mock.ANY, - 'proxies': mock.ANY, - 'timeout': mock.ANY, - 'verify': mock.ANY, - 'allow_redirects': mock.ANY, - } - http_wargs.update(expected_http_kwargs) - - r.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/datadog_checks_base/datadog_checks/base/utils/http.py b/datadog_checks_base/datadog_checks/base/utils/http.py index eb6699dfda6fe..5b55effd5828d 100644 --- a/datadog_checks_base/datadog_checks/base/utils/http.py +++ b/datadog_checks_base/datadog_checks/base/utils/http.py @@ -448,6 +448,20 @@ def __init__(self, instance, init_config, remapper=None, logger=None, session=No self.tls_config = {key: value for key, value in config.items() if key.startswith('tls_')} self._https_adapters = {} + def get_header(self, name: str, default: str | None = None) -> str | None: + """Look up a request header by name. Lookup is case-insensitive.""" + for key, value in self.options['headers'].items(): + if key.lower() == name.lower(): + return value + return default + + def set_header(self, name: str, value: str) -> None: + for key in self.options['headers']: + if key.lower() == name.lower(): + self.options['headers'][key] = value + return + self.options['headers'][name] = value + def get(self, url, **options): return self._request('get', url, options) 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 cf2dc71663288..f6fb97ca5c849 100644 --- a/datadog_checks_base/datadog_checks/base/utils/http_protocol.py +++ b/datadog_checks_base/datadog_checks/base/utils/http_protocol.py @@ -3,10 +3,19 @@ # Licensed under a 3-clause BSD style license (see LICENSE) from __future__ import annotations +from collections.abc import Mapping from typing import Any, Iterator, Protocol class HTTPResponseProtocol(Protocol): + status_code: int + content: bytes + text: str + headers: Mapping[str, str] + + def json(self, **kwargs: Any) -> Any: ... + def raise_for_status(self) -> None: ... + def close(self) -> None: ... def iter_content(self, chunk_size: int | None = None, decode_unicode: bool = False) -> Iterator[bytes | str]: ... def iter_lines( self, @@ -19,6 +28,8 @@ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> bool | None: ... class HTTPClientProtocol(Protocol): + options: dict[str, Any] + def get(self, url: str, **options: Any) -> HTTPResponseProtocol: ... def post(self, url: str, **options: Any) -> HTTPResponseProtocol: ... def head(self, url: str, **options: Any) -> HTTPResponseProtocol: ... @@ -26,3 +37,5 @@ def put(self, url: str, **options: Any) -> HTTPResponseProtocol: ... def patch(self, url: str, **options: Any) -> HTTPResponseProtocol: ... def delete(self, url: str, **options: Any) -> HTTPResponseProtocol: ... def options_method(self, url: str, **options: Any) -> HTTPResponseProtocol: ... + def get_header(self, name: str, default: str | None = None) -> str | None: ... + def set_header(self, name: str, value: str) -> None: ... 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 ab42172973153..dd3bca5d4b46a 100644 --- a/datadog_checks_base/tests/base/utils/http/test_headers.py +++ b/datadog_checks_base/tests/base/utils/http/test_headers.py @@ -97,3 +97,34 @@ def test_extra_headers_on_http_method_call(): # make sure the original headers are not modified assert http.options['headers'] == complete_headers assert extra_headers == {"foo": "bar"} + + +def test_get_header_default_for_missing(): + http = RequestsWrapper({}, {}) + assert http.get_header('X-Missing') is None + assert http.get_header('X-Missing', 'fallback') == 'fallback' + + +def test_get_header_case_insensitive(): + http = RequestsWrapper({}, {}) + assert http.get_header('accept') == '*/*' + assert http.get_header('Accept') == '*/*' + assert http.get_header('ACCEPT') == '*/*' + + +def test_set_header(): + http = RequestsWrapper({}, {}) + http.set_header('X-Token', 'abc123') + assert http.get_header('X-Token') == 'abc123' + http.set_header('Accept', 'application/json') + assert http.get_header('Accept') == 'application/json' + + +def test_set_header_case_insensitive(): + http = RequestsWrapper({}, {}) + http.set_header('accept', 'application/json') + # Overwrites the existing 'Accept' key (preserving original casing) + assert http.get_header('Accept') == 'application/json' + assert http.options['headers']['Accept'] == 'application/json' + # No duplicate key created + assert sum(1 for k in http.options['headers'] if k.lower() == 'accept') == 1 diff --git a/datadog_checks_dev/datadog_checks/dev/plugin/pytest.py b/datadog_checks_dev/datadog_checks/dev/plugin/pytest.py index 16317857ad87c..2e549004fec28 100644 --- a/datadog_checks_dev/datadog_checks/dev/plugin/pytest.py +++ b/datadog_checks_dev/datadog_checks/dev/plugin/pytest.py @@ -309,6 +309,32 @@ def mock_http(mocker): from datadog_checks.base.utils.http_protocol import HTTPClientProtocol client = create_autospec(HTTPClientProtocol) + # Protocol annotations are not picked up by create_autospec, so set options explicitly. + client.options = { + 'auth': None, + 'cert': None, + 'headers': {}, + 'proxies': None, + 'timeout': (10.0, 10.0), + 'verify': True, + 'allow_redirects': True, + } + + def _get_header(name, default=None): + for key, value in client.options['headers'].items(): + if key.lower() == name.lower(): + return value + return default + + def _set_header(name, value): + for key in list(client.options['headers']): + if key.lower() == name.lower(): + client.options['headers'][key] = value + return + client.options['headers'][name] = value + + client.get_header.side_effect = _get_header + client.set_header.side_effect = _set_header 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 diff --git a/druid/tests/test_unit.py b/druid/tests/test_unit.py index 3a21281fbc8bc..b6381dc9d4903 100644 --- a/druid/tests/test_unit.py +++ b/druid/tests/test_unit.py @@ -19,17 +19,15 @@ def test_missing_url_config(aggregator): check.check({}) -def test_service_check_can_connect_success(aggregator, instance): +def test_service_check_can_connect_success(aggregator, instance, mock_http): check = DruidCheck('druid', {}, [instance]) - 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.return_value = {'abc': '123'} - req.get.return_value = mock_resp + mock_resp = mock.MagicMock(status_code=200) + mock_resp.json.return_value = {'abc': '123'} + mock_http.get.return_value = mock_resp - resp = check._get_process_properties('http://hello-world.com:8899', ['foo:bar']) - assert resp == {'abc': '123'} + resp = check._get_process_properties('http://hello-world.com:8899', ['foo:bar']) + assert resp == {'abc': '123'} aggregator.assert_service_check( 'druid.service.can_connect', @@ -39,17 +37,15 @@ def test_service_check_can_connect_success(aggregator, instance): @pytest.mark.parametrize("exception_class", [requests.exceptions.ConnectionError, requests.exceptions.Timeout]) -def test_service_check_can_connect_failure(aggregator, instance, exception_class): +def test_service_check_can_connect_failure(aggregator, instance, mock_http, exception_class): check = DruidCheck('druid', {}, [instance]) - req = mock.MagicMock() - with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=req): - attrs = {'raise_for_status.side_effect': exception_class} - req.get.side_effect = [mock.MagicMock(status_code=500, **attrs)] + attrs = {'raise_for_status.side_effect': exception_class} + mock_http.get.side_effect = [mock.MagicMock(status_code=500, **attrs)] - with pytest.raises(CheckException): - properties = check._get_process_properties('http://hello-world.com:8899', ['foo:bar']) - assert properties is None + with pytest.raises(CheckException): + properties = check._get_process_properties('http://hello-world.com:8899', ['foo:bar']) + assert properties is None aggregator.assert_service_check( 'druid.service.can_connect', diff --git a/ecs_fargate/tests/test_unit.py b/ecs_fargate/tests/test_unit.py index c4f967166bcec..813e2a5768d51 100644 --- a/ecs_fargate/tests/test_unit.py +++ b/ecs_fargate/tests/test_unit.py @@ -289,24 +289,9 @@ def test_successful_check_wrong_sys_delta(check, aggregator, dd_run_check): [("explicit timeout", {'timeout': 30}, {'timeout': (30, 30)}), ("default timeout", {}, {'timeout': (5, 5)})], ) @pytest.mark.unit -def test_config(test_case, extra_config, expected_http_kwargs, dd_run_check): +def test_config(test_case, extra_config, expected_http_kwargs): instance = extra_config check = FargateCheck('ecs_fargate', {}, instances=[instance]) - r = mock.MagicMock() - with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=r): - r.get.return_value = mock.MagicMock(status_code=200) - - dd_run_check(check) - - http_wargs = { - 'auth': mock.ANY, - 'cert': mock.ANY, - 'headers': mock.ANY, - 'proxies': mock.ANY, - 'timeout': mock.ANY, - 'verify': mock.ANY, - 'allow_redirects': mock.ANY, - } - http_wargs.update(expected_http_kwargs) - r.get.assert_called_with('http://169.254.170.2/v2/metadata', **http_wargs) + for key, value in expected_http_kwargs.items(): + assert check.http.options[key] == value diff --git a/envoy/tests/legacy/test_unit.py b/envoy/tests/legacy/test_unit.py index b43b531857fc6..cdcad5ba85923 100644 --- a/envoy/tests/legacy/test_unit.py +++ b/envoy/tests/legacy/test_unit.py @@ -18,7 +18,6 @@ EXT_AUTHZ_METRICS, EXT_PROC_METRICS, FLAVOR, - HOST, INSTANCES, LOCAL_RATE_LIMIT_METRICS, RATE_LIMIT_STAT_PREFIX_TAG, @@ -135,28 +134,13 @@ def test_unknown(fixture_path, mock_http_response, dd_run_check, check): pytest.param({}, {'verify': True}, id="legacy ssl config unset"), ], ) -def test_config(extra_config, expected_http_kwargs, check, dd_run_check): +def test_config(extra_config, expected_http_kwargs, check): instance = deepcopy(INSTANCES['main']) instance.update(extra_config) check = check(instance) - r = mock.MagicMock() - with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=r): - r.get.return_value = mock.MagicMock(status_code=200) - - dd_run_check(check) - - http_wargs = { - 'auth': mock.ANY, - 'cert': mock.ANY, - 'headers': mock.ANY, - 'proxies': mock.ANY, - 'timeout': mock.ANY, - 'verify': mock.ANY, - 'allow_redirects': mock.ANY, - } - http_wargs.update(expected_http_kwargs) - r.get.assert_called_with('http://{}:8001/stats'.format(HOST), **http_wargs) + for key, value in expected_http_kwargs.items(): + assert check.http.options[key] == value @pytest.mark.parametrize( diff --git a/etcd/tests/test_integration.py b/etcd/tests/test_integration.py index da94be9a527c3..b5387de0d9467 100644 --- a/etcd/tests/test_integration.py +++ b/etcd/tests/test_integration.py @@ -3,7 +3,6 @@ # Licensed under a 3-clause BSD style license (see LICENSE) from copy import deepcopy -import mock import pytest from datadog_checks.etcd import Etcd @@ -63,41 +62,6 @@ def test_service_check(aggregator, instance, dd_run_check): aggregator.assert_service_check('etcd.prometheus.health', Etcd.OK, tags=tags, count=1) -@pytest.mark.parametrize( - 'test_case, extra_config, expected_http_kwargs', - [ - ("new auth config", {'username': 'new_foo', 'password': 'new_bar'}, {'auth': ('new_foo', 'new_bar')}), - ("legacy ssl config True", {'ssl_verify': True}, {'verify': True}), - ("legacy ssl config False", {'ssl_verify': False}, {'verify': False}), - ("legacy ssl config unset", {}, {'verify': False}), - ("timeout", {'prometheus_timeout': 100}, {'timeout': (100.0, 100.0)}), - ], -) -@pytest.mark.integration -def test_config(instance, test_case, extra_config, expected_http_kwargs, dd_run_check): - instance.update(extra_config) - check = Etcd(CHECK_NAME, {}, [instance]) - - r = mock.MagicMock() - with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=r): - r.get.return_value = mock.MagicMock(status_code=200) - - dd_run_check(check) - - http_kwargs = { - 'auth': mock.ANY, - 'cert': mock.ANY, - 'data': mock.ANY, - 'headers': mock.ANY, - 'proxies': mock.ANY, - 'timeout': mock.ANY, - 'verify': mock.ANY, - 'allow_redirects': mock.ANY, - } - http_kwargs.update(expected_http_kwargs) - r.post.assert_called_with(URL + '/v3/maintenance/status', **http_kwargs) - - @pytest.mark.integration def test_version_metadata(aggregator, instance, dd_environment, datadog_agent, dd_run_check): check_instance = Etcd(CHECK_NAME, {}, [instance]) diff --git a/etcd/tests/test_unit.py b/etcd/tests/test_unit.py new file mode 100644 index 0000000000000..5987830c6efeb --- /dev/null +++ b/etcd/tests/test_unit.py @@ -0,0 +1,26 @@ +# (C) Datadog, Inc. 2026-present +# All rights reserved +# Licensed under a 3-clause BSD style license (see LICENSE) +import pytest + +from datadog_checks.etcd import Etcd + +CHECK_NAME = 'etcd' + + +@pytest.mark.parametrize( + 'test_case, extra_config, expected_http_kwargs', + [ + ("new auth config", {'username': 'new_foo', 'password': 'new_bar'}, {'auth': ('new_foo', 'new_bar')}), + ("legacy ssl config True", {'ssl_verify': True}, {'verify': True}), + ("legacy ssl config False", {'ssl_verify': False}, {'verify': False}), + ("legacy ssl config unset", {}, {'verify': False}), + ("timeout", {'prometheus_timeout': 100}, {'timeout': (100.0, 100.0)}), + ], +) +def test_config(instance, test_case, extra_config, expected_http_kwargs): + instance.update(extra_config) + check = Etcd(CHECK_NAME, {}, [instance]) + + for key, value in expected_http_kwargs.items(): + assert check.http.options[key] == value diff --git a/gitlab_runner/tests/test_unit.py b/gitlab_runner/tests/test_unit.py index cc72d9a5ad861..35b89bc2109d2 100644 --- a/gitlab_runner/tests/test_unit.py +++ b/gitlab_runner/tests/test_unit.py @@ -4,7 +4,6 @@ from copy import deepcopy -import mock import pytest from datadog_checks.dev.utils import get_metadata_metrics @@ -29,22 +28,7 @@ def test_timeout(test_case, timeout_config, expected_timeout): gitlab_runner = GitlabRunnerCheck('gitlab_runner', common.CONFIG['init_config'], instances=config['instances']) - r = mock.MagicMock() - with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=r): - r.get.return_value = mock.MagicMock(status_code=200) - - gitlab_runner.check(config['instances'][0]) - - r.get.assert_called_with( - 'http://localhost:8085/ci', - auth=mock.ANY, - cert=mock.ANY, - headers=mock.ANY, - proxies=mock.ANY, - timeout=expected_timeout, - verify=mock.ANY, - allow_redirects=mock.ANY, - ) + assert gitlab_runner.http.options['timeout'] == expected_timeout @pytest.mark.unit diff --git a/marathon/tests/test_unit.py b/marathon/tests/test_unit.py index ef104e6264e90..042ab6f38ccd5 100644 --- a/marathon/tests/test_unit.py +++ b/marathon/tests/test_unit.py @@ -2,8 +2,8 @@ # All rights reserved # Licensed under a 3-clause BSD style license (see LICENSE) from copy import deepcopy +from unittest.mock import MagicMock -import mock import pytest from datadog_checks.marathon import Marathon @@ -38,13 +38,13 @@ def test_process_apps_ko(check, aggregator): If the check can't hit the Marathon master Url, no metric should be collected """ - check.get_apps_json = mock.MagicMock(return_value=None) + check.get_apps_json = MagicMock(return_value=None) check.process_apps('url', 'acs_url', [], [], None) assert len(aggregator.metric_names) == 0 def test_process_apps(check, aggregator): - check.get_apps_json = mock.MagicMock( + check.get_apps_json = MagicMock( return_value={ 'apps': [ {'id': '/', 'version': '', 'backoffSeconds': 99}, @@ -107,20 +107,5 @@ def test_config(test_case, init_config, extra_config, expected_http_kwargs): instance.update(extra_config) check = Marathon('marathon', init_config, instances=[instance]) - r = mock.MagicMock() - with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=r): - r.get.return_value = mock.MagicMock(status_code=200) - - check.check(instance) - - http_wargs = { - 'auth': mock.ANY, - 'cert': mock.ANY, - 'headers': mock.ANY, - 'proxies': mock.ANY, - 'timeout': mock.ANY, - 'verify': mock.ANY, - 'allow_redirects': mock.ANY, - } - http_wargs.update(expected_http_kwargs) - r.get.assert_called_with('http://localhost:8080/v2/queue', **http_wargs) + for key, value in expected_http_kwargs.items(): + assert check.http.options[key] == value diff --git a/mesos_master/tests/test_check.py b/mesos_master/tests/test_check.py index 4c026dcabc9c2..daff6b4033480 100644 --- a/mesos_master/tests/test_check.py +++ b/mesos_master/tests/test_check.py @@ -1,7 +1,8 @@ # (C) Datadog, Inc. 2018-present # All rights reserved # Licensed under a 3-clause BSD style license (see LICENSE) -import mock +from unittest.mock import MagicMock + import pytest import requests @@ -84,28 +85,28 @@ def test_instance_timeout(check, instance): [ ( 'OK case for /state endpoint', - [mock.MagicMock(status_code=200, content='{}')], + [MagicMock(status_code=200, content='{}')], AgentCheck.OK, ['my:tag', 'url:http://hello.com/state'], False, ), ( 'OK case with failing /state due to bad status and fallback on /state.json', - [mock.MagicMock(status_code=500), mock.MagicMock(status_code=200, content='{}')], + [MagicMock(status_code=500), MagicMock(status_code=200, content='{}')], AgentCheck.OK, ['my:tag', 'url:http://hello.com/state.json'], False, ), ( 'OK case with failing /state due to Timeout and fallback on /state.json', - [requests.exceptions.Timeout, mock.MagicMock(status_code=200, content='{}')], + [requests.exceptions.Timeout, MagicMock(status_code=200, content='{}')], AgentCheck.OK, ['my:tag', 'url:http://hello.com/state.json'], False, ), ( 'OK case with failing /state due to Exception and fallback on /state.json', - [Exception, mock.MagicMock(status_code=200, content='{}')], + [Exception, MagicMock(status_code=200, content='{}')], AgentCheck.OK, ['my:tag', 'url:http://hello.com/state.json'], False, @@ -119,7 +120,7 @@ def test_instance_timeout(check, instance): ), ( 'NOK case with failing /state and /state.json with bad status', - [mock.MagicMock(status_code=500), mock.MagicMock(status_code=500)], + [MagicMock(status_code=500), MagicMock(status_code=500)], AgentCheck.CRITICAL, ['my:tag', 'url:http://hello.com/state.json'], True, @@ -127,8 +128,8 @@ def test_instance_timeout(check, instance): ( 'OK case with non-leader master on /state', [ - mock.MagicMock(status_code=401, history=[mock.MagicMock(status_code=307)]), - mock.MagicMock(content='{}', history=[], status_code=500), + MagicMock(status_code=401, history=[MagicMock(status_code=307)]), + MagicMock(content='{}', history=[], status_code=500), ], AgentCheck.UNKNOWN, ['my:tag', 'url:http://hello.com/state.json'], @@ -137,8 +138,8 @@ def test_instance_timeout(check, instance): ( 'OK case with non-leader master on /state.json', [ - mock.MagicMock(status_code=500, history=[]), - mock.MagicMock(content='{}', history=[mock.MagicMock(status_code=307)], status_code=401), + MagicMock(status_code=500, history=[]), + MagicMock(content='{}', history=[MagicMock(status_code=307)], status_code=401), ], AgentCheck.UNKNOWN, ['my:tag', 'url:http://hello.com/state.json'], @@ -148,20 +149,25 @@ def test_instance_timeout(check, instance): ) @pytest.mark.integration def test_can_connect_service_check( - instance, aggregator, test_case_name, request_mock_side_effects, expected_status, expected_tags, expect_exception + instance, + aggregator, + mock_http, + test_case_name, + request_mock_side_effects, + expected_status, + expected_tags, + expect_exception, ): check = MesosMaster('mesos_master', {}, [instance]) - r = mock.MagicMock() - with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=r): - r.get.side_effect = request_mock_side_effects + mock_http.get.side_effect = request_mock_side_effects - try: - check._get_master_state('http://hello.com', ['my:tag']) - exception_raised = False - except CheckException: - exception_raised = True + try: + check._get_master_state('http://hello.com', ['my:tag']) + exception_raised = False + except CheckException: + exception_raised = True - assert expect_exception == exception_raised + assert expect_exception == exception_raised aggregator.assert_service_check('mesos_master.can_connect', count=1, status=expected_status, tags=expected_tags) diff --git a/mesos_slave/tests/test_unit.py b/mesos_slave/tests/test_unit.py index 098e3683313cf..e04738108caed 100644 --- a/mesos_slave/tests/test_unit.py +++ b/mesos_slave/tests/test_unit.py @@ -177,37 +177,40 @@ def test_config(check, instance, test_case, extra_config, expected_http_kwargs): @pytest.mark.parametrize(PARAMETERS, state_test_data) @pytest.mark.integration def test_can_connect_service_check_state( - instance, aggregator, test_case_name, request_mock_effects, expected_tags, expect_exception, expected_status + instance, + aggregator, + mock_http, + test_case_name, + request_mock_effects, + expected_tags, + expect_exception, + expected_status, ): check = MesosSlave('mesos_slave', {}, [instance]) - r = mock.MagicMock() - with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=r): - r.get.side_effect = request_mock_effects - try: - check._process_state_info('http://hello.com', instance['tasks'], 5050, instance['tags']) - assert not expect_exception - except Exception: - if not expect_exception: - raise + mock_http.get.side_effect = request_mock_effects + try: + check._process_state_info('http://hello.com', instance['tasks'], 5050, instance['tags']) + assert not expect_exception + except Exception: + if not expect_exception: + raise aggregator.assert_service_check('mesos_slave.can_connect', count=1, status=expected_status, tags=expected_tags) @pytest.mark.integration -def test_can_connect_service_with_instance_cluster_name(instance, aggregator): +def test_can_connect_service_with_instance_cluster_name(instance, aggregator, mock_http): instance['cluster_name'] = 'test-cluster' expected_tags = ['url:http://hello.com/state'] + cluster_name_tag + additional_tags expected_status = AgentCheck.OK check = MesosSlave('mesos_slave', {}, [instance]) - r = mock.MagicMock() - with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=r): - r.get.side_effect = [mock.MagicMock(status_code=200, content='{}')] - try: - check._process_state_info('http://hello.com', instance['tasks'], 5050, instance['tags']) - assert not False - except Exception: - if not False: - raise + mock_http.get.side_effect = [mock.MagicMock(status_code=200, content='{}')] + try: + check._process_state_info('http://hello.com', instance['tasks'], 5050, instance['tags']) + assert not False + except Exception: + if not False: + raise aggregator.assert_service_check('mesos_slave.can_connect', count=1, status=expected_status, tags=expected_tags) @@ -215,17 +218,22 @@ def test_can_connect_service_with_instance_cluster_name(instance, aggregator): @pytest.mark.parametrize(PARAMETERS, stats_test_data) @pytest.mark.integration def test_can_connect_service_check_stats( - instance, aggregator, test_case_name, request_mock_effects, expected_tags, expect_exception, expected_status + instance, + aggregator, + mock_http, + test_case_name, + request_mock_effects, + expected_tags, + expect_exception, + expected_status, ): check = MesosSlave('mesos_slave', {}, [instance]) - r = mock.MagicMock() - with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=r): - r.get.side_effect = request_mock_effects - try: - check._process_stats_info('http://hello.com', instance['tags']) - assert not expect_exception - except Exception: - if not expect_exception: - raise + mock_http.get.side_effect = request_mock_effects + try: + check._process_stats_info('http://hello.com', instance['tags']) + assert not expect_exception + except Exception: + if not expect_exception: + raise aggregator.assert_service_check('mesos_slave.can_connect', count=1, status=expected_status, tags=expected_tags) diff --git a/nginx/tests/test_unit.py b/nginx/tests/test_unit.py index 66de9c5dfd748..655c41583eb63 100644 --- a/nginx/tests/test_unit.py +++ b/nginx/tests/test_unit.py @@ -68,34 +68,16 @@ def test_config(check, instance, test_case, extra_config, expected_http_kwargs): c = check(instance) - r = mock.MagicMock() - with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=r): - r.get.return_value = mock.MagicMock(status_code=200, content=b'{}') + for key, value in expected_http_kwargs.items(): + assert c.http.options[key] == value - c.check(instance) - http_wargs = { - 'auth': mock.ANY, - 'cert': mock.ANY, - 'headers': mock.ANY, - 'proxies': mock.ANY, - 'timeout': mock.ANY, - 'verify': mock.ANY, - 'allow_redirects': mock.ANY, - } - http_wargs.update(expected_http_kwargs) - - r.get.assert_called_with('http://localhost:8080/nginx_status', **http_wargs) - - -def test_no_version(check, instance, caplog): +def test_no_version(check, instance, caplog, mock_http): c = check(instance) - r = mock.MagicMock() - with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=r): - r.get.return_value = mock.MagicMock(status_code=200, content=b'{}', headers={'server': 'nginx'}) + mock_http.get.return_value = mock.MagicMock(status_code=200, content=b'{}', headers={'server': 'nginx'}) - c.check(instance) + c.check(instance) errors = [record for record in caplog.records if record.levelname == "ERROR"] assert not errors diff --git a/openmetrics/tests/test_openmetrics.py b/openmetrics/tests/test_openmetrics.py index 827fc5baad7b7..b55f8693f7711 100644 --- a/openmetrics/tests/test_openmetrics.py +++ b/openmetrics/tests/test_openmetrics.py @@ -60,7 +60,7 @@ def test_openmetrics(aggregator, dd_run_check, request, poll_mock_fixture): ) aggregator.assert_all_metrics_covered() - assert check.http.options['headers']['Accept'] == '*/*' + assert check.http.get_header('Accept') == '*/*' def test_openmetrics_use_latest_spec(aggregator, dd_run_check, mock_http_response, openmetrics_payload, caplog): @@ -88,7 +88,7 @@ def test_openmetrics_use_latest_spec(aggregator, dd_run_check, mock_http_respons ) aggregator.assert_all_metrics_covered() - assert check.http.options['headers']['Accept'] == '*/*' + assert check.http.get_header('Accept') == '*/*' assert caplog.text == '' assert get_mock.call_args.kwargs['headers']['Accept'] == ( 'application/openmetrics-text;version=1.0.0,application/openmetrics-text;version=0.0.1' diff --git a/php_fpm/tests/test_unit.py b/php_fpm/tests/test_unit.py index b0f46d613c077..c70af599f53a4 100644 --- a/php_fpm/tests/test_unit.py +++ b/php_fpm/tests/test_unit.py @@ -33,50 +33,44 @@ def test_bad_ping(aggregator, dd_run_check): aggregator.all_metrics_asserted() -def test_should_not_retry(check, instance): +def test_should_not_retry(check, instance, mock_http): """ backoff only works when response code is 503, otherwise the error should bubble up """ - r = mock.MagicMock() - with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=r): - r.get.side_effect = FooException("Generic http error here") - with pytest.raises(FooException): - check._process_status(instance['status_url'], [], None, False) + mock_http.get.side_effect = FooException("Generic http error here") + with pytest.raises(FooException): + check._process_status(instance['status_url'], [], None, False) -def test_should_bail_out(check, instance): +def test_should_bail_out(check, instance, mock_http): """ backoff should give up after 3 attempts """ - r = mock.MagicMock() - with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=r): - attrs = {'raise_for_status.side_effect': FooException()} - r.get.side_effect = [ - mock.MagicMock(status_code=503, **attrs), - mock.MagicMock(status_code=503, **attrs), - mock.MagicMock(status_code=503, **attrs), - mock.MagicMock(status_code=200), - ] - with pytest.raises(FooException): - check._process_status(instance['status_url'], [], None, False) - - -def test_backoff_success(check, instance, aggregator, payload): + attrs = {'raise_for_status.side_effect': FooException()} + mock_http.get.side_effect = [ + mock.MagicMock(status_code=503, **attrs), + mock.MagicMock(status_code=503, **attrs), + mock.MagicMock(status_code=503, **attrs), + mock.MagicMock(status_code=200), + ] + with pytest.raises(FooException): + check._process_status(instance['status_url'], [], None, False) + + +def test_backoff_success(check, instance, aggregator, payload, mock_http): """ Success after 2 failed attempts """ instance['ping_url'] = None - r = mock.MagicMock() - with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=r): - attrs = {'json.return_value': payload} - r.get.side_effect = [ - mock.MagicMock(status_code=503), - mock.MagicMock(status_code=503), - mock.MagicMock(status_code=200, **attrs), - ] - pool_name = check._process_status(instance['status_url'], [], None, False) - assert pool_name == 'www' + attrs = {'json.return_value': payload} + mock_http.get.side_effect = [ + mock.MagicMock(status_code=503), + mock.MagicMock(status_code=503), + mock.MagicMock(status_code=200, **attrs), + ] + pool_name = check._process_status(instance['status_url'], [], None, False) + assert pool_name == 'www' @pytest.mark.parametrize( @@ -101,25 +95,14 @@ def test_backoff_success(check, instance, aggregator, payload): ), ], ) -def test_config(test_case, extra_config, expected_http_kwargs, dd_run_check): +def test_config(test_case, extra_config, expected_http_kwargs): instance = {'ping_url': 'http://foo:9001/ping'} instance.update(extra_config) check = PHPFPMCheck('php_fpm', {}, instances=[instance]) - r = mock.MagicMock() - with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=r): - r.get.return_value = mock.MagicMock(status_code=200) - - dd_run_check(check) - - http_kwargs = { - 'auth': mock.ANY, - 'cert': mock.ANY, - 'headers': mock.ANY, - 'proxies': mock.ANY, - 'timeout': mock.ANY, - 'verify': mock.ANY, - 'allow_redirects': mock.ANY, - } - http_kwargs.update(expected_http_kwargs) - r.get.assert_called_with('http://foo:9001/ping', **http_kwargs) + for key, value in expected_http_kwargs.items(): + if key == 'headers': + for h_key, h_value in value.items(): + assert check.http.get_header(h_key) == h_value + else: + assert check.http.options[key] == value diff --git a/rabbitmq/tests/test_unit.py b/rabbitmq/tests/test_unit.py index 4e0d95ea9f06a..bffa86fc8cb6e 100644 --- a/rabbitmq/tests/test_unit.py +++ b/rabbitmq/tests/test_unit.py @@ -24,16 +24,12 @@ pytestmark = [pytest.mark.unit, common.requires_management] -def test__get_data(check): - r = mock.MagicMock() - with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=r): - r.get.side_effect = [requests.exceptions.HTTPError, ValueError] - with pytest.raises(RabbitMQException) as e: - check._get_data('') - assert isinstance(e, RabbitMQException) - with pytest.raises(RabbitMQException) as e: - check._get_data('') - assert isinstance(e, RabbitMQException) +def test__get_data(check, mock_http): + mock_http.get.side_effect = [requests.exceptions.HTTPError, ValueError] + with pytest.raises(RabbitMQException): + check._get_data('') + with pytest.raises(RabbitMQException): + check._get_data('') def test_status_check(check, aggregator): @@ -139,24 +135,8 @@ def test_config(check, test_case, extra_config, expected_http_kwargs): config.update(extra_config) check = RabbitMQ('rabbitmq', {}, instances=[config]) - r = mock.MagicMock() - with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=r): - r.get.return_value = mock.MagicMock(status_code=200) - - check.check(config) - - http_wargs = { - 'auth': mock.ANY, - 'cert': mock.ANY, - 'headers': mock.ANY, - 'proxies': mock.ANY, - 'timeout': mock.ANY, - 'verify': mock.ANY, - 'allow_redirects': mock.ANY, - } - http_wargs.update(expected_http_kwargs) - - r.get.assert_called_with('http://localhost:15672/api/connections', **http_wargs) + for key, value in expected_http_kwargs.items(): + assert check.http.options[key] == value def test_nodes(aggregator, check): diff --git a/squid/tests/test_unit.py b/squid/tests/test_unit.py index 332e8c9123e2d..f1941b042eec9 100644 --- a/squid/tests/test_unit.py +++ b/squid/tests/test_unit.py @@ -103,17 +103,4 @@ def test_legacy_username_password(instance, auth_config): instance.update(auth_config) check = SquidCheck(common.CHECK_NAME, {}, {}, [instance]) - with mock.patch('datadog_checks.base.utils.http.requests.Session.get') as g: - with mock.patch('datadog_checks.squid.SquidCheck.submit_version'): - check.get_counters('host', 'port', []) - - g.assert_called_with( - 'http://host:port/squid-internal-mgr/counters', - auth=('datadog_user', 'datadog_pass'), - cert=mock.ANY, - headers=mock.ANY, - proxies=mock.ANY, - timeout=mock.ANY, - verify=mock.ANY, - allow_redirects=mock.ANY, - ) + assert check.http.options['auth'] == ('datadog_user', 'datadog_pass') diff --git a/teamcity/tests/test_teamcity.py b/teamcity/tests/test_teamcity.py index 65c23a4a12dab..2800bd02efcef 100644 --- a/teamcity/tests/test_teamcity.py +++ b/teamcity/tests/test_teamcity.py @@ -4,7 +4,6 @@ from copy import deepcopy import pytest -from mock import ANY, patch from datadog_checks.teamcity.constants import ( SERVICE_CHECK_BUILD_PROBLEMS, @@ -17,7 +16,6 @@ BUILD_STATS_METRICS, BUILD_TAGS, EXPECTED_SERVICE_CHECK_TEST_RESULTS, - LEGACY_REST_INSTANCE, USE_OPENMETRICS, ) @@ -53,36 +51,6 @@ def test_build_event(dd_run_check, aggregator, rest_instance): aggregator.assert_event(msg_title="", msg_text="", count=0) -@pytest.mark.parametrize( - 'extra_config, expected_http_kwargs', - [ - pytest.param({'ssl_validation': True}, {'verify': True}, id="legacy ssl config True"), - pytest.param({'ssl_validation': False}, {'verify': False}, id="legacy ssl config False"), - pytest.param({}, {'verify': True}, id="legacy ssl config unset"), - ], -) -def test_config(dd_run_check, extra_config, expected_http_kwargs): - instance = deepcopy(LEGACY_REST_INSTANCE) - instance.update(extra_config) - check = TeamCityRest('teamcity', {}, [instance]) - - with patch('datadog_checks.base.utils.http.requests.Session.get') as r: - dd_run_check(check) - - http_wargs = { - 'auth': ANY, - 'cert': ANY, - 'headers': ANY, - 'proxies': ANY, - 'timeout': ANY, - 'verify': ANY, - 'allow_redirects': ANY, - } - http_wargs.update(expected_http_kwargs) - - r.assert_called_with(ANY, **http_wargs) - - @pytest.mark.parametrize( 'build_config, expected_error', [ diff --git a/teamcity/tests/test_unit.py b/teamcity/tests/test_unit.py index 20fd19a482ac6..10414201ffcb2 100644 --- a/teamcity/tests/test_unit.py +++ b/teamcity/tests/test_unit.py @@ -2,10 +2,12 @@ # All rights reserved # Licensed under a 3-clause BSD style license (see LICENSE) from collections import OrderedDict +from copy import deepcopy import pytest from datadog_checks.teamcity.common import filter_build_configs, filter_items, filter_projects, normalize_server_url +from datadog_checks.teamcity.teamcity_rest import TeamCityRest from .common import ( CONFIG_ALL_BUILD_CONFIGS, @@ -18,6 +20,7 @@ CONFIG_ONLY_EXCLUDE_ONE_BUILD_CONFIG, CONFIG_ONLY_EXCLUDE_ONE_PROJECT, CONFIG_ONLY_INCLUDE_ONE_BUILD_CONFIG, + LEGACY_REST_INSTANCE, TEAMCITY_SERVER_VALUES, USE_OPENMETRICS, ) @@ -348,3 +351,20 @@ def test_filter_build_configs( filtered = filter_build_configs(check, build_configs_to_filter, 'ProjectID', {'ProjectID': filter_config}) assert filtered == expected_result + + +@pytest.mark.parametrize( + 'extra_config, expected_http_kwargs', + [ + pytest.param({'ssl_validation': True}, {'verify': True}, id="legacy ssl config True"), + pytest.param({'ssl_validation': False}, {'verify': False}, id="legacy ssl config False"), + pytest.param({}, {'verify': True}, id="legacy ssl config unset"), + ], +) +def test_config(extra_config, expected_http_kwargs): + instance = deepcopy(LEGACY_REST_INSTANCE) + instance.update(extra_config) + check = TeamCityRest('teamcity', {}, [instance]) + + for key, value in expected_http_kwargs.items(): + assert check.http.options[key] == value diff --git a/torchserve/tests/management/test_model_discovery.py b/torchserve/tests/management/test_model_discovery.py index ea17df181c441..cb02407f916e5 100644 --- a/torchserve/tests/management/test_model_discovery.py +++ b/torchserve/tests/management/test_model_discovery.py @@ -95,7 +95,7 @@ ), ], ) -def test_get_models(check, mocked_management_instance, expected_models, fixture_folder, status_codes): +def test_get_models(check, mocked_management_instance, expected_models, fixture_folder, status_codes, mock_http): # Build all the responses our mock will return responses = [] full_path = get_fixture_path(os.path.join("management", "pagination", fixture_folder)) @@ -109,21 +109,19 @@ def test_get_models(check, mocked_management_instance, expected_models, fixture_ mock_resp.raise_for_status.side_effect = HTTPError() if status_code != 200 else None responses.append(mock_resp) - req = mock.MagicMock() - with mock.patch('datadog_checks.base.utils.http.requests.Session', return_value=req): - discovery = ModelDiscovery(check(mocked_management_instance), include=[".*"]) - req.get.side_effect = responses - assert [('.*', model['modelName'], model, None) for model in expected_models] == list(discovery.get_items()) - assert req.get.call_count == len(status_codes) + mock_http.get.side_effect = responses + discovery = ModelDiscovery(check(mocked_management_instance), include=[".*"]) + assert [('.*', model['modelName'], model, None) for model in expected_models] == list(discovery.get_items()) + assert mock_http.get.call_count == len(status_codes) - # Validate we used the right params - assert req.get.call_args_list[0].kwargs["params"] == {"limit": 100} + # Validate we used the right params + assert mock_http.get.call_args_list[0].kwargs["params"] == {"limit": 100} - for index, _ in enumerate(status_codes[1:], start=1): - # The nextPageToken from the call n comes from the answer n-1 - assert req.get.call_args_list[index].kwargs["params"] == { - "limit": 100, - "nextPageToken": responses[index - 1].json.return_value["nextPageToken"], - } + for index, _ in enumerate(status_codes[1:], start=1): + # The nextPageToken from the call n comes from the answer n-1 + assert mock_http.get.call_args_list[index].kwargs["params"] == { + "limit": 100, + "nextPageToken": responses[index - 1].json.return_value["nextPageToken"], + } - assert discovery.api_status == (AgentCheck.CRITICAL if status_codes[0] != 200 else AgentCheck.OK) + assert discovery.api_status == (AgentCheck.CRITICAL if status_codes[0] != 200 else AgentCheck.OK) diff --git a/vault/datadog_checks/vault/check.py b/vault/datadog_checks/vault/check.py index 3661256185999..2e83f811a4d2b 100644 --- a/vault/datadog_checks/vault/check.py +++ b/vault/datadog_checks/vault/check.py @@ -43,7 +43,7 @@ def __init__(self, name, init_config, instances): self.scraper_configs.clear() # https://www.vaultproject.io/api-docs#the-x-vault-request-header - self.http.options['headers']['X-Vault-Request'] = 'true' + self.http.set_header('X-Vault-Request', 'true') # Before scrapers are configured self.check_initializations.insert(-1, self.parse_config) @@ -240,10 +240,10 @@ def configure_scrapers(self): } if hasattr(self, '_http'): del self._http - self.http.options['headers']['X-Vault-Request'] = 'true' + self.http.set_header('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.http.set_header('X-Vault-Token', self.config.client_token) self.scraper_configs.clear() self.scraper_configs.append(config) diff --git a/vault/datadog_checks/vault/vault.py b/vault/datadog_checks/vault/vault.py index b216644712494..f5bb7c1f263d9 100644 --- a/vault/datadog_checks/vault/vault.py +++ b/vault/datadog_checks/vault/vault.py @@ -318,7 +318,7 @@ def renew_client_token(self): self.set_client_token(f.read().decode('utf-8')) def _set_header(self, http_wrapper, header, value): - http_wrapper.options['headers'][header] = value + http_wrapper.set_header(header, value) def get_scraper_config(self, instance): # This validation is called during `__init__` but we don't need it