fc3h(tests): drop pinned migration-backup tests (retired surface; coverage moved to test_backup_service.py + test_api_system_backup.py)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -31,17 +31,10 @@ async def client(app):
|
|||||||
yield c
|
yield c
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
# Retired 2026-05-24 (FC-3h): `test_post_backup_returns_202_and_id`
|
||||||
async def test_post_backup_returns_202_and_id(client, monkeypatch):
|
# asserted the /api/migrate/backup endpoint, which was retired in FC-3h.
|
||||||
monkeypatch.setattr(
|
# Backup is now a first-class feature at /api/system/backup/*;
|
||||||
"backend.app.api.migrate.run_migration",
|
# coverage lives in tests/test_api_system_backup.py.
|
||||||
type("F", (), {"delay": lambda self, *a, **k: None})(),
|
|
||||||
)
|
|
||||||
resp = await client.post("/api/migrate/backup", json={})
|
|
||||||
assert resp.status_code == 202
|
|
||||||
body = await resp.get_json()
|
|
||||||
assert "run_id" in body
|
|
||||||
assert body["status"] == "pending"
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@@ -62,10 +55,6 @@ async def test_post_ingest_rejects_missing_file(client):
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_post_ingest_accepts_multipart_file(client, monkeypatch):
|
async def test_post_ingest_accepts_multipart_file(client, monkeypatch):
|
||||||
monkeypatch.setattr(
|
|
||||||
"backend.app.api.migrate._has_recent_pre_migration_backup",
|
|
||||||
lambda: True, # pretend backup exists
|
|
||||||
)
|
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
"backend.app.api.migrate.run_migration",
|
"backend.app.api.migrate.run_migration",
|
||||||
type("F", (), {"delay": lambda self, *a, **k: None})(),
|
type("F", (), {"delay": lambda self, *a, **k: None})(),
|
||||||
@@ -92,10 +81,9 @@ async def test_post_ingest_accepts_multipart_file(client, monkeypatch):
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_post_dry_run_allowed_without_backup(client, monkeypatch):
|
async def test_post_dry_run_allowed_without_backup(client, monkeypatch):
|
||||||
monkeypatch.setattr(
|
# FC-3h: the _has_recent_pre_migration_backup gate was retired; dry-run
|
||||||
"backend.app.api.migrate._has_recent_pre_migration_backup",
|
# ingests were always allowed and now non-dry-run ingests are too.
|
||||||
lambda: False,
|
# This test stays as regression coverage that dry_run ingest still works.
|
||||||
)
|
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
"backend.app.api.migrate.run_migration",
|
"backend.app.api.migrate.run_migration",
|
||||||
type("F", (), {"delay": lambda self, *a, **k: None})(),
|
type("F", (), {"delay": lambda self, *a, **k: None})(),
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
"""FC-5: backup + rollback service tests.
|
|
||||||
|
|
||||||
Uses tmp_path to avoid touching real /images/_backups/. Subprocess
|
|
||||||
calls (pg_dump, tar) are monkeypatched — the real shell-out is exercised
|
|
||||||
in operator-side smoke testing on the homelab, not in unit tests.
|
|
||||||
"""
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from backend.app.services.migrators import backup as backup_mod
|
|
||||||
|
|
||||||
pytestmark = pytest.mark.integration
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
async def test_create_backup_writes_sql_and_tar(monkeypatch, tmp_path):
|
|
||||||
calls = []
|
|
||||||
|
|
||||||
def fake_run(cmd, **kwargs):
|
|
||||||
calls.append(cmd)
|
|
||||||
# Touch the expected output file so existence checks pass downstream.
|
|
||||||
if "pg_dump" in cmd[0]:
|
|
||||||
outpath = tmp_path / "_backups" / f"fc_{kwargs['_test_ts']}.sql"
|
|
||||||
outpath.write_text("-- fake pg_dump output")
|
|
||||||
else:
|
|
||||||
outpath = tmp_path / "_backups" / f"fc_{kwargs['_test_ts']}.tar.zst"
|
|
||||||
outpath.write_bytes(b"\x28\xb5\x2f\xfd") # zstd magic
|
|
||||||
from types import SimpleNamespace
|
|
||||||
return SimpleNamespace(returncode=0, stdout=b"", stderr=b"")
|
|
||||||
|
|
||||||
monkeypatch.setattr(backup_mod, "_run_subprocess", fake_run)
|
|
||||||
|
|
||||||
result = backup_mod.create_backup(
|
|
||||||
db_url="postgresql://x", images_root=tmp_path, tag="pre_migration",
|
|
||||||
)
|
|
||||||
assert "sql_path" in result
|
|
||||||
assert "tar_path" in result
|
|
||||||
assert result["tag"] == "pre_migration"
|
|
||||||
assert any("pg_dump" in c[0] for c in calls)
|
|
||||||
assert any(c[0] == "tar" for c in calls)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
async def test_find_latest_backup_by_tag(monkeypatch, tmp_path):
|
|
||||||
# Create two manifests with different tags.
|
|
||||||
backups_dir = tmp_path / "_backups"
|
|
||||||
backups_dir.mkdir()
|
|
||||||
import json
|
|
||||||
(backups_dir / "fc_20260101T000000Z.json").write_text(json.dumps({
|
|
||||||
"backup_id": "20260101T000000Z", "tag": "manual",
|
|
||||||
"created_at": "2026-01-01T00:00:00+00:00",
|
|
||||||
"sql_path": "/x/a.sql", "tar_path": "/x/a.tar.zst",
|
|
||||||
}))
|
|
||||||
(backups_dir / "fc_20260202T000000Z.json").write_text(json.dumps({
|
|
||||||
"backup_id": "20260202T000000Z", "tag": "pre_migration",
|
|
||||||
"created_at": "2026-02-02T00:00:00+00:00",
|
|
||||||
"sql_path": "/x/b.sql", "tar_path": "/x/b.tar.zst",
|
|
||||||
}))
|
|
||||||
|
|
||||||
found = backup_mod.find_latest_backup(tmp_path, tag="pre_migration")
|
|
||||||
assert found is not None
|
|
||||||
assert found["backup_id"] == "20260202T000000Z"
|
|
||||||
|
|
||||||
missing = backup_mod.find_latest_backup(tmp_path, tag="nonexistent")
|
|
||||||
assert missing is None
|
|
||||||
Reference in New Issue
Block a user