diff --git a/swh/icinga_plugins/tests/test_vault.py b/swh/icinga_plugins/tests/test_vault.py --- a/swh/icinga_plugins/tests/test_vault.py +++ b/swh/icinga_plugins/tests/test_vault.py @@ -65,7 +65,9 @@ scenario.add_step("get", url_api, {}, status_code=404) scenario.add_step("post", url_api, response_pending) scenario.add_step("get", url_api, response_done) - scenario.add_step("get", url_fetch, "xx" * 40) + scenario.add_step( + "get", url_fetch, "xx" * 40, headers={"Content-Type": "application/gzip"} + ) scenario.install_mock(requests_mock) @@ -98,7 +100,9 @@ scenario.add_step("post", url_api, response_pending) scenario.add_step("get", url_api, response_pending) scenario.add_step("get", url_api, response_done) - scenario.add_step("get", url_fetch, "xx" * 40) + scenario.add_step( + "get", url_fetch, "xx" * 40, headers={"Content-Type": "application/gzip"} + ) scenario.install_mock(requests_mock) @@ -232,7 +236,9 @@ scenario.add_step("get", url_api, {}, status_code=404) scenario.add_step("post", url_api, response_pending) scenario.add_step("get", url_api, response_done) - scenario.add_step("get", url_fetch, "xx" * 40) + scenario.add_step( + "get", url_fetch, "xx" * 40, headers={"Content-Type": "application/gzip"} + ) scenario.install_mock(requests_mock) @@ -283,13 +289,19 @@ assert result.exit_code == 2, result.output -def test_vault_immediate_success_but_fetch_failed(requests_mock, mocker, mocked_time): +def test_vault_fetch_failed(requests_mock, mocker, mocked_time): scenario = WebScenario() scenario.add_step("get", url_api, {}, status_code=404) scenario.add_step("post", url_api, response_pending) scenario.add_step("get", url_api, response_done) - scenario.add_step("get", url_fetch, "", status_code=500) + scenario.add_step( + "get", + url_fetch, + "", + status_code=500, + headers={"Content-Type": "application/gzip"}, + ) scenario.install_mock(requests_mock) @@ -316,13 +328,15 @@ assert result.exit_code == 2, result.output -def test_vault_immediate_success_but_fetch_empty(requests_mock, mocker, mocked_time): +def test_vault_fetch_empty(requests_mock, mocker, mocked_time): scenario = WebScenario() scenario.add_step("get", url_api, {}, status_code=404) scenario.add_step("post", url_api, response_pending) scenario.add_step("get", url_api, response_done) - scenario.add_step("get", url_fetch, "") + scenario.add_step( + "get", url_fetch, "", headers={"Content-Type": "application/gzip"} + ) scenario.install_mock(requests_mock) @@ -349,7 +363,39 @@ assert result.exit_code == 2, result.output -def test_vault_immediate_success_but_no_fetch_url(requests_mock, mocker, mocked_time): +def test_vault_fetch_missing_content_type(requests_mock, mocker, mocked_time): + scenario = WebScenario() + + scenario.add_step("get", url_api, {}, status_code=404) + scenario.add_step("post", url_api, response_pending) + scenario.add_step("get", url_api, response_done) + scenario.add_step("get", url_fetch, "") + + scenario.install_mock(requests_mock) + + get_storage_mock = mocker.patch("swh.icinga_plugins.vault.get_storage") + get_storage_mock.side_effect = FakeStorage + + result = invoke( + [ + "check-vault", + "--swh-web-url", + "mock://swh-web.example.org", + "--swh-storage-url", + "foo://example.org", + "directory", + ], + catch_exceptions=True, + ) + + assert result.output == ( + "VAULT CRITICAL - Unexpected Content-Type when downloading bundle: None\n" + "| 'total_time' = 10.00s\n" + ) + assert result.exit_code == 2, result.output + + +def test_vault_no_fetch_url(requests_mock, mocker, mocked_time): scenario = WebScenario() scenario.add_step("get", url_api, {}, status_code=404) diff --git a/swh/icinga_plugins/tests/web_scenario.py b/swh/icinga_plugins/tests/web_scenario.py --- a/swh/icinga_plugins/tests/web_scenario.py +++ b/swh/icinga_plugins/tests/web_scenario.py @@ -1,4 +1,4 @@ -# Copyright (C) 2019 The Software Heritage developers +# Copyright (C) 2019-2022 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU General Public License version 3, or any later version # See top-level LICENSE file for more information @@ -9,23 +9,24 @@ Tests can build successive steps by calling :py:meth:`WebScenario.add_step` with specifications of what endpoints should be called and in what order.""" -from dataclasses import dataclass +import dataclasses import json -from typing import Callable, List, Optional, Set +from typing import Callable, Dict, List, Optional, Set, Union import requests_mock -@dataclass(frozen=True) +@dataclasses.dataclass(frozen=True) class Step: expected_method: str expected_url: str - response: object + response: Union[str, bytes, Dict, List] status_code: int = 200 + headers: Dict[str, str] = dataclasses.field(default_factory=dict) callback: Optional[Callable[[], int]] = None -@dataclass(frozen=True) +@dataclasses.dataclass(frozen=True) class Endpoint: method: str url: str @@ -68,9 +69,7 @@ """ for endpoint in self._endpoints: mocker.register_uri( - endpoint.method.upper(), - endpoint.url, - text=self._request_callback, # type: ignore # stubs are too strict + endpoint.method.upper(), endpoint.url, content=self._request_callback, ) def _request_callback(self, request, context): @@ -82,11 +81,14 @@ self._current_step += 1 context.status_code = step.status_code + context.headers.update(step.headers) if step.callback: step.callback() if isinstance(step.response, str): + return step.response.encode() + elif isinstance(step.response, bytes): return step.response else: - return json.dumps(step.response) + return json.dumps(step.response).encode() diff --git a/swh/icinga_plugins/vault.py b/swh/icinga_plugins/vault.py --- a/swh/icinga_plugins/vault.py +++ b/swh/icinga_plugins/vault.py @@ -114,6 +114,15 @@ ) return 2 + content_type = fetch_response.headers.get("Content-Type") + if content_type != "application/gzip": + self.print_result( + "CRITICAL", + f"Unexpected Content-Type when downloading bundle: {content_type}", + total_time=total_time, + ) + return 2 + response_length = 0 for chunk in fetch_response.iter_content(decode_unicode=False): response_length += len(chunk)