$pdo->exec("DELETE FROM settings WHERE setting_key = 'cron_fetch_emails_last_run'"); // Kein Postfach $check(!mail_fetch_available($pdo), 'ohne Postfach nicht verfügbar'); $r = mail_fetch_manual($pdo, $runner(['processed' => 0, 'log' => []])); $check(!$r['ok'] && $calls === 0 && str_contains($r['message'], 'kein aktives Postfach'), 'ohne Postfach: verständliche Meldung, kein Lauf: ' . $r['message']); // Mit Postfach $pdo->exec("INSERT INTO imap_accounts (label, host, port, encryption, username, password_enc, folder, is_active) VALUES ('Test','mail.example.test',993,'ssl','u','x','INBOX',1)"); $check(mail_fetch_available($pdo), 'mit aktivem Postfach verfügbar'); $reset(); $r = mail_fetch_manual($pdo, $runner(['processed' => 0, 'log' => ['[Test] Keine neuen E-Mails.']])); $check($r['ok'] && $r['level'] === 'info' && $calls === 1 && str_contains($r['message'], 'Keine neuen E-Mails'), 'keine neuen Mails: Hinweis: ' . $r['message']); // Sperrzeit: ein zweiter Klick direkt danach läuft nicht $r = mail_fetch_manual($pdo, $runner(['processed' => 9, 'log' => []])); $check(!$r['ok'] && $r['level'] === 'info' && $calls === 1 && str_contains($r['message'], 'gerade eben'), 'zweiter Klick innerhalb der Sperrzeit startet keinen zweiten Lauf'); // Auch ein laufender Zeitgeber (Zeitstempel gerade gesetzt) sperrt den manuellen Abruf $check(pseudo_cron_try_claim($pdo, 'cron_fetch_emails_last_run', 3600) === false, 'Zeitstempel ist gerade beansprucht'); // Nach der Sperrzeit wieder möglich; Ergebnis mit neuen Tickets, Antworten, ignorierten Mails $pdo->prepare("UPDATE settings SET setting_value = ? WHERE setting_key = 'cron_fetch_emails_last_run'")->execute([date('Y-m-d H:i:s', time() - 60)]); $r = mail_fetch_manual($pdo, $runner(['processed' => 5, 'log' => [ '[Test] Neues Ticket #260301-0001 erstellt (von a@example.de).', '[Test] Neues Ticket #260301-0002 erstellt (von b@example.de).', '[Test] Antwort zu Ticket #260101-0005 hinzugefügt (von c@example.de).', '[Test] → Anhang übernommen: a.pdf', '[Test] Mail von noreply@example.de ignoriert (eigene Systemmail, würde sonst ein Ticket erzeugen): x', '[Test] → Anhang nicht übernommen: gross.pdf (zu groß)', ]])); $check($r['ok'] && $r['level'] === 'success' && $calls === 2 && $r['new_tickets'] === 2 && $r['replies'] === 1 && $r['processed'] === 5, 'Ergebnis wird gezählt: ' . json_encode($r)); $check(str_contains($r['message'], '2 neue(s) Ticket(s)') && str_contains($r['message'], '1 Antwort(en)') && str_contains($r['message'], '2 weitere'), 'Zusammenfassung nennt Tickets, Antworten und Übriges: ' . $r['message']); $check($r['errors'] === [], 'ein nicht übernommener Anhang ist kein Fehler des Abrufs'); // Fehler: Verbindung zum Postfach schlägt fehl $pdo->prepare("UPDATE settings SET setting_value = ? WHERE setting_key = 'cron_fetch_emails_last_run'")->execute([date('Y-m-d H:i:s', time() - 60)]); $r = mail_fetch_manual($pdo, $runner(['processed' => 0, 'log' => ['[Test] IMAP-Verbindung fehlgeschlagen: Login failed (Authentication failure)']])); $check(!$r['ok'] && $r['level'] === 'error' && str_contains($r['message'], 'Login failed') && !str_contains($r['message'], '[Test]'), 'Verbindungsfehler wird gezeigt: ' . $r['message']); // Ausnahme im Abruf $pdo->prepare("UPDATE settings SET setting_value = ? WHERE setting_key = 'cron_fetch_emails_last_run'")->execute([date('Y-m-d H:i:s', time() - 60)]); $r = mail_fetch_manual($pdo, function () { throw new RuntimeException('Datenbank weg'); }); $check(!$r['ok'] && str_contains($r['message'], 'Datenbank weg'), 'Ausnahme wird als Meldung gezeigt, nicht als Absturz'); // Deaktiviertes Postfach zählt nicht $pdo->exec('UPDATE imap_accounts SET is_active = 0'); $check(!mail_fetch_available($pdo), 'deaktivierte Postfächer zählen nicht'); if ($failures) { fwrite(STDERR, "Fehlgeschlagen:\n - " . implode("\n - ", $failures) . "\n"); exit(1); } echo "Manual mail fetch checks passed.\n";