b2in/tests/Feature/Monitoring/AdminMonitoringPageTest.php
Kevin Adametz 061f004013 Admin: Monitoring-Seite (Systemstatus) und Navigation neu sortiert
- /admin/monitoring (nur Admin): Prüfungen wie /health, Version und Deploy-Zeit, geplante
  Aufgaben mit nächstem Lauf, letzte Fehler aus dem Log (ohne E-Mail-Adressen), Alarme,
  fehlgeschlagene Jobs, Links zu GlitchTip/Uptime Kuma (MONITORING_STATUS_URL), Test-Alarm
- Navigation: CMS, Cabinet, Produkte, Regionen, Admin, ganz unten Monitoring

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:27:04 +00:00

93 lines
3.2 KiB
PHP

<?php
use App\Models\User;
use App\Services\Monitoring\HealthProbe;
use App\Services\Monitoring\SystemStatus;
use Illuminate\Support\Facades\Http;
use Livewire\Volt\Volt;
use Spatie\Permission\Models\Role;
/**
* Monitoring-Seite im Admin (09.10.2026).
*/
beforeEach(function () {
Role::create(['name' => 'Admin']);
Role::create(['name' => 'Retailer']);
config()->set('monitoring.health.disk_min_free_percent', 0);
});
afterEach(function () {
@unlink(HealthProbe::heartbeatPath());
@unlink(storage_path('logs/laravel-monitoring-test.log'));
});
function monitoringAdmin(): User
{
return tap(User::factory()->create(), fn (User $user) => $user->assignRole('Admin'));
}
it('shows the checks, the version and the scheduled tasks to admins', function () {
config()->set('app.version', 'v2.0.6');
app(HealthProbe::class)->recordHeartbeat();
$this->actingAs(monitoringAdmin());
Volt::test('admin.monitoring')
->assertSee('Prüfungen')
->assertSee('Datenbank')
->assertSee('Scheduler')
->assertSee('v2.0.6')
->assertSee('monitoring:heartbeat')
->assertSee('cabinet:reset-overrides');
});
it('is closed to partners without admin role', function () {
$partner = tap(User::factory()->create(), fn (User $user) => $user->assignRole('Retailer'));
$this->actingAs($partner);
Volt::test('admin.monitoring')->assertForbidden();
});
it('sends a test alert from the page', function () {
Http::fake();
config()->set('monitoring.alerts.enabled', true);
config()->set('monitoring.alerts.ntfy', ['url' => 'https://push.example.com', 'topic' => 'b2in-ops', 'token' => null, 'priority' => 4]);
$this->actingAs(monitoringAdmin());
Volt::test('admin.monitoring')->call('sendTestAlert');
Http::assertSent(fn ($request) => str_contains((string) $request['message'], 'Test-Alarm aus dem Admin'));
});
it('reads the latest errors from the log without email addresses', function () {
file_put_contents(storage_path('logs/laravel-monitoring-test.log'), implode("\n", [
'[2026-10-09 08:00:00] production.INFO: Nur Info',
'[2026-10-09 09:00:00] production.ERROR: Mail an kunde@example.com fehlgeschlagen {"exception":"[object] ..."}',
'#0 /home/stacktrace',
])."\n");
touch(storage_path('logs/laravel-monitoring-test.log'), time() + 60);
$entries = app(SystemStatus::class)->recentLogEntries('laravel', ['ERROR']);
expect($entries)->toHaveCount(1)
->and($entries[0]['message'])->toBe('Mail an [email] fehlgeschlagen')
->and($entries[0]['at']->format('H:i'))->toBe('11:00');
});
it('places monitoring at the very end of the admin navigation, after cms, cabinet, products, regions and admin', function () {
$this->actingAs(monitoringAdmin());
$html = $this->get(route('admin.monitoring'))->assertSuccessful()->getContent();
$offset = strpos($html, '>CMS<');
expect($offset)->not->toBeFalse();
foreach (['>Cabinet<', '>Produkte<', '>Regionen<', '>Admin<', '>Monitoring<'] as $heading) {
$next = strpos($html, $heading, $offset);
expect($next)->not->toBeFalse("{$heading} fehlt oder steht zu weit oben");
$offset = $next;
}
expect(strpos($html, '>Superadmin<', $offset))->toBeFalse();
});