// retention_hold: TTL boundary (89 kept, 91 deleted), grace days, legal holds // block deletion, apply honors the pinned policy version only. #include #include #include #include "audit/retention/enforcer.h" #include "audit/retention/hold.h" #include "audit/retention/policy.h" #define CHECK(c, msg) \ if (!(c)) { \ std::cerr << "FAIL retention_hold: " << msg << "\n"; \ return 1; \ } int main() { using namespace molo::audit::retention; Policy policy(7, {{"users", TableRule{90, 0}}, {"logs", TableRule{90, 5}}}); std::vector rows = { {"t1", "users", "a", 89}, {"t1", "users", "b", 91}, {"t1", "logs", "c", 93}}; Hold hold; auto scan = [&](ScannedRow& out) -> bool { static std::size_t i = 0; if (i >= rows.size()) { i = 0; return false; } out = rows[i++]; return true; }; DryRunReport dry = Enforcer::DryRun(policy, hold, scan); CHECK(dry.scanned == 3 && dry.kept == 2 && dry.would_delete == 1 && dry.held == 0, "89 kept, 91 deleted, 93 in grace"); CHECK(dry.deletions.size() == 1 && dry.deletions[0].pk == "b", "deletion names pk b"); hold.Add(Hold::RowKey("t1", "users", "b"), "litigation"); DryRunReport dry2 = Enforcer::DryRun(policy, hold, scan); CHECK(dry2.held == 1 && dry2.would_delete == 0, "hold blocks deletion"); hold.Remove(Hold::RowKey("t1", "users", "b")); std::vector deleted; ApplyResult applied = Enforcer::Apply(policy, hold, dry, [&](const ScannedRow& r) { deleted.push_back(r.pk); }); CHECK(applied.deleted == 1 && deleted[0] == "b", "apply deletes pinned rows"); hold.Add(Hold::RowKey("t1", "users", "b"), "late hold"); ApplyResult held = Enforcer::Apply(policy, hold, dry, [&](const ScannedRow&) { deleted.push_back("x"); }); CHECK(held.deleted == 0 && held.skipped_hold == 1, "late hold skips apply"); Policy newer(8, {{"users", TableRule{90, 0}}}); ApplyResult stale = Enforcer::Apply(newer, Hold{}, dry, [&](const ScannedRow&) { deleted.push_back("x"); }); CHECK(stale.deleted == 0 && stale.skipped_policy == 1, "version change skips apply"); std::cout << "PASS retention_hold\n"; return 0; }