diff --git a/app/Services/Schedules/ScheduleUpdateService.php b/app/Services/Schedules/ScheduleUpdateService.php index fd29d9c2d..96da1b106 100644 --- a/app/Services/Schedules/ScheduleUpdateService.php +++ b/app/Services/Schedules/ScheduleUpdateService.php @@ -15,19 +15,22 @@ class ScheduleUpdateService * @var \Illuminate\Database\ConnectionInterface */ private $connection; + /** * @var \Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface */ private $repository; - /** - * @var \Pterodactyl\Contracts\Repository\TaskRepositoryInterface - */ - private $taskRepository; + /** * @var \Pterodactyl\Services\Schedules\Tasks\TaskCreationService */ private $taskCreationService; + /** + * @var \Pterodactyl\Contracts\Repository\TaskRepositoryInterface + */ + private $taskRepository; + /** * ScheduleUpdateService constructor. * diff --git a/app/Services/Servers/StartupCommandViewService.php b/app/Services/Servers/StartupCommandViewService.php index 14a4cc3c3..7895ec6dd 100644 --- a/app/Services/Servers/StartupCommandViewService.php +++ b/app/Services/Servers/StartupCommandViewService.php @@ -37,14 +37,15 @@ class StartupCommandViewService $server = $this->repository->getPrimaryAllocation($response->server); $find = ['{{SERVER_MEMORY}}', '{{SERVER_IP}}', '{{SERVER_PORT}}']; - $replace = [$server->memory, $server->allocation->ip, $server->allocation->port]; + $replace = [$server->memory, $server->getRelation('allocation')->ip, $server->getRelation('allocation')->port]; - $variables = $server->egg->variables->each(function ($variable) use (&$find, &$replace, $response) { - $find[] = '{{' . $variable->env_variable . '}}'; - $replace[] = $variable->user_viewable ? $response->data[$variable->env_variable] : '[hidden]'; - })->filter(function ($variable) { - return $variable->user_viewable === 1; - }); + $variables = $server->getRelation('egg')->getRelation('variables') + ->each(function ($variable) use (&$find, &$replace, $response) { + $find[] = '{{' . $variable->env_variable . '}}'; + $replace[] = $variable->user_viewable ? $response->data[$variable->env_variable] : '[hidden]'; + })->filter(function ($variable) { + return $variable->user_viewable === 1; + }); return collect([ 'startup' => str_replace($find, $replace, $server->startup), diff --git a/tests/Unit/Services/Acl/Api/AdminAclTest.php b/tests/Unit/Services/Acl/Api/AdminAclTest.php new file mode 100644 index 000000000..2f2f07641 --- /dev/null +++ b/tests/Unit/Services/Acl/Api/AdminAclTest.php @@ -0,0 +1,48 @@ +assertSame($outcome, AdminAcl::can($permission, $check)); + } + + /** + * Test that checking aganist a model works as expected. + */ + public function testCheck() + { + $model = factory(ApiKey::class)->make(['r_servers' => AdminAcl::READ | AdminAcl::WRITE]); + + $this->assertTrue(AdminAcl::check($model, AdminAcl::RESOURCE_SERVERS, AdminAcl::WRITE)); + } + + /** + * Provide valid and invalid permissions combos for testing. + * + * @return array + */ + public function permissionsDataProvider(): array + { + return [ + [AdminAcl::READ, AdminAcl::READ, true], + [AdminAcl::READ | AdminAcl::WRITE, AdminAcl::READ, true], + [AdminAcl::READ | AdminAcl::WRITE, AdminAcl::WRITE, true], + [AdminAcl::WRITE, AdminAcl::WRITE, true], + [AdminAcl::READ, AdminAcl::WRITE, false], + [AdminAcl::NONE, AdminAcl::READ, false], + [AdminAcl::NONE, AdminAcl::WRITE, false], + ]; + } +} diff --git a/tests/Unit/Services/Schedules/ScheduleUpdateServiceTest.php b/tests/Unit/Services/Schedules/ScheduleUpdateServiceTest.php new file mode 100644 index 000000000..3f26f69b9 --- /dev/null +++ b/tests/Unit/Services/Schedules/ScheduleUpdateServiceTest.php @@ -0,0 +1,97 @@ +connection = m::mock(ConnectionInterface::class); + $this->repository = m::mock(ScheduleRepositoryInterface::class); + $this->taskCreationService = m::mock(TaskCreationService::class); + $this->taskRepository = m::mock(TaskRepositoryInterface::class); + } + + /** + * Test that a schedule can be updated. + */ + public function testUpdate() + { + $schedule = factory(Schedule::class)->make(); + $tasks = [['action' => 'test-action']]; + $data = [ + 'cron_minute' => 1, + 'cron_hour' => 2, + 'cron_day_of_month' => 3, + 'cron_day_of_week' => 4, + 'next_run_at' => '_INVALID_VALUE', + ]; + + $this->connection->shouldReceive('beginTransaction')->once()->withNoArgs(); + $this->repository->shouldReceive('update')->once()->with($schedule->id, array_merge($data, [ + 'next_run_at' => CronExpression::factory('1 2 3 * 4 *')->getNextRunDate(), + ]))->andReturn($schedule); + + $this->taskRepository->shouldReceive('deleteWhere')->once()->with([['schedule_id', '=', $schedule->id]]); + $this->taskCreationService->shouldReceive('handle')->once()->with($schedule, m::subset([ + 'sequence_id' => 1, + 'action' => 'test-action', + ]), false); + + $this->connection->shouldReceive('commit')->once()->withNoArgs(); + + $response = $this->getService()->handle($schedule, $data, $tasks); + $this->assertInstanceOf(Schedule::class, $response); + $this->assertSame($schedule, $response); + } + + /** + * Return an instance of the service with mocked dependencies. + * + * @return \Pterodactyl\Services\Schedules\ScheduleUpdateService + */ + private function getService(): ScheduleUpdateService + { + return new ScheduleUpdateService( + $this->connection, + $this->repository, + $this->taskCreationService, + $this->taskRepository + ); + } +} diff --git a/tests/Unit/Services/Servers/StartupCommandViewServiceTest.php b/tests/Unit/Services/Servers/StartupCommandViewServiceTest.php new file mode 100644 index 000000000..12f71f134 --- /dev/null +++ b/tests/Unit/Services/Servers/StartupCommandViewServiceTest.php @@ -0,0 +1,85 @@ +repository = m::mock(ServerRepositoryInterface::class); + } + + /** + * Test that the correct startup string is returned. + */ + public function testServiceResponse() + { + $allocation = factory(Allocation::class)->make(); + $egg = factory(Egg::class)->make(); + $server = factory(Server::class)->make([ + 'startup' => 'example {{SERVER_MEMORY}} {{SERVER_IP}} {{SERVER_PORT}} {{TEST_VARIABLE}} {{TEST_VARIABLE_HIDDEN}} {{UNKNOWN}}', + ]); + + $variables = collect([ + factory(EggVariable::class)->make(['env_variable' => 'TEST_VARIABLE', 'user_viewable' => 1]), + factory(EggVariable::class)->make(['env_variable' => 'TEST_VARIABLE_HIDDEN', 'user_viewable' => 0]), + ]); + + $egg->setRelation('variables', $variables); + $server->setRelation('allocation', $allocation); + $server->setRelation('egg', $egg); + + $this->repository->shouldReceive('getVariablesWithValues')->once()->with($server->id, true)->andReturn((object) [ + 'data' => [ + 'TEST_VARIABLE' => 'Test Value', + 'TEST_VARIABLE_HIDDEN' => 'Hidden Value', + ], + 'server' => $server, + ]); + + $this->repository->shouldReceive('getPrimaryAllocation')->once()->with($server)->andReturn($server); + + $response = $this->getService()->handle($server->id); + $this->assertInstanceOf(Collection::class, $response); + + $this->assertSame( + sprintf('example %s %s %s %s %s {{UNKNOWN}}', $server->memory, $allocation->ip, $allocation->port, 'Test Value', '[hidden]'), + $response->get('startup') + ); + $this->assertEquals($variables->only(0), $response->get('variables')); + $this->assertSame([ + 'TEST_VARIABLE' => 'Test Value', + 'TEST_VARIABLE_HIDDEN' => 'Hidden Value', + ], $response->get('server_values')); + } + + /** + * Return an instance of the service with mocked dependencies. + * + * @return \Pterodactyl\Services\Servers\StartupCommandViewService + */ + private function getService(): StartupCommandViewService + { + return new StartupCommandViewService($this->repository); + } +}