Files
2026-10-24 20:14:43 +00:00

79 lines
4.4 KiB
PHP

<?php
declare(strict_types=1);
/**
* Prüft, dass der Administrator eine Mail bekommt, wenn ein Plugin Fehler wirft oder wegen Fehlern abgeschaltet wird, und wenn ein
* Hintergrundjob scheitert, mit Drosselung und Ausschalter.
*/
$pluginDir = sys_get_temp_dir() . '/deskhub-pm-' . bin2hex(random_bytes(4));
mkdir($pluginDir, 0755, true);
putenv('DESKHUB_PLUGINS_DIR=' . $pluginDir);
putenv('DESKHUB_TESTING=1');
putenv('DESKHUB_CATALOG_DEFAULTS=' . __DIR__ . '/fixtures/no-catalog.php');
putenv('DESKHUB_SQLITE_PATH=:memory:');
require_once dirname(__DIR__) . '/includes/bootstrap.php';
$failures = [];
$check = function (bool $ok, string $what) use (&$failures): void {
if (!$ok) $failures[] = $what;
};
$pdo = get_db();
set_setting('admin_email', 'admin@firma.example');
$mails = [];
$GLOBALS['error_alert_send'] = function (string $to, string $subject, string $html) use (&$mails): bool { $mails[] = compact('to', 'subject', 'html'); return true; };
$zipPath = sys_get_temp_dir() . '/pm-' . bin2hex(random_bytes(3)) . '.zip';
$zip = new ZipArchive();
$zip->open($zipPath, ZipArchive::CREATE);
$zip->addFromString('mailprobe/plugin.json', json_encode(['slug' => 'mailprobe', 'name' => 'Mail-Probe', 'version' => '1.0.0', 'permissions' => ['hooks.cron']]));
$zip->addFromString('mailprobe/plugin.php', "<?php\nplugin_add_hook('cron.run', function () { throw new RuntimeException('Spalte fehlt: first_fail_at'); });\n");
$zip->close();
$check(plugin_install_zip($pdo, $zipPath)['ok'] && plugin_set_active($pdo, 'mailprobe', true, ['hooks.cron'])['ok'], 'Test-Plugin installiert und aktiv');
$state = &plugin_state();
$state['booted'] = false;
plugins_boot();
// 1. Fehler: Mail „meldet einen Fehler“
plugin_hook('cron.run');
$check(count($mails) === 1 && $mails[0]['to'] === 'admin@firma.example' && str_contains($mails[0]['subject'], 'Plugin „Mail-Probe“ meldet einen Fehler'), 'erster Fehler: Mail an den Administrator: ' . json_encode(array_column($mails, 'subject'), JSON_UNESCAPED_UNICODE));
$h = $mails[0]['html'] ?? '';
$check(str_contains($h, 'Spalte fehlt: first_fail_at') && str_contains($h, 'Fehler 1 von ' . PLUGIN_FAIL_LIMIT) && str_contains($h, 'plugins/mailprobe') && !str_contains($h, 'Zeile 0') && !str_contains($h, 'Die aufgerufene Seite konnte nicht angezeigt werden'), 'Inhalt nennt Plugin, Fehlertext und Zähler, ohne die Seiten-Formulierung');
// 2. Derselbe Fehler noch einmal: gedrosselt
plugin_hook('cron.run');
$check(count($mails) === 1, 'derselbe Fehler wird nicht noch einmal gemailt (höchstens einmal pro Stunde)');
// 3. Abschaltung nach dem dritten Fehler: eigene Mail
plugin_hook('cron.run');
$row = plugins_installed($pdo)['mailprobe'];
$check((int) $row['is_active'] === 0 && (int) $row['fail_count'] >= PLUGIN_FAIL_LIMIT, 'Plugin ist nach den Fehlern deaktiviert');
$off = array_values(array_filter($mails, fn($m) => str_contains($m['subject'], 'wurde wegen Fehlern deaktiviert')));
$check(count($off) === 1 && str_contains($off[0]['html'], 'automatisch deaktiviert') && str_contains($off[0]['html'], 'mailprobe'), 'Mail „wegen Fehlern deaktiviert“ kommt trotz Drosselung (eigener Betreff)');
// Ausschalter
set_setting('error_alert', '0');
$before = count($mails);
plugin_record_failure('mailprobe', 'Ein ganz anderer Fehler');
$check(count($mails) === $before, 'bei ausgeschalteter Fehler-Mail wird nichts gesendet');
set_setting('error_alert', '1');
// Hintergrundjob: Meldung
error_alert_notice('Hintergrundjob „x“ ist fehlgeschlagen', 'Der Hintergrundjob „x“ hat einen Fehler gemeldet.', 'cron/x.php', 'Verbindung abgelehnt');
$last = end($mails);
$check(str_contains($last['subject'], 'Hintergrundjob „x“ ist fehlgeschlagen') && str_contains($last['html'], 'Verbindung abgelehnt'), 'fehlgeschlagene Hintergrundjobs werden gemeldet');
// Wirkt auch im eingebauten Hintergrund-Betrieb
$pc = (string) file_get_contents(dirname(__DIR__) . '/includes/pseudo_cron.php');
$check(str_contains($pc, 'error_alert_notice('), 'der eingebaute Hintergrund-Betrieb meldet fehlgeschlagene Jobs');
unset($GLOBALS['error_alert_send']);
foreach (scandir($pluginDir) ?: [] as $entry) {
if ($entry === '.' || $entry === '..') continue;
is_dir($pluginDir . '/' . $entry) ? plugin_rmdir($pluginDir . '/' . $entry) : @unlink($pluginDir . '/' . $entry);
}
@rmdir($pluginDir);
@unlink($zipPath);
if ($failures) {
fwrite(STDERR, "Fehlgeschlagen:\n - " . implode("\n - ", $failures) . "\n");
exit(1);
}
echo 'Plugin error mail checks passed.' . "\n";