create(); $fremder = Customer::factory()->create(); Host::factory()->active()->create([ 'datacenter' => 'fsn', 'total_gb' => 4000, 'reserved_for_customer_id' => $mieter->id, ]); expect(Host::placeableIn('fsn', 100, $fremder->id))->toBeNull() ->and(Host::placeableIn('fsn', 100, $mieter->id))->not->toBeNull(); }); it('zählt einen reservierten Host nicht zum allgemeinen Bestand', function () { $mieter = Customer::factory()->create(); Host::factory()->active()->create([ 'datacenter' => 'fsn', 'total_gb' => 4000, 'reserved_for_customer_id' => $mieter->id, ]); expect(app(HostCapacity::class)->largestPlaceableGb('fsn'))->toBe(0) ->and(app(HostCapacity::class)->canPlace('fsn', 40))->toBeFalse(); }); it('lässt einen freien Host frei', function () { Host::factory()->active()->create(['datacenter' => 'fsn', 'total_gb' => 500]); expect(app(HostCapacity::class)->canPlace('fsn', 40))->toBeTrue(); }); /** * Die Konsole: setzen und lösen. * * Setzen braucht keine Bestätigung — ein Host, der noch niemandem gehört, * bekommt einen Besitzer, nichts geht verloren. Lösen schon (R23): danach * ist die Maschine wieder allgemeiner Bestand, und der nächste Startkunde * kann darauf landen. */ it('reserviert einen Host für einen Kunden von der Konsole aus', function () { $host = Host::factory()->active()->create(); $customer = Customer::factory()->create(); Livewire::actingAs(admin(), 'operator') ->test(HostDetail::class, ['host' => $host]) ->call('reserveFor', $customer->uuid) ->assertDispatched('notify'); expect($host->fresh()->reserved_for_customer_id)->toBe($customer->id); }); it('verweigert das Reservieren ohne hosts.manage', function () { $host = Host::factory()->active()->create(); $customer = Customer::factory()->create(); Livewire::actingAs(operator('Read-only'), 'operator') ->test(HostDetail::class, ['host' => $host]) ->call('reserveFor', $customer->uuid) ->assertForbidden(); expect($host->fresh()->reserved_for_customer_id)->toBeNull(); }); it('bestätigt das Lösen im eigenen Modal, ohne dabei selbst etwas zu ändern', function () { $mieter = Customer::factory()->create(['name' => 'Acme GmbH']); $host = Host::factory()->active()->create(['reserved_for_customer_id' => $mieter->id]); Livewire::actingAs(admin(), 'operator') ->test(ConfirmReleaseReservation::class, ['uuid' => $host->uuid]) ->assertSee('Acme GmbH') ->call('confirmRelease') ->assertDispatched('host-reservation-release-confirmed'); // Das Modal selbst rührt nichts an — die Reservierung steht noch. expect($host->fresh()->reserved_for_customer_id)->toBe($mieter->id); }); it('löst die Reservierung, sobald die Seite das bestätigte Ereignis empfängt', function () { $mieter = Customer::factory()->create(); $host = Host::factory()->active()->create(['reserved_for_customer_id' => $mieter->id]); Livewire::actingAs(admin(), 'operator') ->test(HostDetail::class, ['host' => $host]) ->call('onReleaseConfirmed') ->assertDispatched('notify'); expect($host->fresh()->reserved_for_customer_id)->toBeNull(); }); /** * Erklärt statt versteckt (Aufgabenauflösung #4): eine reservierte Maschine * verschwindet nirgends kommentarlos aus dem Bestand — Host-Detailseite, * Host-Liste und Kapazitätsseite weisen sie jeweils als solche aus. */ it('zeigt die Reservierung auf der Host-Detailseite', function () { $mieter = Customer::factory()->create(['name' => 'Contoso KG']); $host = Host::factory()->active()->create(['reserved_for_customer_id' => $mieter->id]); $this->actingAs(admin(), 'operator')->get(route('admin.hosts.show', $host)) ->assertOk() ->assertSee(__('hosts.detail.reserved_for', ['name' => 'Contoso KG'])); }); it('bietet auf der Host-Detailseite eine Kundenauswahl, solange nichts reserviert ist', function () { $host = Host::factory()->active()->create(); $customer = Customer::factory()->create(['name' => 'Globex AG']); $this->actingAs(admin(), 'operator')->get(route('admin.hosts.show', $host)) ->assertOk() ->assertSee(__('hosts.detail.reserved_general')) ->assertSee('Globex AG'); }); it('weist die Reservierung auf der Host-Liste aus', function () { $mieter = Customer::factory()->create(['name' => 'Umbrella Corp']); Host::factory()->active()->create(['name' => 'pve-reserved-1', 'reserved_for_customer_id' => $mieter->id]); $this->actingAs(admin(), 'operator')->get(route('admin.hosts')) ->assertOk() ->assertSee(__('hosts.reserved_badge', ['name' => 'Umbrella Corp'])); }); it('weist die Reservierung auf der Kapazitätsseite aus', function () { App\Models\Datacenter::factory()->create(['code' => 'fsn2']); $mieter = Customer::factory()->create(['name' => 'Initech Ltd']); Host::factory()->active()->create(['datacenter' => 'fsn2', 'reserved_for_customer_id' => $mieter->id]); $this->actingAs(admin(), 'operator')->get(route('admin.capacity')) ->assertOk() ->assertSee(__('hosts.reserved_badge', ['name' => 'Initech Ltd'])); });