requestRescueTunnel('chef@example.com'))->toBeTrue(); $request = json_decode(File::get(storage_path('app/deploy/update-request.json')), true); expect($request['kind'])->toBe('rescue-tunnel') ->and($request['requested_by'])->toBe('chef@example.com'); }); it('takes only one request at a time', function () { $channel = app(UpdateChannel::class); expect($channel->requestRescueTunnel('chef@example.com'))->toBeTrue() ->and($channel->requestRescueTunnel('chef@example.com'))->toBeFalse(); }); it('rescues the tunnel from the console', function () { $owner = Operator::factory()->role('Owner')->create(); Livewire::actingAs($owner, 'operator') ->test(Settings::class) ->call('rescueTunnel'); expect(File::exists(storage_path('app/deploy/update-request.json')))->toBeTrue(); }); it('refuses to rescue without site.manage', function () { // Eine Livewire-Aktion ist ein oeffentlicher Endpunkt. $staff = Operator::factory()->create(); Livewire::actingAs($staff, 'operator') ->test(Settings::class) ->call('rescueTunnel') ->assertForbidden(); }); it('reads the outcome without falling over when it is rubbish', function () { File::put(storage_path('app/deploy/rescue-last-run.json'), 'kein json {'); expect(app(UpdateChannel::class)->state()['rescue_last_run'])->toBeNull(); }); it('agent knows the kind', function () { // Der Agent muss die Art kennen, sonst liegt die Anfrage bis zum Ablauf // im Postkasten und niemand erfaehrt warum. expect(File::get(base_path('deploy/update-agent.sh'))) ->toContain('rescue-tunnel') ->toContain('rescue-tunnel.sh'); });