Die Migration in participants/ledger_entries ist abgeschlossen: kein
Teilnehmer traegt noch eine legacy_mitarbeiter_id, kein Journaleintrag eine
legacy_table. Damit war der jeweils zweite Zweig ("Default-Mandant schreibt
zusaetzlich nach kl_Einzahlungen/kl_Kaffeeverbrauch/kl_Mitarbeiter") in
sechs Dateien nicht mehr erreichbar - er musste aber bei jeder Aenderung
mitgepflegt werden, zuletzt bei der Bemerkung fuer Einzahlungen.
Entfernt:
- Dual-Write beim Buchen: einzahlung.php, stricheintragen.php, index.php,
jahresauswertung.php, app/imports.php, app/paypal-inbox.php
- Dual-Write in der Mitgliederverwaltung: ledger_create_participant,
ledger_update_participant, ledger_set_participant_active,
ledger_anonymize_participant
- die verwaisten Spiegelfunktionen ledger_mirror_legacy_payment,
ledger_mirror_legacy_consumption und ledger_void_entry_by_legacy_id
Nebenbei behoben: kaffeeliste.php hat die Teilnehmer-Detailseite nur fuer
Mitglieder mit legacy_mitarbeiter_id verlinkt - die hat seit der Migration
niemand mehr, die Seite war also fuer alle unerreichbar. Verlinkt und
adressiert wird jetzt ueber participant_id; "user_id" bleibt als Alias
erhalten. Der Mandanten-Isolationstest prueft jetzt ledger_void_entry, also
den Pfad, den letzteneintraege.php tatsaechlich nutzt.
Pruefskripte unveraendert gegenueber der Baseline vor dem Umbau
(http-smoke 27/6, role-matrix 55/0); die Isolationspruefung steigt von
9 auf 11 PASS bei gleichem vorbestehendem Fehler.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
320 lines
8.9 KiB
PHP
320 lines
8.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
$baseUrl = rtrim((string)(getenv('SMOKE_BASE_URL') ?: 'http://127.0.0.1:8080'), '/');
|
|
$issuePattern = '~(?:Deprecated|Warning|Fatal error|Parse error|Notice|Uncaught (?:Error|Exception))~i';
|
|
|
|
$checks = [
|
|
[
|
|
'label' => 'Landingpage',
|
|
'path' => 'landing.php',
|
|
'contains' => ['Kaffeeliste', 'Kundenkonto anlegen', 'Mandantenfähig'],
|
|
],
|
|
[
|
|
'label' => 'Impressum',
|
|
'path' => 'impressum.php',
|
|
'contains' => ['Impressum', 'In den Sieben Stücken 9d', '30655 Hannover'],
|
|
],
|
|
[
|
|
'label' => 'AGB',
|
|
'path' => 'agb.php',
|
|
'contains' => ['Allgemeine Geschäftsbedingungen', 'Entwurf'],
|
|
],
|
|
[
|
|
'label' => 'Preise',
|
|
'path' => 'preise.php',
|
|
'contains' => ['Preise', '3,99', '7,99', '12,99', '§ 19 UStG'],
|
|
],
|
|
[
|
|
'label' => 'Datenschutzerklärung',
|
|
'path' => 'datenschutz.php',
|
|
'contains' => ['Datenschutzerklärung', 'Verantwortlicher', 'Auftragsverarbeiter'],
|
|
],
|
|
[
|
|
'label' => 'Dashboard',
|
|
'path' => 'index.php',
|
|
'contains' => ['Hallo Test Admin', 'Aktueller Stand', 'Jahresübersicht', 'Letzte Einzahlungen'],
|
|
],
|
|
[
|
|
'label' => 'Striche erfassen',
|
|
'path' => 'stricheintragen.php',
|
|
'contains' => ['Anzahl der Striche'],
|
|
],
|
|
[
|
|
'label' => 'Einzahlungen erfassen',
|
|
'path' => 'einzahlung.php',
|
|
'contains' => ['Einzahlungen'],
|
|
],
|
|
[
|
|
'label' => 'Kaffeeliste',
|
|
'path' => 'kaffeeliste.php',
|
|
'contains' => [
|
|
'Aktive Mitarbeiter',
|
|
'teilnehmerauswertung.php?participant_id=',
|
|
'GM Negativ',
|
|
'gm-negative@test.local',
|
|
'-2,00 €',
|
|
'GM Positiv',
|
|
'23,60 €',
|
|
'GM Ohne Buchungen',
|
|
'0,00 €',
|
|
],
|
|
'not_contains' => ['GM Inaktiv'],
|
|
],
|
|
[
|
|
'label' => 'Ledger Preview',
|
|
'path' => 'ledger-preview.php',
|
|
'contains' => ['Ledger Preview', 'Tenant-Summen', 'Letzte Ledger-Buchungen'],
|
|
],
|
|
[
|
|
'label' => 'Mitgliederverwaltung',
|
|
'path' => 'mitarbeiterverwalten.php',
|
|
'contains' => ['Mitglieder verwalten', 'PayPal-Name'],
|
|
],
|
|
[
|
|
'label' => 'Letzte Einträge',
|
|
'path' => 'letzteneintraege.php',
|
|
'contains' => ['Letzte 100 Einzahlungen'],
|
|
],
|
|
[
|
|
'label' => 'CSV-Upload',
|
|
'path' => 'csvupload.php',
|
|
'contains' => ['CSV Verarbeitung'],
|
|
],
|
|
[
|
|
'label' => 'Hinweise',
|
|
'path' => 'hinweise.php',
|
|
'contains' => ['Kaffeeliste - Hinweise'],
|
|
],
|
|
[
|
|
'label' => 'FAQ',
|
|
'path' => 'faq.php',
|
|
'contains' => ['FAQ - Kaffeeliste'],
|
|
],
|
|
[
|
|
'label' => 'Login',
|
|
'path' => 'login.php',
|
|
'contains' => ['Login', 'Registrieren', 'Passwort vergessen'],
|
|
],
|
|
[
|
|
'label' => 'Registrierung',
|
|
'path' => 'register.php',
|
|
'contains' => ['Registrierung', 'Kundenkonto anlegen'],
|
|
],
|
|
[
|
|
'label' => 'Passwort vergessen',
|
|
'path' => 'passwort-vergessen.php',
|
|
'contains' => ['Passwort vergessen', 'Link vorbereiten'],
|
|
],
|
|
[
|
|
'label' => 'Mandantenauswahl Login-Schutz',
|
|
'path' => 'mandant-auswahl.php',
|
|
'contains' => ['Login'],
|
|
],
|
|
[
|
|
'label' => 'Passwort zurücksetzen Invalid',
|
|
'path' => 'passwort-zuruecksetzen.php',
|
|
'contains' => ['Passwort zurücksetzen', 'ungültig oder abgelaufen'],
|
|
],
|
|
[
|
|
'label' => 'E-Mail verifizieren Invalid',
|
|
'path' => 'email-verifizieren.php',
|
|
'contains' => ['E-Mail verifizieren', 'ungültig oder abgelaufen'],
|
|
],
|
|
[
|
|
'label' => 'Mandant-Einstellungen Login-Schutz',
|
|
'path' => 'mandant-einstellungen.php',
|
|
'contains' => ['Login'],
|
|
],
|
|
[
|
|
'label' => 'Namensanpassung',
|
|
'path' => 'namenanpassen.php',
|
|
'contains' => ['Anzeigenamen aktualisieren'],
|
|
],
|
|
[
|
|
'label' => 'Datenexport Login-Schutz',
|
|
'path' => 'datenexport.php',
|
|
'contains' => ['Login'],
|
|
],
|
|
[
|
|
'label' => 'Abo-Upgrade GET-Redirect',
|
|
'path' => 'abo-upgrade.php',
|
|
'contains' => ['Login'],
|
|
],
|
|
[
|
|
'label' => 'Abo-Portal GET-Redirect',
|
|
'path' => 'abo-portal.php',
|
|
'contains' => ['Login'],
|
|
],
|
|
[
|
|
'label' => 'Mandant löschen Login-Schutz',
|
|
'path' => 'mandant-loeschen.php',
|
|
'contains' => ['Login'],
|
|
],
|
|
[
|
|
'label' => 'Back-Office Login-Schutz',
|
|
'path' => 'backoffice.php',
|
|
'contains' => ['Login'],
|
|
],
|
|
[
|
|
'label' => 'Back-Office Mandantendetail Login-Schutz',
|
|
'path' => 'backoffice-mandant.php?tenant_id=1',
|
|
'contains' => ['Login'],
|
|
],
|
|
[
|
|
'label' => 'Teilnehmerauswertung',
|
|
'path' => 'teilnehmerauswertung.php?user_id=1',
|
|
'contains' => ['Auswertung', 'Test Admin', 'Jahresübersicht', 'Letzte Einzahlungen'],
|
|
],
|
|
[
|
|
'label' => 'PDF-Export',
|
|
'path' => 'exportKaffeeliste.php',
|
|
'contains' => ['%PDF'],
|
|
],
|
|
[
|
|
'label' => 'Mailversand',
|
|
'path' => 'mailversenden.php',
|
|
'contains' => ['Info-Mail versenden', 'Dry-Run', 'Versandlog'],
|
|
],
|
|
[
|
|
'label' => 'Jahresabschluss',
|
|
'path' => 'jahresauswertung.php',
|
|
'contains' => ['Jahresabschluss', 'Dry-Run', 'Jahresstriche gesamt'],
|
|
],
|
|
];
|
|
|
|
$knownIssueChecks = [
|
|
];
|
|
|
|
$skippedUnsafe = [
|
|
];
|
|
|
|
function smoke_fetch(string $url): array
|
|
{
|
|
$context = stream_context_create([
|
|
'http' => [
|
|
'method' => 'GET',
|
|
'timeout' => 15,
|
|
'ignore_errors' => true,
|
|
'header' => "User-Agent: KaffeelisteHttpSmoke/1.0\r\n",
|
|
],
|
|
]);
|
|
|
|
$body = @file_get_contents($url, false, $context);
|
|
$headers = $http_response_header ?? [];
|
|
$status = 0;
|
|
|
|
foreach ($headers as $header) {
|
|
if (preg_match('~^HTTP/\S+\s+(\d{3})~', $header, $matches) === 1) {
|
|
$status = (int)$matches[1];
|
|
}
|
|
}
|
|
|
|
if ($body === false) {
|
|
$error = error_get_last();
|
|
return [
|
|
'status' => $status,
|
|
'body' => '',
|
|
'error' => $error['message'] ?? 'Unknown HTTP error',
|
|
];
|
|
}
|
|
|
|
return [
|
|
'status' => $status,
|
|
'body' => $body,
|
|
'error' => null,
|
|
];
|
|
}
|
|
|
|
function smoke_url(string $baseUrl, string $path): string
|
|
{
|
|
return $baseUrl . '/' . ltrim($path, '/');
|
|
}
|
|
|
|
$failures = [];
|
|
$passes = 0;
|
|
|
|
echo "HTTP smoke base URL: {$baseUrl}\n";
|
|
|
|
foreach ($checks as $check) {
|
|
$url = smoke_url($baseUrl, $check['path']);
|
|
$response = smoke_fetch($url);
|
|
$label = $check['label'] . ' (' . $check['path'] . ')';
|
|
|
|
if ($response['error'] !== null) {
|
|
$failures[] = "{$label}: {$response['error']}";
|
|
echo "FAIL {$label}\n";
|
|
continue;
|
|
}
|
|
|
|
if ($response['status'] !== 200) {
|
|
$failures[] = "{$label}: expected HTTP 200, got HTTP {$response['status']}";
|
|
echo "FAIL {$label}\n";
|
|
continue;
|
|
}
|
|
|
|
if (preg_match($issuePattern, $response['body'], $matches) === 1) {
|
|
$failures[] = "{$label}: PHP issue marker found ({$matches[0]})";
|
|
echo "FAIL {$label}\n";
|
|
continue;
|
|
}
|
|
|
|
foreach ($check['contains'] as $needle) {
|
|
if (!str_contains($response['body'], $needle)) {
|
|
$failures[] = "{$label}: expected text not found: {$needle}";
|
|
echo "FAIL {$label}\n";
|
|
continue 2;
|
|
}
|
|
}
|
|
|
|
foreach (($check['not_contains'] ?? []) as $needle) {
|
|
if (str_contains($response['body'], $needle)) {
|
|
$failures[] = "{$label}: unexpected text found: {$needle}";
|
|
echo "FAIL {$label}\n";
|
|
continue 2;
|
|
}
|
|
}
|
|
|
|
$passes++;
|
|
echo "PASS {$label}\n";
|
|
}
|
|
|
|
foreach ($knownIssueChecks as $check) {
|
|
$url = smoke_url($baseUrl, $check['path']);
|
|
$response = smoke_fetch($url);
|
|
$label = $check['label'] . ' (' . $check['path'] . ')';
|
|
|
|
if ($response['error'] !== null) {
|
|
echo "KNOWN {$label}: {$check['reason']} ({$response['error']})\n";
|
|
continue;
|
|
}
|
|
|
|
if (preg_match($check['expected_issue'], $response['body']) === 1) {
|
|
echo "KNOWN {$label}: {$check['reason']}\n";
|
|
continue;
|
|
}
|
|
|
|
if ($response['status'] === 200 && preg_match($issuePattern, $response['body']) !== 1) {
|
|
echo "RESOLVED {$label}: bitte in die regulären Smoke-Checks aufnehmen.\n";
|
|
continue;
|
|
}
|
|
|
|
$failures[] = "{$label}: unexpected response while checking known issue";
|
|
echo "FAIL {$label}\n";
|
|
}
|
|
|
|
foreach ($skippedUnsafe as $skip) {
|
|
echo "SKIP {$skip['path']}: {$skip['reason']}\n";
|
|
}
|
|
|
|
if ($failures !== []) {
|
|
echo "\nHTTP smoke failed with " . count($failures) . " failure(s):\n";
|
|
foreach ($failures as $failure) {
|
|
echo "- {$failure}\n";
|
|
}
|
|
exit(1);
|
|
}
|
|
|
|
echo "\nHTTP smoke passed with {$passes} checked pages.\n";
|