Upstream pelican/panel state of the touched files before 2a80f9bf21
This commit is contained in:
1 parent
8860a5c5e5
commit
72779c7ea6
6 files changed
+1204
No files matched your search
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
use App\Enums\RolePermissionModels;
|
||||
use App\Filament\Admin\Resources\Servers\Pages\CreateServer;
|
||||
use App\Filament\Admin\Resources\Servers\Pages\EditServer;
|
||||
use App\Models\Allocation;
|
||||
use App\Models\Egg;
|
||||
use App\Models\Node;
|
||||
use App\Models\Role;
|
||||
use App\Models\Server;
|
||||
use App\Repositories\Daemon\DaemonServerRepository;
|
||||
use Filament\Actions\Testing\TestAction;
|
||||
use Filament\Facades\Filament;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
|
||||
use function Pest\Livewire\livewire;
|
||||
|
||||
beforeEach(function () {
|
||||
Filament::setCurrentPanel(Filament::getPanel('admin'));
|
||||
|
||||
[$this->admin] = generateTestAccount();
|
||||
$this->admin->syncRoles(Role::getRootAdmin());
|
||||
$this->actingAs($this->admin);
|
||||
});
|
||||
afterEach(fn () => Filament::setCurrentPanel(null));
|
||||
|
||||
it('can create a server', function () {
|
||||
$daemon = Mockery::mock(DaemonServerRepository::class);
|
||||
$daemon->expects('setServer')->andReturnSelf();
|
||||
$daemon->expects('create')->andReturnUndefined();
|
||||
$this->swap(DaemonServerRepository::class, $daemon);
|
||||
|
||||
$node = Node::factory()->create();
|
||||
$allocation = Allocation::factory()->create(['node_id' => $node->id, 'server_id' => null]);
|
||||
// A factory egg has no variables, so no required environment values get in the way.
|
||||
$egg = Egg::factory()->create();
|
||||
|
||||
livewire(CreateServer::class)
|
||||
->fillForm([
|
||||
'name' => 'test-server',
|
||||
'node_id' => $node->id,
|
||||
'owner_id' => $this->admin->id,
|
||||
'allocation_id' => $allocation->id,
|
||||
'egg_id' => $egg->id,
|
||||
'startup' => 'java -jar test.jar',
|
||||
'image' => 'ghcr.io/pelican-eggs/yolks:java_21',
|
||||
])
|
||||
->call('create')
|
||||
->assertHasNoFormErrors();
|
||||
|
||||
$this->assertDatabaseHas('servers', [
|
||||
'name' => 'test-server',
|
||||
'node_id' => $node->id,
|
||||
'owner_id' => $this->admin->id,
|
||||
'egg_id' => $egg->id,
|
||||
]);
|
||||
});
|
||||
|
||||
it('can edit a server', function () {
|
||||
$server = Server::factory()->withNode()->create();
|
||||
|
||||
// Renaming is excluded from the daemon sync diff, so no daemon call happens.
|
||||
livewire(EditServer::class, ['record' => $server->getKey()])
|
||||
->fillForm([
|
||||
'name' => 'renamed-server',
|
||||
'allocation_limit' => 0,
|
||||
'database_limit' => 0,
|
||||
])
|
||||
->call('save')
|
||||
->assertHasNoFormErrors();
|
||||
|
||||
$this->assertDatabaseHas('servers', ['id' => $server->id, 'name' => 'renamed-server']);
|
||||
});
|
||||
|
||||
it('can delete a server', function () {
|
||||
$daemon = Mockery::mock(DaemonServerRepository::class);
|
||||
$daemon->shouldReceive('setServer')->andReturnSelf();
|
||||
// Rendering the edit page polls the server's container status.
|
||||
$daemon->shouldReceive('getDetails')->andReturn(['state' => 'offline']);
|
||||
$daemon->shouldReceive('delete');
|
||||
$this->swap(DaemonServerRepository::class, $daemon);
|
||||
|
||||
$server = Server::factory()->withNode()->create();
|
||||
|
||||
livewire(EditServer::class, ['record' => $server->getKey()])
|
||||
->callAction(TestAction::make('Delete'));
|
||||
|
||||
$this->assertDatabaseMissing('servers', ['id' => $server->id]);
|
||||
});
|
||||
|
||||
it('non root admin without permission cannot create servers', function () {
|
||||
$role = Role::factory()->create(['name' => 'Egg Viewer', 'guard_name' => 'web']);
|
||||
// Egg permission is on purpose, we check the wrong permissions.
|
||||
$role->givePermissionTo(Permission::findOrCreate(RolePermissionModels::Egg->viewAny(), 'web'));
|
||||
[$user] = generateTestAccount();
|
||||
$user->syncRoles($role);
|
||||
|
||||
$this->actingAs($user);
|
||||
livewire(CreateServer::class)->assertForbidden();
|
||||
});
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests\Integration\Api\Client\Server\Allocation;
|
||||
|
||||
use App\Enums\SubuserPermission;
|
||||
use App\Models\Allocation;
|
||||
use App\Models\Server;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
use Illuminate\Http\Response;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class DeleteAllocationTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
/**
|
||||
* Test that an allocation is deleted from the server and the notes are properly reset
|
||||
* to an empty value on assignment.
|
||||
*/
|
||||
#[DataProvider('permissionDataProvider')]
|
||||
public function test_allocation_can_be_deleted_from_server(array $permission): void
|
||||
{
|
||||
/** @var Server $server */
|
||||
[$user, $server] = $this->generateTestAccount($permission);
|
||||
$server->update(['allocation_limit' => 2]);
|
||||
|
||||
/** @var Allocation $allocation */
|
||||
$allocation = Allocation::factory()->create([
|
||||
'server_id' => $server->id,
|
||||
'node_id' => $server->node_id,
|
||||
'is_locked' => true,
|
||||
'notes' => 'hodor',
|
||||
'show_port' => false,
|
||||
]);
|
||||
|
||||
$this->actingAs($user)->deleteJson($this->link($allocation))->assertStatus(Response::HTTP_NO_CONTENT);
|
||||
|
||||
$this->assertDatabaseHas('allocations', [
|
||||
'id' => $allocation->id,
|
||||
'is_locked' => false,
|
||||
'server_id' => null,
|
||||
'notes' => null,
|
||||
'show_port' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that an allocation is deleted if it is currently marked as the primary allocation
|
||||
* for the server.
|
||||
*/
|
||||
public function test_primary_allocation_can_be_deleted_from_server(): void
|
||||
{
|
||||
/** @var Server $server */
|
||||
[$user, $server] = $this->generateTestAccount();
|
||||
$server->update(['allocation_limit' => 2]);
|
||||
|
||||
$allocation = $server->allocation;
|
||||
|
||||
$this->actingAs($user)->deleteJson($this->link($allocation))->assertStatus(Response::HTTP_NO_CONTENT);
|
||||
|
||||
$this->assertDatabaseHas('allocations', ['id' => $allocation->id, 'server_id' => null, 'notes' => null]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that an error is returned if the user does not have permissiont to delete an allocation.
|
||||
*/
|
||||
public function test_error_is_returned_if_user_does_not_have_permission(): void
|
||||
{
|
||||
/** @var Server $server */
|
||||
[$user, $server] = $this->generateTestAccount([SubuserPermission::AllocationCreate]);
|
||||
|
||||
/** @var Allocation $allocation */
|
||||
$allocation = Allocation::factory()->create([
|
||||
'server_id' => $server->id,
|
||||
'node_id' => $server->node_id,
|
||||
'notes' => 'hodor',
|
||||
]);
|
||||
|
||||
$this->actingAs($user)->deleteJson($this->link($allocation))->assertForbidden();
|
||||
|
||||
$this->assertDatabaseHas('allocations', ['id' => $allocation->id, 'server_id' => $server->id]);
|
||||
}
|
||||
|
||||
public function test_allocation_cannot_be_deleted_if_server_limit_is_not_defined(): void
|
||||
{
|
||||
[$user, $server] = $this->generateTestAccount();
|
||||
|
||||
/** @var Allocation $allocation */
|
||||
$allocation = Allocation::factory()->forServer($server)->create(['notes' => 'Test notes']);
|
||||
|
||||
$this->actingAs($user)->deleteJson($this->link($allocation))
|
||||
->assertStatus(400)
|
||||
->assertJsonPath('errors.0.detail', 'You cannot delete allocations for this server: no allocation limit is set.');
|
||||
|
||||
$allocation->refresh();
|
||||
$this->assertNotNull($allocation->notes);
|
||||
$this->assertEquals($server->id, $allocation->server_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that an allocation cannot be deleted if it does not belong to the server instance.
|
||||
*/
|
||||
public function test_error_is_returned_if_allocation_does_not_belong_to_server(): void
|
||||
{
|
||||
/** @var Server $server */
|
||||
[$user, $server] = $this->generateTestAccount();
|
||||
[, $server2] = $this->generateTestAccount();
|
||||
|
||||
$this->actingAs($user)->deleteJson($this->link($server2->allocation))->assertNotFound();
|
||||
$this->actingAs($user)->deleteJson($this->link($server, "/network/allocations/{$server2->allocation_id}"))->assertNotFound();
|
||||
}
|
||||
|
||||
public static function permissionDataProvider(): array
|
||||
{
|
||||
return [[[SubuserPermission::AllocationDelete]], [[]]];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests\Unit\Models;
|
||||
|
||||
use App\Models\Node;
|
||||
use App\Models\Server;
|
||||
use App\Tests\TestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class ServerTest extends TestCase
|
||||
{
|
||||
#[DataProvider('sftpUrlDataProvider')]
|
||||
public function test_sftp_url_points_at_the_given_directory(?string $directory, string $expectedPath): void
|
||||
{
|
||||
$server = $this->serverWithNode();
|
||||
|
||||
$this->assertSame("sftp://user.abcdefgh@node.example.com:2022{$expectedPath}", $server->getSftpUrl('user', $directory));
|
||||
}
|
||||
|
||||
public static function sftpUrlDataProvider(): array
|
||||
{
|
||||
return [
|
||||
'no directory' => [null, ''],
|
||||
'root' => ['/', ''],
|
||||
'single directory' => ['/data', '/data/'],
|
||||
'directory without a leading slash' => ['data', '/data/'],
|
||||
'directory with a trailing slash' => ['data/', '/data/'],
|
||||
'nested directory' => ['/data/world', '/data/world/'],
|
||||
'directory with encoded parts' => ['/data/my world', '/data/my%20world/'],
|
||||
];
|
||||
}
|
||||
|
||||
public function test_sftp_url_uses_the_node_sftp_alias_when_set(): void
|
||||
{
|
||||
$server = $this->serverWithNode(sftpAlias: 'sftp.example.com');
|
||||
|
||||
$this->assertSame('sftp://user.abcdefgh@sftp.example.com:2022/data/', $server->getSftpUrl('user', '/data'));
|
||||
}
|
||||
|
||||
public function test_sftp_url_encodes_the_username(): void
|
||||
{
|
||||
$server = $this->serverWithNode();
|
||||
|
||||
$this->assertSame('sftp://user%20name.abcdefgh@node.example.com:2022/data/', $server->getSftpUrl('user name', '/data'));
|
||||
}
|
||||
|
||||
private function serverWithNode(string $fqdn = 'node.example.com', ?string $sftpAlias = null): Server
|
||||
{
|
||||
$node = new Node();
|
||||
$node->fqdn = $fqdn;
|
||||
$node->daemon_sftp_alias = $sftpAlias;
|
||||
$node->daemon_sftp = 2022;
|
||||
|
||||
$server = new Server();
|
||||
$server->uuid_short = 'abcdefgh';
|
||||
$server->setRelation('node', $node);
|
||||
|
||||
return $server;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user