feat(v2): complete v2 reimplementation

This commit is contained in:
2026-07-31 13:33:39 +02:00
parent 396219e776
commit bd107d6a30
137 changed files with 20737 additions and 155 deletions
+32 -6
View File
@@ -3,6 +3,7 @@ from __future__ import annotations
import json
from datetime import UTC, datetime, timedelta
from pathlib import Path
from typing import Any, cast
import httpx
import pytest
@@ -18,7 +19,6 @@ from backup_tool.execution import (
recover_stale,
request_cancellation,
)
from backup_tool.worker import Worker
PASSWORD = "correct-horse-battery-staple"
@@ -58,7 +58,7 @@ async def test_local_source_probe_archive_and_repository_targeted_job(
async with app.state.engine.begin() as connection:
await connection.run_sync(Base.metadata.create_all)
transport = httpx.ASGITransport(app=app)
transport = httpx.ASGITransport(app=cast(Any, app))
async with httpx.AsyncClient(transport=transport, base_url="https://test") as client:
headers = await login(client)
repository = await client.post(
@@ -108,6 +108,24 @@ async def test_local_source_probe_archive_and_repository_targeted_job(
assert duplicate.status_code == 409
assert duplicate.json()["code"] == "execution_active"
execution_id = execution.json()["id"]
listed_sources = await client.get("/api/v2/sources", headers=headers)
assert listed_sources.status_code == 200
assert listed_sources.json()["items"] == [
{
"id": source_id,
"name": "local",
"kind": "local",
"state": "active",
"public_config": {"root": str(source_root)},
}
]
listed_jobs = await client.get("/api/v2/jobs", headers=headers)
assert listed_jobs.status_code == 200
assert listed_jobs.json()["items"][0]["id"] == job.json()["id"]
assert listed_jobs.json()["items"][0]["schedule"] is None
listed_executions = await client.get("/api/v2/executions", headers=headers)
assert listed_executions.status_code == 200
assert listed_executions.json()["items"][0]["id"] == execution_id
scoped_token = await client.post(
"/api/v2/auth/tokens",
json={"scopes": ["audit:read"], "expires_at": None},
@@ -252,7 +270,9 @@ async def test_execution_sse_replays_later_redacted_revision(tmp_path: Path) ->
@pytest.mark.asyncio
async def test_execution_events_preserve_progress_replay_and_recovery_order(tmp_path: Path) -> None:
async def test_execution_events_preserve_progress_replay_and_recovery_order(
tmp_path: Path,
) -> None:
source_root = tmp_path / "sources"
source_root.mkdir()
data_dir = tmp_path / "data"
@@ -306,8 +326,14 @@ async def test_execution_events_preserve_progress_replay_and_recovery_order(tmp_
execution = await enqueue(db, job.id)
execution_id = execution.id
worker = Worker(settings, owner="ordering-worker")
assert await worker.run_once()
async with app.state.sessions() as db:
assert await claim(db, execution_id, "ordering-worker") is not None
execution = await db.get(Execution, execution_id)
assert execution is not None and execution.state == "preparing"
execution.state = "running"
execution.started_at = datetime.now(UTC)
await record_event(db, execution)
await db.commit()
async with app.state.sessions() as db:
execution = await db.get(Execution, execution_id)
assert execution is not None and execution.state == "running"
@@ -383,7 +409,7 @@ async def test_local_source_rejects_unallowlisted_root(tmp_path: Path) -> None:
async with app.state.engine.begin() as connection:
await connection.run_sync(Base.metadata.create_all)
async with httpx.AsyncClient(
transport=httpx.ASGITransport(app=app), base_url="https://test"
transport=httpx.ASGITransport(app=cast(Any, app)), base_url="https://test"
) as client:
headers = await login(client)
response = await client.post(