feat(v2): complete v2 reimplementation
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import UTC, datetime, timedelta
|
||||
from typing import Any, cast
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
from backup_tool.config import Settings
|
||||
from backup_tool.db.models import NotificationDelivery, NotificationEvent, Schedule
|
||||
from backup_tool.scheduler import SchedulerService
|
||||
from sqlalchemy import select
|
||||
|
||||
PASSWORD = "correct-horse-battery-staple"
|
||||
|
||||
|
||||
async def setup_job(client: httpx.AsyncClient, settings: Settings) -> tuple[dict[str, str], str]:
|
||||
source_root = settings.local_source_roots[0] / "source"
|
||||
source_root.mkdir()
|
||||
headers = await login(client)
|
||||
repository = await client.post(
|
||||
"/api/v2/repositories",
|
||||
json={
|
||||
"name": "repo",
|
||||
"relative_path": "repo",
|
||||
"compression": "none",
|
||||
"encryption": "none",
|
||||
},
|
||||
headers=headers,
|
||||
)
|
||||
source = await client.post(
|
||||
"/api/v2/sources",
|
||||
json={
|
||||
"name": "source",
|
||||
"kind": "local",
|
||||
"public_config": {"root": str(source_root)},
|
||||
},
|
||||
headers=headers,
|
||||
)
|
||||
job = await client.post(
|
||||
"/api/v2/jobs",
|
||||
json={
|
||||
"name": "job",
|
||||
"source_id": source.json()["id"],
|
||||
"repository_id": repository.json()["id"],
|
||||
"requested_mode": "full",
|
||||
"exclusions": [],
|
||||
"retention": {},
|
||||
"enabled": True,
|
||||
"allow_empty": True,
|
||||
},
|
||||
headers=headers,
|
||||
)
|
||||
assert job.status_code == 201
|
||||
return headers, job.json()["id"]
|
||||
|
||||
|
||||
async def login(client: httpx.AsyncClient) -> dict[str, str]:
|
||||
response = await client.post("/api/v2/setup", json={"username": "admin", "password": PASSWORD})
|
||||
assert response.status_code == 201
|
||||
return {"X-CSRF-Token": client.cookies["backup_tool_csrf"]}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_schedule_role_delivery_and_live_crud_sync(
|
||||
app_client: tuple[httpx.AsyncClient, Settings],
|
||||
) -> None:
|
||||
client, settings = app_client
|
||||
headers, job_id = await setup_job(client, settings)
|
||||
subscription = await client.post(
|
||||
"/api/v2/notifications/subscriptions",
|
||||
json={
|
||||
"channel": "email",
|
||||
"event_filters": ["schedule.occurrence_enqueued"],
|
||||
"destination": {"recipients": ["operator@example.test"]},
|
||||
},
|
||||
headers=headers,
|
||||
)
|
||||
assert subscription.status_code == 201
|
||||
created = await client.post(
|
||||
f"/api/v2/jobs/{job_id}/schedule",
|
||||
json={"cron": "* * * * *", "timezone": "UTC"},
|
||||
headers=headers,
|
||||
)
|
||||
assert created.status_code == 201
|
||||
app = cast(Any, client._transport).app
|
||||
async with app.state.sessions() as db:
|
||||
schedule = await db.scalar(select(Schedule).where(Schedule.job_id == job_id))
|
||||
assert schedule is not None
|
||||
schedule.next_nominal_at = datetime.now(UTC) - timedelta(seconds=1)
|
||||
await db.commit()
|
||||
service = SchedulerService(settings)
|
||||
try:
|
||||
assert await service.run_once() == 1
|
||||
finally:
|
||||
await service.engine.dispose()
|
||||
async with app.state.sessions() as db:
|
||||
delivery = await db.scalar(
|
||||
select(NotificationDelivery.id)
|
||||
.join(NotificationEvent, NotificationDelivery.event_id == NotificationEvent.id)
|
||||
.where(NotificationEvent.type == "schedule.occurrence_enqueued")
|
||||
.limit(1)
|
||||
)
|
||||
assert delivery is not None
|
||||
|
||||
updated = await client.patch(
|
||||
f"/api/v2/jobs/{job_id}/schedule",
|
||||
json={"cron": "0 10 * * *", "timezone": "UTC", "enabled": False},
|
||||
headers=headers,
|
||||
)
|
||||
assert updated.status_code == 200
|
||||
assert updated.json()["next_nominal_at"] is None
|
||||
# Deletion with historical executions is deliberately restricted; schedule
|
||||
# delete behavior is covered before occurrence enqueue in the catalog test.
|
||||
Reference in New Issue
Block a user