add dev-mode

This commit is contained in:
Abel Luck 2026-03-30 15:36:12 +02:00
parent 0803617e62
commit 31e1da937f
7 changed files with 146 additions and 51 deletions

71
tests/test_dev_mode.py Normal file
View file

@ -0,0 +1,71 @@
from __future__ import annotations
import asyncio
from pathlib import Path
from repub.web import create_app
def test_dev_mode_serves_published_feeds(monkeypatch, tmp_path: Path) -> None:
db_path = tmp_path / "dev-mode.db"
feeds_dir = tmp_path / "out" / "feeds"
monkeypatch.setenv("REPUBLISHER_DB_PATH", str(db_path))
async def run() -> None:
app = create_app(dev_mode=True)
app.config["REPUB_FEEDS_DIR"] = feeds_dir
feed_path = feeds_dir / "demo-source" / "feed.rss"
feed_path.parent.mkdir(parents=True)
feed_path.write_text("<rss/>\n", encoding="utf-8")
client = app.test_client()
response = await client.get("/feeds/demo-source/feed.rss")
assert response.status_code == 200
assert response.mimetype == "application/rss+xml"
assert await response.get_data(as_text=True) == "<rss/>\n"
asyncio.run(run())
def test_dev_mode_serves_feed_enclosure_assets(monkeypatch, tmp_path: Path) -> None:
db_path = tmp_path / "dev-mode-assets.db"
feeds_dir = tmp_path / "out" / "feeds"
monkeypatch.setenv("REPUBLISHER_DB_PATH", str(db_path))
async def run() -> None:
app = create_app(dev_mode=True)
app.config["REPUB_FEEDS_DIR"] = feeds_dir
enclosure_path = feeds_dir / "demo-source" / "audio" / "episode.mp3"
enclosure_path.parent.mkdir(parents=True)
enclosure_path.write_bytes(b"mp3-data")
client = app.test_client()
response = await client.get("/feeds/demo-source/audio/episode.mp3")
assert response.status_code == 200
assert await response.get_data() == b"mp3-data"
asyncio.run(run())
def test_default_mode_does_not_serve_published_feeds(
monkeypatch, tmp_path: Path
) -> None:
db_path = tmp_path / "default-mode.db"
feeds_dir = tmp_path / "out" / "feeds"
monkeypatch.setenv("REPUBLISHER_DB_PATH", str(db_path))
async def run() -> None:
app = create_app()
app.config["REPUB_FEEDS_DIR"] = feeds_dir
feed_path = feeds_dir / "demo-source" / "feed.rss"
feed_path.parent.mkdir(parents=True)
feed_path.write_text("<rss/>\n", encoding="utf-8")
client = app.test_client()
response = await client.get("/feeds/demo-source/feed.rss")
assert response.status_code == 404
asyncio.run(run())

View file

@ -31,6 +31,20 @@ def test_parse_args_uses_republisher_host_and_port_env_vars(monkeypatch) -> None
assert args.port == "9090"
def test_parse_args_supports_dev_mode_flag() -> None:
command, args = parse_args(["serve", "--dev-mode"])
assert command == "serve"
assert args.dev_mode is True
def test_parse_args_defaults_to_dev_mode_when_no_args() -> None:
command, args = parse_args([])
assert command == "serve"
assert args.dev_mode is True
def test_entrypoint_rejects_invalid_republisher_port(monkeypatch) -> None:
monkeypatch.setenv("REPUBLISHER_PORT", "not-a-number")
stream = io.StringIO()
@ -49,3 +63,25 @@ def test_entrypoint_rejects_invalid_republisher_port(monkeypatch) -> None:
assert exit_code == 2
assert "Invalid REPUBLISHER_PORT/--port value" in stream.getvalue()
def test_entrypoint_passes_dev_mode_to_create_app(monkeypatch) -> None:
recorded: dict[str, object] = {}
class StubApp:
def run(self, *, host: str, port: int) -> None:
recorded["host"] = host
recorded["port"] = port
def fake_create_app(*, dev_mode: bool) -> StubApp:
recorded["dev_mode"] = dev_mode
return StubApp()
monkeypatch.setattr("repub.entrypoint.create_app", fake_create_app)
exit_code = entrypoint(
["serve", "--dev-mode", "--host", "0.0.0.0", "--port", "9090"]
)
assert exit_code == 0
assert recorded == {"dev_mode": True, "host": "0.0.0.0", "port": 9090}

View file

@ -59,12 +59,7 @@ def test_job_runtime_syncs_enabled_jobs_into_apscheduler(tmp_path: Path) -> None
enabled_job = Job.get(Job.source == enabled_source)
disabled_job = Job.get(Job.source == disabled_source)
runtime = JobRuntime(
log_dir=tmp_path / "out" / "logs",
worker_duration_seconds=0.4,
worker_stats_interval_seconds=0.05,
worker_failure_probability=0.0,
)
runtime = JobRuntime(log_dir=tmp_path / "out" / "logs")
try:
runtime.start()
runtime.sync_jobs()
@ -104,12 +99,7 @@ def test_job_runtime_run_now_writes_log_and_stats_and_marks_success(
)
job = Job.get(Job.source == source)
runtime = JobRuntime(
log_dir=tmp_path / "out" / "logs",
worker_duration_seconds=0.35,
worker_stats_interval_seconds=0.05,
worker_failure_probability=0.0,
)
runtime = JobRuntime(log_dir=tmp_path / "out" / "logs")
try:
runtime.start()
execution_id = runtime.run_job_now(job.id, reason="manual")
@ -164,12 +154,7 @@ def test_job_runtime_cancel_marks_execution_canceled(tmp_path: Path) -> None:
)
job = Job.get(Job.source == source)
runtime = JobRuntime(
log_dir=tmp_path / "out" / "logs",
worker_duration_seconds=2.0,
worker_stats_interval_seconds=0.1,
worker_failure_probability=0.0,
)
runtime = JobRuntime(log_dir=tmp_path / "out" / "logs")
try:
runtime.start()
execution_id = runtime.run_job_now(job.id, reason="manual")
@ -227,12 +212,7 @@ def test_job_runtime_start_reconciles_stale_running_execution(tmp_path: Path) ->
encoding="utf-8",
)
runtime = JobRuntime(
log_dir=tmp_path / "out" / "logs",
worker_duration_seconds=0.5,
worker_stats_interval_seconds=0.05,
worker_failure_probability=0.0,
)
runtime = JobRuntime(log_dir=tmp_path / "out" / "logs")
try:
runtime.start()
reconciled_execution = JobExecution.get_by_id(execution.get_id())
@ -344,10 +324,6 @@ def test_render_runs_uses_database_backed_jobs_and_executions(
app = create_app()
app.config["REPUB_LOG_DIR"] = log_dir
app.config["REPUB_JOB_WORKER_DURATION_SECONDS"] = 0.35
app.config["REPUB_JOB_WORKER_STATS_INTERVAL_SECONDS"] = 0.05
app.config["REPUB_JOB_WORKER_FAILURE_PROBABILITY"] = 0.0
source = create_source(
name="Runs page source",
slug="runs-page-source",