Skip to content

Commit

Permalink
Improved test coverage, update temporary test directory for user name…
Browse files Browse the repository at this point in the history
…s with spaces and non-latin characters, added mocked API call, added mocked create_settings call, moved test_http_helper, added TODOs for the future, #45
  • Loading branch information
MarcoHuebner authored and pmayd committed Sep 4, 2022
1 parent c869d4d commit 0391812
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 137 deletions.
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ python = "^3.8"
requests = "^2.27.1"
pandas = "^1.4.3"

# TODO: add mock
[tool.poetry.dev-dependencies]
bandit = "^1.7.4"
black = "^22.3.0"
Expand Down
11 changes: 6 additions & 5 deletions src/pygenesis/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,14 @@ def clean_cache(file: Optional[str] = None) -> None:
config = load_config()

# check for cache_dir in DATA section of the config.ini
# TODO: What happens if this key is not defined? is that error understandable?
cache_dir = Path(config["DATA"]["cache_dir"])

if not cache_dir.is_dir() or not cache_dir.exists():
try:
cache_dir = Path(config["DATA"]["cache_dir"])
except KeyError as e:
logger.critical(
"Cache dir does not exist! Please make sure init_config() was run properly. Path: %s",
"Cache dir does not exist! Please make sure init_config() was run properly. \
Path: %s, Error: %s",
cache_dir,
e,
)

# remove specified file (directory) from the data cache
Expand Down
59 changes: 0 additions & 59 deletions src/pygenesis/destatis.py

This file was deleted.

5 changes: 2 additions & 3 deletions src/pygenesis/http_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ def _check_destatis_status(destatis_status: dict) -> None:
If the status message is erroneous an error will be raised.
Possible Codes (2.1.2 Grundstruktur der Responses):
# TODO: Ask Destatis for full list of error codes
- 0: "erfolgreich" (Type: "Information")
- 22: "erfolgreich mit Parameteranpassung" (Type: "Warnung")
- 104: "Kein passendes Objekt zu Suche" (Type: "Information")
Expand All @@ -110,8 +111,7 @@ def _check_destatis_status(destatis_status: dict) -> None:
# check for generic/ system error
if destatis_status_code == -1:
raise DestatisStatusError(
"Error: There is a system error.\
Please check your query parameters."
"Error: There is a system error. Please check your query parameters."
)

# check for destatis/ query errors
Expand All @@ -125,7 +125,6 @@ def _check_destatis_status(destatis_status: dict) -> None:
logger.warning(destatis_status_content)

