mivita/tests/Feature/PaymentDashboard/CheckPaymentUptimeCommandTest.php
2026-04-14 18:07:45 +02:00

112 lines
4 KiB
PHP

<?php
use App\Mail\PaymentIncidentAlert;
use App\Models\IncidentActivity;
use App\Models\PaymentIncident;
use App\Models\ProviderUptimeLog;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Mail;
uses(RefreshDatabase::class);
// ─── Uptime-Command: Erfolgsfall ──────────────────────────────────────────────
it('schreibt einen positiven ProviderUptimeLog wenn PAYONE erreichbar ist', function () {
Http::fake([
'api.pay1.de/*' => Http::response('', 200),
]);
$this->artisan('payment:check-uptime')->assertSuccessful();
$log = ProviderUptimeLog::where('provider', 'payone')->latest()->first();
expect($log)->not->toBeNull();
expect($log->is_up)->toBeTrue();
expect($log->error_message)->toBeNull();
});
it('schreibt einen negativen ProviderUptimeLog und legt Incident an wenn PAYONE nicht erreichbar ist', function () {
Http::fake([
'api.pay1.de/*' => Http::response('Server Error', 503),
]);
$this->artisan('payment:check-uptime')->assertSuccessful();
$log = ProviderUptimeLog::where('provider', 'payone')->latest()->first();
expect($log)->not->toBeNull();
expect($log->is_up)->toBeFalse();
$incident = PaymentIncident::where('provider', 'payone')->where('type', 'outage')->first();
expect($incident)->not->toBeNull();
expect($incident->severity)->toBe('critical');
expect($incident->status)->toBe('open');
});
it('erstellt keine doppelten Outage-Incidents bei mehrfachem Ausfall in derselben Stunde', function () {
Http::fake([
'api.pay1.de/*' => Http::response('', 503),
]);
$this->artisan('payment:check-uptime');
$this->artisan('payment:check-uptime');
expect(PaymentIncident::where('provider', 'payone')->where('type', 'outage')->count())->toBe(1);
});
it('löst offene Outage-Incidents automatisch auf wenn PAYONE wieder erreichbar ist', function () {
PaymentIncident::create([
'title' => 'Automatischer Ausfall',
'provider' => 'payone',
'type' => 'outage',
'severity' => 'critical',
'status' => 'open',
'detected_at' => now()->subMinutes(10),
]);
Http::fake([
'api.pay1.de/*' => Http::response('', 200),
]);
$this->artisan('payment:check-uptime')->assertSuccessful();
$incident = PaymentIncident::where('provider', 'payone')->where('type', 'outage')->first();
expect($incident->fresh()->status)->toBe('resolved');
expect($incident->fresh()->resolved_at)->not->toBeNull();
$activity = IncidentActivity::where('incident_id', $incident->id)
->where('type', 'status_change')
->first();
expect($activity)->not->toBeNull();
});
it('verarbeitet Verbindungsfehler als Ausfall', function () {
Http::fake([
'api.pay1.de/*' => fn () => throw new \Exception('Connection refused'),
]);
$this->artisan('payment:check-uptime')->assertSuccessful();
$log = ProviderUptimeLog::where('provider', 'payone')->latest()->first();
expect($log->is_up)->toBeFalse();
expect($log->error_message)->toContain('Connection refused');
});
// ─── Mailable ────────────────────────────────────────────────────────────────
it('sendet PaymentIncidentAlert-Mail wenn critical Incident angelegt wird', function () {
Mail::fake();
$incident = PaymentIncident::create([
'title' => 'Kritischer Test-Incident',
'provider' => 'payone',
'type' => 'outage',
'severity' => 'critical',
'detected_at' => now(),
]);
Mail::to(config('app.exception_mail'))->queue(new PaymentIncidentAlert($incident));
Mail::assertQueued(PaymentIncidentAlert::class, function (PaymentIncidentAlert $mail) use ($incident) {
return $mail->incident->id === $incident->id;
});
});