1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
from __future__ import annotations
from collections.abc import Generator
from collections.abc import Iterator
from pathlib import Path
from typing import Any
import pytest
import typer
from packaging.version import Version
from typer.testing import CliRunner
from zabbix_cli.app import StatefulApp
from zabbix_cli.config.model import Config
from zabbix_cli.main import app
from zabbix_cli.pyzabbix.client import ZabbixAPI
from zabbix_cli.state import State
from zabbix_cli.state import get_state
runner = CliRunner()
@pytest.fixture(name="app")
def _app() -> Iterator[StatefulApp]:
yield app
@pytest.fixture
def ctx(app: StatefulApp) -> typer.Context:
"""Create context for the main command."""
# Use the CliRunner to invoke a command and capture the context
obj = {}
with runner.isolated_filesystem():
@app.callback(invoke_without_command=True)
def callback(ctx: typer.Context):
obj["ctx"] = ctx # Capture the context in a non-local object
runner.invoke(app, [], obj=obj)
return obj["ctx"]
DATA_DIR = Path(__file__).parent / "data"
# Read sample configs once per test run to avoid too much I/O
TOML_CONFIG = DATA_DIR / "zabbix-cli.toml"
TOML_CONFIG_STR = TOML_CONFIG.read_text()
CONF_CONFIG = DATA_DIR / "zabbix-cli.conf"
CONF_CONFIG_STR = CONF_CONFIG.read_text()
@pytest.fixture()
def data_dir() -> Iterator[Path]:
yield Path(__file__).parent / "data"
@pytest.fixture()
def config_path(tmp_path: Path) -> Iterator[Path]:
config_copy = tmp_path / "zabbix-cli.toml"
config_copy.write_text(TOML_CONFIG_STR)
yield config_copy
@pytest.fixture()
def legacy_config_path(tmp_path: Path) -> Iterator[Path]:
config_copy = tmp_path / "zabbix-cli.conf"
config_copy.write_text(CONF_CONFIG_STR)
yield config_copy
@pytest.fixture(name="state")
def state(config: Config, zabbix_client: ZabbixAPI) -> Iterator[State]:
"""Return a fresh State object with a config and client.
The client is not logged in to the Zabbix API.
Modifies the State singleton to ensure a fresh state is returned
each time.
"""
State._instance = None # pyright: ignore[reportPrivateUsage]
state = get_state()
state.config = config
state.client = zabbix_client
yield state
# reset after test
State._instance = None # pyright: ignore[reportPrivateUsage]
@pytest.fixture(name="config")
def config(tmp_path: Path) -> Iterator[Config]:
"""Return a sample config."""
conf = Config.sample_config()
# Set up logging for the test environment
log_file = tmp_path / "zabbix-cli.log"
conf.logging.log_file = log_file
conf.logging.log_level = "DEBUG" # we want to see all logs
yield conf
@pytest.fixture(name="zabbix_client")
def zabbix_client() -> Iterator[ZabbixAPI]:
config = Config.sample_config()
client = ZabbixAPI.from_config(config)
yield client
@pytest.fixture(name="zabbix_client_mock_version")
def zabbix_client_mock_version(
zabbix_client: ZabbixAPI, monkeypatch: pytest.MonkeyPatch
) -> Iterator[ZabbixAPI]:
monkeypatch.setattr(zabbix_client, "api_version", lambda: Version("7.0.0"))
yield zabbix_client
@pytest.fixture(name="force_color")
def force_color() -> Generator[Any, Any, Any]:
import os
os.environ["FORCE_COLOR"] = "1"
yield
os.environ.pop("FORCE_COLOR", None)
@pytest.fixture(name="no_color")
def no_color() -> Generator[Any, Any, Any]:
"""Disable color in a test. Takes precedence over force_color."""
import os
os.environ.pop("FORCE_COLOR", None)
os.environ["NO_COLOR"] = "1"
yield
os.environ.pop("NO_COLOR", None)
|