[PATCH b4 v2 09/44] tests: cover the thank-you send's post-send bookkeeping
Christian Brauner <[email protected]> Fri, 31 Jul 2026 23:58:50 +0200
| Newsgroups | org.kernel.linux.tools |
|---|---|
| Message-ID | <20260731-work-b4-editor-branch-guard-v2-9-243fd19d322d@kernel.org> |
The note is recorded as read at send time, a broken archive is not reported as "Send failed", and a dry run records nothing. Signed-off-by: Christian Brauner (Amutable) <[email protected]> --- src/tests/test_tui_tracking.py | 81 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/tests/test_tui_tracking.py b/src/tests/test_tui_tracking.py index 1212ab1..3e69621 100644 --- a/src/tests/test_tui_tracking.py +++ b/src/tests/test_tui_tracking.py @@ -4495,6 +4495,87 @@ class TestTakeThankArchiveChain: assert not notices +class TestSendThankMessage: + """Everything after a successful send is bookkeeping, and bookkeeping + must not be able to claim the send failed.""" + + def _send( + self, archive_raises: bool, dryrun: bool = False + ) -> Tuple[List[Tuple[str, str]], List[List[Any]]]: + """Drive _send_thank_message with a send that succeeds. + + Returns (notifications as (message, severity), mark_outgoing_seen + calls). + """ + import contextlib + + notices: List[Tuple[str, str]] = [] + seen_calls: List[List[Any]] = [] + archived: List[str] = [] + app = TrackingApp.__new__(TrackingApp) + app._email_dryrun = dryrun + app._patatt_sign = False + app._identifier = '' + msg = email.message.EmailMessage() + msg['Message-Id'] = '<[email protected]>' + series = {'change_id': 'send-1', 'revision': 1} + + def _archive(self: Any, _series: Dict[str, Any]) -> None: + archived.append(str(_series.get('change_id', ''))) + if archive_raises: + raise OSError(28, 'No space left on device') + + with ( + patch.object(TrackingApp, 'suspend', lambda self: contextlib.nullcontext()), + patch.object(TrackingApp, '_invalidate_caches', lambda self, cid: None), + patch.object(TrackingApp, '_load_series', lambda self: None), + patch.object(TrackingApp, '_archive_after_thanks', _archive), + patch.object( + TrackingApp, + 'notify', + lambda self, message, severity='information', **k: notices.append( + (str(message), severity) + ), + ), + patch('b4.get_smtp', return_value=(None, '[email protected]')), + patch('b4.send_mail', return_value=0 if dryrun else 1), + patch( + 'b4.review_tui._tracking_app.mark_outgoing_seen', + lambda msgs, dryrun=False: seen_calls.append(list(msgs)), + ), + ): + app._send_thank_message(msg, series, archive_after=True) + self.archived = archived + return notices, seen_calls + + def test_marks_the_sent_message_seen(self) -> None: + """The thank-you is a reply into the series thread, so it comes back + from the list; recording it at send time keeps the badge dark.""" + _notices, seen_calls = self._send(archive_raises=False) + assert len(seen_calls) == 1 + assert seen_calls[0][0]['Message-Id'] == '<[email protected]>' + + def test_failed_archive_is_not_a_send_failure(self) -> None: + """A broken archive must never read as 'Send failed': that tells the + maintainer to re-send a note that is already on the list.""" + notices, _seen = self._send(archive_raises=True) + texts = [n for n, _sev in notices] + assert 'Thank-you message sent' in texts + assert not any('Send failed' in n for n in texts) + assert any('No space left on device' in n for n in texts) + + def test_a_dry_run_is_not_recorded_as_thanked(self) -> None: + """--email-dry-run logs the note and stops there. Marking the series + thanked -- and archiving it, which deletes the review branch -- would + spend a real series on a rehearsal.""" + notices, seen = self._send(archive_raises=False, dryrun=True) + texts = [n for n, _sev in notices] + assert any('Dry-run' in n for n in texts) + assert not any('Thank-you message sent' in n for n in texts) + assert not seen + assert not self.archived + + # --------------------------------------------------------------------------- # take->merge conflict resolution (must never drop a non-empty commit) # --------------------------------------------------------------------------- -- 2.53.0