set('provisioning.dns.platform_zone', 'clupilot.com'); // Die Migration von `create_datacenters_table` legt fsn und hel schon an; // firstOrCreate steht hier, damit der Test nicht daran hängt. Datacenter::query()->firstOrCreate(['code' => 'fsn'], ['name' => 'Falkenstein']); }); /** Ein Host, der so angelegt wird, wie die Konsole es tut. */ function onboard(string $dc = 'fsn'): Host { static $n = 0; $n++; return app(StartHostOnboarding::class)->run([ 'datacenter' => $dc, 'public_ip' => '203.0.113.'.$n, 'root_password' => 'supersecret', ]); } // --- Abnahme 1 + 2 --- it('vergibt den Namen selbst, fortlaufend je Rechenzentrum', function () { expect(onboard()->name)->toBe('fsn-01') ->and(onboard()->name)->toBe('fsn-02'); }); it('führt je Rechenzentrum einen eigenen Zähler', function () { Datacenter::query()->firstOrCreate(['code' => 'hel'], ['name' => 'Helsinki']); expect(onboard('fsn')->name)->toBe('fsn-01') ->and(onboard('hel')->name)->toBe('hel-01'); }); // --- Abnahme 3: der Punkt, der die Sorgfalt trägt --- it('gibt die Nummer eines entfernten Hosts nie wieder aus', function () { onboard(); // fsn-01 $zweiter = onboard(); // fsn-02 onboard(); // fsn-03 // Die HÖCHSTE zu entfernen ist der gefährliche Fall: MAX(nummer) + 1 // reichte fsn-03 sofort wieder heraus, und ein zwischengespeicherter Name // zeigte danach auf eine andere Maschine. $zweiter->delete(); expect(onboard()->name)->toBe('fsn-04'); }); it('überlebt auch das Entfernen des höchsten Hosts', function () { onboard(); // fsn-01 $hoechster = onboard(); // fsn-02 $hoechster->delete(); expect(onboard()->name)->toBe('fsn-03'); }); // --- Abnahme 5 --- it('zeigt den Namen vorher an, ohne ihn zu verbrauchen', function () { onboard(); // fsn-01 ist weg $seite = Livewire::actingAs(admin(), 'operator')->test(HostCreate::class) ->set('datacenter', 'fsn'); $seite->assertSee('fsn-02')->assertSee('fsn-02.node.clupilot.com'); // Zweimal ansehen verbraucht nichts. Livewire::actingAs(admin(), 'operator')->test(HostCreate::class) ->set('datacenter', 'fsn') ->assertSee('fsn-02'); expect(HostName::preview('fsn'))->toBe('fsn-02'); }); it('gibt zwei gleichzeitig geöffneten Formularen zwei verschiedene Namen', function () { // Beide sehen fsn-01, gespeichert wird fsn-01 und fsn-02. expect(HostName::preview('fsn'))->toBe('fsn-01') ->and(HostName::preview('fsn'))->toBe('fsn-01'); expect(onboard()->name)->toBe('fsn-01') ->and(onboard()->name)->toBe('fsn-02'); }); // --- Der Riegel --- it('lässt zwei Hosts nicht denselben Namen tragen', function () { onboard(); expect(fn () => Host::factory()->create(['name' => 'fsn-01'])) ->toThrow(Illuminate\Database\QueryException::class); }); it('gibt zwei ähnlich geschriebenen Rechenzentrums-Codes nicht denselben Namen', function () { // Codes von vor der Verschärfung der Prüfregel: eu_west und eu-west werden // zur selben DNS-Bezeichnung, führen aber getrennte Zähler. Ohne das // Weiterzählen bekäme der zweite eu-west-01 und liefe in den Index. Datacenter::factory()->create(['code' => 'eu_west', 'name' => 'EU West (alt)']); Datacenter::factory()->create(['code' => 'eu-west', 'name' => 'EU West']); expect(onboard('eu_west')->name)->toBe('eu-west-01') ->and(onboard('eu-west')->name)->toBe('eu-west-02'); }); it('zählt ab hundert ohne Sonderfall weiter', function () { Datacenter::query()->where('code', 'fsn')->update(['next_host_number' => 100]); expect(onboard()->name)->toBe('fsn-100'); }); // --- Ein Name, überall derselbe --- it('nennt den Host im DNS so, wie die Konsole ihn nennt', function () { $host = onboard(); expect(HostName::fqdn($host->name))->toBe('fsn-01.node.clupilot.com') ->and(App\Support\HostTakeoverCommand::fqdnFor($host)) ->toBe(HostName::fqdn($host->name)); });