# output information to user
# TODO: Would logger.info (with forced visibility) be the better option?
elif destatis_status_type.lower() == "information":
logger.info(
"Code %d : %s", destatis_status_code, destatis_status_content
Expand Down
35 changes: 0 additions & 35 deletions src/pygenesis/statistic.py

This file was deleted.

28 changes: 24 additions & 4 deletions tests/test_cache.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import re
import time
from datetime import date
from pathlib import Path
Expand All @@ -20,7 +21,11 @@

@pytest.fixture()
def cache_dir(tmp_path_factory):
return tmp_path_factory.mktemp(".pygenesis")
# remove white-space and non-latin characters (issue fo some user names)
temp_dir = str(tmp_path_factory.mktemp(".pygenesis"))
temp_dir = re.sub(r"[^\x00-\x7f]", r"", temp_dir.replace(" ", ""))

return Path(temp_dir)


@pytest.fixture(autouse=True)
Expand Down Expand Up @@ -77,6 +82,15 @@ def test_cache_data_wrapper(cache_dir):
pd.testing.assert_frame_equal(data, restored_data, check_index_type=False)


def test_cache_data_wrapper_without_name(cache_dir):
init_config(cache_dir)

data = decorated_data(name=None)

assert isinstance(data, pd.DataFrame)
assert not data.empty


def test_cache_data_twice(cache_dir):
init_config(cache_dir)

Expand All @@ -93,7 +107,6 @@ def test_cache_data_twice(cache_dir):
assert load_time < SLEEP_TIME


# TODO: double-check functionality of this test
def clean_cache_setup(cache_dir, file: Optional[str] = None):
"""
Convenience function to cache a file and remove it with different options.
Expand All @@ -102,7 +115,7 @@ def clean_cache_setup(cache_dir, file: Optional[str] = None):

assert len(list((cache_dir / "data").glob("*"))) == 0

name = "test_clean_cache_decorator" if file is None else file
name = "test_clean_cache_cache_file" if file is None else file
data = decorated_data(name=name)

assert isinstance(data, pd.DataFrame)
Expand All @@ -124,5 +137,12 @@ def clean_cache_setup(cache_dir, file: Optional[str] = None):


def test_clean_cache(cache_dir):
# clean complete cache
clean_cache_setup(cache_dir)
clean_cache_setup(cache_dir, file="test_clean_cache_decorator_file")
# TODO: So far not working as expected: is_file returns false & treated like directory
# clean only one file
name = "test_clean_cache_cache_file"
file_path = (
Path("data") / name / str(date.today()).replace("-", "") / f"{name}.xz"
)
clean_cache_setup(cache_dir, file=str(file_path))
17 changes: 16 additions & 1 deletion tests/test_config.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import logging
import re
from configparser import ConfigParser
from pathlib import Path

import pytest
from mock import patch

from pygenesis.config import (
DEFAULT_SETTINGS_FILE,
_write_config,
create_settings,
get_config_path_from_settings,
init_config,
load_config,
Expand All @@ -16,7 +19,11 @@

@pytest.fixture()
def config_dir(tmp_path_factory):
return tmp_path_factory.mktemp(".pygenesis")
# remove white-space and non-latin characters (issue fo some user names)
temp_dir = str(tmp_path_factory.mktemp(".pygenesis"))
temp_dir = re.sub(r"[^\x00-\x7f]", r"", temp_dir.replace(" ", ""))

return Path(temp_dir)


@pytest.fixture(autouse=True)
Expand All @@ -30,6 +37,14 @@ def test_settings():
assert DEFAULT_SETTINGS_FILE.exists() and DEFAULT_SETTINGS_FILE.is_file()


@patch("pygenesis.config.DEFAULT_CONFIG_DIR")
@patch("pygenesis.config.DEFAULT_SETTINGS_FILE")
def test_create_settings(mock_config, mock_settings, config_dir):
mock_config.return_value = config_dir
mock_settings.return_value = config_dir / "settings.ini"
create_settings()


def test_load_settings():
settings = load_settings()

Expand Down
80 changes: 50 additions & 30 deletions tests/unit_tests/test_http_helper.py → tests/test_http_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,15 @@

import pytest
import requests
from mock import patch

from pygenesis.custom_exceptions import DestatisStatusError
from pygenesis.http_helper import (
_check_invalid_destatis_status_code,
_check_invalid_status_code,
get_response_from_endpoint,
)

# TODO: Add generic dummy request to the server, which is not getting us timed out,
# to test get_response_from_endpoint completely?


def test__check_invalid_status_code_with_error():
"""
Basic tests to check an error status code (4xx, 5xx)
for _handle_status_code method.
"""
for status_code in [400, 500]:
with pytest.raises(requests.exceptions.HTTPError) as e:
_check_invalid_status_code(status_code)
assert (
str(e.value)
== f"Error {status_code}: The server returned a {status_code} status code"
)


def test__check_invalid_status_code_without_error():
"""
Basic test to check a valid status code (2xx)
for the _handle_status_code method.
"""
status_code = 200
try:
_check_invalid_status_code(status_code)
except Exception:
assert False


def _generic_request_status(
status_response: bool = True,
Expand Down Expand Up @@ -84,10 +57,47 @@ def _generic_request_status(
return request_status


@patch("requests.get")
def test_get_response_from_endpoint(mocker):
"""
Test once with generic API response, more detailed tests
of subfunctions and specific cases below.
"""
mocker.return_value = _generic_request_status()

get_response_from_endpoint("endpoint", "method", {})


def test__check_invalid_status_code_with_error():
"""
Basic tests to check an error status code (4xx, 5xx)
for _handle_status_code method.
"""
for status_code in [400, 500]:
with pytest.raises(requests.exceptions.HTTPError) as e:
_check_invalid_status_code(status_code)
assert (
str(e.value)
== f"Error {status_code}: The server returned a {status_code} status code"
)


def test__check_invalid_status_code_without_error():
"""
Basic test to check a valid status code (2xx)
for the _handle_status_code method.
"""
status_code = 200
try:
_check_invalid_status_code(status_code)
except Exception:
assert False


def test__check_invalid_destatis_status_code_with_error():
"""
Basic tests to check an error status code as defined in the
documentation via code (e.g. 104) or type ('Error', 'Fehler').
documentation via code (e.g. -1, 104) or type ('Error', 'Fehler').
"""
for status in [
_generic_request_status(code=104),
Expand All @@ -101,6 +111,16 @@ def test__check_invalid_destatis_status_code_with_error():
_check_invalid_destatis_status_code(status)
assert str(e.value) == status_content

# also test generic -1 error code
generic_error_status = _generic_request_status(code=-1)

with pytest.raises(DestatisStatusError) as e:
_check_invalid_destatis_status_code(generic_error_status)
assert (
str(e.value)
== "Error: There is a system error. Please check your query parameters."
)


def test__check_invalid_destatis_status_code_with_warning(caplog):
"""
Expand Down
Empty file removed tests/unit_tests/__init__.py
Empty file.

0 comments on commit 0391812

Please sign in to comment.