- /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>
93 lines
3.2 KiB
PHP
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();
|
|
});
|