Files
gaokao-volunteer-system/tests/test_retention_cleanup.py

188 lines
6.0 KiB
Python
Raw Normal View History

2026-06-14 20:55:06 +08:00
from __future__ import annotations
import os
import subprocess
import sys
2026-06-14 20:55:06 +08:00
from pathlib import Path
from data.orders.dao import OrdersDAO
from data.orders.models import Order
PROJECT_ROOT = Path(__file__).resolve().parents[1]
def _seed_old_completed_order(
db_path: str, order_id: str = "GKO-20250101-RETENTION"
) -> Order:
order = Order(
id=order_id,
source="web",
service_version="standard",
amount_cents=9900,
status="completed",
customer_name="张家长",
customer_phone="13800138000",
customer_wechat="wx-retention",
candidate_name="张三",
candidate_province="湖南",
notes="old completed order",
created_at="2025-01-01T00:00:00+00:00",
completed_at="2025-01-02T00:00:00+00:00",
status_updated_at="2025-01-02T00:00:00+00:00",
)
with OrdersDAO.connect(db_path) as dao:
return dao.create(order, actor="test", reason="seed_old_completed")
def test_retention_cleanup_dry_run_reports_candidates(settings):
_seed_old_completed_order(settings.orders_db_path)
from data.orders.retention_cleanup import run_cleanup
result = run_cleanup(
settings.orders_db_path,
cutoff_iso="2025-06-30T00:00:00+00:00",
apply=False,
)
assert result.scanned >= 1
assert result.candidates == 1
assert result.anonymized == 0
def test_retention_cleanup_apply_anonymizes_old_completed_order(settings):
_seed_old_completed_order(
settings.orders_db_path, order_id="GKO-20250101-RETENTION-APPLY"
)
from data.orders.retention_cleanup import run_cleanup
result = run_cleanup(
settings.orders_db_path,
cutoff_iso="2025-06-30T00:00:00+00:00",
apply=True,
)
assert result.candidates == 1
assert result.anonymized == 1
with OrdersDAO.connect(settings.orders_db_path) as dao:
order = dao.get("GKO-20250101-RETENTION-APPLY")
assert order.customer_phone is None
assert order.customer_name == "已匿名化"
def test_retention_cleanup_script_prints_summary(settings):
_seed_old_completed_order(
settings.orders_db_path, order_id="GKO-20250101-RETENTION-CLI"
)
env = {**os.environ, "GAOKAO_ORDERS_DB_PATH": settings.orders_db_path}
proc = subprocess.run(
[
sys.executable,
2026-06-14 20:55:06 +08:00
"scripts/gaokao-retention-cleanup.py",
"--cutoff",
"2025-06-30T00:00:00+00:00",
"--dry-run",
],
cwd=PROJECT_ROOT,
text=True,
capture_output=True,
env=env,
check=False,
)
assert proc.returncode == 0, proc.stderr
assert '"cutoff_iso": "2025-06-30T00:00:00+00:00"' in proc.stdout
assert '"dry_run": true' in proc.stdout
assert '"candidates": 1' in proc.stdout
def test_retention_cleanup_script_supports_retention_days(settings):
_seed_old_completed_order(
settings.orders_db_path, order_id="GKO-20250101-RETENTION-DAYS"
)
env = {**os.environ, "GAOKAO_ORDERS_DB_PATH": settings.orders_db_path}
proc = subprocess.run(
[
sys.executable,
"scripts/gaokao-retention-cleanup.py",
"--retention-days",
"180",
"--dry-run",
],
cwd=PROJECT_ROOT,
text=True,
capture_output=True,
env=env,
check=False,
)
assert proc.returncode == 0, proc.stderr
assert '"cutoff_iso":' in proc.stdout
assert '"dry_run": true' in proc.stdout
assert '"candidates": 1' in proc.stdout
def test_retention_cleanup_apply_anonymizes_multiple_old_orders_in_sequence(
settings,
) -> None:
"""T12-D regression: 服务持有 conn 时,连续 anonymize 多笔订单必须全部成功。
历史 bug: ``deletion_service.anonymize_order`` ``self._conn`` 包成
``OrdersDAO(self._conn)`` with-block ``OrdersDAO.__exit__`` 不区分
conn 所有权一律 close第一个订单执行完就把 service 持有的连接关掉
第二个订单开始全部 ``Cannot operate on a closed database``
"""
from data.orders.retention_cleanup import run_cleanup
order_ids = [
"GKO-20250101-RETENTION-MULTI-A",
"GKO-20250101-RETENTION-MULTI-B",
"GKO-20250101-RETENTION-MULTI-C",
]
for idx, oid in enumerate(order_ids, start=1):
_seed_old_completed_order(settings.orders_db_path, order_id=oid)
# 给每个订单一点时间间隔,确保 status_updated_at 不完全相同
# cleanup 按 cutoff 命中即可,无需显式 sleep
result = run_cleanup(
settings.orders_db_path,
cutoff_iso="2025-06-30T00:00:00+00:00",
apply=True,
)
assert result.scanned >= 3
assert result.candidates == 3
assert result.anonymized == 3, (
f"连续多笔订单应全部匿名化,实际 anonymized={result.anonymized} "
f"(历史 bug: 第一个 anonymize 关闭 service.conn 后后续全部失败)"
)
with OrdersDAO.connect(settings.orders_db_path) as dao:
for oid in order_ids:
order = dao.get(oid)
assert order.customer_phone is None, f"{oid} phone 未被清空"
assert order.customer_name == "已匿名化", (
f"{oid} name 未被替换为'已匿名化',实际={order.customer_name!r}"
)
def test_retention_cleanup_underscore_script_alias_works(settings):
_seed_old_completed_order(
settings.orders_db_path, order_id="GKO-20250101-RETENTION-ALIAS"
)
env = {**os.environ, "GAOKAO_ORDERS_DB_PATH": settings.orders_db_path}
proc = subprocess.run(
[
sys.executable,
"scripts/gaokao_retention_cleanup.py",
"--cutoff",
"2025-06-30T00:00:00+00:00",
"--dry-run",
],
cwd=PROJECT_ROOT,
text=True,
capture_output=True,
env=env,
check=False,
)
assert proc.returncode == 0, proc.stderr
2026-06-14 20:55:06 +08:00
assert '"candidates": 1' in proc.stdout