125 lines
3.6 KiB
Python
125 lines
3.6 KiB
Python
"""Shared fixtures for the volumen test suite."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import tempfile
|
|
from collections.abc import Generator
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
from volumen import reset_login_attempts
|
|
from volumen.config import Config
|
|
from volumen.password import hash_password as hash_pw
|
|
from volumen.store import Store
|
|
from volumen.users import Users
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _reset_login_attempts() -> Generator[None, None, None]:
|
|
"""Reset the global login-attempts tracker before every test."""
|
|
reset_login_attempts()
|
|
yield
|
|
|
|
|
|
@pytest.fixture
|
|
def tmp_dir() -> Generator[Path, None, None]:
|
|
"""Create a temporary directory that is cleaned up after the test."""
|
|
with tempfile.TemporaryDirectory() as d:
|
|
yield Path(d)
|
|
|
|
|
|
@pytest.fixture
|
|
def tmp_content_dir(tmp_path: Path) -> Path:
|
|
"""Temporary content directory with sample posts."""
|
|
content = tmp_path / "posts"
|
|
content.mkdir()
|
|
(content / "hello.md").write_text(
|
|
'+++\ntitle = "Hello"\ntags = ["intro"]\n+++\n\nHello **world**.\n'
|
|
)
|
|
(content / "draft.md").write_text('+++\ntitle = "Draft"\ndraft = true\n+++\n\nSecret.\n')
|
|
return content
|
|
|
|
|
|
@pytest.fixture
|
|
def config(tmp_content_dir: Path) -> Config:
|
|
"""Test Config instance pointing at a temp content directory."""
|
|
return Config.load(
|
|
path="/nonexistent/volumen.toml",
|
|
overrides={"content": str(tmp_content_dir)},
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def store(tmp_content_dir: Path) -> Store:
|
|
"""Test Store instance backed by a temp content directory."""
|
|
return Store(str(tmp_content_dir), default_lang="en")
|
|
|
|
|
|
@pytest.fixture
|
|
def users_path(tmp_path: Path) -> str:
|
|
"""Path for a temporary users.toml file."""
|
|
return str(tmp_path / "users.toml")
|
|
|
|
|
|
@pytest.fixture
|
|
def bootstrap_hash() -> str:
|
|
"""A pre-hashed password for bootstrap tests."""
|
|
return hash_pw("secret")
|
|
|
|
|
|
@pytest.fixture
|
|
def users(users_path: str, bootstrap_hash: str) -> Users:
|
|
"""Test Users instance with bootstrap admin user."""
|
|
return Users(path=users_path, bootstrap_hash=bootstrap_hash)
|
|
|
|
|
|
@pytest.fixture
|
|
def client(config: Config, store: Store) -> TestClient:
|
|
"""FastAPI TestClient for public API tests."""
|
|
from volumen.server import create_app
|
|
|
|
app = create_app(config, store)
|
|
return TestClient(app)
|
|
|
|
|
|
@pytest.fixture
|
|
def admin_config_dir(tmp_path: Path) -> Path:
|
|
"""Create a directory with config and posts for admin tests."""
|
|
posts_dir = tmp_path / "posts"
|
|
posts_dir.mkdir()
|
|
users_path = tmp_path / "users.toml"
|
|
config_path = tmp_path / "config.toml"
|
|
pw_hash = hash_pw("secret")
|
|
config_path.write_text(
|
|
f'content_dir = "{posts_dir}"\n'
|
|
f'users_file = "{users_path}"\n\n'
|
|
"[admin]\n"
|
|
f'password_hash = "{pw_hash}"\n'
|
|
)
|
|
return tmp_path
|
|
|
|
|
|
@pytest.fixture
|
|
def admin_client(admin_config_dir: Path) -> TestClient:
|
|
"""FastAPI TestClient for admin tests with bootstrap admin."""
|
|
from volumen.config import Config
|
|
from volumen.server import create_app
|
|
from volumen.store import Store
|
|
|
|
config = Config.load(path=str(admin_config_dir / "config.toml"))
|
|
store = Store(config.content_dir, default_lang="en")
|
|
app = create_app(config, store)
|
|
return TestClient(app)
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_post_md() -> str:
|
|
"""Sample post in Markdown with TOML frontmatter."""
|
|
return (
|
|
'+++\ntitle = "Test Post"\nslug = "test-post"\nlang = "en"\n'
|
|
'tags = ["python", "blog"]\ndate = 2026-01-15\ndraft = false\n+++\n\n'
|
|
"This is the **body** of the post.\n\nSecond paragraph."
|
|
)
|