image_server/tests/conftest.py
2026-04-23 22:11:51 -05:00

146 lines
4.1 KiB
Python

"""Shared fixtures for the test suite."""
import argparse
import zipfile
from pathlib import Path
from typing import Generator
import pytest
from httpx import ASGITransport, AsyncClient
import main
def _reset_state() -> None:
"""Reset all global state to defaults."""
main.file_mapping.clear()
main.indexers.clear()
main.expected_password = None
@pytest.fixture(autouse=True)
def reset_globals() -> Generator[None, None, None]:
"""Reset global state before and after each test."""
_reset_state()
yield
_reset_state()
@pytest.fixture
def sample_files(tmp_path: Path) -> dict[str, Path]:
"""Create a directory with sample files for testing.
Returns:
Dict mapping logical names to file paths.
"""
subdir = tmp_path / "subdir"
subdir.mkdir()
files: dict[str, Path] = {}
files["root_file"] = tmp_path / "root.txt"
files["root_file"].write_text("root content")
files["sub_file"] = subdir / "nested.txt"
files["sub_file"].write_text("nested content")
files["binary_file"] = tmp_path / "data.bin"
files["binary_file"].write_bytes(b"\x00\x01\x02\x03")
files["image_file"] = tmp_path / "photo.jpg"
files["image_file"].write_bytes(b"\xff\xd8\xff\xe0fake_jpeg_data")
return files
@pytest.fixture
def sample_zip(tmp_path: Path) -> dict[str, Path]:
"""Create a ZIP file with sample files for testing.
Returns:
Dict mapping logical names to file paths inside the zip.
"""
zip_path = tmp_path / "test_archive.zip"
inner_files: dict[str, Path] = {}
with zipfile.ZipFile(zip_path, "w") as zf:
zf.writestr("top.txt", "top level content")
inner_files["top"] = Path("top.txt")
zf.writestr("folder/deep.txt", "deep content")
inner_files["deep"] = Path("folder/deep.txt")
zf.writestr("folder/image.png", b"\x89PNG fake png")
inner_files["image"] = Path("folder/image.png")
return inner_files
@pytest.fixture
def args_directory(sample_files: dict[str, Path], tmp_path: Path) -> argparse.Namespace:
"""Argparse namespace pointing at the sample directory."""
return argparse.Namespace(
source=str(tmp_path),
host="127.0.0.1",
port=0,
salt="test-salt",
password=None,
)
@pytest.fixture
def args_zip(sample_zip: dict[str, Path], tmp_path: Path) -> argparse.Namespace:
"""Argparse namespace pointing at the sample zip."""
return argparse.Namespace(
source=str(tmp_path / "test_archive.zip"),
host="127.0.0.1",
port=0,
salt="test-salt",
password=None,
)
@pytest.fixture
def initialized_dir(args_directory: argparse.Namespace) -> None:
"""Initialize the server with sample directory files (no auth)."""
main.initialize_server(args_directory)
main.set_auth_password(None)
@pytest.fixture
def initialized_zip(args_zip: argparse.Namespace) -> None:
"""Initialize the server with sample zip files (no auth)."""
main.initialize_server(args_zip)
main.set_auth_password(None)
def _dummy_auth_header() -> str:
"""Create a dummy Basic Auth header (any creds work when no password is set)."""
import base64
creds = "test:test"
return f"Basic {base64.b64encode(creds.encode()).decode()}"
@pytest.fixture
async def client_dir(initialized_dir: None) -> Generator[AsyncClient, None, None]:
"""Async HTTP client against the app initialized with directory files.
Sends dummy auth headers since HTTPBasic() always requires them.
"""
transport = ASGITransport(app=main.app)
async with AsyncClient(transport=transport, base_url="http://test") as ac:
ac.headers["Authorization"] = _dummy_auth_header()
yield ac
@pytest.fixture
async def client_zip(initialized_zip: None) -> Generator[AsyncClient, None, None]:
"""Async HTTP client against the app initialized with zip files.
Sends dummy auth headers since HTTPBasic() always requires them.
"""
transport = ASGITransport(app=main.app)
async with AsyncClient(transport=transport, base_url="http://test") as ac:
ac.headers["Authorization"] = _dummy_auth_header()
yield ac