Files
Stefan LohmaierandClaude Opus 4.8 c9ccb4392b harden: per-item robustness + deadlines/caps across connectors; layered tests
Mail: _safe_decode + _iter_messages (per-mail try/except) -> eine kaputte Mail
(charset x-unknown) bricht die Suche nicht mehr ab, findet so auch uralte Mails.
Vollscan + Datum-Sort + MAX_SCAN/DEADLINE_S (Selbstheilung, kein 24h-Haenger mehr).

Files: search_files mit SEARCH_DEADLINE_S + SEARCH_MAX_DIRS begrenzt (war
unbegrenzte rekursive PROPFIND -> real 35s/449 Calls).

Calendar/Contacts: PARSE_DEADLINE_S fuer client-seitiges vobject-Parsen;
MAX_RESULTS-Output-Cap in get_events/get_tasks (war 10939 Zeilen bei 6000 Events);
search Top-N + Hinweise.

Tests: in Schichten getrennt -> Smoke (nightly), Edge + Stress (on-demand).
Neu: test_smoke/test_edge/test_stress + conftest-Marker + run_full_tests.sh,
nightly laeuft nur Smoke. Kontakt-Foto-Roundtrip-Test, Mail-Edge-Mails
(x-unknown, kaputter Header, 2009er Alt-Mail).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 21:17:26 +02:00

84 lines
4.3 KiB
Python

import mailbox, os, shutil
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.audio import MIMEAudio
from email import encoders
BASE="/opt/mcp-servers/tests/testdata/maildir"
SRC="/tmp/mcptest-files"
if os.path.isdir(BASE): shutil.rmtree(BASE)
def add(acct, folder, msg):
path=os.path.join(BASE,acct,folder); os.makedirs(os.path.dirname(path),exist_ok=True)
mailbox.Maildir(path,create=True).add(msg)
def simple(frm,to,subj,body):
m=MIMEText(body,"plain","utf-8"); m["From"]=frm; m["To"]=to; m["Subject"]=subj
m["Date"]="Mon, 16 Jun 2026 09:00:00 +0200"; return m
def attach(part, fn):
p=os.path.join(SRC,fn); data=open(p,"rb").read()
part.add_header("Content-Disposition","attachment",filename=fn)
return part
def mail_with(frm,subj,body,files,date="Tue, 17 Jun 2026 10:00:00 +0200"):
m=MIMEMultipart(); m["From"]=frm; m["To"]="mcptest@local"; m["Subject"]=subj; m["Date"]=date
m.attach(MIMEText(body,"plain","utf-8"))
for fn in files:
data=open(os.path.join(SRC,fn),"rb").read()
part=MIMEBase("application","octet-stream"); part.set_payload(data); encoders.encode_base64(part)
part.add_header("Content-Disposition","attachment",filename=fn)
m.attach(part)
return m
# Basis-Mails (Suche/Read)
add("mcp-test-mail","INBOX", simple("test@example.com","mcptest@local","Willkommen","Hallo, dies ist eine Testnachricht fuer stefan zum Suchen."))
add("mcp-test-mail","Sent", simple("mcptest@local","kunde@example.com","Re: Angebot","Danke fuer Ihre Anfrage."))
add("mcp-test-empty","INBOX",simple("noreply@example.com","mcptest@local","Newsletter","Nichts besonderes hier."))
# Mails mit Anhaengen (verschiedene Typen)
add("mcp-test-mail","INBOX", mail_with("billing@example.com","Ihre Rechnung Juni 2026","Im Anhang die Rechnung (Text-PDF) und der Scan (Bild-PDF).",["document.pdf","scanned.pdf"]))
add("mcp-test-mail","INBOX", mail_with("foto@example.com","Fotos vom Wochenende","Anbei zwei Bilder.",["photo.jpg","screenshot.png"]))
add("mcp-test-mail","INBOX", mail_with("buero@example.com","Quartalsbericht Q2","Bericht (Word) und Zahlen (Excel) anbei.",["report.docx","budget.xlsx"]))
add("mcp-test-mail","INBOX", mail_with("voice@example.com","Sprachnachricht","Kurze Audionachricht im Anhang.",["tone.mp3"]))
add("mcp-test-mail","INBOX", mail_with("projekt@example.com","Projektdateien","Archiv und Notizen.",["archive.zip","notes.txt","data.csv"]))
add("mcp-test-mail","INBOX", mail_with("media@example.com","Praesentation + Clip","Folien und ein kurzes Video.",["slides.pptx","clip.mp4"]))
# --- Edge-Cases: Robustheit + uralte Mails (Fix 2026-06-24) ---
def addraw(acct, folder, raw_bytes):
path=os.path.join(BASE,acct,folder); os.makedirs(os.path.dirname(path),exist_ok=True)
mailbox.Maildir(path,create=True).add(raw_bytes)
# Uralte Mail (2009) mit eindeutigem Token -> Suche muss alte Mails finden
_old=simple("archiv@example.com","mcptest@local","Uralte Rechnung URALTMAIL2009","Sehr alte Mail aus 2009 zum Testen der Alt-Mail-Suche.")
_old.replace_header("Date","Tue, 03 Mar 2009 08:15:00 +0100")
add("mcp-test-mail","Archive",_old)
# Mail mit kaputtem Charset x-unknown -> darf die Suche NICHT killen, Token findbar
addraw("mcp-test-mail","INBOX",
b"From: weird@example.com\r\nTo: mcptest@local\r\n"
b"Subject: Kaputtes Encoding XUNKNOWNTOKEN\r\n"
b"Date: Wed, 10 Jan 2018 12:00:00 +0100\r\n"
b'Content-Type: text/plain; charset="x-unknown"\r\n'
b"Content-Transfer-Encoding: 8bit\r\n\r\n"
b"Koerpertext mit kaputtem Charset XUNKNOWNTOKEN und Umlaut \xfc.\r\n")
# Mail mit kaputtem encoded-word-Header -> decode_hdr darf nicht crashen
addraw("mcp-test-mail","INBOX",
b"From: =?invalid-charset?Q?Br=F6tchen?= <bad@example.com>\r\nTo: mcptest@local\r\n"
b"Subject: =?x-unknown?B?a2FwdXR0?= BADHEADERTOKEN\r\n"
b"Date: Fri, 05 Jul 2013 09:00:00 +0200\r\n"
b"Content-Type: text/plain; charset=utf-8\r\n\r\n"
b"Body BADHEADERTOKEN.\r\n")
# new -> cur
for r,d,f in os.walk(BASE):
if r.endswith("new"):
for x in list(f):
os.rename(os.path.join(r,x), os.path.join(os.path.dirname(r),"cur",x+":2,S"))
print("Maildir neu gebaut.")
for r,d,f in os.walk(BASE):
if r.endswith("cur"): print(f" {r.replace(BASE+'/',''):30} {len(f)} msgs")