'array', 'timebank_cc.health_monitor.enabled' => true, 'timebank_cc.health_monitor.healthcheck_url' => self::PING, 'timebank_cc.health_monitor.website_url' => 'https://site.test', 'timebank_cc.health_monitor.disk_max_percent' => 100, 'elasticsearch.host' => 'es.test:9200', ]); } public function test_a_healthy_run_sends_a_plain_ping(): void { Http::fake([ 'es.test:9200/*' => Http::response(['status' => 'yellow']), 'site.test*' => Http::response('ok'), 'hc-ping.test/*' => Http::response('OK'), ]); $this->artisan('health:check')->assertExitCode(0); Http::assertSent(fn (Request $r) => $r->url() === self::PING); Http::assertNotSent(fn (Request $r) => str_ends_with($r->url(), '/fail')); } public function test_a_failing_service_is_reported_with_its_reason(): void { Http::fake([ 'es.test:9200/*' => Http::response(['status' => 'red']), 'site.test*' => Http::response('down', 500), 'hc-ping.test/*' => Http::response('OK'), ]); $this->artisan('health:check')->assertExitCode(1); Http::assertSent(function (Request $r) { return $r->url() === self::PING . '/fail' && str_contains($r->body(), 'elasticsearch: cluster status red') && str_contains($r->body(), 'website: https://site.test answered HTTP 500'); }); } public function test_a_full_disk_fails(): void { config(['timebank_cc.health_monitor.disk_max_percent' => 1]); Http::fake([ 'es.test:9200/*' => Http::response(['status' => 'green']), 'site.test*' => Http::response('ok'), 'hc-ping.test/*' => Http::response('OK'), ]); $this->artisan('health:check')->assertExitCode(1); Http::assertSent(fn (Request $r) => $r->url() === self::PING . '/fail' && str_contains($r->body(), 'disk:')); } public function test_it_runs_every_five_minutes(): void { $this->artisan('schedule:list')->expectsOutputToContain('health:check'); $event = collect(app(\Illuminate\Console\Scheduling\Schedule::class)->events()) ->first(fn ($e) => str_contains($e->command ?? '', 'health:check')); $this->assertNotNull($event); $this->assertSame('*/5 * * * *', $event->expression); } }