presseportale/tests/Support/FailingDisk.php
Kevin Adametz 2a2215b3c3 audit: Nacharbeit Umsetzungsaudit 25.09.2026 — Bildfreigabe, Beweisarchiv, KI-Atomarität, Berichte (Block 8, N01–N05, N07, N08, N10–N21, 5.1, 5.2)
Bilder (N01, N05, N07, N08): gemeinsamer Freigabezustand
PressReleaseImage::isPubliclyDeliverable() für Seiten, OG und Medienroute
(Bestand bleibt sichtbar, v2 nur mit Bestätigung, Admin-Upload bis zum
Kundenklick nicht öffentlich); eigene Ability confirmImageRights nur für den
Kontoinhaber, ohne Super-Admin-Kurzschluss, Identität und ausstehende
Bestätigung auch im Service; Status-Regel unter der PM-Sperre; Cache-Flush
nach dem Commit außerhalb der Dateibereinigung; Snapshot nach Bestätigung an
veröffentlichter PM; Bestätigungstexte an die gezeigte Kennung gebunden.

Beweisarchiv (N02, N10, N11, N12, N13, 5.1): Tombstone unter Zeilensperre mit
erneuter Hold-/Fristprüfung; Dateioperationen ausgewertet, Commands mit
FAILURE; record() über .tmp + move; Marker archive_pending_at mit
archive:retry-pending und archive:sweep-orphans; Anonymisierung entfernt Bilder
über den Remover mit Antragsbezug; Draft-Purge räumt Medien nie
veröffentlichter abgelehnter Einreichungen; App-Kopien fallen mit dem
Archiv-Tombstone; label_corrected nur für veröffentlichte Bilder;
archive_entries.legal_request_id; FileDeletion-Helfer; Systemstatus-Checks.

KI und Hintergrund (N03, N04, N14, N20, N21): Ergebnis-UPDATE und Audit in
einer Transaktion; erwarteter Hash bis in reject()/holdForManualReview();
Ablaufmail per beanspruchtem Marker in einer Transaktion; strikte
Schemaprüfung der Vision-Antwort; Fortschrittsmarke ungecacht.

Berichte und Canonical (N15–N19, 5.2): lückenlose Alterskohorten;
Feed-Identität mit Portal und Sprache; Sitemap-Rolle in der Kundenansicht;
Indexverteilung auf einer Grundgesamtheit; Kopien nach Wegfall der
Erstquelle neu bewertet; Kategorie-Admin leert Seiten-Caches; Dry-Run
zählt alle Tabellen.

Gesamtsuite: 2.122 Tests grün, einer übersprungen; Larastan und Pint sauber.
Zwei Migrationen (nullable Spalten, INSTANT). N09 offen.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-25 14:26:49 +00:00

78 lines
2.2 KiB
PHP

<?php
namespace Tests\Support;
use Illuminate\Filesystem\FilesystemAdapter;
use Illuminate\Support\Facades\Storage;
/**
* Storage-Fake mit gezielt eingebautem Fehlverhalten für einzelne
* Methoden (put, delete, move, exists). Die Fake-Disk bleibt das Backend;
* die Hooks bekommen den Pfad und einen Callback auf das echte Verhalten.
*
* Nutzung: FailingDisk::install('archive', ['delete' => fn () => false]);
* Zurücksetzen: FailingDisk::restore('archive').
*/
class FailingDisk extends FilesystemAdapter
{
/** @var array<string, FilesystemAdapter> */
private static array $originals = [];
/**
* @param array<string, callable> $hooks
*/
public function __construct(FilesystemAdapter $inner, private readonly array $hooks)
{
parent::__construct($inner->getDriver(), $inner->getAdapter(), $inner->getConfig());
}
/**
* @param array<string, callable> $hooks
*/
public static function install(string $disk, array $hooks): FilesystemAdapter
{
/** @var FilesystemAdapter $original */
$original = self::$originals[$disk] ?? Storage::disk($disk);
self::$originals[$disk] = $original;
Storage::set($disk, new self($original, $hooks));
return $original;
}
public static function restore(string $disk): void
{
if (isset(self::$originals[$disk])) {
Storage::set($disk, self::$originals[$disk]);
unset(self::$originals[$disk]);
}
}
public function exists($path)
{
return $this->hook('exists', $path, fn () => parent::exists($path));
}
public function put($path, $contents, $options = [])
{
return $this->hook('put', $path, fn () => parent::put($path, $contents, $options));
}
public function delete($paths)
{
return $this->hook('delete', $paths, fn () => parent::delete($paths));
}
public function move($from, $to)
{
return $this->hook('move', $from, fn () => parent::move($from, $to));
}
private function hook(string $method, mixed $path, callable $real): mixed
{
if (isset($this->hooks[$method])) {
return ($this->hooks[$method])($path, $real);
}
return $real();
}
}