test(v2): define local source and job contracts
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
from backup_tool.api.app import create_app
|
||||
from backup_tool.config import Settings
|
||||
|
||||
PASSWORD = "correct-horse-battery-staple"
|
||||
|
||||
|
||||
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": response.json()["csrf_token"]}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_local_source_probe_archive_and_repository_targeted_job(tmp_path: Path) -> None:
|
||||
source_root = tmp_path / "sources"
|
||||
source_root.mkdir()
|
||||
(source_root / "data.txt").write_text("contents")
|
||||
settings = Settings(
|
||||
data_dir=tmp_path / "data",
|
||||
database_url=f"sqlite+aiosqlite:///{tmp_path / 'data' / 'db.sqlite'}",
|
||||
repository_roots=(tmp_path / "repositories",),
|
||||
local_source_roots=(source_root,),
|
||||
restore_roots=(tmp_path / "restore",),
|
||||
master_key_file=tmp_path / "master.key",
|
||||
)
|
||||
settings.master_key_file.write_bytes(b"x" * 32)
|
||||
settings.master_key_file.chmod(0o600)
|
||||
for root in (*settings.repository_roots, *settings.restore_roots):
|
||||
root.mkdir(parents=True)
|
||||
app = create_app(settings)
|
||||
transport = httpx.ASGITransport(app=app)
|
||||
async with httpx.AsyncClient(transport=transport, base_url="http://test") as client:
|
||||
headers = await login(client)
|
||||
repository = await client.post(
|
||||
"/api/v2/repositories", json={"name": "repo", "relative_path": "main"}, headers=headers
|
||||
)
|
||||
assert repository.status_code == 201
|
||||
source = await client.post(
|
||||
"/api/v2/sources",
|
||||
json={"name": "local", "kind": "local", "public_config": {"root": str(source_root)}},
|
||||
headers=headers,
|
||||
)
|
||||
assert source.status_code == 201
|
||||
source_id = source.json()["id"]
|
||||
probe = await client.post(f"/api/v2/sources/{source_id}/probe", headers=headers)
|
||||
assert probe.status_code == 200
|
||||
assert probe.json()["entry_count"] == 1
|
||||
job = await client.post(
|
||||
"/api/v2/jobs",
|
||||
json={"name": "job", "source_id": source_id, "repository_id": repository.json()["id"], "requested_mode": "full", "exclusions": ["*.tmp"], "retention": {}, "enabled": True, "allow_empty": False},
|
||||
headers=headers,
|
||||
)
|
||||
assert job.status_code == 201
|
||||
assert "destination_path" not in job.json()
|
||||
archived = await client.delete(f"/api/v2/sources/{source_id}", headers=headers)
|
||||
assert archived.status_code == 204
|
||||
assert (await client.post(f"/api/v2/sources/{source_id}/probe", headers=headers)).status_code == 409
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_local_source_rejects_unallowlisted_root(tmp_path: Path) -> None:
|
||||
allowed = tmp_path / "allowed"
|
||||
allowed.mkdir()
|
||||
outside = tmp_path / "outside"
|
||||
outside.mkdir()
|
||||
key = tmp_path / "master.key"
|
||||
key.write_bytes(b"x" * 32)
|
||||
key.chmod(0o600)
|
||||
settings = Settings(
|
||||
data_dir=tmp_path / "data",
|
||||
database_url=f"sqlite+aiosqlite:///{tmp_path / 'data' / 'db.sqlite'}",
|
||||
repository_roots=(tmp_path / "repositories",),
|
||||
local_source_roots=(allowed,),
|
||||
restore_roots=(tmp_path / "restore",),
|
||||
master_key_file=key,
|
||||
)
|
||||
settings.repository_roots[0].mkdir()
|
||||
settings.restore_roots[0].mkdir()
|
||||
app = create_app(settings)
|
||||
async with httpx.AsyncClient(transport=httpx.ASGITransport(app=app), base_url="http://test") as client:
|
||||
headers = await login(client)
|
||||
response = await client.post("/api/v2/sources", json={"name":"bad","kind":"local","public_config":{"root":str(outside)}}, headers=headers)
|
||||
assert response.status_code == 422
|
||||
Reference in New Issue
Block a user