fix(mailu): extend backup/restore seed to cover /mail Maildir volume (ADV-mailu-01)
continuous-integration/drone/push Build is failing
continuous-integration/drone Build is passing

This commit is contained in:
autonomic-bot
2026-06-11 20:56:00 +00:00
parent bb1ebd34f6
commit b9352e8313
3 changed files with 92 additions and 15 deletions
+47 -6
View File
@@ -1,10 +1,12 @@
"""mailu — pre-op seed hooks. Creates / deletes a test mailbox in the admin sqlite DB to prove
backup→restore data integrity on real mail data (P4 coverage, phase-mailu)."""
"""mailu — pre-op seed hooks. Creates a test mailbox AND injects a test message to prove
backup→restore data integrity on BOTH the admin sqlite /data volume and the imap mail /mail
volume (P4 coverage, phase-mailu, ADV-mailu-01 fix)."""
from __future__ import annotations
import os
import sys
import time
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "runner"))
from harness import lifecycle # noqa: E402
@@ -14,16 +16,48 @@ import _mailu # noqa: E402
_CI_LOCALPART = "citest"
_CI_PASSWORD = "CcCi-BackupTest1!Aa"
_CI_MAIL_SUBJECT = "ccci-backup-probe"
def pre_backup(ctx):
_mailu.ensure_domain(ctx.domain, ctx.domain)
_mailu.create_user(ctx.domain, _CI_LOCALPART, ctx.domain, _CI_PASSWORD)
mail_domain = ctx.domain
_mailu.ensure_domain(ctx.domain, mail_domain)
_mailu.create_user(ctx.domain, _CI_LOCALPART, mail_domain, _CI_PASSWORD)
# Inject a test message so /mail (Maildir) is also covered by the backup/restore cycle.
# Uses in-container sendmail (same path as test_mail_flow.py: no greylist, no TLS needed).
email = f"{_CI_LOCALPART}@{mail_domain}"
sender = f"admin@{mail_domain}"
msg = (
f"From: {sender}\\n"
f"To: {email}\\n"
f"Subject: {_CI_MAIL_SUBJECT}\\n"
f"\\nbody {_CI_MAIL_SUBJECT}\\n"
)
lifecycle.exec_in_app(
ctx.domain, ["sh", "-c", f"printf '{msg}' | sendmail -f {sender} {email}"], service="smtp"
)
# Wait for dovecot to deliver the message (poll doveadm, ≤60s)
deadline = time.time() + 60
while time.time() < deadline:
out = lifecycle.exec_in_app(
ctx.domain,
["sh", "-c", f"doveadm search -u '{email}' mailbox INBOX header subject '{_CI_MAIL_SUBJECT}'"],
service="imap",
)
if out.strip():
return
time.sleep(3)
raise RuntimeError(
f"pre_backup: test message {_CI_MAIL_SUBJECT!r} not delivered to {email} within 60s"
)
def pre_restore(ctx):
# Delete the seeded user directly from sqlite to simulate data loss before restore.
# (flask mailu has no user-delete subcommand in 2024.06.52; sqlite3 module is always available.)
mail_domain = ctx.domain
# 1. Delete the user from sqlite (/data) — wipes the account record
lifecycle.exec_in_app(
ctx.domain,
[
@@ -34,3 +68,10 @@ def pre_restore(ctx):
],
service="admin",
)
# 2. Wipe the user's Maildir (/mail) — wipes the mail data so restore is observable
lifecycle.exec_in_app(
ctx.domain,
["sh", "-c", f"rm -rf /mail/{mail_domain}/{_CI_LOCALPART}"],
service="imap",
)