Testovanie
Health::fake() nahradí manažér — pre fasádu aj pre všetko, čo si HealthManager injektuje — zaznamenávajúcim HealthFake a vráti ho. Fake si ponechá registrované kontroly, spúšťa ich bez odosielania jobov, notifikácií či zápisu riadkov, na report(), status() a stlmenia odpovedá z pamäte a zaznamená každé volanie, aj cez trait UsesHealthChecks a príkazy Artisan:
use RoundlyConsulting\Alerts\CheckResult;
use RoundlyConsulting\Alerts\Facades\Health;
$fake = Health::fake();
Health::define('disk-full', fn () => CheckResult::failed('Disk full'));
Health::for($team)->run(DiskUsageCheck::class); // healthy: checked, nothing to recover
Health::for($team)->run('disk-full'); // failing: alerted
$team->monitorCheck(DiskUsageCheck::class)->hourly()->save();
Health::silences()->mute('db', for: $team);
$this->artisan('alerts:prune-runs', ['--days' => 7]);
$fake->assertChecked('disk_usage_check');
$fake->assertNothingRecovered(); // a first healthy run recovers nothing
$fake->assertAlerted('disk-full'); // not recorded while a fake silence matches
$fake->assertMonitored(DiskUsageCheck::class, $team);
$fake->assertMuted('db', $team);
$fake->assertPruned(7);
$fake->assertNothingRanDue();Všetky aserácie
| Aserácia | Negácia | Prejde, keď |
|---|---|---|
assertChecked(string $key) | assertNothingChecked() | Kontrola s týmto kľúčom bežala pre niektorého vlastníka. |
assertAlerted(string $key) | assertNothingAlerted() | Pre kľúč sa spustil alert: dosiahol sa failAfter po sebe idúcich zlyhaní (warning alebo failed) a jeho kľúču, tagom ani * nezodpovedalo žiadne stlmenie vo fake. |
assertRecovered(string $key) | assertNothingRecovered() | Otvorený alert kľúča sa zatvoril po recoverAfter po sebe idúcich úspechoch a nezodpovedalo mu žiadne stlmenie vo fake. Úspešný beh bez otvoreného alertu nezaznamená nič. |
assertMonitored(string $checkOrKey, ?Model $owner = null) | assertNothingMonitored() | Kontrola (názov triedy alebo kľúč) bola naplánovaná — cez monitor()->save(), schedule() alebo trait — pre zadaného vlastníka, ak ho uvediete. |
assertUnmonitored(string $checkOrKey, ?Model $owner = null) | assertNothingUnmonitored() | Pre kontrolu sa zavolal unmonitor(), pri zadanom vlastníkovi pre neho. |
assertMuted(string $key, ?Model $owner = null) | assertNothingMuted() | Pre kľúč sa zavolal silences()->mute(), pri zadanom vlastníkovi s obmedzením naňho. |
assertUnmuted(string $key, ?Model $owner = null) | assertNothingUnmuted() | Pre kľúč sa zavolal silences()->unmute(), pri zadanom vlastníkovi s obmedzením naňho. |
assertRanDue(?int $times = null) | assertNothingRanDue() | Zavolal sa runDue() — aspoň raz, alebo presne $times-krát. |
assertPruned(?int $days = null) | assertNothingPruned() | Zavolal sa prune() — pri zadanom počte dní práve s ním. |
assertSilencesPruned(?int $days = null) | assertNoSilencesPruned() | Zavolal sa silences()->prune() — pri zadanom počte dní práve s ním. |
assertReconfigured(string $checkOrKey, ?Model $owner = null) | assertNothingReconfigured() | Pre plán kontroly (názov triedy alebo kľúč) sa zavolal reconfigure(), pri zadanom vlastníkovi pre neho. Odmietnuté volanie sa nezaznamená. |
$fake = Health::fake();
$healthy = false;
Health::define('payments-api', function () use (&$healthy): bool {
return $healthy;
})->failAfter(2)->recoverAfter(2);
Health::for($team)->run('payments-api'); // 1st failure — below failAfter
$fake->assertNothingAlerted();
Health::for($team)->run('payments-api'); // 2nd failure — the alert opens
$fake->assertAlerted('payments-api');
$healthy = true;
Health::for($team)->run('payments-api'); // 1st OK — still open
$fake->assertNothingRecovered();
Health::for($team)->status(); // Status::Failed until recovery is confirmed
Health::for($team)->run('payments-api'); // 2nd OK — the alert closes
$fake->assertRecovered('payments-api');
Health::for($team)->unmonitor(DiskUsageCheck::class);
Health::silences()->unmute('db', for: $team);
Health::runDue();
$fake->assertUnmonitored(DiskUsageCheck::class, $team);
$fake->assertUnmuted('db', $team);
$fake->assertRanDue(1);
$fake->assertNothingMonitored();
$fake->assertNothingMuted();
$fake->assertNothingPruned();Ako sa fake správa
- Beh prejde rovnakými bránami ako skutočný, s pamäťou pre každého vlastníka a kontrolu: vyhodená výnimka alebo prekročený časový limit sa stane výsledkom failed, alert sa zaznamená až po dosiahnutí failAfter po sebe idúcich zlyhaní a obnova len vtedy, keď sa otvorený alert zatvorí po recoverAfter po sebe idúcich úspechoch. Žiadne riadky, behy, udalosti ani notifikácie.
- Beh kontroly prejde cez najstarší monitoring vlastníka pre túto kontrolu, rovnako ako skutočný beh, inak cez monitoring na požiadanie s voľbami z define() inline kontroly; beh riadka použije tento riadok. Riadok iného vlastníka aj tak odmietne s InvalidHealthCheck.
- report() a status() sa zostavia z monitoringov fake v pamäti a ich otvorených alertov, rovnako ako skutočný report — nikdy nie z databázy. Platí since: aj scheduledOnly: (každý výsledok v pamäti dostane časovú pečiatku now(), takže funguje travel()), monitoring, ktorý ešte nebežal, ukáže ok s dostupnosťou null, muted sa určí zo stlmení vo fake podľa skutočného pravidla, meta sú uložené meta otvoreného alertu vo fake a p95LatencyMs zostáva null — fake trvanie behov nezaznamenáva.
- Stlmenia žijú v pamäti, jedno na kľúč a rozsah, rovnako ako pri upserte cez mute(): zodpovedajúce stlmenie vo fake (kľúč, tag alebo *) potlačí zaznamenanie alertu; isMuted(), active(), snapshot() aj covers() ich čítajú a silences()->prune() odstráni skončené a zaznamená sa.
- schedule(), monitor()->save() a mute() vracajú neuložené modely; neplatný cron, eskalačnú politiku či identitu z uniqueBy() odmietnu rovnako ako skutočná akcia. Pri kontrole s uniqueBy() urobí schedule() upsert v pamäti so skutočným pravidlom rozdielu aj nulovania počítadiel a každé ďalšie schedule() tej istej identity vráti čerstvú kópiu riadka, ktorá hlási wasRecentlyCreated a wasChanged(). for($owner)->monitors() vypíše, čo sa naplánovalo, od najstaršieho.
- reconfigure() zlučuje v pamäti podľa skutočných pravidiel: riadok iného vlastníka odmietne a identita iného plánu vyhodí ScheduleConflict — ani jedno sa nezaznamená.
- unmonitor() odstráni monitoringy kontroly pre vlastníka — aj ten na požiadanie — z ďalších behov aj z reportu a vráti ich počet; databázový riadok, ktorý fake nenaplánoval, nechá tak (0).
- runDue() a prune() vracajú 0; prune() aj silences()->prune() s menej ako 1 dňom vyhodia InvalidRetention, rovnako ako skutočné.
- Výsledky skipped nemenia počítadlá a nezaznamenajú alert ani obnovu.
Test celej cesty
Pre end-to-end správanie spustite skutočnú cestu nad vašou databázou s fakes Notification a Event z Laravelu:
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Notification;
use RoundlyConsulting\Alerts\CheckResult;
use RoundlyConsulting\Alerts\Events\HealthCheckFailed;
use RoundlyConsulting\Alerts\Facades\Health;
it('opens an alert and notifies the team when a check fails', function () {
Notification::fake();
Event::fake([HealthCheckFailed::class]);
Health::define('always-down', fn () => CheckResult::failed('Down'));
$team = Team::factory()->create();
$result = Health::for($team)->run('always-down');
expect($result->status->isAlertable())->toBeTrue()
->and($team->alerts()->open()->count())->toBe(1);
Event::assertDispatched(HealthCheckFailed::class);
});Factories
HealthCheck, Alert, HealthCheckRun a AlertSilence majú pribalené factories. Stĺpce vlastníka health checku nasmerujte na skutočného vlastníka. Alert::factory() otvorí alert rovnako ako beh — na vlastníkovi jeho health checku a s obsadeným open slotom kontroly, kým ho recovered() neuvoľní —, takže ho report vidí, zlyhaný beh naň nadviaže a druhý otvorený alert tej istej kontroly unikátny index odmietne. Alert má aj stavy warning(), failed() a skipped():
use RoundlyConsulting\Alerts\Alert;
use RoundlyConsulting\Alerts\HealthCheck;
use RoundlyConsulting\Alerts\HealthCheckRun;
$row = HealthCheck::factory()->create([
'notifiable_type' => $team->getMorphClass(),
'notifiable_id' => $team->getKey(),
'health_check' => 'disk_usage_check',
]);
HealthCheckRun::factory()->count(20)->create(['health_check_id' => $row->id]);
// Opens on the row's owner and holds its open slot, as the pipeline does
Alert::factory()->warning()->create([ // also failed(), skipped(), recovered()
'health_check_id' => $row->id,
]);Vlastné testy balíka
composer testPrejavte lásku k open source
Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.
Ďalšie spôsoby podpory vrátane kryptomienOdoslaním daru súhlasíte s našimi podmienkami prijímania darov.
Chcete to zabudovať do svojho produktu?
Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.