get('/') ->assertOk() ->assertSee('firmeneigene Cloud') ->assertSee(route('login'), false); }); it('renders the legal placeholder pages', function (string $route) { $this->get(route($route))->assertOk()->assertSee('CluPilot'); })->with(['legal.impressum', 'legal.datenschutz', 'legal.agb']); it('serves the status page at its own address, not under legal', function () { // It used to sit beside the imprint and the terms. Nothing about the // current health of the platform is a legal document. $this->get('/status') ->assertOk() ->assertSee(__('status.component.instances')) ->assertSee(__('status.component.backups')); // The old address still works, permanently, for anything already linking it. $this->get('/legal/status')->assertRedirect('/status'); }); it('reports a component it cannot see as unknown, never as operational', function () { // A status page that reports green because nothing is being watched is // worse than no status page: someone will believe it. App\Models\Instance::factory()->create(['status' => 'active']); $this->get('/status') ->assertOk() ->assertSee(__('status.state.unknown')) ->assertDontSee(__('status.overall.operational')); }); it('does not call the estate protected when an instance has no backup at all', function () { // Counting backup ROWS leaves an instance with no schedule out of the // arithmetic entirely, and the page reports green because the backups that // do exist happen to be fine. $withBackup = App\Models\Instance::factory()->create(['status' => 'active']); App\Models\Backup::query()->create([ 'instance_id' => $withBackup->id, 'external_job_id' => 'job-1', 'schedule' => 'daily', 'status' => 'ok', 'last_ok_at' => now()->subHour(), ]); App\Models\Instance::factory()->create(['status' => 'active']); $this->get('/status') ->assertOk() ->assertSee(__('status.detail.backups', ['stale' => 1, 'total' => 2])); }); it('serves the status page at the root of its own hostname, and the landing page everywhere else', function () { // "status.clupilot.com/status" says the same word twice. And the generic // `/` route is registered host-agnostically, so a domain-bound `/` has to // come FIRST or Laravel matches the landing page on the status host. config()->set('admin_access.status_host', 'status.example.test'); $router = new Illuminate\Routing\Router(app('events'), app()); Illuminate\Support\Facades\Route::swap($router); require base_path('routes/web.php'); $router->getRoutes()->refreshNameLookups(); $matches = fn (string $host, string $path) => $router->getRoutes() ->match(Illuminate\Http\Request::create("http://{$host}{$path}", 'GET')) ->getActionName(); expect($matches('status.example.test', '/'))->toContain('StatusController') ->and($matches('www.example.test', '/'))->toContain('LandingController'); });