106 lines
4.1 KiB
PHP
106 lines
4.1 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Livewire\Servers\Show;
|
|
use App\Models\MetricSample;
|
|
use App\Models\Server;
|
|
use App\Models\User;
|
|
use App\Services\MetricHistory;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Livewire\Livewire;
|
|
use Tests\TestCase;
|
|
|
|
class MetricHistoryTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private function server(): Server
|
|
{
|
|
return Server::create(['name' => 'box', 'ip' => '10.0.0.9', 'ssh_port' => 22, 'status' => 'online']);
|
|
}
|
|
|
|
public function test_sample_metrics_persists_a_row_from_the_cached_reading(): void
|
|
{
|
|
$s = $this->server();
|
|
Cache::put("metrics:latest:{$s->id}", ['cpu' => 40, 'mem' => 55, 'disk' => 12, 'load' => 0.7], now()->addMinutes(5));
|
|
|
|
$this->artisan('clusev:sample-metrics')->assertSuccessful();
|
|
|
|
$this->assertDatabaseHas('metric_samples', ['server_id' => $s->id, 'cpu' => 40, 'mem' => 55, 'disk' => 12]);
|
|
$this->assertSame(1, MetricSample::count());
|
|
}
|
|
|
|
public function test_sample_metrics_skips_a_server_with_no_cached_reading(): void
|
|
{
|
|
$this->server(); // no cached reading → no sample (honest gap)
|
|
|
|
$this->artisan('clusev:sample-metrics')->assertSuccessful();
|
|
|
|
$this->assertSame(0, MetricSample::count());
|
|
}
|
|
|
|
public function test_sample_metrics_prunes_beyond_the_retention_window(): void
|
|
{
|
|
$s = $this->server();
|
|
MetricSample::create(['server_id' => $s->id, 'cpu' => 1, 'mem' => 1, 'disk' => 1, 'load' => 0, 'sampled_at' => now()->subDays(40)]);
|
|
MetricSample::create(['server_id' => $s->id, 'cpu' => 2, 'mem' => 2, 'disk' => 2, 'load' => 0, 'sampled_at' => now()->subDays(5)]);
|
|
|
|
$this->artisan('clusev:sample-metrics', ['--retention' => 30])->assertSuccessful();
|
|
|
|
$this->assertDatabaseMissing('metric_samples', ['cpu' => 1]); // 40d old → pruned
|
|
$this->assertDatabaseHas('metric_samples', ['cpu' => 2]); // 5d old → kept
|
|
}
|
|
|
|
public function test_series_buckets_and_averages_samples_with_null_gaps(): void
|
|
{
|
|
$s = $this->server();
|
|
MetricSample::create(['server_id' => $s->id, 'cpu' => 20, 'mem' => 40, 'disk' => 10, 'load' => 0.5, 'sampled_at' => now()->subSeconds(90)]);
|
|
MetricSample::create(['server_id' => $s->id, 'cpu' => 40, 'mem' => 60, 'disk' => 10, 'load' => 1.5, 'sampled_at' => now()->subSeconds(80)]);
|
|
|
|
$series = app(MetricHistory::class)->series($s, 300, 10);
|
|
|
|
$this->assertSame(300, $series['window']);
|
|
$this->assertCount(10, $series['points']);
|
|
|
|
$cpu = array_column($series['points'], 'cpu');
|
|
// the bucket holding both samples averages them (20 + 40) / 2 = 30
|
|
$this->assertContains(30, $cpu);
|
|
// empty buckets stay null — gaps, not fabricated values
|
|
$this->assertContains(null, $cpu);
|
|
}
|
|
|
|
public function test_show_passes_a_history_series_to_the_view(): void
|
|
{
|
|
$this->actingAs(User::factory()->create());
|
|
$s = $this->server();
|
|
MetricSample::create(['server_id' => $s->id, 'cpu' => 30, 'mem' => 40, 'disk' => 10, 'load' => 0.3, 'sampled_at' => now()->subMinutes(5)]);
|
|
|
|
Livewire::test(Show::class, ['server' => $s])
|
|
->assertViewHas('history', fn ($h) => is_array($h) && isset($h['points']) && $h['window'] === 86400);
|
|
}
|
|
|
|
public function test_set_range_clamps_to_allowed_keys(): void
|
|
{
|
|
$this->actingAs(User::factory()->create());
|
|
$s = $this->server();
|
|
|
|
Livewire::test(Show::class, ['server' => $s])
|
|
->assertSet('historyRange', '24h')
|
|
->call('setRange', '7d')->assertSet('historyRange', '7d')
|
|
->call('setRange', 'bogus')->assertSet('historyRange', '7d'); // invalid → unchanged
|
|
}
|
|
|
|
public function test_a_direct_invalid_range_property_is_clamped(): void
|
|
{
|
|
$this->actingAs(User::factory()->create());
|
|
$s = $this->server();
|
|
|
|
// historyRange is a public prop — a client can set it directly, bypassing setRange().
|
|
Livewire::test(Show::class, ['server' => $s])
|
|
->set('historyRange', 'evil')
|
|
->assertSet('historyRange', '24h');
|
|
}
|
|
}
|