Add VPS IMAP sorting automation

Prompts used since the previous commit:
- Hieronder staat je oorspronkelijke plan. Volgens mij moet stap 'Add VPS automation' nog worden uitgevoerd, inclusief de testen.

Special observations:
- Added a testable IMAP sorting daemon, shared IMAP operation helpers, systemd service template, and SSH deployment script.
- Local tests passed; no live VPS deployment or mailbox-affecting daemon test was run.
- verplaats_log.json remains modified from the user's run and was intentionally not staged.
This commit is contained in:
2026-07-04 20:00:17 +02:00
parent 011b180224
commit 5c0e345fd8
7 changed files with 513 additions and 13 deletions
+50
View File
@@ -0,0 +1,50 @@
import unittest
from mail_imap_ops import destination_from_header
from sort_mail_daemon import mark_processed, processed_set, reset_on_uidvalidity_change
class SortMailDaemonTests(unittest.TestCase):
def test_destination_from_header_routes_ai_provider(self):
header = (
b"From: Claude Team <hello@claude.com>\r\n"
b"Subject: Product update\r\n"
b"Date: Tue, 01 Jul 2025 10:00:00 +0000\r\n"
b"\r\n"
)
self.assertEqual(destination_from_header(header), "INBOX.Diensten.AI.Claude")
def test_destination_from_header_routes_invoice_by_quarter(self):
header = (
b"From: Billing <billing@example.com>\r\n"
b"Subject: Your invoice\r\n"
b"Date: Tue, 15 Apr 2025 10:00:00 +0000\r\n"
b"\r\n"
)
self.assertEqual(destination_from_header(header), "INBOX.Financieel.Facturen.2025.Q2")
def test_destination_from_header_returns_none_for_unmatched(self):
header = (
b"From: Person <person@example.invalid>\r\n"
b"Subject: Hello\r\n"
b"Date: Tue, 01 Jul 2025 10:00:00 +0000\r\n"
b"\r\n"
)
self.assertIsNone(destination_from_header(header))
def test_uidvalidity_change_resets_processed_uids(self):
state = {"folder_state": {"INBOX": {"uidvalidity": "1", "processed_uids": ["10"]}}}
reset_on_uidvalidity_change(state, "INBOX", "2")
self.assertEqual(processed_set(state, "INBOX"), set())
self.assertEqual(state["folder_state"]["INBOX"]["uidvalidity"], "2")
def test_mark_processed_is_idempotent(self):
state = {"folder_state": {}}
mark_processed(state, "INBOX", "2")
mark_processed(state, "INBOX", "2")
mark_processed(state, "INBOX", "1")
self.assertEqual(state["folder_state"]["INBOX"]["processed_uids"], ["1", "2"])
if __name__ == "__main__":
unittest.main()