Files

94 lines
3.1 KiB
Python
Raw Permalink Normal View History

"""自动备份/恢复演练单元测试(临时目录,不碰真实数据)。"""
import os
import sqlite3
import zipfile
from unittest.mock import patch
import pytest
from app import backup as bk
@pytest.fixture()
def isolated_backup(monkeypatch, tmp_path):
"""隔离 DATA_DIR/KB_DIR/BACKUP_DIR 到临时目录,并造一个含业务表的库。"""
data_dir = tmp_path / "data"
data_dir.mkdir()
db_path = data_dir / "workspace.db"
with sqlite3.connect(str(db_path)) as conn:
conn.executescript("""
CREATE TABLE campaign (id INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE agent (id INTEGER PRIMARY KEY);
CREATE TABLE appuser (id INTEGER PRIMARY KEY);
CREATE TABLE other (x INTEGER);
INSERT INTO campaign (name) VALUES ('任务一'), ('任务二');
""")
kb_dir = data_dir / "kb"
kb_dir.mkdir()
(kb_dir / "note.txt").write_text("知识内容", encoding="utf-8")
monkeypatch.setattr(bk, "DATA_DIR", data_dir)
monkeypatch.setattr(bk, "KB_DIR", kb_dir)
monkeypatch.setattr(bk, "BACKUP_DIR", data_dir / "backups")
return data_dir
def test_create_backup_returns_zip(isolated_backup):
result = bk.create_backup("test")
assert result is not None and result.exists()
assert result.name.startswith("backup-test-")
with zipfile.ZipFile(result) as zf:
assert "workspace.db" in zf.namelist()
assert "kb/note.txt" in zf.namelist()
def test_backup_skipped_when_no_db(tmp_path):
empty = tmp_path / "empty"
empty.mkdir()
(empty / "kb").mkdir()
with patch.object(bk, "DATA_DIR", empty), patch.object(bk, "KB_DIR", empty / "kb"), \
patch.object(bk, "BACKUP_DIR", empty / "backups"):
assert bk.create_backup("x") is None
def test_verify_backup_checks_tables(isolated_backup):
result = bk.create_backup("test")
ok, detail = bk.verify_backup(result)
assert ok, detail
assert "campaign 2 行" in detail
def test_verify_backup_rejects_corrupt(isolated_backup):
bk.BACKUP_DIR.mkdir(parents=True, exist_ok=True)
bad = bk.BACKUP_DIR / "backup-bad.zip"
bad.write_bytes(b"not a zip")
ok, _detail = bk.verify_backup(bad)
assert not ok
def test_prune_keeps_recent(isolated_backup, monkeypatch):
monkeypatch.setattr(bk, "KEEP_COUNT", 3)
bk.BACKUP_DIR.mkdir(parents=True, exist_ok=True)
for i in range(5):
target = bk.BACKUP_DIR / f"backup-auto-2026010{i}-000000.zip"
target.write_bytes(b"placeholder")
os.utime(target, (1700000000 + i * 100, 1700000000 + i * 100))
removed = bk._prune_old_backups()
assert removed == 2
remaining = list(bk.BACKUP_DIR.glob("backup-*.zip"))
assert len(remaining) == 3
def test_restore_drill_latest(isolated_backup):
bk.create_backup("drill")
report = bk.verify_restore_latest()
assert report["ok"], report["detail"]
assert "解压演练通过" in report["detail"]
def test_backup_status_summary(isolated_backup):
bk.create_backup("status")
status = bk.backup_status()
assert status["count"] == 1
assert status["latest"].startswith("backup-status-")
assert status["latest_size_kb"] > 0