From a498bbc7d502a534efd7f0632f18b675b5e60f5d Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 15 Sep 2017 00:16:03 -0500 Subject: [PATCH] Move location service to match other services --- app/Console/Commands/AddLocation.php | 1 - app/Console/Commands/Inspire.php | 33 -------- app/Console/Kernel.php | 1 - .../LocationRepositoryInterface.php | 21 +++-- .../Location/HasActiveNodesException.php | 31 +++++++ .../Controllers/Admin/LocationController.php | 36 ++++++-- .../Eloquent/LocationRepository.php | 36 ++++---- .../LocationCreationService.php} | 37 ++------- .../Locations/LocationDeletionService.php | 78 ++++++++++++++++++ .../Locations/LocationUpdateService.php | 63 ++++++++++++++ resources/lang/en/exceptions.php | 3 + .../Locations/LocationCreationServiceTest.php | 71 ++++++++++++++++ .../LocationDeletionServiceTest.php} | 70 +++++++--------- .../Locations/LocationUpdateServiceTest.php | 82 +++++++++++++++++++ 14 files changed, 414 insertions(+), 149 deletions(-) delete mode 100644 app/Console/Commands/Inspire.php create mode 100644 app/Exceptions/Service/Location/HasActiveNodesException.php rename app/Services/{LocationService.php => Locations/LocationCreationService.php} (69%) create mode 100644 app/Services/Locations/LocationDeletionService.php create mode 100644 app/Services/Locations/LocationUpdateService.php create mode 100644 tests/Unit/Services/Locations/LocationCreationServiceTest.php rename tests/Unit/Services/{LocationServiceTest.php => Locations/LocationDeletionServiceTest.php} (51%) create mode 100644 tests/Unit/Services/Locations/LocationUpdateServiceTest.php diff --git a/app/Console/Commands/AddLocation.php b/app/Console/Commands/AddLocation.php index 80338a33f..c0a41de20 100644 --- a/app/Console/Commands/AddLocation.php +++ b/app/Console/Commands/AddLocation.php @@ -25,7 +25,6 @@ namespace Pterodactyl\Console\Commands; use Illuminate\Console\Command; -use Pterodactyl\Repositories\LocationRepository; class AddLocation extends Command { diff --git a/app/Console/Commands/Inspire.php b/app/Console/Commands/Inspire.php deleted file mode 100644 index b579f2c86..000000000 --- a/app/Console/Commands/Inspire.php +++ /dev/null @@ -1,33 +0,0 @@ -comment(PHP_EOL . Inspiring::quote() . PHP_EOL); - } -} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index e5fa22ee3..233e03ea5 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -13,7 +13,6 @@ class Kernel extends ConsoleKernel * @var array */ protected $commands = [ - \Pterodactyl\Console\Commands\Inspire::class, \Pterodactyl\Console\Commands\MakeUser::class, \Pterodactyl\Console\Commands\ShowVersion::class, \Pterodactyl\Console\Commands\UpdateEnvironment::class, diff --git a/app/Contracts/Repository/LocationRepositoryInterface.php b/app/Contracts/Repository/LocationRepositoryInterface.php index 600c41c14..a293d9855 100644 --- a/app/Contracts/Repository/LocationRepositoryInterface.php +++ b/app/Contracts/Repository/LocationRepositoryInterface.php @@ -28,17 +28,6 @@ use Pterodactyl\Contracts\Repository\Attributes\SearchableInterface; interface LocationRepositoryInterface extends RepositoryInterface, SearchableInterface { - /** - * Delete a location only if there are no nodes attached to it. - * - * @param $id - * @return bool|mixed|null - * - * @throws \Pterodactyl\Exceptions\DisplayException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException - */ - public function deleteIfNoNodes($id); - /** * Return locations with a count of nodes and servers attached to it. * @@ -62,4 +51,14 @@ interface LocationRepositoryInterface extends RepositoryInterface, SearchableInt * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ public function getWithNodes($id); + + /** + * Return a location and the count of nodes in that location. + * + * @param int $id + * @return mixed + * + * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + */ + public function getWithNodeCount($id); } diff --git a/app/Exceptions/Service/Location/HasActiveNodesException.php b/app/Exceptions/Service/Location/HasActiveNodesException.php new file mode 100644 index 000000000..2ebf0368a --- /dev/null +++ b/app/Exceptions/Service/Location/HasActiveNodesException.php @@ -0,0 +1,31 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Exceptions\Service\Location; + +use Pterodactyl\Exceptions\DisplayException; + +class HasActiveNodesException extends DisplayException +{ +} diff --git a/app/Http/Controllers/Admin/LocationController.php b/app/Http/Controllers/Admin/LocationController.php index c7a78baf0..72cba5c96 100644 --- a/app/Http/Controllers/Admin/LocationController.php +++ b/app/Http/Controllers/Admin/LocationController.php @@ -26,10 +26,12 @@ namespace Pterodactyl\Http\Controllers\Admin; use Pterodactyl\Models\Location; use Prologue\Alerts\AlertsMessageBag; -use Pterodactyl\Services\LocationService; use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Http\Requests\Admin\LocationFormRequest; +use Pterodactyl\Services\Locations\LocationUpdateService; +use Pterodactyl\Services\Locations\LocationCreationService; +use Pterodactyl\Services\Locations\LocationDeletionService; use Pterodactyl\Contracts\Repository\LocationRepositoryInterface; class LocationController extends Controller @@ -39,31 +41,47 @@ class LocationController extends Controller */ protected $alert; + /** + * @var \Pterodactyl\Services\Locations\LocationCreationService + */ + protected $creationService; + + /** + * @var \Pterodactyl\Services\Locations\LocationDeletionService + */ + protected $deletionService; + /** * @var \Pterodactyl\Contracts\Repository\LocationRepositoryInterface */ protected $repository; /** - * @var \Pterodactyl\Services\\LocationService + * @var \Pterodactyl\Services\Locations\LocationUpdateService */ - protected $service; + protected $updateService; /** * LocationController constructor. * * @param \Prologue\Alerts\AlertsMessageBag $alert + * @param \Pterodactyl\Services\Locations\LocationCreationService $creationService + * @param \Pterodactyl\Services\Locations\LocationDeletionService $deletionService * @param \Pterodactyl\Contracts\Repository\LocationRepositoryInterface $repository - * @param \Pterodactyl\Services\LocationService $service + * @param \Pterodactyl\Services\Locations\LocationUpdateService $updateService */ public function __construct( AlertsMessageBag $alert, + LocationCreationService $creationService, + LocationDeletionService $deletionService, LocationRepositoryInterface $repository, - LocationService $service + LocationUpdateService $updateService ) { $this->alert = $alert; + $this->creationService = $creationService; + $this->deletionService = $deletionService; $this->repository = $repository; - $this->service = $service; + $this->updateService = $updateService; } /** @@ -104,7 +122,7 @@ class LocationController extends Controller */ public function create(LocationFormRequest $request) { - $location = $this->service->create($request->normalize()); + $location = $this->creationService->handle($request->normalize()); $this->alert->success('Location was created successfully.')->flash(); return redirect()->route('admin.locations.view', $location->id); @@ -126,7 +144,7 @@ class LocationController extends Controller return $this->delete($location); } - $this->service->update($location->id, $request->normalize()); + $this->updateService->handle($location->id, $request->normalize()); $this->alert->success('Location was updated successfully.')->flash(); return redirect()->route('admin.locations.view', $location->id); @@ -144,7 +162,7 @@ class LocationController extends Controller public function delete(Location $location) { try { - $this->service->delete($location->id); + $this->deletionService->handle($location->id); return redirect()->route('admin.locations'); } catch (DisplayException $ex) { diff --git a/app/Repositories/Eloquent/LocationRepository.php b/app/Repositories/Eloquent/LocationRepository.php index 318493a8b..c7e3867ce 100644 --- a/app/Repositories/Eloquent/LocationRepository.php +++ b/app/Repositories/Eloquent/LocationRepository.php @@ -25,7 +25,6 @@ namespace Pterodactyl\Repositories\Eloquent; use Pterodactyl\Models\Location; -use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Repositories\Concerns\Searchable; use Pterodactyl\Exceptions\Repository\RecordNotFoundException; use Pterodactyl\Contracts\Repository\LocationRepositoryInterface; @@ -47,25 +46,6 @@ class LocationRepository extends EloquentRepository implements LocationRepositor return Location::class; } - /** - * {@inheritdoc} - * @todo remove this, do logic in service - */ - public function deleteIfNoNodes($id) - { - $location = $this->getBuilder()->with('nodes')->find($id); - - if (! $location) { - throw new RecordNotFoundException(); - } - - if ($location->nodes_count > 0) { - throw new DisplayException('Cannot delete a location that has nodes assigned to it.'); - } - - return $location->delete(); - } - /** * {@inheritdoc} */ @@ -88,9 +68,21 @@ class LocationRepository extends EloquentRepository implements LocationRepositor public function getWithNodes($id) { $instance = $this->getBuilder()->with('nodes.servers')->find($id, $this->getColumns()); - if (! $instance) { - throw new RecordNotFoundException(); + throw new RecordNotFoundException; + } + + return $instance; + } + + /** + * {@inheritdoc} + */ + public function getWithNodeCount($id) + { + $instance = $this->getBuilder()->withCount('nodes')->find($id, $this->getColumns()); + if (! $instance) { + throw new RecordNotFoundException; } return $instance; diff --git a/app/Services/LocationService.php b/app/Services/Locations/LocationCreationService.php similarity index 69% rename from app/Services/LocationService.php rename to app/Services/Locations/LocationCreationService.php index fc8880335..93db1a7b5 100644 --- a/app/Services/LocationService.php +++ b/app/Services/Locations/LocationCreationService.php @@ -22,11 +22,11 @@ * SOFTWARE. */ -namespace Pterodactyl\Services; +namespace Pterodactyl\Services\Locations; use Pterodactyl\Contracts\Repository\LocationRepositoryInterface; -class LocationService +class LocationCreationService { /** * @var \Pterodactyl\Contracts\Repository\LocationRepositoryInterface @@ -34,7 +34,7 @@ class LocationService protected $repository; /** - * LocationService constructor. + * LocationCreationService constructor. * * @param \Pterodactyl\Contracts\Repository\LocationRepositoryInterface $repository */ @@ -44,42 +44,15 @@ class LocationService } /** - * Create the location in the database and return it. + * Create a new location. * * @param array $data * @return \Pterodactyl\Models\Location * * @throws \Pterodactyl\Exceptions\Model\DataValidationException */ - public function create(array $data) + public function handle(array $data) { return $this->repository->create($data); } - - /** - * Update location model in the DB. - * - * @param int $id - * @param array $data - * @return \Pterodactyl\Models\Location - * - * @throws \Pterodactyl\Exceptions\Model\DataValidationException - */ - public function update($id, array $data) - { - return $this->repository->update($id, $data); - } - - /** - * Delete a model from the DB. - * - * @param int $id - * @return bool - * - * @throws \Pterodactyl\Exceptions\DisplayException - */ - public function delete($id) - { - return $this->repository->deleteIfNoNodes($id); - } } diff --git a/app/Services/Locations/LocationDeletionService.php b/app/Services/Locations/LocationDeletionService.php new file mode 100644 index 000000000..1f4bd3199 --- /dev/null +++ b/app/Services/Locations/LocationDeletionService.php @@ -0,0 +1,78 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Services\Locations; + +use Webmozart\Assert\Assert; +use Pterodactyl\Contracts\Repository\NodeRepositoryInterface; +use Pterodactyl\Contracts\Repository\LocationRepositoryInterface; +use Pterodactyl\Exceptions\Service\Location\HasActiveNodesException; + +class LocationDeletionService +{ + /** + * @var \Pterodactyl\Contracts\Repository\NodeRepositoryInterface + */ + protected $nodeRepository; + + /** + * @var \Pterodactyl\Contracts\Repository\LocationRepositoryInterface + */ + protected $repository; + + /** + * LocationDeletionService constructor. + * + * @param \Pterodactyl\Contracts\Repository\LocationRepositoryInterface $repository + * @param \Pterodactyl\Contracts\Repository\NodeRepositoryInterface $nodeRepository + */ + public function __construct( + LocationRepositoryInterface $repository, + NodeRepositoryInterface $nodeRepository + ) { + $this->nodeRepository = $nodeRepository; + $this->repository = $repository; + } + + /** + * Delete an existing location. + * + * @param int $location + * @return int|null + * + * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + * @throws \Pterodactyl\Exceptions\Service\Location\HasActiveNodesException + */ + public function handle($location) + { + Assert::integerish($location, 'First argument passed to handle must be numeric, received %s.'); + + $count = $this->nodeRepository->findCountWhere([['location_id', '=', $location]]); + if ($count > 0) { + throw new HasActiveNodesException(trans('exceptions.locations.has_nodes')); + } + + return $this->repository->delete($location); + } +} diff --git a/app/Services/Locations/LocationUpdateService.php b/app/Services/Locations/LocationUpdateService.php new file mode 100644 index 000000000..927772a04 --- /dev/null +++ b/app/Services/Locations/LocationUpdateService.php @@ -0,0 +1,63 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Services\Locations; + +use Pterodactyl\Models\Location; +use Pterodactyl\Contracts\Repository\LocationRepositoryInterface; + +class LocationUpdateService +{ + /** + * @var \Pterodactyl\Contracts\Repository\LocationRepositoryInterface + */ + protected $repository; + + /** + * LocationUpdateService constructor. + * + * @param \Pterodactyl\Contracts\Repository\LocationRepositoryInterface $repository + */ + public function __construct(LocationRepositoryInterface $repository) + { + $this->repository = $repository; + } + + /** + * Update an existing location. + * + * @param int|\Pterodactyl\Models\Location $location + * @param array $data + * @return \Pterodactyl\Models\Location + * + * @throws \Pterodactyl\Exceptions\Model\DataValidationException + * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + */ + public function handle($location, array $data) + { + $location = ($location instanceof Location) ? $location->id : $location; + + return $this->repository->update($location, $data); + } +} diff --git a/resources/lang/en/exceptions.php b/resources/lang/en/exceptions.php index bf876019a..2b17d2ea3 100644 --- a/resources/lang/en/exceptions.php +++ b/resources/lang/en/exceptions.php @@ -65,4 +65,7 @@ return [ 'tasks' => [ 'chain_interval_too_long' => 'The maximum interval time for a chained task is 15 minutes.', ], + 'locations' => [ + 'has_nodes' => 'Cannot delete a location that has active nodes attached to it.', + ], ]; diff --git a/tests/Unit/Services/Locations/LocationCreationServiceTest.php b/tests/Unit/Services/Locations/LocationCreationServiceTest.php new file mode 100644 index 000000000..899d29aa0 --- /dev/null +++ b/tests/Unit/Services/Locations/LocationCreationServiceTest.php @@ -0,0 +1,71 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +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() + { + 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/LocationServiceTest.php b/tests/Unit/Services/Locations/LocationDeletionServiceTest.php similarity index 51% rename from tests/Unit/Services/LocationServiceTest.php rename to tests/Unit/Services/Locations/LocationDeletionServiceTest.php index 442b02b58..4f35e8e68 100644 --- a/tests/Unit/Services/LocationServiceTest.php +++ b/tests/Unit/Services/Locations/LocationDeletionServiceTest.php @@ -1,5 +1,5 @@ . * @@ -22,22 +22,30 @@ * SOFTWARE. */ -namespace Tests\Unit\Services; +namespace Tests\Unit\Services\Locations; use Mockery as m; use Tests\TestCase; -use Pterodactyl\Services\LocationService; +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 LocationServiceTest extends TestCase +class LocationDeletionServiceTest extends TestCase { + /** + * @var \Pterodactyl\Contracts\Repository\NodeRepositoryInterface + */ + protected $nodeRepository; + /** * @var \Pterodactyl\Contracts\Repository\LocationRepositoryInterface */ protected $repository; /** - * @var \Pterodactyl\Services\LocationService + * @var \Pterodactyl\Services\Locations\LocationDeletionService */ protected $service; @@ -48,54 +56,36 @@ class LocationServiceTest extends TestCase { parent::setUp(); + $this->nodeRepository = m::mock(NodeRepositoryInterface::class); $this->repository = m::mock(LocationRepositoryInterface::class); - $this->service = new LocationService($this->repository); + $this->service = new LocationDeletionService($this->repository, $this->nodeRepository); } /** - * Test that creating a location returns the correct information. + * Test that a location is deleted. */ - public function test_create_location() + public function testLocationIsDeleted() { - $data = ['short' => 'shortCode', 'long' => 'longCode']; + $this->nodeRepository->shouldReceive('findCountWhere')->with([['location_id', '=', 123]])->once()->andReturn(0); + $this->repository->shouldReceive('delete')->with(123)->once()->andReturn(1); - $this->repository->shouldReceive('create')->with($data)->once()->andReturn((object) $data); - - $response = $this->service->create($data); - - $this->assertNotNull($response); - $this->assertObjectHasAttribute('short', $response); - $this->assertObjectHasAttribute('long', $response); - $this->assertEquals('shortCode', $response->short); - $this->assertEquals('longCode', $response->long); + $response = $this->service->handle(123); + $this->assertEquals(1, $response); } /** - * Test that updating a location updates it correctly. + * Test that an exception is thrown if nodes are attached to a location. */ - public function test_update_location() + public function testExceptionIsThrownIfNodesAreAttached() { - $data = ['short' => 'newShort']; + $this->nodeRepository->shouldReceive('findCountWhere')->with([['location_id', '=', 123]])->once()->andReturn(1); - $this->repository->shouldReceive('update')->with(1, $data)->once()->andReturn((object) $data); - - $response = $this->service->update(1, $data); - - $this->assertNotNull($response); - $this->assertObjectHasAttribute('short', $response); - $this->assertEquals('newShort', $response->short); - } - - /** - * Test that a location deletion returns valid data. - */ - public function test_delete_location() - { - $this->repository->shouldReceive('deleteIfNoNodes')->with(1)->once()->andReturn(true); - - $response = $this->service->delete(1); - - $this->assertTrue($response); + 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 new file mode 100644 index 000000000..0b3c7af6e --- /dev/null +++ b/tests/Unit/Services/Locations/LocationUpdateServiceTest.php @@ -0,0 +1,82 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +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() + { + 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); + } +}