127 lines
3.9 KiB
PHP
127 lines
3.9 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Livewire\Health\Index;
|
|
use App\Models\HealthCheck;
|
|
use App\Models\User;
|
|
use App\Services\HealthService;
|
|
use App\Support\Confirm\ConfirmToken;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Livewire\Livewire;
|
|
use Mockery;
|
|
use Tests\TestCase;
|
|
|
|
class HealthComponentTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
Mockery::close();
|
|
parent::tearDown();
|
|
}
|
|
|
|
private function operator(): User
|
|
{
|
|
return User::factory()->operator()->create(['must_change_password' => false]);
|
|
}
|
|
|
|
private function viewer(): User
|
|
{
|
|
return User::factory()->viewer()->create(['must_change_password' => false]);
|
|
}
|
|
|
|
public function test_viewer_cannot_open_health(): void
|
|
{
|
|
$this->actingAs($this->viewer())->get('/health')->assertForbidden();
|
|
}
|
|
|
|
public function test_operator_can_open_health(): void
|
|
{
|
|
$this->actingAs($this->operator())->get('/health')->assertOk();
|
|
}
|
|
|
|
public function test_operator_adds_an_http_check_and_it_is_audited(): void
|
|
{
|
|
$this->actingAs($this->operator());
|
|
|
|
Livewire::test(Index::class)
|
|
->set('type', 'http')
|
|
->set('target', 'https://svc.example.com/health')
|
|
->call('addCheck')
|
|
->assertHasNoErrors();
|
|
|
|
$this->assertDatabaseHas('health_checks', ['type' => 'http', 'target' => 'https://svc.example.com/health', 'port' => null]);
|
|
$this->assertDatabaseHas('audit_events', ['action' => 'health.check_add']);
|
|
}
|
|
|
|
public function test_http_check_rejects_a_non_url(): void
|
|
{
|
|
$this->actingAs($this->operator());
|
|
|
|
Livewire::test(Index::class)
|
|
->set('type', 'http')
|
|
->set('target', 'not a url; rm -rf')
|
|
->call('addCheck')
|
|
->assertHasErrors('target');
|
|
|
|
$this->assertDatabaseCount('health_checks', 0);
|
|
}
|
|
|
|
public function test_tcp_check_requires_a_host_and_port(): void
|
|
{
|
|
$this->actingAs($this->operator());
|
|
|
|
Livewire::test(Index::class)
|
|
->set('type', 'tcp')
|
|
->set('target', 'db.example.com')
|
|
->set('port', 5432)
|
|
->call('addCheck')
|
|
->assertHasNoErrors();
|
|
|
|
$this->assertDatabaseHas('health_checks', ['type' => 'tcp', 'target' => 'db.example.com', 'port' => 5432]);
|
|
}
|
|
|
|
public function test_tcp_check_rejects_a_missing_port(): void
|
|
{
|
|
$this->actingAs($this->operator());
|
|
|
|
Livewire::test(Index::class)
|
|
->set('type', 'tcp')
|
|
->set('target', 'db.example.com')
|
|
->set('port', null)
|
|
->call('addCheck')
|
|
->assertHasErrors('port');
|
|
}
|
|
|
|
public function test_scan_probes_each_check(): void
|
|
{
|
|
$this->actingAs($this->operator());
|
|
HealthCheck::create(['type' => 'http', 'target' => 'https://svc.example.com']);
|
|
|
|
$health = Mockery::mock(HealthService::class);
|
|
$health->shouldReceive('probe')->once()->andReturn(['ok' => true, 'latency' => 42, 'detail' => 'HTTP 200']);
|
|
app()->instance(HealthService::class, $health);
|
|
|
|
Livewire::test(Index::class)
|
|
->call('scan')
|
|
->assertOk()
|
|
->assertSet('ready', true)
|
|
->assertSee(__('health.status_up'))
|
|
->assertViewHas('up', 1);
|
|
}
|
|
|
|
public function test_operator_deletes_a_check_via_a_confirmed_token(): void
|
|
{
|
|
$this->actingAs($this->operator());
|
|
$check = HealthCheck::create(['type' => 'http', 'target' => 'https://gone.example.com']);
|
|
$token = ConfirmToken::issue('healthCheckDeleted', ['uuid' => $check->uuid], 'health.check_delete', $check->target, null);
|
|
ConfirmToken::confirm($token);
|
|
|
|
Livewire::test(Index::class)->call('deleteCheck', $token)->assertOk();
|
|
|
|
$this->assertDatabaseMissing('health_checks', ['id' => $check->id]);
|
|
}
|
|
}
|