Files
EOS/tests/conftest.py
T

210 lines
6.9 KiB
Python
Raw Normal View History

2024-11-10 23:49:10 +01:00
import logging
import shutil
2024-10-08 14:29:45 +02:00
import subprocess
import sys
import tempfile
2024-11-11 21:38:13 +01:00
from pathlib import Path
from typing import Optional
2024-10-08 14:29:45 +02:00
import pendulum
import platformdirs
2024-10-08 14:29:45 +02:00
import pytest
from xprocess import ProcessStarter
from akkudoktoreos.config.config import get_config
from akkudoktoreos.utils.logutil import get_logger
logger = get_logger(__name__)
2024-11-11 21:38:13 +01:00
@pytest.fixture()
def disable_debug_logging(scope="session", autouse=True):
"""Automatically disable debug logging for all tests."""
original_levels = {}
root_logger = logging.getLogger()
2024-11-11 21:38:13 +01:00
original_levels[root_logger] = root_logger.level
root_logger.setLevel(logging.INFO)
for logger_name, logger in logging.root.manager.loggerDict.items():
if isinstance(logger, logging.Logger):
original_levels[logger] = logger.level
if logger.level <= logging.DEBUG:
logger.setLevel(logging.INFO)
2024-10-08 14:29:45 +02:00
2024-11-10 23:49:10 +01:00
yield
for logger, level in original_levels.items():
logger.setLevel(level)
2024-11-10 23:49:10 +01:00
2024-11-10 23:22:30 +01:00
def pytest_addoption(parser):
parser.addoption(
"--full-run", action="store_true", default=False, help="Run with all optimization tests."
)
@pytest.fixture
def is_full_run(request):
yield bool(request.config.getoption("--full-run"))
@pytest.fixture
def reset_config(disable_debug_logging):
"""Fixture to reset EOS config to default values."""
config_eos = get_config()
config_eos.reset_settings()
config_eos.reset_to_defaults()
return config_eos
@pytest.fixture
def config_default_dirs():
"""Fixture that provides a list of directories to be used as config dir."""
config_eos = get_config()
# Default config directory from platform user config directory
config_default_dir_user = Path(platformdirs.user_config_dir(config_eos.APP_NAME))
# Default config directory from current working directory
config_default_dir_cwd = Path.cwd()
# Default config directory from default config file
config_default_dir_default = Path(__file__).parent.parent.joinpath("src/akkudoktoreos/data")
return config_default_dir_user, config_default_dir_cwd, config_default_dir_default
@pytest.fixture
def stash_config_file(config_default_dirs):
"""Fixture to temporarily stash away an existing config file during a test.
If the specified config file exists, it moves the file to a temporary directory.
The file is restored to its original location after the test.
Keep right most in fixture parameter list to assure application at last.
Returns:
Path: Path to the stashed config file.
"""
config_eos = get_config()
config_default_dir_user, config_default_dir_cwd, _ = config_default_dirs
config_file_path_user = config_default_dir_user.joinpath(config_eos.CONFIG_FILE_NAME)
config_file_path_cwd = config_default_dir_cwd.joinpath(config_eos.CONFIG_FILE_NAME)
original_config_file_user = None
original_config_file_cwd = None
if config_file_path_user.exists():
original_config_file_user = config_file_path_user
if config_file_path_cwd.exists():
original_config_file_cwd = config_file_path_cwd
temp_dir = tempfile.TemporaryDirectory()
temp_file_user = None
temp_file_cwd = None
# If the file exists, move it to the temporary directory
if original_config_file_user:
temp_file_user = Path(temp_dir.name) / f"user.{original_config_file_user.name}"
shutil.move(original_config_file_user, temp_file_user)
assert not original_config_file_user.exists()
logger.debug(f"Stashed: '{original_config_file_user}'")
if original_config_file_cwd:
temp_file_cwd = Path(temp_dir.name) / f"cwd.{original_config_file_cwd.name}"
shutil.move(original_config_file_cwd, temp_file_cwd)
assert not original_config_file_cwd.exists()
logger.debug(f"Stashed: '{original_config_file_cwd}'")
# Yield the temporary file path to the test
yield temp_file_user, temp_file_cwd
# Cleanup after the test
if temp_file_user:
# Restore the file to its original location
shutil.move(temp_file_user, original_config_file_user)
assert original_config_file_user.exists()
if temp_file_cwd:
# Restore the file to its original location
shutil.move(temp_file_cwd, original_config_file_cwd)
assert original_config_file_cwd.exists()
temp_dir.cleanup()
2024-10-08 14:29:45 +02:00
@pytest.fixture
2024-11-11 21:38:13 +01:00
def server(xprocess, tmp_path: Path):
2024-11-10 23:49:10 +01:00
"""Fixture to start the server.
Provides URL of the server.
"""
2024-10-08 14:29:45 +02:00
class Starter(ProcessStarter):
# assure server to be installed
try:
subprocess.run(
[sys.executable, "-c", "import akkudoktoreos.server.fastapi_server"],
2024-10-08 14:29:45 +02:00
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
except subprocess.CalledProcessError:
project_dir = Path(__file__).parent.parent.parent
2024-10-08 14:29:45 +02:00
subprocess.run(
[sys.executable, "-m", "pip", "install", "-e", project_dir],
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
# command to start server process
2024-11-15 22:27:25 +01:00
args = [sys.executable, "-m", "akkudoktoreos.server.fastapi_server"]
config_eos = get_config()
settings = {
"data_folder_path": tmp_path,
}
config_eos.merge_settings_from_dict(settings)
2024-10-08 14:29:45 +02:00
# startup pattern
2024-11-15 22:27:25 +01:00
pattern = "Application startup complete."
# search this number of lines for the startup pattern, if not found
2024-10-08 14:29:45 +02:00
# a RuntimeError will be raised informing the user
2024-11-11 21:38:13 +01:00
max_read_lines = 30
2024-10-08 14:29:45 +02:00
2024-11-11 21:38:13 +01:00
# will wait for 30 seconds before timing out
2024-10-10 12:59:33 +02:00
timeout = 30
2024-10-08 14:29:45 +02:00
# xprocess will now attempt to clean up upon interruptions
terminate_on_interrupt = True
# ensure process is running and return its logfile
pid, logfile = xprocess.ensure("eos", Starter)
2024-10-08 14:29:45 +02:00
# create url/port info to the server
url = "http://127.0.0.1:8503"
yield url
# clean up whole process tree afterwards
2024-11-15 22:27:25 +01:00
xprocess.getinfo("eos").terminate()
2024-11-10 23:49:10 +01:00
@pytest.fixture
def set_other_timezone():
"""Temporarily sets a timezone for Pendulum during a test.
2024-11-10 23:49:10 +01:00
Resets to the original timezone after the test completes.
2024-11-10 23:49:10 +01:00
"""
original_timezone = pendulum.local_timezone()
2024-11-10 23:49:10 +01:00
default_other_timezone = "Atlantic/Canary"
if default_other_timezone == original_timezone:
default_other_timezone = "Asia/Singapore"
2024-11-10 23:49:10 +01:00
def _set_timezone(other_timezone: Optional[str] = None) -> str:
if other_timezone is None:
other_timezone = default_other_timezone
pendulum.set_local_timezone(other_timezone)
assert pendulum.local_timezone() == other_timezone
return other_timezone
2024-11-10 23:49:10 +01:00
yield _set_timezone
2024-11-10 23:49:10 +01:00
# Restore the original timezone
pendulum.set_local_timezone(original_timezone)
assert pendulum.local_timezone() == original_timezone