clusev/tests/Feature/ServicesJournalPollTest.php

109 lines
3.8 KiB
PHP

<?php
namespace Tests\Feature;
use App\Livewire\Services\Index;
use App\Models\Server;
use App\Models\User;
use App\Services\FleetService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use Mockery;
use Tests\TestCase;
/**
* The journal is "live" via an incremental poll: each tick appends entries AFTER the
* stored cursor (no gaps), advances the cursor, and caps the retained rows.
*/
class ServicesJournalPollTest extends TestCase
{
use RefreshDatabase;
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
private function activeServer(): Server
{
$server = Server::create(['name' => 'box', 'ip' => '10.0.0.2', 'ssh_port' => 22, 'status' => 'online']);
$server->credential()->create(['username' => 'root', 'auth_type' => 'password', 'secret' => 'x']);
session(['active_server_id' => $server->id]);
return $server;
}
public function test_poll_appends_new_entries_and_advances_the_cursor(): void
{
$this->actingAs(User::factory()->create());
$this->activeServer();
$fleet = Mockery::mock(FleetService::class);
$fleet->shouldReceive('journalSince')
->once()
->with(Mockery::type(Server::class), 'cur-0', 200)
->andReturn([
'journal' => [['time' => '10:00:05', 'unit' => 'nginx', 'level' => 'info', 'text' => 'new line']],
'cursor' => 'cur-1',
]);
app()->instance(FleetService::class, $fleet);
Livewire::test(Index::class)
->set('ready', true)
->set('connected', true)
->set('journalCursor', 'cur-0')
->set('journal', [['time' => '10:00:01', 'unit' => 'sshd', 'level' => 'info', 'text' => 'old line']])
->call('pollJournal')
->assertSet('journalCursor', 'cur-1')
->assertSet('journal', [
['time' => '10:00:01', 'unit' => 'sshd', 'level' => 'info', 'text' => 'old line'],
['time' => '10:00:05', 'unit' => 'nginx', 'level' => 'info', 'text' => 'new line'],
]);
}
public function test_poll_caps_retained_rows_at_the_ceiling(): void
{
$this->actingAs(User::factory()->create());
$this->activeServer();
$fresh = array_map(
fn (int $i) => ['time' => '10:00:'.$i, 'unit' => 'u', 'level' => 'info', 'text' => 'n'.$i],
range(1, 350),
);
$fleet = Mockery::mock(FleetService::class);
$fleet->shouldReceive('journalSince')->once()->andReturn(['journal' => $fresh, 'cursor' => 'c']);
app()->instance(FleetService::class, $fleet);
$component = Livewire::test(Index::class)
->set('ready', true)
->set('connected', true)
->set('journal', [['time' => '09:59:59', 'unit' => 'old', 'level' => 'info', 'text' => 'oldest']])
->call('pollJournal');
$journal = $component->get('journal');
$this->assertCount(200, $journal);
// The oldest row is evicted; the newest survives.
$this->assertSame('n350', end($journal)['text']);
$this->assertNotSame('oldest', $journal[0]['text']);
}
public function test_poll_is_a_noop_until_connected(): void
{
$this->actingAs(User::factory()->create());
$this->activeServer();
$fleet = Mockery::mock(FleetService::class);
$fleet->shouldNotReceive('journalSince');
app()->instance(FleetService::class, $fleet);
Livewire::test(Index::class)
->set('ready', true)
->set('connected', false)
->set('journal', [['time' => 't', 'unit' => 'u', 'level' => 'info', 'text' => 'unchanged']])
->call('pollJournal')
->assertSet('journal', [['time' => 't', 'unit' => 'u', 'level' => 'info', 'text' => 'unchanged']]);
}
}