create(['status' => 'active']); return MonitoringTarget::query()->create(array_merge([ 'instance_id' => $instance->id, 'external_id' => $externalId, 'url' => 'https://example.test', 'status' => 'unknown', ], $attributes)); } it('records what monitoring actually reports', function () { $up = target('mon-up'); $down = target('mon-down'); $this->mock(MonitoringClient::class, function ($mock) { $mock->shouldReceive('health')->with('mon-up')->andReturnTrue(); $mock->shouldReceive('health')->with('mon-down')->andReturnFalse(); }); (new SyncMonitoringStatus)->handle(app(MonitoringClient::class)); expect($up->refresh()->status)->toBe('up') ->and($up->checked_at)->not->toBeNull() ->and($down->refresh()->status)->toBe('down'); }); it('does not blame the instance when the monitoring service is the one that is down', function () { // "The monitor did not answer" says nothing about the instance. Writing // 'down' would raise an alarm about the wrong system; writing 'up' would // hide a real one. $target = target('mon-x', ['status' => 'up', 'checked_at' => now()->subMinutes(3)]); $wasCheckedAt = $target->checked_at; $this->mock(MonitoringClient::class, function ($mock) { $mock->shouldReceive('health')->andThrow(new RuntimeException('connection refused')); }); (new SyncMonitoringStatus)->handle(app(MonitoringClient::class)); expect($target->refresh()->status)->toBe('up') // Not advanced — so the verdict is allowed to go stale and stop counting. ->and($target->checked_at->timestamp)->toBe($wasCheckedAt->timestamp); }); it('does not treat a never-checked target as healthy on the public page', function () { target('mon-fresh'); $this->get('/status') ->assertOk() ->assertSee(__('status.state.unknown')) ->assertDontSee(__('status.overall.operational')); }); it('stops trusting a verdict nobody has refreshed', function () { target('mon-old', ['status' => 'up', 'checked_at' => now()->subHours(2)]); $this->get('/status') ->assertOk() ->assertSee(__('status.state.unknown')); }); it('records nothing when the monitor cannot answer at all', function () { // The boolean contract folded "no monitoring configured" into true and // "monitor unreachable" into false. Recording either as a measurement // publishes a fleet-wide all-clear nobody took, or a fleet-wide outage that // is really one broken monitor. $target = target('mon-quiet', ['status' => 'up', 'checked_at' => now()->subMinutes(4)]); $wasCheckedAt = $target->checked_at; $this->mock(MonitoringClient::class, function ($mock) { $mock->shouldReceive('health')->andReturnNull(); }); (new SyncMonitoringStatus)->handle(app(MonitoringClient::class)); expect($target->refresh()->status)->toBe('up') ->and($target->checked_at->timestamp)->toBe($wasCheckedAt->timestamp); }); it('keeps the acceptance check passing when monitoring is not set up', function () { // isHealthy() still folds "cannot tell" into a pass — deliberately, and // only there: a delivery must not fail because monitoring is unconfigured. config()->set('services.monitoring.url', ''); $client = new App\Services\Monitoring\HttpMonitoringClient; expect($client->health('anything'))->toBeNull() ->and($client->isHealthy('anything'))->toBeTrue(); });