timeout(90)->env([ 'PATH' => $stub.':'.env('PATH', '/usr/local/bin:/usr/bin:/bin'), 'STUB_UP_CALLED' => $dir.'/.stub-up-called', ])->run(<</dev/null 2>&1 || true pkill -f 'sleep 20' 2>/dev/null || true BASH); expect($result->successful())->toBeTrue($result->errorOutput()); return json_decode(File::get($dir.'/watchdog-last-run.json'), true); } afterEach(function () { File::deleteDirectory(storage_path('app/deploy')); }); it('records a run where there was nothing to do', function () { $run = runWatchdog(); expect($run['outcome'])->toBe('idle') ->and($run['actions'])->toBe([]) ->and($run['at'])->not->toBeEmpty(); }); it('records what it healed', function () { // `app` fehlt in der Liste der laufenden Dienste — der Waechter startet // die Dienste und muss das hinterlassen. $run = runWatchdog(running: 'redis'); expect($run['outcome'])->toBe('healed') ->and($run['actions'])->not->toBeEmpty(); }); it('records that it stood down because the lock was held', function () { // DER Zustand, der bisher unsichtbar war. Ohne ihn sieht ein Waechter, // der seit einer Stunde nicht eingreifen kann, genauso aus wie einer, // der nichts zu tun hat. $run = runWatchdog(running: 'redis', holdLock: true); expect($run['outcome'])->toBe('stood_down'); }); it('reads nothing rather than falling over when the file is absent', function () { File::ensureDirectoryExists(storage_path('app/deploy')); expect(app(WatchdogLog::class)->lastRun())->toBeNull(); }); it('reads nothing rather than falling over when the file is rubbish', function () { File::ensureDirectoryExists(storage_path('app/deploy')); File::put(storage_path('app/deploy/watchdog-last-run.json'), 'kein json {'); expect(app(WatchdogLog::class)->lastRun())->toBeNull(); }); it('calls a run from long ago stale', function () { // Ein toter Waechter muss als solcher lesbar sein. Bisher wuerde niemand // es je erfahren. File::ensureDirectoryExists(storage_path('app/deploy')); File::put(storage_path('app/deploy/watchdog-last-run.json'), json_encode([ 'at' => now()->subMinutes(30)->utc()->format('Y-m-d\TH:i:s\Z'), 'outcome' => 'idle', 'actions' => [], ])); $run = app(WatchdogLog::class)->lastRun(); expect($run['stale'])->toBeTrue(); }); it('does not call a fresh run stale', function () { File::ensureDirectoryExists(storage_path('app/deploy')); File::put(storage_path('app/deploy/watchdog-last-run.json'), json_encode([ 'at' => now()->utc()->format('Y-m-d\TH:i:s\Z'), 'outcome' => 'idle', 'actions' => [], ])); expect(app(WatchdogLog::class)->lastRun()['stale'])->toBeFalse(); });