clusev/tests/Feature/ServerDockerTest.php

125 lines
4.1 KiB
PHP

<?php
namespace Tests\Feature;
use App\Livewire\Servers\ServerDocker;
use App\Models\Server;
use App\Models\User;
use App\Services\DockerService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use Mockery;
use Tests\TestCase;
/**
* Per-server container management (the "Docker" tab of the server-details page). Viewing is open to
* any role; actions require `operate`. The host-targeted sidebar page is covered by DockerComponentTest.
*/
class ServerDockerTest extends TestCase
{
use RefreshDatabase;
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
private function viewer(): User
{
return User::factory()->viewer()->create(['must_change_password' => false]);
}
private function operator(): User
{
return User::factory()->operator()->create(['must_change_password' => false]);
}
private function server(): 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']);
// Re-load with the withExists('credential') attribute the component reads.
return Server::withExists('credential')->find($server->id);
}
private function stubDocker(array $containers = []): DockerService
{
$docker = Mockery::mock(DockerService::class);
$docker->shouldReceive('available')->andReturn(true);
$docker->shouldReceive('containers')->andReturn($containers);
app()->instance(DockerService::class, $docker);
return $docker;
}
public function test_viewer_can_browse_the_server_container_list(): void
{
$this->actingAs($this->viewer());
$server = $this->server();
$this->stubDocker([['id' => 'abc', 'name' => 'web', 'image' => 'nginx', 'state' => 'running', 'status' => 'Up', 'ports' => '80/tcp']]);
Livewire::test(ServerDocker::class, ['server' => $server])
->call('load')
->assertOk()
->assertSet('connected', true)
->assertSee('web');
}
public function test_viewer_cannot_run_a_server_container_action(): void
{
$this->actingAs($this->viewer());
$server = $this->server();
$docker = $this->stubDocker();
$docker->shouldReceive('containerAction')->never();
Livewire::test(ServerDocker::class, ['server' => $server])
->call('action', 'web', 'stop')
->assertForbidden();
}
public function test_operator_can_run_a_server_container_action_and_it_is_audited(): void
{
$this->actingAs($this->operator());
$server = $this->server();
$docker = $this->stubDocker();
$docker->shouldReceive('containerAction')->once()
->with(Mockery::type(Server::class), 'web', 'restart')
->andReturn(['ok' => true, 'output' => 'web']);
Livewire::test(ServerDocker::class, ['server' => $server])
->call('action', 'web', 'restart')
->assertOk();
$this->assertDatabaseHas('audit_events', ['action' => 'docker.action', 'server_id' => $server->id]);
}
public function test_shows_a_clean_not_installed_state(): void
{
$this->actingAs($this->viewer());
$server = $this->server();
$docker = Mockery::mock(DockerService::class);
$docker->shouldReceive('available')->once()->andReturn(false);
$docker->shouldReceive('containers')->never();
app()->instance(DockerService::class, $docker);
Livewire::test(ServerDocker::class, ['server' => $server])
->call('load')
->assertOk()
->assertSet('notInstalled', true)
->assertSee(__('docker.not_installed_title'));
}
public function test_viewer_cannot_open_server_logs(): void
{
$this->actingAs($this->viewer());
$server = $this->server();
$this->stubDocker();
Livewire::test(ServerDocker::class, ['server' => $server])
->call('viewLogs', 'web')
->assertForbidden();
}
}