diff --git a/swh/vault/api/server.py b/swh/vault/api/server.py --- a/swh/vault/api/server.py +++ b/swh/vault/api/server.py @@ -6,6 +6,7 @@ import asyncio import collections import os +from typing import Any, Dict, Optional import aiohttp.web @@ -192,15 +193,14 @@ return app -def get_local_backend(cfg): +def check_config(cfg: Dict[str, Any]) -> Dict[str, Any]: if "vault" not in cfg: - raise ValueError("missing '%vault' configuration") + raise ValueError("missing 'vault' configuration") vcfg = cfg["vault"] if vcfg["cls"] != "local": raise EnvironmentError( - "The vault backend can only be started with a 'local' " "configuration", - err=True, + "The vault backend can only be started with a 'local' configuration", ) args = vcfg["args"] if "cache" not in args: @@ -212,20 +212,22 @@ for key in ("cache", "storage", "scheduler"): if not args.get(key): - raise ValueError("invalid configuration; missing %s config entry." % key) + raise ValueError(f"invalid configuration: missing {key} config entry.") - return get_vault("local", **args) + return args -def make_app_from_configfile(config_file=None, **kwargs): +def make_app_from_configfile(config_file: Optional[str] = None, **kwargs): if config_file is None: config_file = DEFAULT_CONFIG_PATH config_file = os.environ.get("SWH_CONFIG_FILENAME", config_file) + assert config_file is not None if os.path.isfile(config_file): cfg = config.read(config_file, DEFAULT_CONFIG) else: cfg = config.load_named_config(config_file, DEFAULT_CONFIG) - vault = get_local_backend(cfg) + kwargs = check_config(cfg) + vault = get_vault("local", **kwargs) return make_app(backend=vault, client_max_size=cfg["client_max_size"], **kwargs) diff --git a/swh/vault/tests/test_server.py b/swh/vault/tests/test_server.py --- a/swh/vault/tests/test_server.py +++ b/swh/vault/tests/test_server.py @@ -3,10 +3,12 @@ # License: GNU General Public License version 3, or any later version # See top-level LICENSE file for more information +import copy + import pytest from swh.core.api.serializers import msgpack_dumps, msgpack_loads -from swh.vault.api.server import make_app +from swh.vault.api.server import check_config, make_app @pytest.fixture @@ -53,3 +55,37 @@ content = msgpack_loads(await resp.content.read()) assert content["exception"]["type"] == "NotFoundExc" assert content["exception"]["args"] == ["Batch 1 does not exist."] + + +def test_check_config_missing_vault_configuration() -> None: + """Irrelevant configuration file path raises""" + with pytest.raises(ValueError, match="missing 'vault' configuration"): + check_config({}) + + +def test_check_config_not_local() -> None: + """Wrong configuration raises""" + expected_error = ( + "The vault backend can only be started with a 'local' configuration" + ) + with pytest.raises(EnvironmentError, match=expected_error): + check_config({"vault": {"cls": "remote"}}) + + +@pytest.mark.parametrize("missing_key", ["storage", "cache", "scheduler"]) +def test_check_config_missing_key(missing_key, swh_vault_config) -> None: + """Any other configuration than 'local' (the default) is rejected""" + config_ok = {"vault": {"cls": "local", "args": swh_vault_config}} + config_ko = copy.deepcopy(config_ok) + config_ko["vault"]["args"].pop(missing_key, None) + + expected_error = f"invalid configuration: missing {missing_key} config entry" + with pytest.raises(ValueError, match=expected_error): + check_config(config_ko) + + +@pytest.mark.parametrize("missing_key", ["storage", "cache", "scheduler"]) +def test_check_config_ok(missing_key, swh_vault_config) -> None: + """Any other configuration than 'local' (the default) is rejected""" + config_ok = {"vault": {"cls": "local", "args": swh_vault_config}} + assert check_config(config_ok) is not None