docs: round-3 copy corrections, and pin the two behaviours nothing was guarding
Round 3's correctness/security pass came back clean; what was left said more than the code does. - emailOff promised the access-request list is where sign-ups show up. A sign-up on an address that is already approved or already pending adds nothing to it (roadmap UX-25), and "only" was falsified by this release's own inbox notice. - deleteConfirm claimed the admin was dropping "an approval you already gave" — it is the confirmation for pending and denied rows too. - sendFailed blamed the mail server for rejecting a message; the reason covers connect, DNS, TLS and login failures alike, so it now describes the symptom and leaves the diagnosis to the log. - ADMIN_EMAILS re-promotion happens in the Google callback only, not on any sign-in. Tests: the decided-list copy of the delete affordance was never rendered (both new cases fail if that branch is dropped), and the throttle release — a deliberate behaviour the notes advertise — was asserted by nothing; a drop with no admin yet, or with a failing write, must not silence the following hour.
This commit is contained in:
@@ -102,6 +102,40 @@ def test_no_admins_means_no_notification_and_no_error(db, make_user):
|
||||
assert _notifications(db, plain.id) == []
|
||||
|
||||
|
||||
def test_a_drop_with_nobody_to_tell_does_not_burn_the_hour(db, make_user):
|
||||
# The throttle window must only be spent on a notice that was actually written. Otherwise a drop
|
||||
# during setup — before any admin exists — silences the next hour for the admin created a minute
|
||||
# later, which is exactly the blind spot this alert exists to remove.
|
||||
email_mod.send_test("someone@example.com") # no admins yet
|
||||
admin = make_user(email="admin@example.com", role="admin")
|
||||
|
||||
assert email_mod.send_test("someone@example.com") is False
|
||||
|
||||
db.expire_all()
|
||||
assert len(_notifications(db, admin.id)) == 1
|
||||
|
||||
|
||||
def test_a_failed_alert_does_not_burn_the_hour_either(db, make_user, monkeypatch):
|
||||
admin = make_user(email="admin@example.com", role="admin")
|
||||
boom = {"on": True}
|
||||
|
||||
def _maybe_boom(*a, **kw):
|
||||
if boom["on"]:
|
||||
raise RuntimeError("notification store is down")
|
||||
from app.notifications import create_notification as real
|
||||
|
||||
return real(*a, **kw)
|
||||
|
||||
monkeypatch.setattr(email_mod, "create_notification", _maybe_boom)
|
||||
email_mod.send_test("someone@example.com") # the write blows up; nothing recorded
|
||||
boom["on"] = False
|
||||
|
||||
assert email_mod.send_test("someone@example.com") is False
|
||||
|
||||
db.expire_all()
|
||||
assert len(_notifications(db, admin.id)) == 1
|
||||
|
||||
|
||||
def test_a_broken_alert_never_breaks_the_send(db, make_user, monkeypatch):
|
||||
# The alert is the fallback path; if IT fails, the caller must still get the ordinary fail-soft
|
||||
# False rather than an exception surfacing from a background task.
|
||||
|
||||
Reference in New Issue
Block a user