146 lines
4.1 KiB
Python
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
|