185 lines
6.7 KiB
PHP
185 lines
6.7 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Livewire\Servers\Groups;
|
|
use App\Livewire\Servers\Index as ServersIndex;
|
|
use App\Models\Server;
|
|
use App\Models\ServerGroup;
|
|
use App\Models\User;
|
|
use App\Support\Confirm\ConfirmToken;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Livewire\Livewire;
|
|
use Tests\TestCase;
|
|
|
|
class ServerGroupsComponentTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private function admin(): User
|
|
{
|
|
return User::factory()->create(['must_change_password' => false]);
|
|
}
|
|
|
|
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]);
|
|
}
|
|
|
|
// ── route gating (manage-fleet = admin only) ────────────────────────────────
|
|
|
|
public function test_viewer_cannot_open_the_groups_page(): void
|
|
{
|
|
$this->actingAs($this->viewer())->get('/servers/groups')->assertForbidden();
|
|
}
|
|
|
|
public function test_operator_cannot_open_the_groups_page(): void
|
|
{
|
|
$this->actingAs($this->operator())->get('/servers/groups')->assertForbidden();
|
|
}
|
|
|
|
public function test_admin_can_open_the_groups_page(): void
|
|
{
|
|
$this->actingAs($this->admin())->get('/servers/groups')->assertOk();
|
|
}
|
|
|
|
// ── create ──────────────────────────────────────────────────────────────────
|
|
|
|
public function test_admin_creates_a_group_and_it_is_audited(): void
|
|
{
|
|
$this->actingAs($this->admin());
|
|
|
|
Livewire::test(Groups::class)
|
|
->set('name', 'Produktion')
|
|
->set('color', 'online')
|
|
->call('create')
|
|
->assertOk()
|
|
->assertHasNoErrors();
|
|
|
|
$this->assertDatabaseHas('server_groups', ['name' => 'Produktion', 'color' => 'online']);
|
|
$this->assertDatabaseHas('audit_events', ['action' => 'group.create', 'target' => 'Produktion']);
|
|
}
|
|
|
|
public function test_create_rejects_a_duplicate_name(): void
|
|
{
|
|
$this->actingAs($this->admin());
|
|
ServerGroup::create(['name' => 'prod', 'color' => 'accent']);
|
|
|
|
Livewire::test(Groups::class)
|
|
->set('name', 'prod')
|
|
->call('create')
|
|
->assertHasErrors('name');
|
|
|
|
$this->assertSame(1, ServerGroup::where('name', 'prod')->count());
|
|
}
|
|
|
|
public function test_create_rejects_an_unknown_color_token(): void
|
|
{
|
|
$this->actingAs($this->admin());
|
|
|
|
Livewire::test(Groups::class)
|
|
->set('name', 'x')
|
|
->set('color', 'rebeccapurple')
|
|
->call('create')
|
|
->assertHasErrors('color');
|
|
|
|
$this->assertDatabaseCount('server_groups', 0);
|
|
}
|
|
|
|
// ── rename / recolour / membership ──────────────────────────────────────────
|
|
|
|
public function test_admin_renames_and_recolors_a_group(): void
|
|
{
|
|
$this->actingAs($this->admin());
|
|
$g = ServerGroup::create(['name' => 'old', 'color' => 'accent']);
|
|
|
|
Livewire::test(Groups::class)
|
|
->call('rename', $g->uuid, 'Neu')
|
|
->call('setColor', $g->uuid, 'cyan');
|
|
|
|
$this->assertDatabaseHas('server_groups', ['id' => $g->id, 'name' => 'Neu', 'color' => 'cyan']);
|
|
}
|
|
|
|
public function test_set_color_ignores_an_unknown_token(): void
|
|
{
|
|
$this->actingAs($this->admin());
|
|
$g = ServerGroup::create(['name' => 'g', 'color' => 'accent']);
|
|
|
|
Livewire::test(Groups::class)->call('setColor', $g->uuid, 'rebeccapurple');
|
|
|
|
$this->assertSame('accent', $g->fresh()->color); // unchanged
|
|
}
|
|
|
|
public function test_toggle_member_adds_then_removes_a_server(): void
|
|
{
|
|
$this->actingAs($this->admin());
|
|
$g = ServerGroup::create(['name' => 'g', 'color' => 'accent']);
|
|
$s = Server::create(['name' => 's', 'ip' => '10.0.0.1', 'ssh_port' => 22, 'status' => 'online']);
|
|
|
|
Livewire::test(Groups::class)->call('toggleMember', $g->uuid, $s->uuid);
|
|
$this->assertTrue($g->servers()->where('servers.id', $s->id)->exists());
|
|
|
|
Livewire::test(Groups::class)->call('toggleMember', $g->uuid, $s->uuid);
|
|
$this->assertFalse($g->servers()->where('servers.id', $s->id)->exists());
|
|
}
|
|
|
|
// ── delete via signed confirm token ─────────────────────────────────────────
|
|
|
|
public function test_admin_deletes_a_group_via_a_confirmed_token(): void
|
|
{
|
|
$this->actingAs($this->admin());
|
|
$g = ServerGroup::create(['name' => 'gone', 'color' => 'offline']);
|
|
|
|
$token = ConfirmToken::issue('groupConfirmed', ['uuid' => $g->uuid], 'group.delete', $g->name, null);
|
|
ConfirmToken::confirm($token); // the modal confirmation step
|
|
|
|
Livewire::test(Groups::class)
|
|
->call('deleteGroup', $token)
|
|
->assertOk();
|
|
|
|
$this->assertDatabaseMissing('server_groups', ['id' => $g->id]);
|
|
}
|
|
|
|
public function test_a_forged_delete_token_is_a_no_op(): void
|
|
{
|
|
$this->actingAs($this->admin());
|
|
$g = ServerGroup::create(['name' => 'stay', 'color' => 'accent']);
|
|
|
|
Livewire::test(Groups::class)->call('deleteGroup', 'not-a-real-token');
|
|
|
|
$this->assertDatabaseHas('server_groups', ['id' => $g->id]);
|
|
}
|
|
|
|
// ── fleet filter (Servers\Index) — open to any role ─────────────────────────
|
|
|
|
public function test_group_filter_shows_only_members(): void
|
|
{
|
|
$this->actingAs($this->viewer()); // filtering is open to everyone
|
|
$g = ServerGroup::create(['name' => 'web', 'color' => 'cyan']);
|
|
$member = Server::create(['name' => 'web1', 'ip' => '10.0.0.1', 'ssh_port' => 22, 'status' => 'online']);
|
|
$other = Server::create(['name' => 'db1', 'ip' => '10.0.0.2', 'ssh_port' => 22, 'status' => 'online']);
|
|
$g->servers()->attach($member->id);
|
|
|
|
Livewire::test(ServersIndex::class)
|
|
->set('group', $g->uuid)
|
|
->assertSee('web1')
|
|
->assertDontSee('db1');
|
|
}
|
|
|
|
public function test_unknown_group_filter_falls_back_to_all(): void
|
|
{
|
|
$this->actingAs($this->viewer());
|
|
Server::create(['name' => 'srv', 'ip' => '10.0.0.1', 'ssh_port' => 22, 'status' => 'online']);
|
|
|
|
Livewire::test(ServersIndex::class)
|
|
->set('group', 'no-such-uuid')
|
|
->assertOk()
|
|
->assertSee('srv'); // not filtered out by a bogus group
|
|
}
|
|
}
|