<?php namespace Pterodactyl\Tests\Integration\Api\Client\Server; use Mockery; use Illuminate\Http\Response; use Pterodactyl\Models\Permission; use Pterodactyl\Repositories\Wings\DaemonPowerRepository; use Pterodactyl\Tests\Integration\Api\Client\ClientApiIntegrationTestCase; class PowerControllerTest extends ClientApiIntegrationTestCase { /** * Test that a subuser without permission to send a command to the server receives * an error in response. This checks against the specific permission needed to send * the command to the server. * * @param string[] $permissions * @dataProvider invalidPermissionDataProvider */ public function testSubuserWithoutPermissionsReceivesError(string $action, array $permissions) { [$user, $server] = $this->generateTestAccount($permissions); $this->actingAs($user) ->postJson("/api/client/servers/{$server->uuid}/power", ['signal' => $action]) ->assertStatus(Response::HTTP_FORBIDDEN); } /** * Test that sending an invalid power signal returns an error. */ public function testInvalidPowerSignalResultsInError() { [$user, $server] = $this->generateTestAccount(); $response = $this->actingAs($user)->postJson("/api/client/servers/{$server->uuid}/power", [ 'signal' => 'invalid', ]); $response->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY); $response->assertJsonPath('errors.0.meta.rule', 'in'); $response->assertJsonPath('errors.0.detail', 'The selected signal is invalid.'); } /** * Test that sending a valid power actions works. * * @dataProvider validPowerActionDataProvider */ public function testActionCanBeSentToServer(string $action, string $permission) { $service = Mockery::mock(DaemonPowerRepository::class); $this->app->instance(DaemonPowerRepository::class, $service); [$user, $server] = $this->generateTestAccount([$permission]); $service->expects('setServer') ->with(Mockery::on(function ($value) use ($server) { return $server->uuid === $value->uuid; })) ->andReturnSelf() ->getMock() ->expects('send') ->with(trim($action)); $this->actingAs($user) ->postJson("/api/client/servers/{$server->uuid}/power", ['signal' => $action]) ->assertStatus(Response::HTTP_NO_CONTENT); } /** * Returns invalid permission combinations for a given power action. */ public function invalidPermissionDataProvider(): array { return [ ['start', [Permission::ACTION_CONTROL_STOP, Permission::ACTION_CONTROL_RESTART]], ['stop', [Permission::ACTION_CONTROL_START]], ['kill', [Permission::ACTION_CONTROL_START, Permission::ACTION_CONTROL_RESTART]], ['restart', [Permission::ACTION_CONTROL_STOP, Permission::ACTION_CONTROL_START]], ['random', [Permission::ACTION_CONTROL_START]], ]; } public function validPowerActionDataProvider(): array { return [ ['start', Permission::ACTION_CONTROL_START], ['stop', Permission::ACTION_CONTROL_STOP], ['restart', Permission::ACTION_CONTROL_RESTART], ['kill', Permission::ACTION_CONTROL_STOP], // Yes, these spaces are intentional. You should be able to send values with or without // a space on the start/end since we should be trimming the values. [' restart', Permission::ACTION_CONTROL_RESTART], ['kill ', Permission::ACTION_CONTROL_STOP], ]; } }