diff --git a/.env.example b/.env.example index 9062de215..67d496d47 100644 --- a/.env.example +++ b/.env.example @@ -19,8 +19,8 @@ HASHIDS_SALT= HASHIDS_LENGTH=8 MAIL_DRIVER=smtp -MAIL_HOST=mailtrap.io -MAIL_PORT=2525 +MAIL_HOST=smtp.example.com +MAIL_PORT=25 MAIL_USERNAME= MAIL_PASSWORD= MAIL_ENCRYPTION=tls diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 1f83ddf93..4fa0845e5 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -25,11 +25,13 @@ class Kernel extends ConsoleKernel // Execute scheduled commands for servers every minute, as if there was a normal cron running. $schedule->command('p:schedule:process')->everyMinute()->withoutOverlapping(); - // Every 30 minutes, run the backup pruning command so that any abandoned backups can be removed - // from the UI view for the server. - $schedule->command('p:maintenance:prune-backups', [ - '--since-minutes' => '30', - ])->everyThirtyMinutes(); + // Every 30 minutes, run the backup pruning command so that any abandoned backups can be deleted. + $pruneAge = config('backups.prune_age', 360); // Defaults to 6 hours (time is in minuteS) + if ($pruneAge > 0) { + $schedule->command('p:maintenance:prune-backups', [ + '--since-minutes' => $pruneAge, + ])->everyThirtyMinutes(); + } // Every day cleanup any internal backups of service files. $schedule->command('p:maintenance:clean-service-backups')->daily(); diff --git a/app/Http/Controllers/Api/Client/Servers/FileController.php b/app/Http/Controllers/Api/Client/Servers/FileController.php index 961b7cd02..317115b29 100644 --- a/app/Http/Controllers/Api/Client/Servers/FileController.php +++ b/app/Http/Controllers/Api/Client/Servers/FileController.php @@ -13,6 +13,7 @@ use Pterodactyl\Repositories\Wings\DaemonFileRepository; use Pterodactyl\Transformers\Daemon\FileObjectTransformer; use Pterodactyl\Http\Controllers\Api\Client\ClientApiController; use Pterodactyl\Http\Requests\Api\Client\Servers\Files\CopyFileRequest; +use Pterodactyl\Http\Requests\Api\Client\Servers\Files\PullFileRequest; use Pterodactyl\Http\Requests\Api\Client\Servers\Files\ListFilesRequest; use Pterodactyl\Http\Requests\Api\Client\Servers\Files\DeleteFileRequest; use Pterodactyl\Http\Requests\Api\Client\Servers\Files\RenameFileRequest; @@ -143,10 +144,7 @@ class FileController extends ClientApiController */ public function write(WriteFileContentRequest $request, Server $server): JsonResponse { - $this->fileRepository->setServer($server)->putContent( - $this->encode($request->get('file')), - $request->getContent() - ); + $this->fileRepository->setServer($server)->putContent($request->get('file'), $request->getContent()); return new JsonResponse([], Response::HTTP_NO_CONTENT); } @@ -284,16 +282,18 @@ class FileController extends ClientApiController } /** - * Encodes a given file name & path in a format that should work for a good majority - * of file names without too much confusing logic. + * Requests that a file be downloaded from a remote location by Wings. * - * @param string $path - * @return string + * @param $request + * @param \Pterodactyl\Models\Server $server + * @return \Illuminate\Http\JsonResponse + * + * @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException */ - private function encode(string $path): string + public function pull(PullFileRequest $request, Server $server): JsonResponse { - return Collection::make(explode('/', rawurldecode($path)))->map(function ($value) { - return rawurlencode($value); - })->join('/'); + $this->fileRepository->setServer($server)->pull($request->input('url'), $request->input('directory')); + + return new JsonResponse([], Response::HTTP_NO_CONTENT); } } diff --git a/app/Http/Controllers/Api/Remote/Backups/BackupRemoteUploadController.php b/app/Http/Controllers/Api/Remote/Backups/BackupRemoteUploadController.php index 497d12904..6d50ad64d 100644 --- a/app/Http/Controllers/Api/Remote/Backups/BackupRemoteUploadController.php +++ b/app/Http/Controllers/Api/Remote/Backups/BackupRemoteUploadController.php @@ -52,7 +52,7 @@ class BackupRemoteUploadController extends Controller public function __invoke(Request $request, string $backup) { // Get the size query parameter. - $size = (int)$request->query('size'); + $size = (int) $request->query('size'); if (empty($size)) { throw new BadRequestHttpException('A non-empty "size" query parameter must be provided.'); } diff --git a/app/Http/Requests/Api/Client/Servers/Files/PullFileRequest.php b/app/Http/Requests/Api/Client/Servers/Files/PullFileRequest.php new file mode 100644 index 000000000..02a2fd376 --- /dev/null +++ b/app/Http/Requests/Api/Client/Servers/Files/PullFileRequest.php @@ -0,0 +1,29 @@ + 'required|string|url', + 'directory' => 'sometimes|nullable|string', + ]; + } +} diff --git a/app/Repositories/Wings/DaemonBackupRepository.php b/app/Repositories/Wings/DaemonBackupRepository.php index 6506ac8a2..0eb9d4792 100644 --- a/app/Repositories/Wings/DaemonBackupRepository.php +++ b/app/Repositories/Wings/DaemonBackupRepository.php @@ -2,6 +2,7 @@ namespace Pterodactyl\Repositories\Wings; +use Illuminate\Support\Arr; use Webmozart\Assert\Assert; use Pterodactyl\Models\Backup; use Pterodactyl\Models\Server; @@ -48,7 +49,7 @@ class DaemonBackupRepository extends DaemonRepository 'json' => [ 'adapter' => $this->adapter ?? config('backups.default'), 'uuid' => $backup->uuid, - 'ignored_files' => $backup->ignored_files, + 'ignore' => implode('\n', $backup->ignored_files), ], ] ); diff --git a/app/Repositories/Wings/DaemonFileRepository.php b/app/Repositories/Wings/DaemonFileRepository.php index c36a8abb0..da6cb7ae2 100644 --- a/app/Repositories/Wings/DaemonFileRepository.php +++ b/app/Repositories/Wings/DaemonFileRepository.php @@ -37,7 +37,7 @@ class DaemonFileRepository extends DaemonRepository throw new DaemonConnectionException($exception); } - $length = (int) $response->getHeader('Content-Length')[0] ?? 0; + $length = (int)$response->getHeader('Content-Length')[0] ?? 0; if ($notLargerThan && $length > $notLargerThan) { throw new FileSizeTooLargeException; @@ -297,4 +297,29 @@ class DaemonFileRepository extends DaemonRepository throw new DaemonConnectionException($exception); } } + + /** + * Pulls a file from the given URL and saves it to the disk. + * + * @param string $url + * @param string|null $directory + * @return \Psr\Http\Message\ResponseInterface + * + * @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException + */ + public function pull(string $url, ?string $directory): ResponseInterface + { + Assert::isInstanceOf($this->server, Server::class); + + try { + return $this->getHttpClient()->post( + sprintf('/api/servers/%s/files/pull', $this->server->uuid), + [ + 'json' => ['url' => $url, 'directory' => $directory ?? '/'], + ] + ); + } catch (TransferException $exception) { + throw new DaemonConnectionException($exception); + } + } } diff --git a/app/Services/Backups/InitiateBackupService.php b/app/Services/Backups/InitiateBackupService.php index 0857478ba..615f357ce 100644 --- a/app/Services/Backups/InitiateBackupService.php +++ b/app/Services/Backups/InitiateBackupService.php @@ -117,9 +117,9 @@ class InitiateBackupService } // Check if the server has reached or exceeded it's backup limit - if (!$server->backup_limit || $server->backups()->where('is_successful', true)->count() >= $server->backup_limit) { + if (! $server->backup_limit || $server->backups()->where('is_successful', true)->count() >= $server->backup_limit) { // Do not allow the user to continue if this server is already at its limit and can't override. - if (!$override || $server->backup_limit <= 0) { + if (! $override || $server->backup_limit <= 0) { throw new TooManyBackupsException($server->backup_limit); } diff --git a/config/backups.php b/config/backups.php index 32ee1aa8a..a309a9ee6 100644 --- a/config/backups.php +++ b/config/backups.php @@ -12,6 +12,10 @@ return [ // uses to upload backups to S3 storage. Value is in minutes, so this would default to an hour. 'presigned_url_lifespan' => env('BACKUP_PRESIGNED_URL_LIFESPAN', 60), + // The time to wait before automatically failing a backup, time is in minutes and defaults + // to 6 hours. To disable this feature, set the value to `0`. + 'prune_age' => env('BACKUP_PRUNE_AGE', 360), + 'disks' => [ // There is no configuration for the local disk for Wings. That configuration // is determined by the Daemon configuration, and not the Panel. diff --git a/database/seeds/eggs/minecraft/egg-sponge--sponge-vanilla.json b/database/seeds/eggs/minecraft/egg-sponge--sponge-vanilla.json index 0a695ac2e..db3f7fc94 100644 --- a/database/seeds/eggs/minecraft/egg-sponge--sponge-vanilla.json +++ b/database/seeds/eggs/minecraft/egg-sponge--sponge-vanilla.json @@ -28,7 +28,7 @@ "name": "Sponge Version", "description": "The version of SpongeVanilla to download and use.", "env_variable": "SPONGE_VERSION", - "default_value": "1.11.2-6.1.0-BETA-21", + "default_value": "1.12.2-7.3.0", "user_viewable": true, "user_editable": false, "rules": "required|regex:\/^([a-zA-Z0-9.\\-_]+)$\/" diff --git a/resources/scripts/components/server/databases/DatabaseRow.tsx b/resources/scripts/components/server/databases/DatabaseRow.tsx index caf4a702e..148415a13 100644 --- a/resources/scripts/components/server/databases/DatabaseRow.tsx +++ b/resources/scripts/components/server/databases/DatabaseRow.tsx @@ -127,7 +127,7 @@ export default ({ database, className }: Props) => {
- +
diff --git a/routes/api-client.php b/routes/api-client.php index 320c8ec55..62cad21c1 100644 --- a/routes/api-client.php +++ b/routes/api-client.php @@ -66,6 +66,7 @@ Route::group(['prefix' => '/servers/{server}', 'middleware' => [AuthenticateServ Route::post('/delete', 'Servers\FileController@delete'); Route::post('/create-folder', 'Servers\FileController@create'); Route::post('/chmod', 'Servers\FileController@chmod'); + Route::post('/pull', 'Servers\FileController@pull'); Route::get('/upload', 'Servers\FileUploadController'); }); diff --git a/tests/Unit/Commands/CommandTestCase.php b/tests/Unit/Commands/CommandTestCase.php deleted file mode 100644 index 7786a4dcf..000000000 --- a/tests/Unit/Commands/CommandTestCase.php +++ /dev/null @@ -1,59 +0,0 @@ -. - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ - -namespace Tests\Unit\Commands; - -use Tests\TestCase; -use Illuminate\Console\Command; -use Illuminate\Contracts\Foundation\Application; -use Symfony\Component\Console\Tester\CommandTester; - -abstract class CommandTestCase extends TestCase -{ - /** - * @var bool - */ - protected $commandIsInteractive = true; - - /** - * Set a command to be non-interactive for testing purposes. - * - * @return $this - */ - public function withoutInteraction() - { - $this->commandIsInteractive = false; - - return $this; - } - - /** - * Return the display from running a command. - * - * @param \Illuminate\Console\Command $command - * @param array $args - * @param array $inputs - * @param array $opts - * @return string - */ - protected function runCommand(Command $command, array $args = [], array $inputs = [], array $opts = []) - { - if (! $command->getLaravel() instanceof Application) { - $command->setLaravel($this->app); - } - - $response = new CommandTester($command); - $response->setInputs($inputs); - - $opts = array_merge($opts, ['interactive' => $this->commandIsInteractive]); - $response->execute($args, $opts); - - return $response->getDisplay(); - } -} diff --git a/tests/Unit/Commands/Environment/EmailSettingsCommandTest.php b/tests/Unit/Commands/Environment/EmailSettingsCommandTest.php deleted file mode 100644 index 6c071124a..000000000 --- a/tests/Unit/Commands/Environment/EmailSettingsCommandTest.php +++ /dev/null @@ -1,275 +0,0 @@ -config = m::mock(Repository::class); - $this->command = m::mock(EmailSettingsCommand::class . '[call, writeToEnvironment]', [$this->config]); - $this->command->setLaravel($this->app); - } - - /** - * Test selection of the SMTP driver with no options passed. - */ - public function testSmtpDriverSelection() - { - // TODO(dane): fix this - $this->markTestSkipped('Skipped, GitHub actions cannot run successfully.'); -// $data = [ -// 'MAIL_DRIVER' => 'smtp', -// 'MAIL_HOST' => 'mail.test.com', -// 'MAIL_PORT' => '567', -// 'MAIL_USERNAME' => 'username', -// 'MAIL_PASSWORD' => 'password', -// 'MAIL_FROM' => 'mail@from.com', -// 'MAIL_FROM_NAME' => 'MailName', -// 'MAIL_ENCRYPTION' => 'tls', -// ]; -// -// $this->setupCoreFunctions($data); -// $display = $this->runCommand($this->command, [], array_values($data)); -// -// $this->assertNotEmpty($display); -// $this->assertStringContainsString('Updating stored environment configuration file.', $display); - } - - /** - * Test that the command can run when all variables are passed in as options. - */ - public function testSmtpDriverSelectionWithOptionsPassed() - { - $data = [ - 'MAIL_DRIVER' => 'smtp', - 'MAIL_HOST' => 'mail.test.com', - 'MAIL_PORT' => '567', - 'MAIL_USERNAME' => 'username', - 'MAIL_PASSWORD' => 'password', - 'MAIL_FROM' => 'mail@from.com', - 'MAIL_FROM_NAME' => 'MailName', - 'MAIL_ENCRYPTION' => 'tls', - ]; - - $this->setupCoreFunctions($data); - $display = $this->withoutInteraction()->runCommand($this->command, [ - '--driver' => $data['MAIL_DRIVER'], - '--email' => $data['MAIL_FROM'], - '--from' => $data['MAIL_FROM_NAME'], - '--encryption' => $data['MAIL_ENCRYPTION'], - '--host' => $data['MAIL_HOST'], - '--port' => $data['MAIL_PORT'], - '--username' => $data['MAIL_USERNAME'], - '--password' => $data['MAIL_PASSWORD'], - ]); - - $this->assertNotEmpty($display); - $this->assertStringContainsString('Updating stored environment configuration file.', $display); - } - - /** - * Test selection of PHP mail() as the driver. - */ - public function testPHPMailDriverSelection() - { - $data = [ - 'MAIL_DRIVER' => 'mail', - 'MAIL_FROM' => 'mail@from.com', - 'MAIL_FROM_NAME' => 'MailName', - 'MAIL_ENCRYPTION' => 'tls', - ]; - - $this->setupCoreFunctions($data); - - // The driver flag is passed because there seems to be some issue with the command tester - // when using a choice() method when two keys start with the same letters. - // - // In this case, mail and mailgun. - unset($data['MAIL_DRIVER']); - $display = $this->runCommand($this->command, ['--driver' => 'mail'], array_values($data)); - - $this->assertNotEmpty($display); - $this->assertStringContainsString('Updating stored environment configuration file.', $display); - } - - /** - * Test selection of the Mailgun driver with no options passed. - */ - public function testMailgunDriverSelection() - { - $data = [ - 'MAIL_DRIVER' => 'mailgun', - 'MAILGUN_DOMAIN' => 'domain.com', - 'MAILGUN_SECRET' => '123456', - 'MAIL_FROM' => 'mail@from.com', - 'MAIL_FROM_NAME' => 'MailName', - 'MAIL_ENCRYPTION' => 'tls', - ]; - - $this->setupCoreFunctions($data); - $display = $this->runCommand($this->command, [], array_values($data)); - - $this->assertNotEmpty($display); - $this->assertStringContainsString('Updating stored environment configuration file.', $display); - } - - /** - * Test mailgun driver selection when variables are passed as options. - */ - public function testMailgunDriverSelectionWithOptionsPassed() - { - $data = [ - 'MAIL_DRIVER' => 'mailgun', - 'MAILGUN_DOMAIN' => 'domain.com', - 'MAILGUN_SECRET' => '123456', - 'MAIL_FROM' => 'mail@from.com', - 'MAIL_FROM_NAME' => 'MailName', - 'MAIL_ENCRYPTION' => 'tls', - ]; - - $this->setupCoreFunctions($data); - $display = $this->withoutInteraction()->runCommand($this->command, [ - '--driver' => $data['MAIL_DRIVER'], - '--email' => $data['MAIL_FROM'], - '--from' => $data['MAIL_FROM_NAME'], - '--encryption' => $data['MAIL_ENCRYPTION'], - '--host' => $data['MAILGUN_DOMAIN'], - '--password' => $data['MAILGUN_SECRET'], - ]); - - $this->assertNotEmpty($display); - $this->assertStringContainsString('Updating stored environment configuration file.', $display); - } - - /** - * Test selection of the Mandrill driver with no options passed. - */ - public function testMandrillDriverSelection() - { - $data = [ - 'MAIL_DRIVER' => 'mandrill', - 'MANDRILL_SECRET' => '123456', - 'MAIL_FROM' => 'mail@from.com', - 'MAIL_FROM_NAME' => 'MailName', - 'MAIL_ENCRYPTION' => 'tls', - ]; - - $this->setupCoreFunctions($data); - $display = $this->runCommand($this->command, [], array_values($data)); - - $this->assertNotEmpty($display); - $this->assertStringContainsString('Updating stored environment configuration file.', $display); - } - - /** - * Test mandrill driver selection when variables are passed as options. - */ - public function testMandrillDriverSelectionWithOptionsPassed() - { - $data = [ - 'MAIL_DRIVER' => 'mandrill', - 'MANDRILL_SECRET' => '123456', - 'MAIL_FROM' => 'mail@from.com', - 'MAIL_FROM_NAME' => 'MailName', - 'MAIL_ENCRYPTION' => 'tls', - ]; - - $this->setupCoreFunctions($data); - $display = $this->withoutInteraction()->runCommand($this->command, [ - '--driver' => $data['MAIL_DRIVER'], - '--email' => $data['MAIL_FROM'], - '--from' => $data['MAIL_FROM_NAME'], - '--encryption' => $data['MAIL_ENCRYPTION'], - '--password' => $data['MANDRILL_SECRET'], - ]); - - $this->assertNotEmpty($display); - $this->assertStringContainsString('Updating stored environment configuration file.', $display); - } - - /** - * Test selection of the Postmark driver with no options passed. - */ - public function testPostmarkDriverSelection() - { - $data = [ - 'MAIL_DRIVER' => 'smtp', - 'MAIL_HOST' => 'smtp.postmarkapp.com', - 'MAIL_PORT' => '587', - 'MAIL_USERNAME' => '123456', - 'MAIL_PASSWORD' => '123456', - 'MAIL_FROM' => 'mail@from.com', - 'MAIL_FROM_NAME' => 'MailName', - 'MAIL_ENCRYPTION' => 'tls', - ]; - - $this->setupCoreFunctions($data); - $display = $this->runCommand($this->command, [], [ - 'postmark', '123456', $data['MAIL_FROM'], $data['MAIL_FROM_NAME'], $data['MAIL_ENCRYPTION'], - ]); - - $this->assertNotEmpty($display); - $this->assertStringContainsString('Updating stored environment configuration file.', $display); - } - - /** - * Test postmark driver selection when variables are passed as options. - */ - public function testPostmarkDriverSelectionWithOptionsPassed() - { - $data = [ - 'MAIL_DRIVER' => 'smtp', - 'MAIL_HOST' => 'smtp.postmarkapp.com', - 'MAIL_PORT' => '587', - 'MAIL_USERNAME' => '123456', - 'MAIL_PASSWORD' => '123456', - 'MAIL_FROM' => 'mail@from.com', - 'MAIL_FROM_NAME' => 'MailName', - 'MAIL_ENCRYPTION' => 'tls', - ]; - - $this->setupCoreFunctions($data); - $display = $this->withoutInteraction()->runCommand($this->command, [ - '--driver' => 'postmark', - '--email' => $data['MAIL_FROM'], - '--from' => $data['MAIL_FROM_NAME'], - '--encryption' => $data['MAIL_ENCRYPTION'], - '--username' => $data['MAIL_USERNAME'], - ]); - - $this->assertNotEmpty($display); - $this->assertStringContainsString('Updating stored environment configuration file.', $display); - } - - /** - * Setup the core functions that are repeated across all of these tests. - * - * @param array $data - */ - private function setupCoreFunctions(array $data) - { - $this->config->shouldReceive('get')->withAnyArgs()->zeroOrMoreTimes()->andReturnNull(); - $this->command->shouldReceive('writeToEnvironment')->with($data)->once()->andReturnNull(); - } -} diff --git a/tests/Unit/Commands/Location/DeleteLocationCommandTest.php b/tests/Unit/Commands/Location/DeleteLocationCommandTest.php deleted file mode 100644 index 26bd73319..000000000 --- a/tests/Unit/Commands/Location/DeleteLocationCommandTest.php +++ /dev/null @@ -1,128 +0,0 @@ -. - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ - -namespace Tests\Unit\Commands\Location; - -use Mockery as m; -use Pterodactyl\Models\Location; -use Tests\Unit\Commands\CommandTestCase; -use Pterodactyl\Services\Locations\LocationDeletionService; -use Pterodactyl\Console\Commands\Location\DeleteLocationCommand; -use Pterodactyl\Contracts\Repository\LocationRepositoryInterface; - -class DeleteLocationCommandTest extends CommandTestCase -{ - /** - * @var \Pterodactyl\Console\Commands\Location\DeleteLocationCommand - */ - protected $command; - - /** - * @var \Pterodactyl\Services\Locations\LocationDeletionService|\Mockery\Mock - */ - protected $deletionService; - - /** - * @var \Pterodactyl\Contracts\Repository\LocationRepositoryInterface|\Mockery\Mock - */ - protected $repository; - - /** - * Setup tests. - */ - public function setUp(): void - { - parent::setUp(); - - $this->deletionService = m::mock(LocationDeletionService::class); - $this->repository = m::mock(LocationRepositoryInterface::class); - - $this->command = new DeleteLocationCommand($this->deletionService, $this->repository); - $this->command->setLaravel($this->app); - } - - /** - * Test that a location can be deleted. - */ - public function testLocationIsDeleted() - { - $locations = collect([ - $location1 = factory(Location::class)->make(), - $location2 = factory(Location::class)->make(), - ]); - - $this->repository->shouldReceive('all')->withNoArgs()->once()->andReturn($locations); - $this->deletionService->shouldReceive('handle')->with($location2->id)->once()->andReturnNull(); - - $display = $this->runCommand($this->command, [], [$location2->short]); - - $this->assertNotEmpty($display); - $this->assertStringContainsString(trans('command/messages.location.deleted'), $display); - } - - /** - * Test that a location is deleted if passed in as an option. - */ - public function testLocationIsDeletedIfPassedInOption() - { - $locations = collect([ - $location1 = factory(Location::class)->make(), - $location2 = factory(Location::class)->make(), - ]); - - $this->repository->shouldReceive('all')->withNoArgs()->once()->andReturn($locations); - $this->deletionService->shouldReceive('handle')->with($location2->id)->once()->andReturnNull(); - - $display = $this->withoutInteraction()->runCommand($this->command, [ - '--short' => $location2->short, - ]); - - $this->assertNotEmpty($display); - $this->assertStringContainsString(trans('command/messages.location.deleted'), $display); - } - - /** - * Test that prompt shows back up if the user enters the wrong parameters. - */ - public function testInteractiveEnvironmentAllowsReAttemptingSearch() - { - $locations = collect([ - $location1 = factory(Location::class)->make(), - $location2 = factory(Location::class)->make(), - ]); - - $this->repository->shouldReceive('all')->withNoArgs()->once()->andReturn($locations); - $this->deletionService->shouldReceive('handle')->with($location2->id)->once()->andReturnNull(); - - $display = $this->runCommand($this->command, [], ['123_not_exist', 'another_not_exist', $location2->short]); - - $this->assertNotEmpty($display); - $this->assertStringContainsString(trans('command/messages.location.no_location_found'), $display); - $this->assertStringContainsString(trans('command/messages.location.deleted'), $display); - } - - /** - * Test that no re-attempt is performed in a non-interactive environment. - */ - public function testNonInteractiveEnvironmentThrowsErrorIfNoLocationIsFound() - { - $locations = collect([ - $location1 = factory(Location::class)->make(), - $location2 = factory(Location::class)->make(), - ]); - - $this->repository->shouldReceive('all')->withNoArgs()->once()->andReturn($locations); - $this->deletionService->shouldNotReceive('handle'); - - $display = $this->withoutInteraction()->runCommand($this->command, ['--short' => 'randomTestString']); - - $this->assertNotEmpty($display); - $this->assertStringContainsString(trans('command/messages.location.no_location_found'), $display); - } -} diff --git a/tests/Unit/Commands/Location/MakeLocationCommandTest.php b/tests/Unit/Commands/Location/MakeLocationCommandTest.php deleted file mode 100644 index 6b628a6f0..000000000 --- a/tests/Unit/Commands/Location/MakeLocationCommandTest.php +++ /dev/null @@ -1,87 +0,0 @@ -. - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ - -namespace Tests\Unit\Commands\Location; - -use Mockery as m; -use Pterodactyl\Models\Location; -use Tests\Unit\Commands\CommandTestCase; -use Pterodactyl\Services\Locations\LocationCreationService; -use Pterodactyl\Console\Commands\Location\MakeLocationCommand; - -class MakeLocationCommandTest extends CommandTestCase -{ - /** - * @var \Pterodactyl\Console\Commands\Location\MakeLocationCommand - */ - protected $command; - - /** - * @var \Pterodactyl\Services\Locations\LocationCreationService|\Mockery\Mock - */ - protected $creationService; - - /** - * Setup tests. - */ - public function setUp(): void - { - parent::setUp(); - - $this->creationService = m::mock(LocationCreationService::class); - - $this->command = new MakeLocationCommand($this->creationService); - $this->command->setLaravel($this->app); - } - - /** - * Test that a location can be created when no options are passed. - */ - public function testLocationIsCreatedWithNoOptionsPassed() - { - $location = factory(Location::class)->make(); - - $this->creationService->shouldReceive('handle')->with([ - 'short' => $location->short, - 'long' => $location->long, - ])->once()->andReturn($location); - - $display = $this->runCommand($this->command, [], [$location->short, $location->long]); - - $this->assertNotEmpty($display); - $this->assertStringContainsString(trans('command/messages.location.created', [ - 'name' => $location->short, - 'id' => $location->id, - ]), $display); - } - - /** - * Test that a location is created when options are passed. - */ - public function testLocationIsCreatedWhenOptionsArePassed() - { - $location = factory(Location::class)->make(); - - $this->creationService->shouldReceive('handle')->with([ - 'short' => $location->short, - 'long' => $location->long, - ])->once()->andReturn($location); - - $display = $this->withoutInteraction()->runCommand($this->command, [ - '--short' => $location->short, - '--long' => $location->long, - ]); - - $this->assertNotEmpty($display); - $this->assertStringContainsString(trans('command/messages.location.created', [ - 'name' => $location->short, - 'id' => $location->id, - ]), $display); - } -} diff --git a/tests/Unit/Commands/Maintenance/CleanServiceBackupFilesCommandTest.php b/tests/Unit/Commands/Maintenance/CleanServiceBackupFilesCommandTest.php deleted file mode 100644 index ecb412e52..000000000 --- a/tests/Unit/Commands/Maintenance/CleanServiceBackupFilesCommandTest.php +++ /dev/null @@ -1,87 +0,0 @@ -disk = m::mock(Filesystem::class); - $this->filesystem = m::mock(Factory::class); - $this->filesystem->shouldReceive('disk')->withNoArgs()->once()->andReturn($this->disk); - } - - /** - * Test that a file is deleted if it is > 5min old. - */ - public function testCommandCleansFilesMoreThan5MinutesOld() - { - $file = new SplFileInfo('testfile.txt'); - - $this->disk->shouldReceive('files')->with('services/.bak')->once()->andReturn([$file]); - $this->disk->shouldReceive('lastModified')->with($file->getPath())->once()->andReturn(Carbon::now()->subDays(100)->getTimestamp()); - $this->disk->shouldReceive('delete')->with($file->getPath())->once()->andReturnNull(); - - $display = $this->runCommand($this->getCommand()); - - $this->assertNotEmpty($display); - $this->assertStringContainsString(trans('command/messages.maintenance.deleting_service_backup', ['file' => 'testfile.txt']), $display); - } - - /** - * Test that a file isn't deleted if it is < 5min old. - */ - public function testCommandDoesNotCleanFileLessThan5MinutesOld() - { - $file = new SplFileInfo('testfile.txt'); - - $this->disk->shouldReceive('files')->with('services/.bak')->once()->andReturn([$file]); - $this->disk->shouldReceive('lastModified')->with($file->getPath())->once()->andReturn(Carbon::now()->getTimestamp()); - - $display = $this->runCommand($this->getCommand()); - - $this->assertEmpty($display); - } - - /** - * Return an instance of the command for testing. - * - * @return \Pterodactyl\Console\Commands\Maintenance\CleanServiceBackupFilesCommand - */ - private function getCommand(): CleanServiceBackupFilesCommand - { - $command = new CleanServiceBackupFilesCommand($this->filesystem); - $command->setLaravel($this->app); - - return $command; - } -} diff --git a/tests/Unit/Commands/User/DisableTwoFactorCommandTest.php b/tests/Unit/Commands/User/DisableTwoFactorCommandTest.php deleted file mode 100644 index f2868883d..000000000 --- a/tests/Unit/Commands/User/DisableTwoFactorCommandTest.php +++ /dev/null @@ -1,83 +0,0 @@ -. - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ - -namespace Tests\Unit\Commands\User; - -use Mockery as m; -use Pterodactyl\Models\User; -use Tests\Unit\Commands\CommandTestCase; -use Pterodactyl\Contracts\Repository\UserRepositoryInterface; -use Pterodactyl\Console\Commands\User\DisableTwoFactorCommand; - -class DisableTwoFactorCommandTest extends CommandTestCase -{ - /** - * @var \Pterodactyl\Console\Commands\User\DisableTwoFactorCommand - */ - protected $command; - - /** - * @var \Pterodactyl\Contracts\Repository\UserRepositoryInterface|\Mockery\Mock - */ - protected $repository; - - /** - * Setup tests. - */ - public function setUp(): void - { - parent::setUp(); - - $this->repository = m::mock(UserRepositoryInterface::class); - - $this->command = new DisableTwoFactorCommand($this->repository); - $this->command->setLaravel($this->app); - } - - /** - * Test 2-factor auth is disabled when no option is passed. - */ - public function testTwoFactorIsDisabledWhenNoOptionIsPassed() - { - $user = factory(User::class)->make(); - - $this->repository->shouldReceive('setColumns')->with(['id', 'email'])->once()->andReturnSelf() - ->shouldReceive('findFirstWhere')->with([['email', '=', $user->email]])->once()->andReturn($user); - $this->repository->shouldReceive('withoutFreshModel')->withNoArgs()->once()->andReturnSelf() - ->shouldReceive('update')->with($user->id, [ - 'use_totp' => false, - 'totp_secret' => null, - ])->once()->andReturnNull(); - - $display = $this->runCommand($this->command, [], [$user->email]); - - $this->assertNotEmpty($display); - $this->assertStringContainsString(trans('command/messages.user.2fa_disabled', ['email' => $user->email]), $display); - } - - /** - * Test 2-factor auth is disabled when user is passed in option. - */ - public function testTwoFactorIsDisabledWhenOptionIsPassed() - { - $user = factory(User::class)->make(); - - $this->repository->shouldReceive('setColumns')->with(['id', 'email'])->once()->andReturnSelf() - ->shouldReceive('findFirstWhere')->with([['email', '=', $user->email]])->once()->andReturn($user); - $this->repository->shouldReceive('withoutFreshModel')->withNoArgs()->once()->andReturnSelf() - ->shouldReceive('update')->with($user->id, [ - 'use_totp' => false, - 'totp_secret' => null, - ])->once()->andReturnNull(); - - $display = $this->withoutInteraction()->runCommand($this->command, ['--email' => $user->email]); - $this->assertNotEmpty($display); - $this->assertStringContainsString(trans('command/messages.user.2fa_disabled', ['email' => $user->email]), $display); - } -} diff --git a/tests/Unit/Commands/User/MakeUserCommandTest.php b/tests/Unit/Commands/User/MakeUserCommandTest.php deleted file mode 100644 index 676a3c6dc..000000000 --- a/tests/Unit/Commands/User/MakeUserCommandTest.php +++ /dev/null @@ -1,132 +0,0 @@ -. - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ - -namespace Tests\Unit\Commands\User; - -use Mockery as m; -use Pterodactyl\Models\User; -use Tests\Unit\Commands\CommandTestCase; -use Pterodactyl\Services\Users\UserCreationService; -use Pterodactyl\Console\Commands\User\MakeUserCommand; - -class MakeUserCommandTest extends CommandTestCase -{ - /** - * @var \Pterodactyl\Console\Commands\User\MakeUserCommand - */ - protected $command; - - /** - * @var \Pterodactyl\Services\Users\UserCreationService - */ - protected $creationService; - - /** - * Setup tests. - */ - public function setUp(): void - { - parent::setUp(); - - $this->creationService = m::mock(UserCreationService::class); - - $this->command = new MakeUserCommand($this->creationService); - $this->command->setLaravel($this->app); - } - - /** - * Test that the command executes if no options are passed. - */ - public function testCommandWithNoPassedOptions() - { - // TODO(dane): fix this - $this->markTestSkipped('Skipped, GitHub actions cannot run successfully.'); - -// $user = factory(User::class)->make(['root_admin' => true]); -// -// $this->creationService->shouldReceive('handle')->with([ -// 'email' => $user->email, -// 'username' => $user->username, -// 'name_first' => $user->name_first, -// 'name_last' => $user->name_last, -// 'password' => 'Password123', -// 'root_admin' => $user->root_admin, -// ])->once()->andReturn($user); -// -// $display = $this->runCommand($this->command, [], [ -// 'yes', $user->email, $user->username, $user->name_first, $user->name_last, 'Password123', -// ]); -// -// $this->assertNotEmpty($display); -// $this->assertStringContainsString(trans('command/messages.user.ask_password_help'), $display); -// $this->assertStringContainsString($user->uuid, $display); -// $this->assertStringContainsString($user->email, $display); -// $this->assertStringContainsString($user->username, $display); -// $this->assertStringContainsString($user->name, $display); -// $this->assertStringContainsString('Yes', $display); - } - - /** - * Test that the --no-password flag works as intended. - */ - public function testCommandWithNoPasswordOption() - { - $user = factory(User::class)->make(['root_admin' => true]); - - $this->creationService->shouldReceive('handle')->with([ - 'email' => $user->email, - 'username' => $user->username, - 'name_first' => $user->name_first, - 'name_last' => $user->name_last, - 'password' => null, - 'root_admin' => $user->root_admin, - ])->once()->andReturn($user); - - $display = $this->runCommand($this->command, ['--no-password' => true], [ - 'yes', $user->email, $user->username, $user->name_first, $user->name_last, - ]); - - $this->assertNotEmpty($display); - $this->assertStringNotContainsString(trans('command/messages.user.ask_password_help'), $display); - } - - /** - * Test command when arguments are passed as flags. - */ - public function testCommandWithOptionsPassed() - { - $user = factory(User::class)->make(['root_admin' => false]); - - $this->creationService->shouldReceive('handle')->with([ - 'email' => $user->email, - 'username' => $user->username, - 'name_first' => $user->name_first, - 'name_last' => $user->name_last, - 'password' => 'Password123', - 'root_admin' => $user->root_admin, - ])->once()->andReturn($user); - - $display = $this->withoutInteraction()->runCommand($this->command, [ - '--email' => $user->email, - '--username' => $user->username, - '--name-first' => $user->name_first, - '--name-last' => $user->name_last, - '--password' => 'Password123', - '--admin' => 0, - ]); - - $this->assertNotEmpty($display); - $this->assertStringNotContainsString(trans('command/messages.user.ask_password_help'), $display); - $this->assertStringContainsString($user->uuid, $display); - $this->assertStringContainsString($user->email, $display); - $this->assertStringContainsString($user->username, $display); - $this->assertStringContainsString($user->name, $display); - $this->assertStringContainsString('No', $display); - } -} diff --git a/tests/Unit/Http/Controllers/Admin/DatabaseControllerTest.php b/tests/Unit/Http/Controllers/Admin/DatabaseControllerTest.php deleted file mode 100644 index 6188c0c33..000000000 --- a/tests/Unit/Http/Controllers/Admin/DatabaseControllerTest.php +++ /dev/null @@ -1,143 +0,0 @@ -. - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ - -namespace Tests\Unit\Http\Controllers\Admin; - -use Mockery as m; -use Tests\TestCase; -use Pterodactyl\Models\DatabaseHost; -use Prologue\Alerts\AlertsMessageBag; -use Illuminate\Pagination\LengthAwarePaginator; -use Tests\Assertions\ControllerAssertionsTrait; -use Pterodactyl\Http\Controllers\Admin\DatabaseController; -use Pterodactyl\Services\Databases\Hosts\HostUpdateService; -use Pterodactyl\Services\Databases\Hosts\HostCreationService; -use Pterodactyl\Services\Databases\Hosts\HostDeletionService; -use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface; -use Pterodactyl\Contracts\Repository\LocationRepositoryInterface; -use Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface; - -class DatabaseControllerTest extends TestCase -{ - use ControllerAssertionsTrait; - - /** - * @var \Prologue\Alerts\AlertsMessageBag|\Mockery\Mock - */ - private $alert; - - /** - * @var \Pterodactyl\Services\Databases\Hosts\HostCreationService|\Mockery\Mock - */ - private $creationService; - - /** - * @var \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface|\Mockery\Mock - */ - private $databaseRepository; - - /** - * @var \Pterodactyl\Services\Databases\Hosts\HostDeletionService|\Mockery\Mock - */ - private $deletionService; - - /** - * @var \Pterodactyl\Contracts\Repository\LocationRepositoryInterface|\Mockery\Mock - */ - private $locationRepository; - - /** - * @var \Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface|\Mockery\Mock - */ - private $repository; - - /** - * @var \Pterodactyl\Services\Databases\Hosts\HostUpdateService|\Mockery\Mock - */ - private $updateService; - - /** - * Setup tests. - */ - public function setUp(): void - { - parent::setUp(); - - $this->alert = m::mock(AlertsMessageBag::class); - $this->creationService = m::mock(HostCreationService::class); - $this->databaseRepository = m::mock(DatabaseRepositoryInterface::class); - $this->deletionService = m::mock(HostDeletionService::class); - $this->locationRepository = m::mock(LocationRepositoryInterface::class); - $this->repository = m::mock(DatabaseHostRepositoryInterface::class); - $this->updateService = m::mock(HostUpdateService::class); - } - - /** - * Test the index controller. - */ - public function testIndexController() - { - $this->locationRepository->shouldReceive('getAllWithNodes')->withNoArgs()->once()->andReturn(collect(['getAllWithNodes'])); - $this->repository->shouldReceive('getWithViewDetails')->withNoArgs()->once()->andReturn(collect(['getWithViewDetails'])); - - $response = $this->getController()->index(); - - $this->assertIsViewResponse($response); - $this->assertViewNameEquals('admin.databases.index', $response); - $this->assertViewHasKey('locations', $response); - $this->assertViewHasKey('hosts', $response); - $this->assertViewKeyEquals('locations', collect(['getAllWithNodes']), $response); - $this->assertViewKeyEquals('hosts', collect(['getWithViewDetails']), $response); - } - - /** - * Test the view controller for displaying a specific database host. - */ - public function testViewController() - { - $model = factory(DatabaseHost::class)->make(); - $paginator = new LengthAwarePaginator([], 1, 1); - - $this->locationRepository->shouldReceive('getAllWithNodes')->withNoArgs()->once()->andReturn(collect(['getAllWithNodes'])); - $this->repository->shouldReceive('find')->with(1)->once()->andReturn($model); - $this->databaseRepository->shouldReceive('getDatabasesForHost') - ->once() - ->with(1) - ->andReturn($paginator); - - $response = $this->getController()->view(1); - - $this->assertIsViewResponse($response); - $this->assertViewNameEquals('admin.databases.view', $response); - $this->assertViewHasKey('locations', $response); - $this->assertViewHasKey('host', $response); - $this->assertViewHasKey('databases', $response); - $this->assertViewKeyEquals('locations', collect(['getAllWithNodes']), $response); - $this->assertViewKeyEquals('host', $model, $response); - $this->assertViewKeyEquals('databases', $paginator, $response); - } - - /** - * Return an instance of the DatabaseController with mock dependencies. - * - * @return \Pterodactyl\Http\Controllers\Admin\DatabaseController - */ - private function getController(): DatabaseController - { - return new DatabaseController( - $this->alert, - $this->repository, - $this->databaseRepository, - $this->creationService, - $this->deletionService, - $this->updateService, - $this->locationRepository - ); - } -} diff --git a/tests/Unit/Http/Controllers/Admin/MailControllerTest.php b/tests/Unit/Http/Controllers/Admin/MailControllerTest.php deleted file mode 100644 index ecd5258e6..000000000 --- a/tests/Unit/Http/Controllers/Admin/MailControllerTest.php +++ /dev/null @@ -1,82 +0,0 @@ -alert = m::mock(AlertsMessageBag::class); - $this->configRepository = m::mock(ConfigRepository::class); - $this->encrypter = m::mock(Encrypter::class); - $this->kernel = m::mock(Kernel::class); - $this->settingsRepositoryInterface = m::mock(SettingsRepositoryInterface::class); - } - - /** - * Test the mail controller for viewing mail settings page. - */ - public function testIndex() - { - $this->configRepository->shouldReceive('get'); - - $response = $this->getController()->index(); - - $this->assertIsViewResponse($response); - $this->assertViewNameEquals('admin.settings.mail', $response); - } - - /** - * Prepare a MailController using our mocks. - * - * @return MailController - */ - public function getController() - { - return new MailController( - $this->alert, - $this->configRepository, - $this->encrypter, - $this->kernel, - $this->settingsRepositoryInterface - ); - } -} diff --git a/tests/Unit/Http/Controllers/ControllerTestCase.php b/tests/Unit/Http/Controllers/ControllerTestCase.php deleted file mode 100644 index 197f26255..000000000 --- a/tests/Unit/Http/Controllers/ControllerTestCase.php +++ /dev/null @@ -1,99 +0,0 @@ -buildRequestMock(); - } - - /** - * Set an instance of the controller. - * - * @param \Pterodactyl\Http\Controllers\Controller|\Mockery\Mock $controller - */ - public function setControllerInstance($controller) - { - $this->controller = $controller; - } - - /** - * Return an instance of the controller. - * - * @return \Mockery\Mock|\Pterodactyl\Http\Controllers\Controller - */ - public function getControllerInstance() - { - return $this->controller; - } - - /** - * Helper function to mock injectJavascript requests. - * - * @param array|null $args - * @param bool $subset - */ - protected function mockInjectJavascript(array $args = null, bool $subset = false) - { - $controller = $this->getControllerInstance(); - - $controller->shouldReceive('setRequest')->with($this->request)->once()->andReturnSelf(); - if (is_null($args)) { - $controller->shouldReceive('injectJavascript')->withAnyArgs()->once()->andReturnNull(); - } else { - $with = $subset ? m::subset($args) : $args; - - $controller->shouldReceive('injectJavascript')->with($with)->once()->andReturnNull(); - } - } - - /** - * Mocks a request input call. - * - * @param string $param - * @param mixed $return - */ - protected function mockRequestInput(string $param, $return = null) - { - $this->request->shouldReceive('input')->withArgs(function ($k) use ($param) { - return $k === $param; - })->andReturn($return); - } - - /** - * Build and return a mocked controller instance to use for testing. - * - * @param string $class - * @param array $args - * @return \Mockery\Mock|\Pterodactyl\Http\Controllers\Controller - */ - protected function buildMockedController(string $class, array $args = []) - { - $controller = m::mock($class, $args)->makePartial(); - - if (is_null($this->getControllerInstance())) { - $this->setControllerInstance($controller); - } - - return $this->getControllerInstance(); - } -} diff --git a/tests/Unit/Services/Allocations/AllocationDeletionServiceTest.php b/tests/Unit/Services/Allocations/AllocationDeletionServiceTest.php deleted file mode 100644 index 055aedaa1..000000000 --- a/tests/Unit/Services/Allocations/AllocationDeletionServiceTest.php +++ /dev/null @@ -1,60 +0,0 @@ -repository = m::mock(AllocationRepositoryInterface::class); - } - - /** - * Test that an allocation is deleted. - */ - public function testAllocationIsDeleted() - { - $model = factory(Allocation::class)->make(['id' => 123]); - - $this->repository->expects('delete')->with($model->id)->andReturns(1); - - $response = $this->getService()->handle($model); - $this->assertEquals(1, $response); - } - - /** - * Test that an exception gets thrown if an allocation is currently assigned to a server. - */ - public function testExceptionThrownIfAssignedToServer() - { - $this->expectException(ServerUsingAllocationException::class); - - $model = factory(Allocation::class)->make(['server_id' => 123]); - - $this->getService()->handle($model); - } - - /** - * Return an instance of the service with mocked injections. - * - * @return \Pterodactyl\Services\Allocations\AllocationDeletionService - */ - private function getService(): AllocationDeletionService - { - return new AllocationDeletionService($this->repository); - } -} diff --git a/tests/Unit/Services/Allocations/AssignmentServiceTest.php b/tests/Unit/Services/Allocations/AssignmentServiceTest.php deleted file mode 100644 index 0e6da9035..000000000 --- a/tests/Unit/Services/Allocations/AssignmentServiceTest.php +++ /dev/null @@ -1,291 +0,0 @@ -node = factory(Node::class)->make(); - $this->connection = m::mock(ConnectionInterface::class); - $this->repository = m::mock(AllocationRepositoryInterface::class); - } - - /** - * Test a non-CIDR notated IP address without a port range. - */ - public function testIndividualIpAddressWithoutRange() - { - $data = [ - 'allocation_ip' => '192.168.1.1', - 'allocation_ports' => ['2222'], - ]; - - $this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull(); - $this->repository->shouldReceive('insertIgnore')->with([ - [ - 'node_id' => $this->node->id, - 'ip' => '192.168.1.1', - 'port' => 2222, - 'ip_alias' => null, - 'server_id' => null, - ], - ])->once()->andReturn(true); - $this->connection->shouldReceive('commit')->once()->withNoArgs()->andReturnNull(); - - $this->getService()->handle($this->node, $data); - } - - /** - * Test a non-CIDR IP address with a port range provided. - */ - public function testIndividualIpAddressWithRange() - { - $data = [ - 'allocation_ip' => '192.168.1.1', - 'allocation_ports' => ['1025-1027'], - ]; - - $this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull(); - $this->repository->shouldReceive('insertIgnore')->once()->with([ - [ - 'node_id' => $this->node->id, - 'ip' => '192.168.1.1', - 'port' => 1025, - 'ip_alias' => null, - 'server_id' => null, - ], - [ - 'node_id' => $this->node->id, - 'ip' => '192.168.1.1', - 'port' => 1026, - 'ip_alias' => null, - 'server_id' => null, - ], - [ - 'node_id' => $this->node->id, - 'ip' => '192.168.1.1', - 'port' => 1027, - 'ip_alias' => null, - 'server_id' => null, - ], - ])->andReturn(true); - $this->connection->shouldReceive('commit')->once()->withNoArgs()->andReturnNull(); - - $this->getService()->handle($this->node, $data); - } - - /** - * Test a non-CIDR IP address with a single port and an alias. - */ - public function testIndividualIPAddressWithAlias() - { - $data = [ - 'allocation_ip' => '192.168.1.1', - 'allocation_ports' => ['2222'], - 'allocation_alias' => 'my.alias.net', - ]; - - $this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull(); - $this->repository->shouldReceive('insertIgnore')->once()->with([ - [ - 'node_id' => $this->node->id, - 'ip' => '192.168.1.1', - 'port' => 2222, - 'ip_alias' => 'my.alias.net', - 'server_id' => null, - ], - ])->andReturn(true); - $this->connection->shouldReceive('commit')->once()->withNoArgs()->andReturnNull(); - - $this->getService()->handle($this->node, $data); - } - - /** - * Test that a domain name can be passed in place of an IP address. - */ - public function testDomainNamePassedInPlaceOfIPAddress() - { - $data = [ - 'allocation_ip' => 'unit-test-static.pterodactyl.io', - 'allocation_ports' => ['2222'], - ]; - - $this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull(); - $this->repository->shouldReceive('insertIgnore')->once()->with([ - [ - 'node_id' => $this->node->id, - 'ip' => '127.0.0.1', - 'port' => 2222, - 'ip_alias' => null, - 'server_id' => null, - ], - ])->andReturn(true); - $this->connection->shouldReceive('commit')->once()->withNoArgs()->andReturnNull(); - - $this->getService()->handle($this->node, $data); - } - - /** - * Test that a CIDR IP address without a range works properly. - */ - public function testCIDRNotatedIPAddressWithoutRange() - { - $data = [ - 'allocation_ip' => '192.168.1.100/31', - 'allocation_ports' => ['2222'], - ]; - - $this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull(); - $this->repository->shouldReceive('insertIgnore')->once()->with([ - [ - 'node_id' => $this->node->id, - 'ip' => '192.168.1.100', - 'port' => 2222, - 'ip_alias' => null, - 'server_id' => null, - ], - ])->andReturn(true); - - $this->repository->shouldReceive('insertIgnore')->once()->with([ - [ - 'node_id' => $this->node->id, - 'ip' => '192.168.1.101', - 'port' => 2222, - 'ip_alias' => null, - 'server_id' => null, - ], - ])->andReturn(true); - $this->connection->shouldReceive('commit')->once()->withNoArgs()->andReturnNull(); - - $this->getService()->handle($this->node, $data); - } - - /** - * Test that a CIDR IP address with a range works properly. - */ - public function testCIDRNotatedIPAddressOutsideRangeLimit() - { - $this->expectException(CidrOutOfRangeException::class); - $this->expectExceptionMessage('CIDR notation only allows masks between /25 and /32.'); - - $data = [ - 'allocation_ip' => '192.168.1.100/20', - 'allocation_ports' => ['2222'], - ]; - - $this->getService()->handle($this->node, $data); - } - - /** - * Test that an exception is thrown if there are too many ports. - */ - public function testAllocationWithPortsExceedingLimit() - { - $this->expectException(TooManyPortsInRangeException::class); - $this->expectExceptionMessage('Adding more than 1000 ports in a single range at once is not supported.'); - - $data = [ - 'allocation_ip' => '192.168.1.1', - 'allocation_ports' => ['5000-7000'], - ]; - - $this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull(); - - $this->getService()->handle($this->node, $data); - } - - /** - * Test that an exception is thrown if an invalid port is provided. - */ - public function testInvalidPortProvided() - { - $this->expectException(InvalidPortMappingException::class); - $this->expectExceptionMessage('The mapping provided for test123 was invalid and could not be processed.'); - - $data = [ - 'allocation_ip' => '192.168.1.1', - 'allocation_ports' => ['test123'], - ]; - - $this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull(); - $this->getService()->handle($this->node, $data); - } - - /** - * Test that ports outside of defined limits throw an error. - * - * @param array $ports - * - * @dataProvider invalidPortsDataProvider - */ - public function testPortRangeOutsideOfRangeLimits(array $ports) - { - $this->expectException(PortOutOfRangeException::class); - $this->expectExceptionMessage('Ports in an allocation must be greater than 1024 and less than or equal to 65535.'); - - $data = ['allocation_ip' => '192.168.1.1', 'allocation_ports' => $ports]; - - $this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull(); - $this->getService()->handle($this->node, $data); - } - - /** - * Provide ports and ranges of ports that exceed the viable port limits for the software. - * - * @return array - */ - public function invalidPortsDataProvider(): array - { - return [ - [['65536']], - [['1024']], - [['1000']], - [['0']], - [['65530-65540']], - [['65540-65560']], - [[PHP_INT_MAX]], - ]; - } - - /** - * Returns an instance of the service with mocked dependencies for testing. - * - * @return \Pterodactyl\Services\Allocations\AssignmentService - */ - private function getService(): AssignmentService - { - return new AssignmentService($this->repository, $this->connection); - } -} diff --git a/tests/Unit/Services/Databases/DatabasePasswordServiceTest.php b/tests/Unit/Services/Databases/DatabasePasswordServiceTest.php deleted file mode 100644 index 226723e9d..000000000 --- a/tests/Unit/Services/Databases/DatabasePasswordServiceTest.php +++ /dev/null @@ -1,92 +0,0 @@ -connection = m::mock(ConnectionInterface::class); - $this->dynamic = m::mock(DynamicDatabaseConnection::class); - $this->encrypter = m::mock(Encrypter::class); - $this->repository = m::mock(DatabaseRepositoryInterface::class); - } - - /** - * Test that a password can be updated. - */ - public function testPasswordIsChanged() - { - /** @var \Pterodactyl\Models\Database $model */ - $model = factory(Database::class)->make(['max_connections' => 0]); - - $this->connection->expects('transaction')->with(m::on(function ($closure) { - return is_null($closure()); - })); - - $this->dynamic->expects('set')->with('dynamic', $model->database_host_id)->andReturnNull(); - - $this->encrypter->expects('encrypt')->with(m::on(function ($string) { - preg_match_all('/[!@+=.^-]/', $string, $matches, PREG_SET_ORDER); - $this->assertTrue(count($matches) >= 2 && count($matches) <= 6, "Failed asserting that [{$string}] contains 2 to 6 special characters."); - $this->assertTrue(strlen($string) === 24, "Failed asserting that [{$string}] is 24 characters in length."); - - return true; - }))->andReturn('enc123'); - - $this->repository->expects('withoutFreshModel')->withNoArgs()->andReturnSelf(); - $this->repository->expects('update')->with($model->id, ['password' => 'enc123'])->andReturn(true); - - $this->repository->expects('dropUser')->with($model->username, $model->remote)->andReturn(true); - $this->repository->expects('createUser')->with($model->username, $model->remote, m::any(), 0)->andReturn(true); - $this->repository->expects('assignUserToDatabase')->with($model->database, $model->username, $model->remote)->andReturn(true); - $this->repository->expects('flush')->withNoArgs()->andReturn(true); - - $response = $this->getService()->handle($model); - $this->assertNotEmpty($response); - } - - /** - * Return an instance of the service with mocked dependencies. - * - * @return \Pterodactyl\Services\Databases\DatabasePasswordService - */ - private function getService(): DatabasePasswordService - { - return new DatabasePasswordService($this->connection, $this->repository, $this->dynamic, $this->encrypter); - } -} diff --git a/tests/Unit/Services/Databases/Hosts/HostCreationServiceTest.php b/tests/Unit/Services/Databases/Hosts/HostCreationServiceTest.php deleted file mode 100644 index 41fbb5de2..000000000 --- a/tests/Unit/Services/Databases/Hosts/HostCreationServiceTest.php +++ /dev/null @@ -1,103 +0,0 @@ -connection = m::mock(ConnectionInterface::class); - $this->databaseManager = m::mock(DatabaseManager::class); - $this->dynamic = m::mock(DynamicDatabaseConnection::class); - $this->encrypter = m::mock(Encrypter::class); - $this->repository = m::mock(DatabaseHostRepositoryInterface::class); - } - - /** - * Test that a database host can be created. - */ - public function testDatabaseHostIsCreated() - { - $model = factory(DatabaseHost::class)->make(); - - $this->connection->expects('transaction')->with(m::on(function ($closure) { - return ! is_null($closure()); - }))->andReturn($model); - - $this->encrypter->expects('encrypt')->with('test123')->andReturn('enc123'); - $this->repository->expects('create')->with(m::subset([ - 'password' => 'enc123', - 'username' => $model->username, - 'node_id' => $model->node_id, - ]))->andReturn($model); - - $this->dynamic->expects('set')->with('dynamic', $model)->andReturnNull(); - $this->databaseManager->expects('connection')->with('dynamic')->andReturnSelf(); - $this->databaseManager->expects('select')->with('SELECT 1 FROM dual')->andReturnNull(); - - $response = $this->getService()->handle([ - 'password' => 'test123', - 'username' => $model->username, - 'node_id' => $model->node_id, - ]); - - $this->assertNotEmpty($response); - $this->assertSame($model, $response); - } - - /** - * Return an instance of the service with mocked dependencies. - * - * @return \Pterodactyl\Services\Databases\Hosts\HostCreationService - */ - private function getService(): HostCreationService - { - return new HostCreationService( - $this->connection, - $this->databaseManager, - $this->repository, - $this->dynamic, - $this->encrypter - ); - } -} diff --git a/tests/Unit/Services/Databases/Hosts/HostDeletionServiceTest.php b/tests/Unit/Services/Databases/Hosts/HostDeletionServiceTest.php deleted file mode 100644 index 092ceb6f8..000000000 --- a/tests/Unit/Services/Databases/Hosts/HostDeletionServiceTest.php +++ /dev/null @@ -1,85 +0,0 @@ -databaseRepository = m::mock(DatabaseRepositoryInterface::class); - $this->repository = m::mock(DatabaseHostRepositoryInterface::class); - } - - /** - * Test that a host can be deleted. - */ - public function testHostIsDeleted() - { - $this->databaseRepository->shouldReceive('findCountWhere')->with([['database_host_id', '=', 1234]])->once()->andReturn(0); - $this->repository->shouldReceive('delete')->with(1234)->once()->andReturn(1); - - $response = $this->getService()->handle(1234); - $this->assertNotEmpty($response); - $this->assertSame(1, $response); - } - - /** - * Test that an exception is thrown if a host with databases is deleted. - * - * @dataProvider databaseCountDataProvider - */ - public function testExceptionIsThrownIfDeletingHostWithDatabases(int $count) - { - $this->databaseRepository->shouldReceive('findCountWhere')->with([['database_host_id', '=', 1234]])->once()->andReturn($count); - - try { - $this->getService()->handle(1234); - } catch (PterodactylException $exception) { - $this->assertInstanceOf(HasActiveServersException::class, $exception); - $this->assertEquals(trans('exceptions.databases.delete_has_databases'), $exception->getMessage()); - } - } - - /** - * Data provider to ensure exceptions are thrown for any value > 0. - * - * @return array - */ - public function databaseCountDataProvider(): array - { - return [[1], [2], [10]]; - } - - /** - * Return an instance of the service with mocked dependencies. - * - * @return \Pterodactyl\Services\Databases\Hosts\HostDeletionService - */ - private function getService(): HostDeletionService - { - return new HostDeletionService($this->databaseRepository, $this->repository); - } -} diff --git a/tests/Unit/Services/Databases/Hosts/HostUpdateServiceTest.php b/tests/Unit/Services/Databases/Hosts/HostUpdateServiceTest.php deleted file mode 100644 index 18bf336ef..000000000 --- a/tests/Unit/Services/Databases/Hosts/HostUpdateServiceTest.php +++ /dev/null @@ -1,114 +0,0 @@ -connection = m::mock(ConnectionInterface::class); - $this->databaseManager = m::mock(DatabaseManager::class); - $this->dynamic = m::mock(DynamicDatabaseConnection::class); - $this->encrypter = m::mock(Encrypter::class); - $this->repository = m::mock(DatabaseHostRepositoryInterface::class); - } - - /** - * Test that a password is encrypted before storage if provided. - */ - public function testPasswordIsEncryptedWhenProvided() - { - $model = factory(DatabaseHost::class)->make(); - - $this->connection->expects('transaction')->with(m::on(function ($closure) { - return ! is_null($closure()); - }))->andReturn($model); - - $this->encrypter->expects('encrypt')->with('test123')->andReturn('enc123'); - $this->repository->expects('update')->with(1234, ['password' => 'enc123'])->andReturn($model); - $this->dynamic->expects('set')->with('dynamic', $model)->andReturnNull(); - $this->databaseManager->expects('connection')->with('dynamic')->andReturnSelf(); - $this->databaseManager->expects('select')->with('SELECT 1 FROM dual')->andReturnNull(); - - $response = $this->getService()->handle(1234, ['password' => 'test123']); - $this->assertNotEmpty($response); - $this->assertSame($model, $response); - } - - /** - * Test that updates still occur when no password is provided. - */ - public function testUpdateOccursWhenNoPasswordIsProvided() - { - $model = factory(DatabaseHost::class)->make(); - - $this->connection->expects('transaction')->with(m::on(function ($closure) { - return ! is_null($closure()); - }))->andReturn($model); - - $this->repository->expects('update')->with(1234, ['username' => 'test'])->andReturn($model); - $this->dynamic->expects('set')->with('dynamic', $model)->andReturnNull(); - $this->databaseManager->expects('connection')->with('dynamic')->andReturnSelf(); - $this->databaseManager->expects('select')->with('SELECT 1 FROM dual')->andReturnNull(); - - $response = $this->getService()->handle(1234, ['password' => '', 'username' => 'test']); - $this->assertNotEmpty($response); - $this->assertSame($model, $response); - } - - /** - * Return an instance of the service with mocked dependencies. - * - * @return \Pterodactyl\Services\Databases\Hosts\HostUpdateService - */ - private function getService(): HostUpdateService - { - return new HostUpdateService( - $this->connection, - $this->databaseManager, - $this->repository, - $this->dynamic, - $this->encrypter - ); - } -} diff --git a/tests/Unit/Services/Eggs/EggCreationServiceTest.php b/tests/Unit/Services/Eggs/EggCreationServiceTest.php deleted file mode 100644 index 2b042571f..000000000 --- a/tests/Unit/Services/Eggs/EggCreationServiceTest.php +++ /dev/null @@ -1,145 +0,0 @@ -. - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ - -namespace Tests\Unit\Services\Services\Options; - -use Mockery as m; -use Tests\TestCase; -use Pterodactyl\Models\Egg; -use Tests\Traits\MocksUuids; -use Illuminate\Contracts\Config\Repository; -use Pterodactyl\Exceptions\PterodactylException; -use Pterodactyl\Services\Eggs\EggCreationService; -use Pterodactyl\Contracts\Repository\EggRepositoryInterface; -use Pterodactyl\Exceptions\Service\Egg\NoParentConfigurationFoundException; - -class EggCreationServiceTest extends TestCase -{ - use MocksUuids; - - /** - * @var \Illuminate\Contracts\Config\Repository|\Mockery\Mock - */ - protected $config; - - /** - * @var \Pterodactyl\Contracts\Repository\EggRepositoryInterface|\Mockery\Mock - */ - protected $repository; - - /** - * @var \Pterodactyl\Services\Eggs\EggCreationService - */ - protected $service; - - /** - * Setup tests. - */ - public function setUp(): void - { - parent::setUp(); - - $this->config = m::mock(Repository::class); - $this->repository = m::mock(EggRepositoryInterface::class); - - $this->service = new EggCreationService($this->config, $this->repository); - } - - /** - * Test that a new model is created when not using the config from attribute. - */ - public function testCreateNewModelWithoutUsingConfigFrom() - { - $model = factory(Egg::class)->make(); - - $this->config->shouldReceive('get')->with('pterodactyl.service.author')->once()->andReturn('test@example.com'); - $this->repository->shouldReceive('create')->with([ - 'uuid' => $this->getKnownUuid(), - 'author' => 'test@example.com', - 'config_from' => null, - 'name' => $model->name, - ], true, true)->once()->andReturn($model); - - $response = $this->service->handle(['name' => $model->name]); - - $this->assertNotEmpty($response); - $this->assertNull(object_get($response, 'config_from')); - $this->assertEquals($model->name, $response->name); - } - - /** - * Test that a new model is created when using the config from attribute. - */ - public function testCreateNewModelUsingConfigFrom() - { - $model = factory(Egg::class)->make(); - - $this->repository->shouldReceive('findCountWhere')->with([ - ['nest_id', '=', $model->nest_id], - ['id', '=', 12345], - ])->once()->andReturn(1); - - $this->config->shouldReceive('get')->with('pterodactyl.service.author')->once()->andReturn('test@example.com'); - $this->repository->shouldReceive('create')->with([ - 'nest_id' => $model->nest_id, - 'config_from' => 12345, - 'uuid' => $this->getKnownUuid(), - 'author' => 'test@example.com', - ], true, true)->once()->andReturn($model); - - $response = $this->service->handle([ - 'nest_id' => $model->nest_id, - 'config_from' => 12345, - ]); - - $this->assertNotEmpty($response); - $this->assertEquals($response, $model); - } - - /** - * Test that certain data, such as the UUID or author takes priority over data - * that is passed into the function. - */ - public function testDataProvidedByHandlerTakesPriorityOverPassedData() - { - $model = factory(Egg::class)->make(); - - $this->config->shouldReceive('get')->with('pterodactyl.service.author')->once()->andReturn('test@example.com'); - $this->repository->shouldReceive('create')->with([ - 'uuid' => $this->getKnownUuid(), - 'author' => 'test@example.com', - 'config_from' => null, - 'name' => $model->name, - ], true, true)->once()->andReturn($model); - - $response = $this->service->handle(['name' => $model->name, 'uuid' => 'should-be-ignored', 'author' => 'should-be-ignored']); - - $this->assertNotEmpty($response); - $this->assertNull(object_get($response, 'config_from')); - $this->assertEquals($model->name, $response->name); - } - - /** - * Test that an exception is thrown if no parent configuration can be located. - */ - public function testExceptionIsThrownIfNoParentConfigurationIsFound() - { - $this->repository->shouldReceive('findCountWhere')->with([ - ['nest_id', '=', null], - ['id', '=', 1], - ])->once()->andReturn(0); - - try { - $this->service->handle(['config_from' => 1]); - } catch (PterodactylException $exception) { - $this->assertInstanceOf(NoParentConfigurationFoundException::class, $exception); - $this->assertEquals(trans('exceptions.nest.egg.must_be_child'), $exception->getMessage()); - } - } -} diff --git a/tests/Unit/Services/Eggs/EggDeletionServiceTest.php b/tests/Unit/Services/Eggs/EggDeletionServiceTest.php deleted file mode 100644 index bfc93f4b7..000000000 --- a/tests/Unit/Services/Eggs/EggDeletionServiceTest.php +++ /dev/null @@ -1,93 +0,0 @@ -. - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ - -namespace Tests\Unit\Services\Services\Options; - -use Mockery as m; -use Tests\TestCase; -use Pterodactyl\Exceptions\PterodactylException; -use Pterodactyl\Services\Eggs\EggDeletionService; -use Pterodactyl\Contracts\Repository\EggRepositoryInterface; -use Pterodactyl\Exceptions\Service\Egg\HasChildrenException; -use Pterodactyl\Exceptions\Service\HasActiveServersException; -use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; - -class EggDeletionServiceTest extends TestCase -{ - /** - * @var \Pterodactyl\Contracts\Repository\EggRepositoryInterface|\Mockery\Mock - */ - protected $repository; - - /** - * @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface|\Mockery\Mock - */ - protected $serverRepository; - - /** - * @var \Pterodactyl\Services\Eggs\EggDeletionService - */ - protected $service; - - /** - * Setup tests. - */ - public function setUp(): void - { - parent::setUp(); - - $this->repository = m::mock(EggRepositoryInterface::class); - $this->serverRepository = m::mock(ServerRepositoryInterface::class); - - $this->service = new EggDeletionService($this->serverRepository, $this->repository); - } - - /** - * Test that Egg is deleted if no servers are found. - */ - public function testEggIsDeletedIfNoServersAreFound() - { - $this->serverRepository->shouldReceive('findCountWhere')->with([['egg_id', '=', 1]])->once()->andReturn(0); - $this->repository->shouldReceive('findCountWhere')->with([['config_from', '=', 1]])->once()->andReturn(0); - $this->repository->shouldReceive('delete')->with(1)->once()->andReturn(1); - - $this->assertEquals(1, $this->service->handle(1)); - } - - /** - * Test that Egg is not deleted if servers are found. - */ - public function testExceptionIsThrownIfServersAreFound() - { - $this->serverRepository->shouldReceive('findCountWhere')->with([['egg_id', '=', 1]])->once()->andReturn(1); - - try { - $this->service->handle(1); - } catch (PterodactylException $exception) { - $this->assertInstanceOf(HasActiveServersException::class, $exception); - $this->assertEquals(trans('exceptions.nest.egg.delete_has_servers'), $exception->getMessage()); - } - } - - /** - * Test that an exception is thrown if children Eggs exist. - */ - public function testExceptionIsThrownIfChildrenArePresent() - { - $this->serverRepository->shouldReceive('findCountWhere')->with([['egg_id', '=', 1]])->once()->andReturn(0); - $this->repository->shouldReceive('findCountWhere')->with([['config_from', '=', 1]])->once()->andReturn(1); - - try { - $this->service->handle(1); - } catch (PterodactylException $exception) { - $this->assertInstanceOf(HasChildrenException::class, $exception); - $this->assertEquals(trans('exceptions.nest.egg.has_children'), $exception->getMessage()); - } - } -} diff --git a/tests/Unit/Services/Eggs/EggUpdateServiceTest.php b/tests/Unit/Services/Eggs/EggUpdateServiceTest.php deleted file mode 100644 index 22104995e..000000000 --- a/tests/Unit/Services/Eggs/EggUpdateServiceTest.php +++ /dev/null @@ -1,91 +0,0 @@ -model = factory(Egg::class)->make(['id' => 123]); - $this->repository = m::mock(EggRepositoryInterface::class); - - $this->service = new EggUpdateService($this->repository); - } - - /** - * Test that an Egg is updated when no config_from attribute is passed. - */ - public function testEggIsUpdatedWhenNoConfigFromIsProvided() - { - $this->repository->shouldReceive('withoutFreshModel->update') - ->with($this->model->id, ['test_field' => 'field_value'])->once()->andReturnNull(); - - $this->service->handle($this->model, ['test_field' => 'field_value']); - - $this->assertTrue(true); - } - - /** - * Test that Egg is updated when a valid config_from attribute is passed. - */ - public function testOptionIsUpdatedWhenValidConfigFromIsPassed() - { - $this->repository->shouldReceive('findCountWhere')->with([ - ['nest_id', '=', $this->model->nest_id], - ['id', '=', 1], - ])->once()->andReturn(1); - - $this->repository->shouldReceive('withoutFreshModel->update') - ->with($this->model->id, ['config_from' => 1])->once()->andReturnNull(); - - $this->service->handle($this->model, ['config_from' => 1]); - - $this->assertTrue(true); - } - - /** - * Test that an exception is thrown if an invalid config_from attribute is passed. - */ - public function testExceptionIsThrownIfInvalidParentConfigIsPassed() - { - $this->repository->shouldReceive('findCountWhere')->with([ - ['nest_id', '=', $this->model->nest_id], - ['id', '=', 1], - ])->once()->andReturn(0); - - try { - $this->service->handle($this->model, ['config_from' => 1]); - } catch (PterodactylException $exception) { - $this->assertInstanceOf(NoParentConfigurationFoundException::class, $exception); - $this->assertEquals(trans('exceptions.nest.egg.must_be_child'), $exception->getMessage()); - } - } -} diff --git a/tests/Unit/Services/Eggs/Scripts/InstallScriptServiceTest.php b/tests/Unit/Services/Eggs/Scripts/InstallScriptServiceTest.php deleted file mode 100644 index cf3987937..000000000 --- a/tests/Unit/Services/Eggs/Scripts/InstallScriptServiceTest.php +++ /dev/null @@ -1,87 +0,0 @@ - 'test-script', - 'script_is_privileged' => true, - 'script_entry' => '/bin/bash', - 'script_container' => 'ubuntu', - 'copy_script_from' => null, - ]; - - /** - * @var \Pterodactyl\Contracts\Repository\EggRepositoryInterface|\Mockery\Mock - */ - protected $repository; - - /** - * Setup tests. - */ - public function setUp(): void - { - parent::setUp(); - - $this->repository = m::mock(EggRepositoryInterface::class); - } - - /** - * Test that passing a new copy_script_from attribute works properly. - */ - public function testUpdateWithValidCopyScriptFromAttribute() - { - $model = factory(Egg::class)->make(['id' => 123, 'nest_id' => 456]); - $this->data['copy_script_from'] = 1; - - $this->repository->shouldReceive('isCopyableScript')->with(1, $model->nest_id)->once()->andReturn(true); - $this->repository->expects('withoutFreshModel->update')->with($model->id, $this->data)->andReturnNull(); - - $this->getService()->handle($model, $this->data); - } - - /** - * Test that an exception gets raised when the script is not copyable. - */ - public function testUpdateWithInvalidCopyScriptFromAttribute() - { - $this->data['copy_script_from'] = 1; - - $this->expectException(InvalidCopyFromException::class); - $this->expectExceptionMessage(trans('exceptions.nest.egg.invalid_copy_id')); - - $model = factory(Egg::class)->make(['id' => 123, 'nest_id' => 456]); - - $this->repository->expects('isCopyableScript')->with(1, $model->nest_id)->andReturn(false); - $this->getService()->handle($model, $this->data); - } - - /** - * Test standard functionality. - */ - public function testUpdateWithoutNewCopyScriptFromAttribute() - { - $model = factory(Egg::class)->make(['id' => 123, 'nest_id' => 456]); - - $this->repository->expects('withoutFreshModel->update')->with($model->id, $this->data)->andReturnNull(); - - $this->getService()->handle($model, $this->data); - } - - private function getService() - { - return new InstallScriptService($this->repository); - } -} diff --git a/tests/Unit/Services/Eggs/Sharing/EggExporterServiceTest.php b/tests/Unit/Services/Eggs/Sharing/EggExporterServiceTest.php deleted file mode 100644 index 630f7e106..000000000 --- a/tests/Unit/Services/Eggs/Sharing/EggExporterServiceTest.php +++ /dev/null @@ -1,69 +0,0 @@ -repository = m::mock(EggRepositoryInterface::class); - } - - /** - * Test that a JSON structure is returned. - */ - public function testJsonStructureIsExported() - { - $egg = factory(Egg::class)->make([ - 'id' => 123, - 'nest_id' => 456, - ]); - $egg->variables = collect([$variable = factory(EggVariable::class)->make()]); - - $this->repository->shouldReceive('getWithExportAttributes')->with($egg->id)->once()->andReturn($egg); - - $service = new EggExporterService($this->repository); - - $response = $service->handle($egg->id); - $this->assertNotEmpty($response); - - $data = json_decode($response); - $this->assertEquals(JSON_ERROR_NONE, json_last_error()); - $this->assertObjectHasNestedAttribute('meta.version', $data); - $this->assertObjectNestedValueEquals('meta.version', 'PTDL_v1', $data); - $this->assertObjectHasNestedAttribute('author', $data); - $this->assertObjectNestedValueEquals('author', $egg->author, $data); - $this->assertObjectHasNestedAttribute('exported_at', $data); - $this->assertObjectNestedValueEquals('exported_at', Carbon::now()->toIso8601String(), $data); - $this->assertObjectHasNestedAttribute('scripts.installation.script', $data); - $this->assertObjectHasNestedAttribute('scripts.installation.container', $data); - $this->assertObjectHasNestedAttribute('scripts.installation.entrypoint', $data); - $this->assertObjectHasAttribute('variables', $data); - $this->assertArrayHasKey('0', $data->variables); - $this->assertObjectHasAttribute('name', $data->variables[0]); - $this->assertObjectNestedValueEquals('name', $variable->name, $data->variables[0]); - } -} diff --git a/tests/Unit/Services/Eggs/Sharing/EggImporterServiceTest.php b/tests/Unit/Services/Eggs/Sharing/EggImporterServiceTest.php deleted file mode 100644 index 0d53d5a7e..000000000 --- a/tests/Unit/Services/Eggs/Sharing/EggImporterServiceTest.php +++ /dev/null @@ -1,187 +0,0 @@ -file = m::mock(UploadedFile::class); - $this->connection = m::mock(ConnectionInterface::class); - $this->eggVariableRepository = m::mock(EggVariableRepositoryInterface::class); - $this->nestRepository = m::mock(NestRepositoryInterface::class); - $this->repository = m::mock(EggRepositoryInterface::class); - - $this->service = new EggImporterService( - $this->connection, $this->repository, $this->eggVariableRepository, $this->nestRepository - ); - } - - /** - * Test that a service option can be successfully imported. - */ - public function testEggConfigurationIsImported() - { - $egg = factory(Egg::class)->make(['id' => 123]); - $nest = factory(Nest::class)->make(['id' => 456]); - - $this->file->expects('getError')->andReturn(UPLOAD_ERR_OK); - $this->file->expects('isFile')->andReturn(true); - $this->file->expects('getSize')->andReturn(100); - - $this->file->expects('openFile->fread')->with(100)->once()->andReturn(json_encode([ - 'meta' => ['version' => 'PTDL_v1'], - 'name' => $egg->name, - 'author' => $egg->author, - 'variables' => [ - $variable = factory(EggVariable::class)->make(), - ], - ])); - $this->nestRepository->shouldReceive('getWithEggs')->with($nest->id)->once()->andReturn($nest); - - $this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); - $this->repository->shouldReceive('create')->with(m::subset([ - 'uuid' => $this->getKnownUuid(), - 'nest_id' => $nest->id, - 'name' => $egg->name, - ]), true, true)->once()->andReturn($egg); - - $this->eggVariableRepository->shouldReceive('create')->with(m::subset([ - 'egg_id' => $egg->id, - 'env_variable' => $variable->env_variable, - ]))->once()->andReturnNull(); - $this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull(); - - $response = $this->service->handle($this->file, $nest->id); - $this->assertNotEmpty($response); - $this->assertInstanceOf(Egg::class, $response); - $this->assertSame($egg, $response); - } - - /** - * Test that an exception is thrown if the file is invalid. - */ - public function testExceptionIsThrownIfFileIsInvalid() - { - $this->expectException(InvalidFileUploadException::class); - $this->expectExceptionMessage( - 'The selected file ["test.txt"] was not in a valid format to import. (is_file: true is_valid: true err_code: 4 err: UPLOAD_ERR_NO_FILE)' - ); - - $this->file->expects('getFilename')->andReturns('test.txt'); - $this->file->expects('isFile')->andReturns(true); - $this->file->expects('isValid')->andReturns(true); - $this->file->expects('getError')->twice()->andReturns(UPLOAD_ERR_NO_FILE); - $this->file->expects('getErrorMessage')->andReturns('UPLOAD_ERR_NO_FILE'); - - $this->service->handle($this->file, 1234); - } - - /** - * Test that an exception is thrown if the file is not a file. - */ - public function testExceptionIsThrownIfFileIsNotAFile() - { - $this->expectException(InvalidFileUploadException::class); - $this->expectExceptionMessage( - 'The selected file ["test.txt"] was not in a valid format to import. (is_file: false is_valid: true err_code: 4 err: UPLOAD_ERR_NO_FILE)' - ); - - $this->file->expects('getFilename')->andReturns('test.txt'); - $this->file->expects('isFile')->andReturns(false); - $this->file->expects('isValid')->andReturns(true); - $this->file->expects('getError')->twice()->andReturns(UPLOAD_ERR_NO_FILE); - $this->file->expects('getErrorMessage')->andReturns('UPLOAD_ERR_NO_FILE'); - - $this->service->handle($this->file, 1234); - } - - /** - * Test that an exception is thrown if the JSON metadata is invalid. - */ - public function testExceptionIsThrownIfJsonMetaDataIsInvalid() - { - $this->expectException(InvalidFileUploadException::class); - $this->expectExceptionMessage(trans('exceptions.nest.importer.invalid_json_provided')); - - $this->file->expects('getError')->andReturn(UPLOAD_ERR_OK); - $this->file->expects('isFile')->andReturn(true); - $this->file->expects('getSize')->andReturn(100); - - $this->file->expects('openFile->fread')->with(100)->andReturn(json_encode([ - 'meta' => ['version' => 'hodor'], - ])); - - $this->service->handle($this->file, 1234); - } - - /** - * Test that an exception is thrown if bad JSON is provided. - */ - public function testExceptionIsThrownIfBadJsonIsProvided() - { - $this->expectException(BadJsonFormatException::class); - $this->expectExceptionMessage(trans('exceptions.nest.importer.json_error', [ - 'error' => 'Syntax error', - ])); - - $this->file->expects('getError')->andReturn(UPLOAD_ERR_OK); - $this->file->expects('isFile')->andReturn(true); - $this->file->expects('getSize')->andReturn(100); - $this->file->expects('openFile->fread')->with(100)->andReturn('}'); - - $this->service->handle($this->file, 1234); - } -} diff --git a/tests/Unit/Services/Eggs/Sharing/EggUpdateImporterServiceTest.php b/tests/Unit/Services/Eggs/Sharing/EggUpdateImporterServiceTest.php deleted file mode 100644 index a73fc1cda..000000000 --- a/tests/Unit/Services/Eggs/Sharing/EggUpdateImporterServiceTest.php +++ /dev/null @@ -1,219 +0,0 @@ -connection = m::mock(ConnectionInterface::class); - $this->file = m::mock(UploadedFile::class); - $this->repository = m::mock(EggRepositoryInterface::class); - $this->variableRepository = m::mock(EggVariableRepositoryInterface::class); - - $this->service = new EggUpdateImporterService($this->connection, $this->repository, $this->variableRepository); - } - - /** - * Test that an egg update is handled correctly using an uploaded file. - */ - public function testEggIsUpdated() - { - $egg = factory(Egg::class)->make(['id' => 123]); - $variable = factory(EggVariable::class)->make(); - - $this->file->shouldReceive('getError')->withNoArgs()->once()->andReturn(UPLOAD_ERR_OK); - $this->file->shouldReceive('isFile')->withNoArgs()->once()->andReturn(true); - $this->file->shouldReceive('getSize')->withNoArgs()->once()->andReturn(100); - $this->file->shouldReceive('openFile->fread')->with(100)->once()->andReturn(json_encode([ - 'meta' => ['version' => 'PTDL_v1'], - 'name' => $egg->name, - 'author' => 'newauthor@example.com', - 'variables' => [$variable->toArray()], - ])); - - $this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); - $this->repository->shouldReceive('update')->with($egg->id, m::subset([ - 'author' => 'newauthor@example.com', - 'name' => $egg->name, - ]), true, true)->once()->andReturn($egg); - - $this->variableRepository->shouldReceive('withoutFreshModel->updateOrCreate')->with([ - 'egg_id' => $egg->id, - 'env_variable' => $variable->env_variable, - ], collect($variable)->except(['egg_id', 'env_variable'])->toArray())->once()->andReturnNull(); - - $this->variableRepository->shouldReceive('setColumns')->with(['id', 'env_variable'])->once()->andReturnSelf() - ->shouldReceive('findWhere')->with([['egg_id', '=', $egg->id]])->once()->andReturn(collect([$variable])); - - $this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull(); - - $this->service->handle($egg, $this->file); - $this->assertTrue(true); - } - - /** - * Test that an imported file with less variables than currently existing deletes - * the un-needed variables from the database. - */ - public function testVariablesMissingFromImportAreDeleted() - { - $egg = factory(Egg::class)->make(['id' => 123]); - $variable1 = factory(EggVariable::class)->make(); - $variable2 = factory(EggVariable::class)->make(); - - $this->file->shouldReceive('getError')->withNoArgs()->once()->andReturn(UPLOAD_ERR_OK); - $this->file->shouldReceive('isFile')->withNoArgs()->once()->andReturn(true); - $this->file->shouldReceive('getSize')->withNoArgs()->once()->andReturn(100); - $this->file->shouldReceive('openFile->fread')->with(100)->once()->andReturn(json_encode([ - 'meta' => ['version' => 'PTDL_v1'], - 'name' => $egg->name, - 'author' => 'newauthor@example.com', - 'variables' => [$variable1->toArray()], - ])); - - $this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); - $this->repository->shouldReceive('update')->with($egg->id, m::subset([ - 'author' => 'newauthor@example.com', - 'name' => $egg->name, - ]), true, true)->once()->andReturn($egg); - - $this->variableRepository->shouldReceive('withoutFreshModel->updateOrCreate')->with([ - 'egg_id' => $egg->id, - 'env_variable' => $variable1->env_variable, - ], collect($variable1)->except(['egg_id', 'env_variable'])->toArray())->once()->andReturnNull(); - - $this->variableRepository->shouldReceive('setColumns')->with(['id', 'env_variable'])->once()->andReturnSelf() - ->shouldReceive('findWhere')->with([['egg_id', '=', $egg->id]])->once()->andReturn(collect([$variable1, $variable2])); - - $this->variableRepository->shouldReceive('deleteWhere')->with([ - ['egg_id', '=', $egg->id], - ['env_variable', '=', $variable2->env_variable], - ])->once()->andReturn(1); - - $this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull(); - - $this->service->handle($egg, $this->file); - $this->assertTrue(true); - } - - /** - * Test that an exception is thrown if the file is invalid. - */ - public function testExceptionIsThrownIfFileIsInvalid() - { - $egg = factory(Egg::class)->make(['id' => 123]); - - $this->expectException(InvalidFileUploadException::class); - $this->expectExceptionMessageMatches('/^The selected file \["test\.txt"\] was not in a valid format to import\./'); - $file = new UploadedFile('test.txt', 'original.txt', 'application/json', UPLOAD_ERR_NO_FILE, true); - - $this->service->handle($egg, $file); - } - - /** - * Test that an exception is thrown if the file is not a file. - */ - public function testExceptionIsThrownIfFileIsNotAFile() - { - $egg = factory(Egg::class)->make(['id' => 123]); - - $this->expectException(InvalidFileUploadException::class); - $this->expectExceptionMessageMatches('/^The selected file \["test\.txt"\] was not in a valid format to import\./'); - - $file = m::mock( - new UploadedFile('test.txt', 'original.txt', 'application/json', UPLOAD_ERR_INI_SIZE, true) - )->makePartial(); - - $file->expects('isFile')->andReturnFalse(); - - $this->service->handle($egg, $file); - } - - /** - * Test that an exception is thrown if the JSON metadata is invalid. - */ - public function testExceptionIsThrownIfJsonMetaDataIsInvalid() - { - $egg = factory(Egg::class)->make(['id' => 123]); - - $this->file->shouldReceive('getError')->withNoArgs()->once()->andReturn(UPLOAD_ERR_OK); - $this->file->shouldReceive('isFile')->withNoArgs()->once()->andReturn(true); - $this->file->shouldReceive('getSize')->withNoArgs()->once()->andReturn(100); - $this->file->shouldReceive('openFile->fread')->with(100)->once()->andReturn(json_encode([ - 'meta' => ['version' => 'hodor'], - ])); - - try { - $this->service->handle($egg, $this->file); - } catch (PterodactylException $exception) { - $this->assertInstanceOf(InvalidFileUploadException::class, $exception); - $this->assertEquals(trans('exceptions.nest.importer.invalid_json_provided'), $exception->getMessage()); - } - } - - /** - * Test that an exception is thrown if bad JSON is provided. - */ - public function testExceptionIsThrownIfBadJsonIsProvided() - { - $egg = factory(Egg::class)->make(['id' => 123]); - - $this->file->shouldReceive('getError')->withNoArgs()->once()->andReturn(UPLOAD_ERR_OK); - $this->file->shouldReceive('isFile')->withNoArgs()->once()->andReturn(true); - $this->file->shouldReceive('getSize')->withNoArgs()->once()->andReturn(100); - $this->file->shouldReceive('openFile->fread')->with(100)->once()->andReturn('}'); - - try { - $this->service->handle($egg, $this->file); - } catch (PterodactylException $exception) { - $this->assertInstanceOf(BadJsonFormatException::class, $exception); - $this->assertEquals(trans('exceptions.nest.importer.json_error', [ - 'error' => json_last_error_msg(), - ]), $exception->getMessage()); - } - } -} diff --git a/tests/Unit/Services/Eggs/Variables/VariableCreationServiceTest.php b/tests/Unit/Services/Eggs/Variables/VariableCreationServiceTest.php deleted file mode 100644 index bbac6009d..000000000 --- a/tests/Unit/Services/Eggs/Variables/VariableCreationServiceTest.php +++ /dev/null @@ -1,185 +0,0 @@ -repository = m::mock(EggVariableRepositoryInterface::class); - $this->validator = m::mock(Factory::class); - } - - /** - * Test basic functionality, data should be stored in the database. - */ - public function testVariableIsCreatedAndStored() - { - $data = ['env_variable' => 'TEST_VAR_123', 'default_value' => 'test']; - $this->repository->shouldReceive('create')->with(m::subset([ - 'egg_id' => 1, - 'default_value' => 'test', - 'user_viewable' => false, - 'user_editable' => false, - 'env_variable' => 'TEST_VAR_123', - ]))->once()->andReturn(new EggVariable); - - $this->assertInstanceOf(EggVariable::class, $this->getService()->handle(1, $data)); - } - - /** - * Test that the option key in the data array is properly parsed. - */ - public function testOptionsPassedInArrayKeyAreParsedProperly() - { - $data = ['env_variable' => 'TEST_VAR_123', 'options' => ['user_viewable', 'user_editable']]; - $this->repository->shouldReceive('create')->with(m::subset([ - 'default_value' => '', - 'user_viewable' => true, - 'user_editable' => true, - 'env_variable' => 'TEST_VAR_123', - ]))->once()->andReturn(new EggVariable); - - $this->assertInstanceOf(EggVariable::class, $this->getService()->handle(1, $data)); - } - - /** - * Test that an empty (null) value passed in the option key is handled - * properly as an array. Also tests the same case against the default_value. - * - * @see https://github.com/Pterodactyl/Panel/issues/841 - * @see https://github.com/Pterodactyl/Panel/issues/943 - */ - public function testNullOptionValueIsPassedAsArray() - { - $data = ['env_variable' => 'TEST_VAR_123', 'options' => null, 'default_value' => null]; - $this->repository->shouldReceive('create')->with(m::subset([ - 'default_value' => '', - 'user_viewable' => false, - 'user_editable' => false, - ]))->once()->andReturn(new EggVariable); - - $this->assertInstanceOf(EggVariable::class, $this->getService()->handle(1, $data)); - } - - /** - * Test that all of the reserved variables defined in the model trigger an exception. - * - * @param string $variable - * - * @dataProvider reservedNamesProvider - */ - public function testExceptionIsThrownIfEnvironmentVariableIsInListOfReservedNames(string $variable) - { - $this->expectException(ReservedVariableNameException::class); - - $this->getService()->handle(1, ['env_variable' => $variable]); - } - - /** - * Test that the egg ID applied in the function takes higher priority than an - * ID passed into the handler. - */ - public function testEggIdPassedInDataIsNotApplied() - { - $data = ['egg_id' => 123456, 'env_variable' => 'TEST_VAR_123']; - $this->repository->shouldReceive('create')->with(m::subset([ - 'egg_id' => 1, - ]))->once()->andReturn(new EggVariable); - - $this->assertInstanceOf(EggVariable::class, $this->getService()->handle(1, $data)); - } - - /** - * Test that validation errors due to invalid rules are caught and handled properly. - */ - public function testInvalidValidationRulesResultInException() - { - $this->expectException(BadValidationRuleException::class); - $this->expectExceptionMessage('The validation rule "hodor_door" is not a valid rule for this application.'); - - $data = ['env_variable' => 'TEST_VAR_123', 'rules' => 'string|hodorDoor']; - - $this->validator->shouldReceive('make')->once() - ->with(['__TEST' => 'test'], ['__TEST' => 'string|hodorDoor']) - ->andReturnSelf(); - - $this->validator->shouldReceive('fails')->once() - ->withNoArgs() - ->andThrow(new BadMethodCallException('Method [validateHodorDoor] does not exist.')); - - $this->getService()->handle(1, $data); - } - - /** - * Test that an exception not stemming from a bad rule is not caught. - */ - public function testExceptionNotCausedByBadRuleIsNotCaught() - { - $this->expectException(BadMethodCallException::class); - $this->expectExceptionMessage('Received something, but no expectations were specified.'); - - $data = ['env_variable' => 'TEST_VAR_123', 'rules' => 'string']; - - $this->validator->shouldReceive('make')->once() - ->with(['__TEST' => 'test'], ['__TEST' => 'string']) - ->andReturnSelf(); - - $this->validator->shouldReceive('fails')->once() - ->withNoArgs() - ->andThrow(new BadMethodCallException('Received something, but no expectations were specified.')); - - $this->getService()->handle(1, $data); - } - - /** - * Provides the data to be used in the tests. - * - * @return array - */ - public function reservedNamesProvider() - { - $data = []; - $exploded = explode(',', EggVariable::RESERVED_ENV_NAMES); - foreach ($exploded as $e) { - $data[] = [$e]; - } - - return $data; - } - - /** - * Return an instance of the service with mocked dependencies for testing. - * - * @return \Pterodactyl\Services\Eggs\Variables\VariableCreationService - */ - private function getService(): VariableCreationService - { - return new VariableCreationService($this->repository, $this->validator); - } -} diff --git a/tests/Unit/Services/Eggs/Variables/VariableUpdateServiceTest.php b/tests/Unit/Services/Eggs/Variables/VariableUpdateServiceTest.php deleted file mode 100644 index a812da274..000000000 --- a/tests/Unit/Services/Eggs/Variables/VariableUpdateServiceTest.php +++ /dev/null @@ -1,241 +0,0 @@ -model = factory(EggVariable::class)->make(); - $this->repository = m::mock(EggVariableRepositoryInterface::class); - $this->validator = m::mock(Factory::class); - } - - /** - * Test the function when no env_variable key is passed into the function. - */ - public function testVariableIsUpdatedWhenNoEnvironmentVariableIsPassed() - { - $this->repository->shouldReceive('withoutFreshModel')->withNoArgs()->once()->andReturnSelf() - ->shouldReceive('update')->with($this->model->id, m::subset([ - 'user_viewable' => false, - 'user_editable' => false, - ]))->once()->andReturn(true); - - $this->assertTrue($this->getService()->handle($this->model, [])); - } - - /** - * Test that a null value passed in for the default is converted to a string. - * - * @see https://github.com/Pterodactyl/Panel/issues/934 - */ - public function testNullDefaultValue() - { - $this->repository->shouldReceive('withoutFreshModel->update')->with($this->model->id, m::subset([ - 'user_viewable' => false, - 'user_editable' => false, - 'default_value' => '', - ]))->once()->andReturn(true); - - $this->assertTrue($this->getService()->handle($this->model, ['default_value' => null])); - } - - /** - * Test the function when a valid env_variable key is passed into the function. - */ - public function testVariableIsUpdatedWhenValidEnvironmentVariableIsPassed() - { - $this->repository->shouldReceive('setColumns')->with('id')->once()->andReturnSelf() - ->shouldReceive('findCountWhere')->with([ - ['env_variable', '=', 'TEST_VAR_123'], - ['egg_id', '=', $this->model->option_id], - ['id', '!=', $this->model->id], - ])->once()->andReturn(0); - - $this->repository->shouldReceive('withoutFreshModel')->withNoArgs()->once()->andReturnSelf() - ->shouldReceive('update')->with($this->model->id, m::subset([ - 'user_viewable' => false, - 'user_editable' => false, - 'env_variable' => 'TEST_VAR_123', - ]))->once()->andReturn(true); - - $this->assertTrue($this->getService()->handle($this->model, ['env_variable' => 'TEST_VAR_123'])); - } - - /** - * Test that an empty (null) value passed in the option key is handled - * properly as an array. Also tests that a null description is handled. - * - * @see https://github.com/Pterodactyl/Panel/issues/841 - */ - public function testNullOptionValueIsPassedAsArray() - { - $this->repository->shouldReceive('withoutFreshModel')->withNoArgs()->once()->andReturnSelf() - ->shouldReceive('update')->with($this->model->id, m::subset([ - 'user_viewable' => false, - 'user_editable' => false, - 'description' => '', - ]))->once()->andReturn(true); - - $this->assertTrue($this->getService()->handle($this->model, ['options' => null, 'description' => null])); - } - - /** - * Test that data passed into the handler is overwritten inside the handler. - */ - public function testDataPassedIntoHandlerTakesLowerPriorityThanDataSet() - { - $this->repository->shouldReceive('setColumns')->with('id')->once()->andReturnSelf() - ->shouldReceive('findCountWhere')->with([ - ['env_variable', '=', 'TEST_VAR_123'], - ['egg_id', '=', $this->model->option_id], - ['id', '!=', $this->model->id], - ])->once()->andReturn(0); - - $this->repository->shouldReceive('withoutFreshModel')->withNoArgs()->once()->andReturnSelf() - ->shouldReceive('update')->with($this->model->id, m::subset([ - 'user_viewable' => false, - 'user_editable' => false, - 'env_variable' => 'TEST_VAR_123', - ]))->once()->andReturn(true); - - $this->assertTrue($this->getService()->handle($this->model, ['user_viewable' => 123456, 'env_variable' => 'TEST_VAR_123'])); - } - - /** - * Test that a non-unique environment variable triggers an exception. - */ - public function testExceptionIsThrownIfEnvironmentVariableIsNotUnique() - { - $this->repository->shouldReceive('setColumns')->with('id')->once()->andReturnSelf() - ->shouldReceive('findCountWhere')->with([ - ['env_variable', '=', 'TEST_VAR_123'], - ['egg_id', '=', $this->model->option_id], - ['id', '!=', $this->model->id], - ])->once()->andReturn(1); - - try { - $this->getService()->handle($this->model, ['env_variable' => 'TEST_VAR_123']); - } catch (Exception $exception) { - $this->assertInstanceOf(DisplayException::class, $exception); - $this->assertEquals(trans('exceptions.service.variables.env_not_unique', [ - 'name' => 'TEST_VAR_123', - ]), $exception->getMessage()); - } - } - - /** - * Test that all of the reserved variables defined in the model trigger an exception. - * - * @dataProvider reservedNamesProvider - */ - public function testExceptionIsThrownIfEnvironmentVariableIsInListOfReservedNames(string $variable) - { - $this->expectException(ReservedVariableNameException::class); - - $this->getService()->handle($this->model, ['env_variable' => $variable]); - } - - /** - * Test that validation errors due to invalid rules are caught and handled properly. - */ - public function testInvalidValidationRulesResultInException() - { - $this->expectException(BadValidationRuleException::class); - $this->expectExceptionMessage('The validation rule "hodor_door" is not a valid rule for this application.'); - - $data = ['env_variable' => 'TEST_VAR_123', 'rules' => 'string|hodorDoor']; - - $this->repository->shouldReceive('setColumns->findCountWhere')->once()->andReturn(0); - - $this->validator->shouldReceive('make')->once() - ->with(['__TEST' => 'test'], ['__TEST' => 'string|hodorDoor']) - ->andReturnSelf(); - - $this->validator->shouldReceive('fails')->once() - ->withNoArgs() - ->andThrow(new BadMethodCallException('Method [validateHodorDoor] does not exist.')); - - $this->getService()->handle($this->model, $data); - } - - /** - * Test that an exception not stemming from a bad rule is not caught. - */ - public function testExceptionNotCausedByBadRuleIsNotCaught() - { - $this->expectException(BadMethodCallException::class); - $this->expectExceptionMessage('Received something, but no expectations were specified.'); - - $data = ['rules' => 'string']; - - $this->validator->shouldReceive('make')->once() - ->with(['__TEST' => 'test'], ['__TEST' => 'string']) - ->andReturnSelf(); - - $this->validator->shouldReceive('fails')->once() - ->withNoArgs() - ->andThrow(new BadMethodCallException('Received something, but no expectations were specified.')); - - $this->getService()->handle($this->model, $data); - } - - /** - * Provides the data to be used in the tests. - * - * @return array - */ - public function reservedNamesProvider() - { - $data = []; - $exploded = explode(',', EggVariable::RESERVED_ENV_NAMES); - foreach ($exploded as $e) { - $data[] = [$e]; - } - - return $data; - } - - /** - * Return an instance of the service with mocked dependencies for testing. - * - * @return \Pterodactyl\Services\Eggs\Variables\VariableUpdateService - */ - private function getService(): VariableUpdateService - { - return new VariableUpdateService($this->repository, $this->validator); - } -} diff --git a/tests/Unit/Services/Locations/LocationCreationServiceTest.php b/tests/Unit/Services/Locations/LocationCreationServiceTest.php deleted file mode 100644 index a7ea91506..000000000 --- a/tests/Unit/Services/Locations/LocationCreationServiceTest.php +++ /dev/null @@ -1,56 +0,0 @@ -. - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ - -namespace Tests\Unit\Services\Locations; - -use Mockery as m; -use Tests\TestCase; -use Pterodactyl\Models\Location; -use Pterodactyl\Services\Locations\LocationCreationService; -use Pterodactyl\Contracts\Repository\LocationRepositoryInterface; - -class LocationCreationServiceTest extends TestCase -{ - /** - * @var \Pterodactyl\Contracts\Repository\LocationRepositoryInterface - */ - protected $repository; - - /** - * @var \Pterodactyl\Services\Locations\LocationCreationService - */ - protected $service; - - /** - * Setup tests. - */ - public function setUp(): void - { - parent::setUp(); - - $this->repository = m::mock(LocationRepositoryInterface::class); - - $this->service = new LocationCreationService($this->repository); - } - - /** - * Test that a location is created. - */ - public function testLocationIsCreated() - { - $location = factory(Location::class)->make(); - - $this->repository->shouldReceive('create')->with(['test_data' => 'test_value'])->once()->andReturn($location); - - $response = $this->service->handle(['test_data' => 'test_value']); - $this->assertNotEmpty($response); - $this->assertInstanceOf(Location::class, $response); - $this->assertEquals($location, $response); - } -} diff --git a/tests/Unit/Services/Locations/LocationDeletionServiceTest.php b/tests/Unit/Services/Locations/LocationDeletionServiceTest.php deleted file mode 100644 index b92874c68..000000000 --- a/tests/Unit/Services/Locations/LocationDeletionServiceTest.php +++ /dev/null @@ -1,76 +0,0 @@ -. - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ - -namespace Tests\Unit\Services\Locations; - -use Mockery as m; -use Tests\TestCase; -use Pterodactyl\Exceptions\DisplayException; -use Pterodactyl\Services\Locations\LocationDeletionService; -use Pterodactyl\Contracts\Repository\NodeRepositoryInterface; -use Pterodactyl\Contracts\Repository\LocationRepositoryInterface; -use Pterodactyl\Exceptions\Service\Location\HasActiveNodesException; - -class LocationDeletionServiceTest extends TestCase -{ - /** - * @var \Pterodactyl\Contracts\Repository\NodeRepositoryInterface - */ - protected $nodeRepository; - - /** - * @var \Pterodactyl\Contracts\Repository\LocationRepositoryInterface - */ - protected $repository; - - /** - * @var \Pterodactyl\Services\Locations\LocationDeletionService - */ - protected $service; - - /** - * Setup tests. - */ - public function setUp(): void - { - parent::setUp(); - - $this->nodeRepository = m::mock(NodeRepositoryInterface::class); - $this->repository = m::mock(LocationRepositoryInterface::class); - - $this->service = new LocationDeletionService($this->repository, $this->nodeRepository); - } - - /** - * Test that a location is deleted. - */ - public function testLocationIsDeleted() - { - $this->nodeRepository->shouldReceive('findCountWhere')->with([['location_id', '=', 123]])->once()->andReturn(0); - $this->repository->shouldReceive('delete')->with(123)->once()->andReturn(1); - - $response = $this->service->handle(123); - $this->assertEquals(1, $response); - } - - /** - * Test that an exception is thrown if nodes are attached to a location. - */ - public function testExceptionIsThrownIfNodesAreAttached() - { - $this->nodeRepository->shouldReceive('findCountWhere')->with([['location_id', '=', 123]])->once()->andReturn(1); - - try { - $this->service->handle(123); - } catch (DisplayException $exception) { - $this->assertInstanceOf(HasActiveNodesException::class, $exception); - $this->assertEquals(trans('exceptions.locations.has_nodes'), $exception->getMessage()); - } - } -} diff --git a/tests/Unit/Services/Locations/LocationUpdateServiceTest.php b/tests/Unit/Services/Locations/LocationUpdateServiceTest.php deleted file mode 100644 index 14d4950a0..000000000 --- a/tests/Unit/Services/Locations/LocationUpdateServiceTest.php +++ /dev/null @@ -1,67 +0,0 @@ -. - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ - -namespace Tests\Unit\Services\Locations; - -use Mockery as m; -use Tests\TestCase; -use Pterodactyl\Models\Location; -use Pterodactyl\Services\Locations\LocationUpdateService; -use Pterodactyl\Contracts\Repository\LocationRepositoryInterface; - -class LocationUpdateServiceTest extends TestCase -{ - /** - * @var \Pterodactyl\Contracts\Repository\LocationRepositoryInterface - */ - protected $repository; - - /** - * @var \Pterodactyl\Services\Locations\LocationUpdateService - */ - protected $service; - - /** - * Setup tests. - */ - public function setUp(): void - { - parent::setUp(); - - $this->repository = m::mock(LocationRepositoryInterface::class); - - $this->service = new LocationUpdateService($this->repository); - } - - /** - * Test location is updated. - */ - public function testLocationIsUpdated() - { - $model = factory(Location::class)->make(['id' => 123]); - $this->repository->shouldReceive('update')->with(123, ['test_data' => 'test_value'])->once()->andReturn($model); - - $response = $this->service->handle($model->id, ['test_data' => 'test_value']); - $this->assertNotEmpty($response); - $this->assertInstanceOf(Location::class, $response); - } - - /** - * Test that a model can be passed in place of an ID. - */ - public function testModelCanBePassedToFunction() - { - $model = factory(Location::class)->make(['id' => 123]); - $this->repository->shouldReceive('update')->with(123, ['test_data' => 'test_value'])->once()->andReturn($model); - - $response = $this->service->handle($model, ['test_data' => 'test_value']); - $this->assertNotEmpty($response); - $this->assertInstanceOf(Location::class, $response); - } -} diff --git a/tests/Unit/Services/Nests/NestCreationServiceTest.php b/tests/Unit/Services/Nests/NestCreationServiceTest.php deleted file mode 100644 index ea1068b21..000000000 --- a/tests/Unit/Services/Nests/NestCreationServiceTest.php +++ /dev/null @@ -1,95 +0,0 @@ -. - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ - -namespace Tests\Unit\Services\Services; - -use Mockery as m; -use Tests\TestCase; -use Pterodactyl\Models\Nest; -use Tests\Traits\MocksUuids; -use Illuminate\Contracts\Config\Repository; -use Pterodactyl\Services\Nests\NestCreationService; -use Pterodactyl\Contracts\Repository\NestRepositoryInterface; - -class NestCreationServiceTest extends TestCase -{ - use MocksUuids; - - /** - * @var \Illuminate\Contracts\Config\Repository|\Mockery\Mock - */ - private $config; - - /** - * @var \Pterodactyl\Contracts\Repository\NestRepositoryInterface|\Mockery\Mock - */ - private $repository; - - /** - * Setup tests. - */ - public function setUp(): void - { - parent::setUp(); - - $this->config = m::mock(Repository::class); - $this->repository = m::mock(NestRepositoryInterface::class); - } - - /** - * Test that a new service can be created using the correct data. - */ - public function testCreateNewService() - { - $model = factory(Nest::class)->make(); - - $this->config->shouldReceive('get')->with('pterodactyl.service.author')->once()->andReturn('testauthor@example.com'); - $this->repository->shouldReceive('create')->with([ - 'uuid' => $this->getKnownUuid(), - 'author' => 'testauthor@example.com', - 'name' => $model->name, - 'description' => $model->description, - ], true, true)->once()->andReturn($model); - - $response = $this->getService()->handle(['name' => $model->name, 'description' => $model->description]); - $this->assertInstanceOf(Nest::class, $response); - $this->assertEquals($model, $response); - } - - /** - * Test creation of a new nest with a defined author. This is used by seeder - * scripts which need to set a specific author for nests in order for other - * functionality to work correctly. - */ - public function testCreateServiceWithDefinedAuthor() - { - $model = factory(Nest::class)->make(); - - $this->repository->shouldReceive('create')->with([ - 'uuid' => $this->getKnownUuid(), - 'author' => 'support@pterodactyl.io', - 'name' => $model->name, - 'description' => $model->description, - ], true, true)->once()->andReturn($model); - - $response = $this->getService()->handle(['name' => $model->name, 'description' => $model->description], 'support@pterodactyl.io'); - $this->assertInstanceOf(Nest::class, $response); - $this->assertEquals($model, $response); - } - - /** - * Return an instance of the service with mocked dependencies. - * - * @return \Pterodactyl\Services\Nests\NestCreationService - */ - private function getService(): NestCreationService - { - return new NestCreationService($this->config, $this->repository); - } -} diff --git a/tests/Unit/Services/Nests/NestDeletionServiceTest.php b/tests/Unit/Services/Nests/NestDeletionServiceTest.php deleted file mode 100644 index 2fbb9f0c6..000000000 --- a/tests/Unit/Services/Nests/NestDeletionServiceTest.php +++ /dev/null @@ -1,91 +0,0 @@ -. - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ - -namespace Tests\Unit\Services\Services; - -use Mockery as m; -use Tests\TestCase; -use Pterodactyl\Exceptions\PterodactylException; -use Pterodactyl\Services\Nests\NestDeletionService; -use Pterodactyl\Contracts\Repository\NestRepositoryInterface; -use Pterodactyl\Exceptions\Service\HasActiveServersException; -use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; - -class NestDeletionServiceTest extends TestCase -{ - /** - * @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface|\Mockery\Mock - */ - protected $serverRepository; - - /** - * @var \Pterodactyl\Contracts\Repository\NestRepositoryInterface|\Mockery\Mock - */ - protected $repository; - - /** - * @var \Pterodactyl\Services\Nests\NestDeletionService - */ - protected $service; - - /** - * Setup tests. - */ - public function setUp(): void - { - parent::setUp(); - - $this->serverRepository = m::mock(ServerRepositoryInterface::class); - $this->repository = m::mock(NestRepositoryInterface::class); - - $this->service = new NestDeletionService($this->serverRepository, $this->repository); - } - - /** - * Test that a service is deleted when there are no servers attached to a service. - */ - public function testServiceIsDeleted() - { - $this->serverRepository->shouldReceive('findCountWhere')->with([['nest_id', '=', 1]])->once()->andReturn(0); - $this->repository->shouldReceive('delete')->with(1)->once()->andReturn(1); - - $this->assertEquals(1, $this->service->handle(1)); - } - - /** - * Test that an exception is thrown when there are servers attached to a service. - * - * @dataProvider serverCountProvider - * - * @param int $count - */ - public function testExceptionIsThrownIfServersAreAttached(int $count) - { - $this->serverRepository->shouldReceive('findCountWhere')->with([['nest_id', '=', 1]])->once()->andReturn($count); - - try { - $this->service->handle(1); - } catch (PterodactylException $exception) { - $this->assertInstanceOf(HasActiveServersException::class, $exception); - $this->assertEquals(trans('exceptions.nest.delete_has_servers'), $exception->getMessage()); - } - } - - /** - * Provide assorted server counts to ensure that an exception is always thrown when more than 0 servers are found. - * - * @return array - */ - public function serverCountProvider() - { - return [ - [1], [2], [5], [10], - ]; - } -} diff --git a/tests/Unit/Services/Nests/NestUpdateServiceTest.php b/tests/Unit/Services/Nests/NestUpdateServiceTest.php deleted file mode 100644 index 670fcec5f..000000000 --- a/tests/Unit/Services/Nests/NestUpdateServiceTest.php +++ /dev/null @@ -1,62 +0,0 @@ -. - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ - -namespace Tests\Unit\Services\Services; - -use Mockery as m; -use Tests\TestCase; -use Pterodactyl\Services\Nests\NestUpdateService; -use Pterodactyl\Contracts\Repository\NestRepositoryInterface; - -class NestUpdateServiceTest extends TestCase -{ - /** - * @var \Pterodactyl\Contracts\Repository\NestRepositoryInterface|\Mockery\Mock - */ - protected $repository; - - /** - * @var \Pterodactyl\Services\Nests\NestUpdateService - */ - protected $service; - - /** - * Setup tests. - */ - public function setUp(): void - { - parent::setUp(); - - $this->repository = m::mock(NestRepositoryInterface::class); - - $this->service = new NestUpdateService($this->repository); - } - - /** - * Test that the author key is removed from the data array before updating the record. - */ - public function testAuthorArrayKeyIsRemovedIfPassed() - { - $this->repository->shouldReceive('withoutFreshModel')->withNoArgs()->once()->andReturnSelf() - ->shouldReceive('update')->with(1, ['otherfield' => 'value'])->once()->andReturnNull(); - - $this->service->handle(1, ['author' => 'author1', 'otherfield' => 'value']); - } - - /** - * Test that the function continues to work when no author key is passed. - */ - public function testServiceIsUpdatedWhenNoAuthorKeyIsPassed() - { - $this->repository->shouldReceive('withoutFreshModel')->withNoArgs()->once()->andReturnSelf() - ->shouldReceive('update')->with(1, ['otherfield' => 'value'])->once()->andReturnNull(); - - $this->service->handle(1, ['otherfield' => 'value']); - } -} diff --git a/tests/Unit/Services/Nodes/NodeCreationServiceTest.php b/tests/Unit/Services/Nodes/NodeCreationServiceTest.php deleted file mode 100644 index 561a14acc..000000000 --- a/tests/Unit/Services/Nodes/NodeCreationServiceTest.php +++ /dev/null @@ -1,79 +0,0 @@ - Uuid::fromString('00000000-0000-0000-0000-000000000000'), - ]) - ); - - $this->repository = m::mock(NodeRepositoryInterface::class); - $this->encrypter = m::mock(Encrypter::class); - } - - /** - * Test that a node is created and a daemon secret token is created. - */ - public function testNodeIsCreatedAndDaemonSecretIsGenerated() - { - /** @var \Pterodactyl\Models\Node $node */ - $node = factory(Node::class)->make(); - - $this->encrypter->expects('encrypt')->with(m::on(function ($value) { - return strlen($value) === Node::DAEMON_TOKEN_LENGTH; - }))->andReturns('encrypted_value'); - - $this->repository->expects('create')->with(m::on(function ($value) { - $this->assertTrue(is_array($value)); - $this->assertSame('NodeName', $value['name']); - $this->assertSame('00000000-0000-0000-0000-000000000000', $value['uuid']); - $this->assertSame('encrypted_value', $value['daemon_token']); - $this->assertTrue(strlen($value['daemon_token_id']) === Node::DAEMON_TOKEN_ID_LENGTH); - - return true; - }), true, true)->andReturn($node); - - $this->assertSame($node, $this->getService()->handle(['name' => 'NodeName'])); - } - - /** - * @return \Pterodactyl\Services\Nodes\NodeCreationService - */ - private function getService() - { - return new NodeCreationService($this->encrypter, $this->repository); - } -} diff --git a/tests/Unit/Services/Nodes/NodeDeletionServiceTest.php b/tests/Unit/Services/Nodes/NodeDeletionServiceTest.php deleted file mode 100644 index dbab15495..000000000 --- a/tests/Unit/Services/Nodes/NodeDeletionServiceTest.php +++ /dev/null @@ -1,94 +0,0 @@ -repository = m::mock(NodeRepositoryInterface::class); - $this->serverRepository = m::mock(ServerRepositoryInterface::class); - $this->translator = m::mock(Translator::class); - - $this->service = new NodeDeletionService( - $this->repository, - $this->serverRepository, - $this->translator - ); - } - - /** - * Test that a node is deleted if there are no servers attached to it. - */ - public function testNodeIsDeletedIfNoServersAreAttached() - { - $this->serverRepository->shouldReceive('setColumns')->with('id')->once()->andReturnSelf() - ->shouldReceive('findCountWhere')->with([['node_id', '=', 1]])->once()->andReturn(0); - $this->repository->shouldReceive('delete')->with(1)->once()->andReturn(1); - - $this->assertEquals(1, $this->service->handle(1)); - } - - /** - * Test that an exception is thrown if servers are attached to the node. - */ - public function testExceptionIsThrownIfServersAreAttachedToNode() - { - $this->expectException(DisplayException::class); - - $this->serverRepository->shouldReceive('setColumns')->with('id')->once()->andReturnSelf() - ->shouldReceive('findCountWhere')->with([['node_id', '=', 1]])->once()->andReturn(1); - $this->translator->shouldReceive('trans')->with('exceptions.node.servers_attached')->once()->andReturnNull(); - $this->repository->shouldNotReceive('delete'); - - $this->service->handle(1); - } - - /** - * Test that a model can be passed into the handle function rather than an ID. - */ - public function testModelCanBePassedToFunctionInPlaceOfNodeId() - { - $node = factory(Node::class)->make(['id' => 123]); - - $this->serverRepository->shouldReceive('setColumns')->with('id')->once()->andReturnSelf() - ->shouldReceive('findCountWhere')->with([['node_id', '=', $node->id]])->once()->andReturn(0); - $this->repository->shouldReceive('delete')->with($node->id)->once()->andReturn(1); - - $this->assertEquals(1, $this->service->handle($node)); - } -} diff --git a/tests/Unit/Services/Nodes/NodeUpdateServiceTest.php b/tests/Unit/Services/Nodes/NodeUpdateServiceTest.php deleted file mode 100644 index 1a836e446..000000000 --- a/tests/Unit/Services/Nodes/NodeUpdateServiceTest.php +++ /dev/null @@ -1,241 +0,0 @@ -connection = m::mock(ConnectionInterface::class); - $this->encrypter = m::mock(Encrypter::class); - $this->configurationRepository = m::mock(DaemonConfigurationRepository::class); - $this->repository = m::mock(NodeRepository::class); - } - - /** - * Test that the daemon secret is reset when `reset_secret` is passed in the data. - */ - public function testNodeIsUpdatedAndDaemonSecretIsReset() - { - /** @var \Pterodactyl\Models\Node $model */ - $model = factory(Node::class)->make([ - 'fqdn' => 'https://example.com', - ]); - - /** @var \Pterodactyl\Models\Node $updatedModel */ - $updatedModel = factory(Node::class)->make([ - 'name' => 'New Name', - 'fqdn' => 'https://example2.com', - ]); - - $this->connection->expects('transaction')->with(m::on(function ($closure) use ($updatedModel) { - $response = $closure(); - - $this->assertIsArray($response); - $this->assertTrue(count($response) === 2); - $this->assertSame($updatedModel, $response[0]); - $this->assertFalse($response[1]); - - return true; - }))->andReturns([$updatedModel, false]); - - $this->encrypter->expects('encrypt')->with(m::on(function ($value) { - return strlen($value) === Node::DAEMON_TOKEN_LENGTH; - }))->andReturns('encrypted_value'); - - $this->repository->expects('withFreshModel->update')->with($model->id, m::on(function ($value) { - $this->assertTrue(is_array($value)); - $this->assertSame('New Name', $value['name']); - $this->assertSame('encrypted_value', $value['daemon_token']); - $this->assertTrue(strlen($value['daemon_token_id']) === Node::DAEMON_TOKEN_ID_LENGTH); - - return true; - }), true, true)->andReturns($updatedModel); - - $this->configurationRepository->expects('setNode')->with(m::on(function ($value) use ($model, $updatedModel) { - $this->assertInstanceOf(Node::class, $value); - $this->assertSame($model->uuid, $value->uuid); - - // Yes, this is correct. Always use the updated model's FQDN when making requests to - // the Daemon so that any changes to that are properly propagated down to the daemon. - // - // @see https://github.com/pterodactyl/panel/issues/1931 - $this->assertSame($updatedModel->fqdn, $value->fqdn); - - return true; - }))->andReturnSelf(); - - $this->configurationRepository->expects('update')->with($updatedModel); - - $this->getService()->handle($model, [ - 'name' => $updatedModel->name, - ], true); - } - - /** - * Test that daemon secret is not modified when no variable is passed in data. - */ - public function testNodeIsUpdatedAndDaemonSecretIsNotChanged() - { - /** @var \Pterodactyl\Models\Node $model */ - $model = factory(Node::class)->make(['fqdn' => 'https://example.com']); - - /** @var \Pterodactyl\Models\Node $updatedModel */ - $updatedModel = factory(Node::class)->make(['name' => 'New Name', 'fqdn' => $model->fqdn]); - - $this->connection->expects('transaction')->with(m::on(function ($closure) use ($updatedModel) { - $response = $closure(); - - $this->assertIsArray($response); - $this->assertTrue(count($response) === 2); - $this->assertSame($updatedModel, $response[0]); - $this->assertFalse($response[1]); - - return true; - }))->andReturns([$updatedModel, false]); - - $this->repository->expects('withFreshModel->update')->with($model->id, m::on(function ($value) { - $this->assertTrue(is_array($value)); - $this->assertSame('New Name', $value['name']); - $this->assertArrayNotHasKey('daemon_token', $value); - $this->assertArrayNotHasKey('daemon_token_id', $value); - - return true; - }), true, true)->andReturns($updatedModel); - - $this->configurationRepository->expects('setNode->update')->with($updatedModel); - - $this->getService()->handle($model, ['name' => $updatedModel->name]); - } - - /** - * Test that an exception caused by a connection error is handled. - */ - public function testExceptionRelatedToConnection() - { - $this->configureExceptionMock(DaemonConnectionException::class); - $this->expectException(ConfigurationNotPersistedException::class); - - /** @var \Pterodactyl\Models\Node $model */ - $model = factory(Node::class)->make(['fqdn' => 'https://example.com']); - - /** @var \Pterodactyl\Models\Node $updatedModel */ - $updatedModel = factory(Node::class)->make(['name' => 'New Name', 'fqdn' => $model->fqdn]); - - $this->connection->expects('transaction')->with(m::on(function ($closure) use ($updatedModel) { - $response = $closure(); - - $this->assertIsArray($response); - $this->assertTrue(count($response) === 2); - $this->assertSame($updatedModel, $response[0]); - $this->assertTrue($response[1]); - - return true; - }))->andReturn([$updatedModel, true]); - - $this->repository->expects('withFreshModel->update')->with($model->id, m::on(function ($value) { - $this->assertTrue(is_array($value)); - $this->assertSame('New Name', $value['name']); - $this->assertArrayNotHasKey('daemon_token', $value); - $this->assertArrayNotHasKey('daemon_token_id', $value); - - return true; - }), true, true)->andReturns($updatedModel); - - $this->configurationRepository->expects('setNode->update')->with($updatedModel)->andThrow( - new DaemonConnectionException( - new ConnectException('', new Request('GET', 'Test'), new Exception) - ) - ); - - $this->getService()->handle($model, ['name' => $updatedModel->name]); - } - - /** - * Test that an exception not caused by a daemon connection error is handled. - */ - public function testExceptionNotRelatedToConnection() - { - /** @var \Pterodactyl\Models\Node $model */ - $model = factory(Node::class)->make(['fqdn' => 'https://example.com']); - - /** @var \Pterodactyl\Models\Node $updatedModel */ - $updatedModel = factory(Node::class)->make(['name' => 'New Name', 'fqdn' => $model->fqdn]); - - $this->connection->expects('transaction')->with(m::on(function ($closure) use ($updatedModel) { - try { - $closure(); - } catch (Exception $exception) { - $this->assertInstanceOf(Exception::class, $exception); - $this->assertSame('Foo', $exception->getMessage()); - - return true; - } - - return false; - })); - - $this->repository->expects('withFreshModel->update')->andReturns($updatedModel); - $this->configurationRepository->expects('setNode->update')->andThrow( - new Exception('Foo') - ); - - $this->getService()->handle($model, ['name' => $updatedModel->name]); - } - - /** - * Return an instance of the service with mocked injections. - * - * @return \Pterodactyl\Services\Nodes\NodeUpdateService - */ - private function getService(): NodeUpdateService - { - return new NodeUpdateService( - $this->connection, $this->encrypter, $this->configurationRepository, $this->repository - ); - } -} diff --git a/tests/Unit/Services/Servers/EnvironmentServiceTest.php b/tests/Unit/Services/Servers/EnvironmentServiceTest.php deleted file mode 100644 index 73a41c346..000000000 --- a/tests/Unit/Services/Servers/EnvironmentServiceTest.php +++ /dev/null @@ -1,173 +0,0 @@ -set('pterodactyl.environment_variables', []); - } - - /** - * Test that set environment key stores the key into a retrievable array. - */ - public function testSettingEnvironmentKeyPersistsItInArray() - { - $service = $this->getService(); - - $service->setEnvironmentKey('TEST_KEY', function () { - return true; - }); - - $this->assertNotEmpty($service->getEnvironmentKeys()); - $this->assertArrayHasKey('TEST_KEY', $service->getEnvironmentKeys()); - } - - /** - * Test that environment defaults are returned by the process function. - */ - public function testProcessShouldReturnDefaultEnvironmentVariablesForAServer() - { - $model = $this->getServerModel([ - 'TEST_VARIABLE' => factory(EggVariable::class)->make([ - 'id' => 987, - 'env_variable' => 'TEST_VARIABLE', - 'default_value' => 'Test Variable', - ]), - ]); - - $response = $this->getService()->handle($model); - $this->assertNotEmpty($response); - $this->assertCount(4, $response); - $this->assertArrayHasKey('TEST_VARIABLE', $response); - $this->assertSame('Test Variable', $response['TEST_VARIABLE']); - } - - /** - * Test that variables included at run-time are also included. - */ - public function testProcessShouldReturnKeySetAtRuntime() - { - $model = $this->getServerModel([]); - $service = $this->getService(); - $service->setEnvironmentKey('TEST_VARIABLE', function ($server) { - return $server->uuidShort; - }); - - $response = $service->handle($model); - - $this->assertNotEmpty($response); - $this->assertArrayHasKey('TEST_VARIABLE', $response); - $this->assertSame($model->uuidShort, $response['TEST_VARIABLE']); - } - - /** - * Test that duplicate variables provided in config override the defaults. - */ - public function testProcessShouldAllowOverwritingVariablesWithConfigurationFile() - { - config()->set('pterodactyl.environment_variables', [ - 'P_SERVER_UUID' => 'name', - ]); - - $model = $this->getServerModel([]); - $response = $this->getService()->handle($model); - - $this->assertNotEmpty($response); - $this->assertSame(3, count($response)); - $this->assertArrayHasKey('P_SERVER_UUID', $response); - $this->assertSame($model->name, $response['P_SERVER_UUID']); - } - - /** - * Test that config based environment variables can be done using closures. - */ - public function testVariablesSetInConfigurationAllowForClosures() - { - config()->set('pterodactyl.environment_variables', [ - 'P_SERVER_UUID' => function ($server) { - return $server->id * 2; - }, - ]); - - $model = $this->getServerModel([]); - $response = $this->getService()->handle($model); - - $this->assertNotEmpty($response); - $this->assertSame(3, count($response)); - $this->assertArrayHasKey('P_SERVER_UUID', $response); - $this->assertSame($model->id * 2, $response['P_SERVER_UUID']); - } - - /** - * Test that duplicate variables provided at run-time override the defaults and those - * that are defined in the configuration file. - */ - public function testProcessShouldAllowOverwritingDefaultVariablesWithRuntimeProvided() - { - config()->set('pterodactyl.environment_variables', [ - 'P_SERVER_UUID' => 'overwritten-config', - ]); - - $model = $this->getServerModel([]); - $service = $this->getService(); - $service->setEnvironmentKey('P_SERVER_UUID', function ($model) { - return 'overwritten'; - }); - - $response = $service->handle($model); - - $this->assertNotEmpty($response); - $this->assertSame(3, count($response)); - $this->assertArrayHasKey('P_SERVER_UUID', $response); - $this->assertSame('overwritten', $response['P_SERVER_UUID']); - } - - /** - * Return an instance of the service with mocked dependencies. - * - * @return \Pterodactyl\Services\Servers\EnvironmentService - */ - private function getService(): EnvironmentService - { - return new EnvironmentService; - } - - /** - * Return a server model with a location relationship to be used in the tests. - * - * @param array $variables - * @return \Pterodactyl\Models\Server - */ - private function getServerModel(array $variables): Server - { - /** @var \Pterodactyl\Models\Server $server */ - $server = factory(Server::class)->make([ - 'id' => 123, - 'location' => factory(Location::class)->make(), - ]); - - $server->setRelation('variables', Collection::make($variables)); - - return $server; - } -} diff --git a/tests/Unit/Services/Servers/ServerConfigurationStructureServiceTest.php b/tests/Unit/Services/Servers/ServerConfigurationStructureServiceTest.php deleted file mode 100644 index 9d32323dd..000000000 --- a/tests/Unit/Services/Servers/ServerConfigurationStructureServiceTest.php +++ /dev/null @@ -1,103 +0,0 @@ -environment = m::mock(EnvironmentService::class); - $this->repository = m::mock(ServerRepositoryInterface::class); - } - - /** - * Test that a configuration is returned in the proper format when passed a - * server model that is missing required relationships. - */ - public function testCorrectStructureIsReturned() - { - /** @var \Pterodactyl\Models\Server $model */ - $model = factory(Server::class)->make(); - $model->setRelation('allocation', factory(Allocation::class)->make()); - $model->setRelation('allocations', collect(factory(Allocation::class)->times(2)->make())); - $model->setRelation('egg', factory(Egg::class)->make()); - - $this->environment->expects('handle')->with($model)->andReturn(['environment_array']); - - $response = $this->getService()->handle($model); - $this->assertNotEmpty($response); - $this->assertArrayNotHasKey('user', $response); - $this->assertArrayNotHasKey('keys', $response); - - $this->assertArrayHasKey('uuid', $response); - $this->assertArrayHasKey('suspended', $response); - $this->assertArrayHasKey('environment', $response); - $this->assertArrayHasKey('invocation', $response); - $this->assertArrayHasKey('skip_egg_scripts', $response); - $this->assertArrayHasKey('build', $response); - $this->assertArrayHasKey('container', $response); - $this->assertArrayHasKey('allocations', $response); - - $this->assertSame([ - 'default' => [ - 'ip' => $model->allocation->ip, - 'port' => $model->allocation->port, - ], - 'mappings' => $model->getAllocationMappings(), - ], $response['allocations']); - - $this->assertSame([ - 'memory_limit' => $model->memory, - 'swap' => $model->swap, - 'io_weight' => $model->io, - 'cpu_limit' => $model->cpu, - 'threads' => $model->threads, - 'disk_space' => $model->disk, - ], $response['build']); - - $this->assertSame([ - 'image' => $model->image, - 'oom_disabled' => $model->oom_disabled, - 'requires_rebuild' => false, - ], $response['container']); - - $this->assertSame($model->uuid, $response['uuid']); - $this->assertSame($model->suspended, $response['suspended']); - $this->assertSame(['environment_array'], $response['environment']); - $this->assertSame($model->startup, $response['invocation']); - } - - /** - * Return an instance of the service with mocked dependencies. - * - * @return \Pterodactyl\Services\Servers\ServerConfigurationStructureService - */ - private function getService(): ServerConfigurationStructureService - { - return new ServerConfigurationStructureService($this->environment); - } -} diff --git a/tests/Unit/Services/Servers/StartupCommandViewServiceTest.php b/tests/Unit/Services/Servers/StartupCommandViewServiceTest.php deleted file mode 100644 index 6444b00dd..000000000 --- a/tests/Unit/Services/Servers/StartupCommandViewServiceTest.php +++ /dev/null @@ -1,73 +0,0 @@ -repository = m::mock(ServerRepositoryInterface::class); - } - - /** - * Test that the correct startup string is returned. - */ - public function testServiceResponse() - { - - $server = factory(Server::class)->make([ - 'id' => 123, - 'startup' => 'example {{SERVER_MEMORY}} {{SERVER_IP}} {{SERVER_PORT}} {{TEST_VARIABLE}} {{TEST_VARIABLE_HIDDEN}} {{UNKNOWN}}', - ]); - - $variables = collect([ - factory(EggVariable::class)->make([ - 'env_variable' => 'TEST_VARIABLE', - 'server_value' => 'Test Value', - 'user_viewable' => 1, - ]), - factory(EggVariable::class)->make([ - 'env_variable' => 'TEST_VARIABLE_HIDDEN', - 'server_value' => 'Hidden Value', - 'user_viewable' => 0, - ]), - ]); - - $server->setRelation('variables', $variables); - $server->setRelation('allocation', $allocation = factory(Allocation::class)->make()); - - $response = $this->getService()->handle($server); - $this->assertSame( - sprintf('example %s %s %s %s %s {{UNKNOWN}}', $server->memory, $allocation->ip, $allocation->port, 'Test Value', '[hidden]'), - $response - ); - } - - /** - * Return an instance of the service with mocked dependencies. - * - * @return \Pterodactyl\Services\Servers\StartupCommandService - */ - private function getService(): StartupCommandService - { - return new StartupCommandService; - } -}