CluPilotCloud/tests/Feature/TunnelNamesTest.php

97 lines
4.1 KiB
PHP

<?php
use App\Services\Dns\FileHostDnsDirectory;
use App\Services\Dns\HostDnsDirectory;
/**
* Die eigenen Namen im Tunnel-Resolver.
*
* Über eine hosts-Datei im schon vorhandenen dns-hosts-Volume, das dnsmasq mit
* --hostsdir überwacht — dieselbe Stelle, an der die Host-Namen landen. Kein
* zweites `--address` im Compose-Befehl: das fängt zusätzlich jede Unterdomain
* mit ab, und über eine variable Namensliste kann eine command-Zeile nicht
* schleifen.
*/
beforeEach(function () {
$this->dir = sys_get_temp_dir().'/clupilot-hosts-'.bin2hex(random_bytes(6));
config()->set('provisioning.dns.hosts_dir', $this->dir);
config()->set('provisioning.wireguard.hub_address', '10.66.0.1');
config()->set('admin_access.vpn_internal_host', 'admin.clupilot.test');
});
afterEach(function () {
foreach (glob($this->dir.'/*') ?: [] as $file) {
@unlink($file);
}
@rmdir($this->dir);
});
it('veröffentlicht Portal, Website und Statusseite auf der Hub-Adresse', function () {
config()->set('admin_access.app_host', 'app.clupilot.test');
config()->set('admin_access.site_hosts', ['www.clupilot.test', 'clupilot.test']);
config()->set('admin_access.status_host', 'status.clupilot.test');
$this->artisan('clupilot:publish-tunnel-names')->assertSuccessful();
$written = file_get_contents($this->dir.'/platform.hosts');
expect($written)->toContain('10.66.0.1 app.clupilot.test')
->and($written)->toContain('10.66.0.1 www.clupilot.test')
->and($written)->toContain('10.66.0.1 clupilot.test')
->and($written)->toContain('10.66.0.1 status.clupilot.test');
});
it('lässt den Dateihost draußen', function () {
// Ein Server im Rettungssystem holt dort sein Archiv — der ist per
// Definition nicht im Tunnel. Bögen wir den Namen um, holte er es nie.
config()->set('admin_access.app_host', 'app.clupilot.test');
config()->set('admin_access.files_host', 'files.clupilot.test');
$this->artisan('clupilot:publish-tunnel-names')->assertSuccessful();
expect(file_get_contents($this->dir.'/platform.hosts'))
->not->toContain('files.clupilot.test');
});
it('räumt die Datei weg, wenn kein Name mehr konfiguriert ist', function () {
config()->set('admin_access.app_host', 'app.clupilot.test');
$this->artisan('clupilot:publish-tunnel-names')->assertSuccessful();
expect(file_exists($this->dir.'/platform.hosts'))->toBeTrue();
// Eine Datei, nicht eine je Name: sonst bliebe beim Wechsel von zwei
// Website-Namen auf einen die verwaiste Zeile im Resolver stehen, und der
// alte Name zeigte weiter in den Tunnel.
config()->set('admin_access.app_host', '');
$this->artisan('clupilot:publish-tunnel-names')->assertSuccessful();
expect(file_exists($this->dir.'/platform.hosts'))->toBeFalse();
});
it('tut nichts, solange kein Tunnel konfiguriert ist', function () {
// Ohne VPN_INTERNAL_HOST gibt es den Gateway nicht, und eine hosts-Datei
// für einen Resolver, den niemand startet, ist nur eine Datei, die beim
// nächsten Einschalten falsch sein kann.
config()->set('admin_access.vpn_internal_host', '');
config()->set('admin_access.app_host', 'app.clupilot.test');
$this->artisan('clupilot:publish-tunnel-names')->assertSuccessful();
expect(file_exists($this->dir.'/platform.hosts'))->toBeFalse();
});
it('schreibt genau eine Zeile je Name, im hosts-Format', function () {
config()->set('admin_access.app_host', 'app.clupilot.test');
config()->set('admin_access.site_hosts', ['www.clupilot.test']);
app(HostDnsDirectory::class)->writeMany('probe', ['a.test', 'b.test'], '10.66.0.1');
expect(file_get_contents($this->dir.'/probe.hosts'))
->toBe("10.66.0.1 a.test\n10.66.0.1 b.test\n");
});
it('ist dieselbe Datei-Umsetzung wie für die Host-Namen', function () {
// Nicht Fake gegen Fake geprüft: die Rechte und das Anlegen des
// Verzeichnisses sind der Teil, der in Produktion schiefgeht.
expect(app(HostDnsDirectory::class))->toBeInstanceOf(FileHostDnsDirectory::class);
})->skip(fn () => ! app()->environment('testing'), 'nur im Testlauf');