Refactor campaign recipient and review presentation
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from govoplan_campaign.backend.retention import (
|
||||
_apply_eml_retention,
|
||||
_apply_raw_json_retention,
|
||||
_apply_report_detail_retention,
|
||||
)
|
||||
|
||||
|
||||
def _querying(items: list[object]) -> MagicMock:
|
||||
session = MagicMock()
|
||||
session.query.return_value.order_by.return_value.all.return_value = items
|
||||
session.query.return_value.filter.return_value.order_by.return_value.all.return_value = items
|
||||
return session
|
||||
|
||||
|
||||
def test_raw_json_retention_preserves_hash_for_final_version() -> None:
|
||||
now = datetime.now(timezone.utc)
|
||||
version = SimpleNamespace(
|
||||
campaign_id="campaign-1",
|
||||
updated_at=now - timedelta(days=10),
|
||||
workflow_state="completed",
|
||||
raw_json={"version": "1.0", "campaign": {"name": "Sensitive"}},
|
||||
schema_version="1.0",
|
||||
execution_snapshot={"campaign_json_sha256": "sealed-hash"},
|
||||
)
|
||||
session = _querying([version])
|
||||
policy = SimpleNamespace(
|
||||
store_raw_campaign_json=True,
|
||||
raw_campaign_json_retention_days=1,
|
||||
)
|
||||
|
||||
result = _apply_raw_json_retention(
|
||||
session,
|
||||
dry_run=False,
|
||||
now=now,
|
||||
policy_for_campaign_id=lambda _campaign_id: policy,
|
||||
)
|
||||
|
||||
assert result["redacted"] == 1
|
||||
assert version.raw_json == {
|
||||
"version": "1.0",
|
||||
"_retention": {
|
||||
"raw_json_redacted": True,
|
||||
"redacted_at": now.isoformat(),
|
||||
"original_sha256": "sealed-hash",
|
||||
},
|
||||
}
|
||||
session.add.assert_called_once_with(version)
|
||||
|
||||
|
||||
def test_raw_json_retention_does_not_redact_unfinished_version() -> None:
|
||||
now = datetime.now(timezone.utc)
|
||||
original = {"version": "1.0", "campaign": {"name": "Editable"}}
|
||||
version = SimpleNamespace(
|
||||
campaign_id="campaign-1",
|
||||
updated_at=now - timedelta(days=10),
|
||||
workflow_state="editing",
|
||||
raw_json=original,
|
||||
schema_version="1.0",
|
||||
execution_snapshot=None,
|
||||
)
|
||||
session = _querying([version])
|
||||
policy = SimpleNamespace(
|
||||
store_raw_campaign_json=True,
|
||||
raw_campaign_json_retention_days=1,
|
||||
)
|
||||
|
||||
result = _apply_raw_json_retention(
|
||||
session,
|
||||
dry_run=False,
|
||||
now=now,
|
||||
policy_for_campaign_id=lambda _campaign_id: policy,
|
||||
)
|
||||
|
||||
assert result["skipped_not_final"] == 1
|
||||
assert version.raw_json is original
|
||||
session.add.assert_not_called()
|
||||
|
||||
|
||||
def test_report_detail_retention_keeps_aggregate_evidence() -> None:
|
||||
now = datetime.now(timezone.utc)
|
||||
version = SimpleNamespace(
|
||||
campaign_id="campaign-1",
|
||||
updated_at=now - timedelta(days=10),
|
||||
validation_summary={"ready": 4, "issues": [{"entry_id": "secret"}]},
|
||||
build_summary={"built": 3, "jobs": [{"recipient": "person@example.test"}]},
|
||||
)
|
||||
session = _querying([version])
|
||||
policy = SimpleNamespace(stored_report_detail_retention_days=1)
|
||||
|
||||
result = _apply_report_detail_retention(
|
||||
session,
|
||||
dry_run=False,
|
||||
now=now,
|
||||
policy_for_campaign_id=lambda _campaign_id: policy,
|
||||
)
|
||||
|
||||
assert result["summaries_redacted"] == 2
|
||||
assert version.validation_summary["ready"] == 4
|
||||
assert "issues" not in version.validation_summary
|
||||
assert version.build_summary["built"] == 3
|
||||
assert "jobs" not in version.build_summary
|
||||
assert version.validation_summary["_retention"]["report_detail_redacted"] is True
|
||||
session.add.assert_called_once_with(version)
|
||||
|
||||
|
||||
def test_eml_retention_removes_only_terminal_artifact(tmp_path) -> None:
|
||||
now = datetime.now(timezone.utc)
|
||||
eml_path = tmp_path / "message.eml"
|
||||
eml_path.write_bytes(b"message")
|
||||
job = SimpleNamespace(
|
||||
campaign_id="campaign-1",
|
||||
updated_at=now - timedelta(days=10),
|
||||
queue_status="draft",
|
||||
send_status="smtp_accepted",
|
||||
imap_status="appended",
|
||||
eml_local_path=str(eml_path),
|
||||
eml_storage_key="campaigns/message.eml",
|
||||
)
|
||||
session = _querying([job])
|
||||
policy = SimpleNamespace(generated_eml_retention_days=1)
|
||||
|
||||
result = _apply_eml_retention(
|
||||
session,
|
||||
dry_run=False,
|
||||
now=now,
|
||||
policy_for_campaign_id=lambda _campaign_id: policy,
|
||||
)
|
||||
|
||||
assert result["files_deleted"] == 1
|
||||
assert result["metadata_cleared"] == 1
|
||||
assert not eml_path.exists()
|
||||
assert job.eml_local_path is None
|
||||
assert job.eml_storage_key is None
|
||||
session.add.assert_called_once_with(job)
|
||||
Reference in New Issue
Block a user