diff --git a/src/utils/checks.py b/src/utils/checks.py new file mode 100644 index 000000000..8d7017503 --- /dev/null +++ b/src/utils/checks.py @@ -0,0 +1,27 @@ +"""Checks that are performed to configuration options.""" + +import os +from typing import Optional + +from pydantic import FilePath + + +class InvalidConfigurationError(Exception): + """Lightspeed configuration is invalid.""" + + +def get_attribute_from_file(data: dict, file_name_key: str) -> Optional[str]: + """Retrieve value of an attribute from a file.""" + file_path = data.get(file_name_key) + if file_path is not None: + with open(file_path, encoding="utf-8") as f: + return f.read().rstrip() + return None + + +def file_check(path: FilePath, desc: str) -> None: + """Check that path is a readable regular file.""" + if not os.path.isfile(path): + raise InvalidConfigurationError(f"{desc} '{path}' is not a file") + if not os.access(path, os.R_OK): + raise InvalidConfigurationError(f"{desc} '{path}' is not readable") diff --git a/tests/unit/utils/test_checks.py b/tests/unit/utils/test_checks.py new file mode 100644 index 000000000..e01b46fc4 --- /dev/null +++ b/tests/unit/utils/test_checks.py @@ -0,0 +1,77 @@ +import os +import pytest + +from unittest.mock import patch + +from utils import checks + + +@pytest.fixture +def input_file(tmp_path): + """Create file manually using the tmp_path fixture.""" + filename = os.path.join(tmp_path, "mydoc.csv") + with open(filename, "wt") as fout: + fout.write("some content!") + return filename + + +def test_get_attribute_from_file_no_record(): + """Test the get_attribute_from_file function when record is not in dictionary.""" + # no data + d = {} + + # non-existing key + key = "" + value = checks.get_attribute_from_file(d, key) + assert value is None + + # non-existing key + key = "this-does-not-exists" + value = checks.get_attribute_from_file(d, "this-does-not-exists") + assert value is None + + +def test_get_attribute_from_file_proper_record(input_file): + """Test the get_attribute_from_file function when record is present in dictionary.""" + # existing key + key = "my_file" + + # attribute with proper and existing filename + d = {key: input_file} + + # file content should be read properly + value = checks.get_attribute_from_file(d, key) + assert value is not None + assert value == "some content!" + + +def test_get_attribute_from_file_improper_filename(): + """Test the get_attribute_from_file when the file does not exist.""" + # existing key + key = "my_file" + + # filename for file that does not exist + input_file = "this-does-not-exists" + d = {key: input_file} + + with pytest.raises(FileNotFoundError, match="this-does-not-exists"): + checks.get_attribute_from_file(d, "my_file") + + +def test_file_check_existing_file(input_file): + """Test the function file_check for existing file.""" + # just call the function, it should not raise an exception + checks.file_check(input_file, "description") + + +def test_file_check_non_existing_file(): + """Test the function file_check for non existing file.""" + with pytest.raises(checks.InvalidConfigurationError): + checks.file_check("does-not-exists", "description") + + +def test_file_check_not_readable_file(input_file): + """Test the function file_check for not readable file.""" + with patch("os.access", return_value=False): + with pytest.raises(checks.InvalidConfigurationError): + checks.file_check(input_file, "description")