Beleg: das Wartungsfenster achtet die Decke ohne eigene Regel

feat/versandtakt
nexxo 2026-08-04 15:39:02 +02:00
parent c93510ffe4
commit d90137c521
1 changed files with 68 additions and 0 deletions

View File

@ -1,6 +1,8 @@
<?php
use App\Services\Deployment\UpdateChannel;
use App\Services\Deployment\UpdateWindow;
use App\Support\Settings as AppSettings;
use Illuminate\Support\Facades\File;
beforeEach(function () {
@ -122,3 +124,69 @@ it('does not claim success when writing the ceiling fails', function () {
->and(File::exists($deployDir.'/release-ceiling.tmp'))->toBeFalse()
->and(File::exists($deployDir.'/release-ceiling'))->toBeFalse();
});
it('makes the automatic window do nothing while the ceiling is reached', function () {
// Der wichtigste Test des ganzen Entwurfs. Er belegt, dass Knopf und
// Wartungsfenster denselben Zustand lesen — die Behauptung, auf der alles
// ruht. Ohne ihn ist „es gibt keinen zweiten Weg in eine Auslieferung"
// eine Absichtserklaerung im Kommentar von AutoUpdate.php, kein Beleg.
//
// Damit ALLEIN die Decke den Ausschlag gibt, muessen alle anderen
// Vorbedingungen aus AutoUpdate::handle() erfuellt sein: das Fenster ist
// eingeschaltet (--force uebergeht nur isOpen(), nicht enabled() — ein
// ausgeschaltetes Fenster wuerde den Test aus dem falschen Grund gruen
// machen), der Agent gilt als lebendig, und es laeuft nichts. Der Agent
// hat gemeldet: nichts verfuegbar, weil die Decke erreicht ist.
AppSettings::set(UpdateWindow::KEY_ENABLED, true);
File::put(storage_path('app/deploy/update-status.json'), json_encode([
'state' => 'idle',
'behind' => 0,
'ceiling_error' => '',
'checked_at' => now()->toIso8601String(),
]));
File::put(storage_path('app/deploy/agent-alive.json'), json_encode([
'at' => now()->toIso8601String(),
'state' => 'running',
'skips' => 0,
]));
// Der Zustand, den Knopf und Wartungsfenster BEIDE lesen: schon hier
// steht `available` auf false, bevor der Befehl ueberhaupt laeuft.
expect(app(UpdateChannel::class)->state()['available'])->toBeFalse();
$this->artisan('clupilot:auto-update', ['--force' => true])
->assertSuccessful();
// Nichts abgelegt: keine Anfrage, kein Wartungsfenster, kein Lauf.
expect(File::exists(storage_path('app/deploy/update-request.json')))->toBeFalse();
});
it('takes the same state without a ceiling, and does request an update', function () {
// Der Gegenbeweis zum Test oben: exakt derselbe Aufbau — Fenster an, Agent
// lebendig, nichts laeuft — nur `behind` steht auf 1 statt 0, so wie der
// Agent es meldet, wenn keine Decke ihn bremst. Erst beide Tests
// zusammen belegen, dass die Decke — und keine der anderen
// Vorbedingungen — den Ausschlag gibt: ohne sie legt dieselbe Automatik
// sehr wohl eine Anfrage ab.
AppSettings::set(UpdateWindow::KEY_ENABLED, true);
File::put(storage_path('app/deploy/update-status.json'), json_encode([
'state' => 'idle',
'behind' => 1,
'ceiling_error' => '',
'checked_at' => now()->toIso8601String(),
]));
File::put(storage_path('app/deploy/agent-alive.json'), json_encode([
'at' => now()->toIso8601String(),
'state' => 'running',
'skips' => 0,
]));
expect(app(UpdateChannel::class)->state()['available'])->toBeTrue();
$this->artisan('clupilot:auto-update', ['--force' => true])
->assertSuccessful();
expect(File::exists(storage_path('app/deploy/update-request.json')))->toBeTrue();
});