Begin unit tests for repositories

This commit is contained in:
Dane Everitt 2017-08-26 19:58:24 -05:00
parent 72735c24f7
commit f451e4dc47
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
18 changed files with 734 additions and 43 deletions

View file

@ -42,15 +42,4 @@ interface DatabaseHostRepositoryInterface extends RepositoryInterface
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/ */
public function getWithServers($id); public function getWithServers($id);
/**
* Delete a database host from the DB if there are no databases using it.
*
* @param int $id
* @return bool|null
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function deleteIfNoDatabases($id);
} }

View file

@ -0,0 +1,31 @@
<?php
/*
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* 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\Repository;
use Pterodactyl\Exceptions\DisplayException;
class DuplicateDatabaseNameException extends DisplayException
{
}

View file

@ -83,6 +83,8 @@ class LocationController extends Controller
* *
* @param int $id * @param int $id
* @return \Illuminate\View\View * @return \Illuminate\View\View
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/ */
public function view($id) public function view($id)
{ {

View file

@ -434,6 +434,7 @@ class ServersController extends Controller
* *
* @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/ */
public function toggleInstall(Server $server) public function toggleInstall(Server $server)
{ {
@ -493,6 +494,7 @@ class ServersController extends Controller
* *
* @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/ */
public function manageSuspension(Request $request, Server $server) public function manageSuspension(Request $request, Server $server)
{ {
@ -533,6 +535,7 @@ class ServersController extends Controller
* @return \Illuminate\Http\RedirectResponse * @return \Illuminate\Http\RedirectResponse
* *
* @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/ */
public function delete(Request $request, Server $server) public function delete(Request $request, Server $server)
{ {
@ -551,6 +554,7 @@ class ServersController extends Controller
* *
* @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/ */
public function saveStartup(Request $request, Server $server) public function saveStartup(Request $request, Server $server)
{ {

View file

@ -25,7 +25,13 @@
namespace Pterodactyl\Providers; namespace Pterodactyl\Providers;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
use Pterodactyl\Contracts\Repository\Daemon\CommandRepositoryInterface;
use Pterodactyl\Contracts\Repository\Daemon\FileRepositoryInterface;
use Pterodactyl\Contracts\Repository\Daemon\PowerRepositoryInterface;
use Pterodactyl\Contracts\Repository\PackRepositoryInterface; use Pterodactyl\Contracts\Repository\PackRepositoryInterface;
use Pterodactyl\Repositories\Daemon\CommandRepository;
use Pterodactyl\Repositories\Daemon\FileRepository;
use Pterodactyl\Repositories\Daemon\PowerRepository;
use Pterodactyl\Repositories\Eloquent\NodeRepository; use Pterodactyl\Repositories\Eloquent\NodeRepository;
use Pterodactyl\Repositories\Eloquent\PackRepository; use Pterodactyl\Repositories\Eloquent\PackRepository;
use Pterodactyl\Repositories\Eloquent\UserRepository; use Pterodactyl\Repositories\Eloquent\UserRepository;
@ -71,8 +77,8 @@ class RepositoryServiceProvider extends ServiceProvider
$this->app->bind(AllocationRepositoryInterface::class, AllocationRepository::class); $this->app->bind(AllocationRepositoryInterface::class, AllocationRepository::class);
$this->app->bind(ApiKeyRepositoryInterface::class, ApiKeyRepository::class); $this->app->bind(ApiKeyRepositoryInterface::class, ApiKeyRepository::class);
$this->app->bind(ApiPermissionRepositoryInterface::class, ApiPermissionRepository::class); $this->app->bind(ApiPermissionRepositoryInterface::class, ApiPermissionRepository::class);
$this->app->bind(DatabaseHostRepositoryInterface::class, DatabaseHostRepository::class);
$this->app->bind(DatabaseRepositoryInterface::class, DatabaseRepository::class); $this->app->bind(DatabaseRepositoryInterface::class, DatabaseRepository::class);
$this->app->bind(DatabaseHostRepositoryInterface::class, DatabaseHostRepository::class);
$this->app->bind(LocationRepositoryInterface::class, LocationRepository::class); $this->app->bind(LocationRepositoryInterface::class, LocationRepository::class);
$this->app->bind(NodeRepositoryInterface::class, NodeRepository::class); $this->app->bind(NodeRepositoryInterface::class, NodeRepository::class);
$this->app->bind(OptionVariableRepositoryInterface::class, OptionVariableRepository::class); $this->app->bind(OptionVariableRepositoryInterface::class, OptionVariableRepository::class);
@ -86,6 +92,9 @@ class RepositoryServiceProvider extends ServiceProvider
// Daemon Repositories // Daemon Repositories
$this->app->bind(ConfigurationRepositoryInterface::class, ConfigurationRepository::class); $this->app->bind(ConfigurationRepositoryInterface::class, ConfigurationRepository::class);
$this->app->bind(CommandRepositoryInterface::class, CommandRepository::class);
$this->app->bind(DaemonServerRepositoryInterface::class, DaemonServerRepository::class); $this->app->bind(DaemonServerRepositoryInterface::class, DaemonServerRepository::class);
$this->app->bind(FileRepositoryInterface::class, FileRepository::class);
$this->app->bind(PowerRepositoryInterface::class, PowerRepository::class);
} }
} }

View file

@ -26,7 +26,6 @@ namespace Pterodactyl\Repositories\Eloquent;
use Webmozart\Assert\Assert; use Webmozart\Assert\Assert;
use Pterodactyl\Models\DatabaseHost; use Pterodactyl\Models\DatabaseHost;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException; use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
use Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface; use Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface;
@ -48,6 +47,9 @@ class DatabaseHostRepository extends EloquentRepository implements DatabaseHostR
return $this->getBuilder()->withCount('databases')->with('node')->get(); return $this->getBuilder()->withCount('databases')->with('node')->get();
} }
/**
* {@inheritdoc}
*/
public function getWithServers($id) public function getWithServers($id)
{ {
Assert::numeric($id, 'First argument passed to getWithServers must be numeric, recieved %s.'); Assert::numeric($id, 'First argument passed to getWithServers must be numeric, recieved %s.');
@ -59,23 +61,4 @@ class DatabaseHostRepository extends EloquentRepository implements DatabaseHostR
return $instance; return $instance;
} }
/**
* {@inheritdoc}
*/
public function deleteIfNoDatabases($id)
{
Assert::numeric($id, 'First argument passed to deleteIfNoDatabases must be numeric, recieved %s.');
$instance = $this->getBuilder()->withCount('databases')->find($id);
if (! $instance) {
throw new RecordNotFoundException();
}
if ($instance->databases_count > 0) {
throw new DisplayException('Cannot delete a database host that has active databases attached to it.');
}
return $instance->delete();
}
} }

View file

@ -24,10 +24,10 @@
namespace Pterodactyl\Repositories\Eloquent; namespace Pterodactyl\Repositories\Eloquent;
use Pterodactyl\Exceptions\Repository\DuplicateDatabaseNameException;
use Pterodactyl\Models\Database; use Pterodactyl\Models\Database;
use Illuminate\Foundation\Application; use Illuminate\Foundation\Application;
use Illuminate\Database\DatabaseManager; use Illuminate\Database\DatabaseManager;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface; use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface;
class DatabaseRepository extends EloquentRepository implements DatabaseRepositoryInterface class DatabaseRepository extends EloquentRepository implements DatabaseRepositoryInterface
@ -67,13 +67,13 @@ class DatabaseRepository extends EloquentRepository implements DatabaseRepositor
public function createIfNotExists(array $data) public function createIfNotExists(array $data)
{ {
$instance = $this->getBuilder()->where([ $instance = $this->getBuilder()->where([
['server_id', $data['server_id']], ['server_id', '=', array_get($data, 'server_id')],
['database_host_id', $data['database_host_id']], ['database_host_id', '=', array_get($data, 'database_host_id')],
['database', $data['database']], ['database', '=', array_get($data, 'database')],
])->count(); ])->count();
if ($instance > 0) { if ($instance > 0) {
throw new DisplayException('A database with those details already exists for the specified server.'); throw new DuplicateDatabaseNameException('A database with those details already exists for the specified server.');
} }
return $this->create($data); return $this->create($data);

View file

@ -49,6 +49,7 @@ class LocationRepository extends EloquentRepository implements LocationRepositor
/** /**
* {@inheritdoc} * {@inheritdoc}
* @todo remove this, do logic in service
*/ */
public function deleteIfNoNodes($id) public function deleteIfNoNodes($id)
{ {

View file

@ -26,6 +26,8 @@ namespace Pterodactyl\Services\Database;
use Illuminate\Database\DatabaseManager; use Illuminate\Database\DatabaseManager;
use Illuminate\Contracts\Encryption\Encrypter; use Illuminate\Contracts\Encryption\Encrypter;
use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Extensions\DynamicDatabaseConnection; use Pterodactyl\Extensions\DynamicDatabaseConnection;
use Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface; use Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface;
@ -36,6 +38,11 @@ class DatabaseHostService
*/ */
protected $database; protected $database;
/**
* @var \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface
*/
protected $databaseRepository;
/** /**
* @var \Pterodactyl\Extensions\DynamicDatabaseConnection * @var \Pterodactyl\Extensions\DynamicDatabaseConnection
*/ */
@ -55,17 +62,20 @@ class DatabaseHostService
* DatabaseHostService constructor. * DatabaseHostService constructor.
* *
* @param \Illuminate\Database\DatabaseManager $database * @param \Illuminate\Database\DatabaseManager $database
* @param \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface $databaseRepository
* @param \Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface $repository * @param \Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface $repository
* @param \Pterodactyl\Extensions\DynamicDatabaseConnection $dynamic * @param \Pterodactyl\Extensions\DynamicDatabaseConnection $dynamic
* @param \Illuminate\Contracts\Encryption\Encrypter $encrypter * @param \Illuminate\Contracts\Encryption\Encrypter $encrypter
*/ */
public function __construct( public function __construct(
DatabaseManager $database, DatabaseManager $database,
DatabaseRepositoryInterface $databaseRepository,
DatabaseHostRepositoryInterface $repository, DatabaseHostRepositoryInterface $repository,
DynamicDatabaseConnection $dynamic, DynamicDatabaseConnection $dynamic,
Encrypter $encrypter Encrypter $encrypter
) { ) {
$this->database = $database; $this->database = $database;
$this->databaseRepository = $databaseRepository;
$this->dynamic = $dynamic; $this->dynamic = $dynamic;
$this->encrypter = $encrypter; $this->encrypter = $encrypter;
$this->repository = $repository; $this->repository = $repository;
@ -111,6 +121,7 @@ class DatabaseHostService
* @return mixed * @return mixed
* *
* @throws \Pterodactyl\Exceptions\Model\DataValidationException * @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/ */
public function update($id, array $data) public function update($id, array $data)
{ {
@ -142,6 +153,11 @@ class DatabaseHostService
*/ */
public function delete($id) public function delete($id)
{ {
return $this->repository->deleteIfNoDatabases($id); $count = $this->databaseRepository->findCountWhere([['database_host_id', '=', $id]]);
if ($count > 0) {
throw new DisplayException(trans('admin/exceptions.databases.delete_has_databases'));
}
return $this->repository->delete($id);
} }
} }

View file

@ -91,6 +91,7 @@ $factory->define(Pterodactyl\Models\Node::class, function (Faker\Generator $fake
$factory->define(Pterodactyl\Models\Service::class, function (Faker\Generator $faker) { $factory->define(Pterodactyl\Models\Service::class, function (Faker\Generator $faker) {
return [ return [
'id' => $faker->unique()->randomNumber(),
'author' => $faker->unique()->uuid, 'author' => $faker->unique()->uuid,
'name' => $faker->word, 'name' => $faker->word,
'description' => null, 'description' => null,
@ -155,3 +156,24 @@ $factory->define(Pterodactyl\Models\Subuser::class, function (Faker\Generator $f
'daemonSecret' => $faker->unique()->uuid, 'daemonSecret' => $faker->unique()->uuid,
]; ];
}); });
$factory->define(Pterodactyl\Models\Allocation::class, function (Faker\Generator $faker) {
return [
'id' => $faker->unique()->randomNumber(),
'node_id' => $faker->randomNumber(),
'ip' => $faker->ipv4,
'port' => $faker->randomNumber(5),
];
});
$factory->define(Pterodactyl\Models\DatabaseHost::class, function (Faker\Generator $faker) {
return [
'id' => $faker->unique()->randomNumber(),
'name' => $faker->colorName,
'host' => $faker->unique()->ipv4,
'port' => 3306,
'username' => $faker->colorName,
'password' => Crypt::encrypt($faker->word),
'node_id' => $faker->randomNumber(),
];
});

View file

@ -58,4 +58,7 @@ return [
'user_is_owner' => 'You cannot add the server owner as a subuser for this server.', 'user_is_owner' => 'You cannot add the server owner as a subuser for this server.',
'subuser_exists' => 'A user with that email address is already assigned as a subuser for this server.', 'subuser_exists' => 'A user with that email address is already assigned as a subuser for this server.',
], ],
'databases' => [
'delete_has_databases' => 'Cannot delete a database host server that has active databases linked to it.',
],
]; ];

View file

@ -0,0 +1,87 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* 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\Repositories\Eloquent;
use Illuminate\Database\Eloquent\Builder;
use Mockery as m;
use Pterodactyl\Models\Allocation;
use Pterodactyl\Repositories\Eloquent\AllocationRepository;
use Tests\TestCase;
class AllocationRepositoryTest extends TestCase
{
/**
* @var \Illuminate\Database\Eloquent\Builder
*/
protected $builder;
/**
* @var \Pterodactyl\Repositories\Eloquent\AllocationRepository
*/
protected $repository;
/**
* Setup tests.
*/
public function setUp()
{
parent::setUp();
$this->builder = m::mock(Builder::class);
$this->repository = m::mock(AllocationRepository::class)->makePartial();
$this->repository->shouldReceive('getBuilder')->withNoArgs()->andReturn($this->builder);
}
/**
* Test that we are returning the correct model.
*/
public function testCorrectModelIsAssigned()
{
$this->assertEquals(Allocation::class, $this->repository->model());
}
/**
* Test that allocations can be assigned to a server correctly.
*/
public function testAllocationsAreAssignedToAServer()
{
$this->builder->shouldReceive('whereIn')->with('id', [1, 2])->once()->andReturnSelf()
->shouldReceive('update')->with(['server_id' => 10])->once()->andReturn(true);
$this->assertTrue($this->repository->assignAllocationsToServer(10, [1, 2]));
}
/**
* Test that allocations with a node relationship are returned.
*/
public function testAllocationsForANodeAreReturned()
{
$this->builder->shouldReceive('where')->with('node_id', 1)->once()->andReturnSelf()
->shouldReceive('get')->once()->andReturn(factory(Allocation::class)->make());
$this->assertInstanceOf(Allocation::class, $this->repository->getAllocationsForNode(1));
}
}

View file

@ -0,0 +1,65 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* 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\Repositories\Eloquent;
use Illuminate\Database\Eloquent\Builder;
use Mockery as m;
use Pterodactyl\Models\APIKey;
use Pterodactyl\Repositories\Eloquent\ApiKeyRepository;
use Tests\TestCase;
class ApiKeyRepositoryTest extends TestCase
{
/**
* @var \Illuminate\Database\Eloquent\Builder
*/
protected $builder;
/**
* @var \Pterodactyl\Repositories\Eloquent\ApiKeyRepository
*/
protected $repository;
/**
* Setup tests.
*/
public function setUp()
{
parent::setUp();
$this->builder = m::mock(Builder::class);
$this->repository = m::mock(ApiKeyRepository::class)->makePartial();
$this->repository->shouldReceive('getBuilder')->withNoArgs()->andReturn($this->builder);
}
/**
* Test that we are returning the correct model.
*/
public function testCorrectModelIsAssigned()
{
$this->assertEquals(APIKey::class, $this->repository->model());
}
}

View file

@ -0,0 +1,65 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* 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\Repositories\Eloquent;
use Illuminate\Database\Eloquent\Builder;
use Mockery as m;
use Pterodactyl\Models\APIPermission;
use Pterodactyl\Repositories\Eloquent\ApiPermissionRepository;
use Tests\TestCase;
class ApiPermissionRepositoryTest extends TestCase
{
/**
* @var \Illuminate\Database\Eloquent\Builder
*/
protected $builder;
/**
* @var \Pterodactyl\Repositories\Eloquent\ApiPermissionRepository
*/
protected $repository;
/**
* Setup tests.
*/
public function setUp()
{
parent::setUp();
$this->builder = m::mock(Builder::class);
$this->repository = m::mock(ApiPermissionRepository::class)->makePartial();
$this->repository->shouldReceive('getBuilder')->withNoArgs()->andReturn($this->builder);
}
/**
* Test that we are returning the correct model.
*/
public function testCorrectModelIsAssigned()
{
$this->assertEquals(APIPermission::class, $this->repository->model());
}
}

View file

@ -0,0 +1,103 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* 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\Repositories\Eloquent;
use Illuminate\Database\Eloquent\Builder;
use Mockery as m;
use Pterodactyl\Models\DatabaseHost;
use Pterodactyl\Repositories\Eloquent\DatabaseHostRepository;
use Tests\TestCase;
class DatabaseHostRepositoryTest extends TestCase
{
/**
* @var \Illuminate\Database\Eloquent\Builder
*/
protected $builder;
/**
* @var \Pterodactyl\Repositories\Eloquent\DatabaseHostRepository
*/
protected $repository;
/**
* Setup tests.
*/
public function setUp()
{
parent::setUp();
$this->builder = m::mock(Builder::class);
$this->repository = m::mock(DatabaseHostRepository::class)->makePartial();
$this->repository->shouldReceive('getBuilder')->withNoArgs()->andReturn($this->builder);
}
/**
* Test that we are returning the correct model.
*/
public function testCorrectModelIsAssigned()
{
$this->assertEquals(DatabaseHost::class, $this->repository->model());
}
/**
* Test query to reutrn all of the default view data.
*/
public function testHostWithDefaultViewDataIsReturned()
{
$this->builder->shouldReceive('withCount')->with('databases')->once()->andReturnSelf()
->shouldReceive('with')->with('node')->once()->andReturnSelf()
->shouldReceive('get')->withNoArgs()->once()->andReturnNull();
$this->assertNull($this->repository->getWithViewDetails());
}
/**
* Test query to return host and servers.
*/
public function testHostIsReturnedWithServers()
{
$model = factory(DatabaseHost::class)->make();
$this->builder->shouldReceive('with')->with('databases.server')->once()->andReturnSelf()
->shouldReceive('find')->with(1, ['*'])->once()->andReturn($model);
$this->assertEquals($model, $this->repository->getWithServers(1));
}
/**
* Test exception is found if no host is found when querying for servers.
*
* @expectedException \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function testExceptionIsThrownIfNoRecordIsFoundWithServers()
{
$this->builder->shouldReceive('with')->with('databases.server')->once()->andReturnSelf()
->shouldReceive('find')->with(1, ['*'])->once()->andReturnNull();
$this->repository->getWithServers(1);
}
}

View file

@ -0,0 +1,172 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* 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\Repositories\Eloquent;
use Illuminate\Database\Eloquent\Builder;
use Mockery as m;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Exceptions\Repository\DuplicateDatabaseNameException;
use Pterodactyl\Models\Database;
use Pterodactyl\Repositories\Eloquent\DatabaseRepository;
use Tests\TestCase;
class DatabaseRepositoryTest extends TestCase
{
/**
* @var \Illuminate\Database\Eloquent\Builder
*/
protected $builder;
/**
* @var \Pterodactyl\Repositories\Eloquent\DatabaseRepository
*/
protected $repository;
/**
* Setup tests.
*/
public function setUp()
{
parent::setUp();
$this->builder = m::mock(Builder::class);
$this->repository = m::mock(DatabaseRepository::class)->makePartial()->shouldAllowMockingProtectedMethods();
$this->repository->shouldReceive('getBuilder')->withNoArgs()->andReturn($this->builder);
$this->repository->shouldNotReceive('runStatement');
}
/**
* Test that we are returning the correct model.
*/
public function testCorrectModelIsAssigned()
{
$this->assertEquals(Database::class, $this->repository->model());
}
/**
* Test that a database can be created if it does not already exist.
*/
public function testDatabaseIsCreatedIfNotExists()
{
$data = [
'server_id' => 1,
'database_host_id' => 100,
'database' => 'somename',
];
$this->builder->shouldReceive('where')->with([
['server_id', '=', array_get($data, 'server_id')],
['database_host_id', '=', array_get($data, 'database_host_id')],
['database', '=', array_get($data, 'database')],
])->once()->andReturnSelf()
->shouldReceive('count')->withNoArgs()->once()->andReturn(0);
$this->repository->shouldReceive('create')->with($data)->once()->andReturn(true);
$this->assertTrue($this->repository->createIfNotExists($data));
}
/**
* Test that an exception is thrown if a database already exists with the given name.
*/
public function testExceptionIsThrownIfDatabaseAlreadyExists()
{
$this->builder->shouldReceive('where->count')->once()->andReturn(1);
$this->repository->shouldNotReceive('create');
try {
$this->repository->createIfNotExists([]);
} catch (DisplayException $exception) {
$this->assertInstanceOf(DuplicateDatabaseNameException::class, $exception);
$this->assertEquals('A database with those details already exists for the specified server.', $exception->getMessage());
}
}
/**
* Test SQL used to create a database.
*/
public function testCreateDatabaseStatement()
{
$query = sprintf('CREATE DATABASE IF NOT EXISTS `%s`', 'test_database');
$this->repository->shouldReceive('runStatement')->with($query, 'test')->once()->andReturn(true);
$this->assertTrue($this->repository->createDatabase('test_database', 'test'));
}
/**
* Test SQL used to create a user.
*/
public function testCreateUserStatement()
{
$query = sprintf('CREATE USER `%s`@`%s` IDENTIFIED BY \'%s\'', 'test', '%', 'password');
$this->repository->shouldReceive('runStatement')->with($query, 'test')->once()->andReturn(true);
$this->assertTrue($this->repository->createUser('test', '%', 'password', 'test'));
}
/**
* Test that a user is assigned the correct permissions on a database.
*/
public function testUserAssignmentToDatabaseStatement()
{
$query = sprintf('GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX ON `%s`.* TO `%s`@`%s`', 'test_database', 'test', '%');
$this->repository->shouldReceive('runStatement')->with($query, 'test')->once()->andReturn(true);
$this->assertTrue($this->repository->assignUserToDatabase('test_database', 'test', '%', 'test'));
}
/**
* Test SQL for flushing privileges.
*/
public function testFlushStatement()
{
$this->repository->shouldReceive('runStatement')->with('FLUSH PRIVILEGES', 'test')->once()->andReturn(true);
$this->assertTrue($this->repository->flush('test'));
}
/**
* Test SQL to drop a database.
*/
public function testDropDatabaseStatement()
{
$query = sprintf('DROP DATABASE IF EXISTS `%s`', 'test_database');
$this->repository->shouldReceive('runStatement')->with($query, 'test')->once()->andReturn(true);
$this->assertTrue($this->repository->dropDatabase('test_database', 'test'));
}
/**
* Test SQL to drop a user.
*/
public function testDropUserStatement()
{
$query = sprintf('DROP USER IF EXISTS `%s`@`%s`', 'test', '%');
$this->repository->shouldReceive('runStatement')->with($query, 'test')->once()->andReturn(true);
$this->assertTrue($this->repository->dropUser('test', '%', 'test'));
}
}

View file

@ -0,0 +1,115 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* 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\Repositories\Eloquent;
use Illuminate\Database\Eloquent\Builder;
use Mockery as m;
use Pterodactyl\Models\Location;
use Pterodactyl\Repositories\Eloquent\LocationRepository;
use Tests\TestCase;
class LocationRepositoryTest extends TestCase
{
/**
* @var \Illuminate\Database\Eloquent\Builder
*/
protected $builder;
/**
* @var \Pterodactyl\Repositories\Eloquent\LocationRepository
*/
protected $repository;
/**
* Setup tests.
*/
public function setUp()
{
parent::setUp();
$this->builder = m::mock(Builder::class);
$this->repository = m::mock(LocationRepository::class)->makePartial();
$this->repository->shouldReceive('getBuilder')->withNoArgs()->andReturn($this->builder);
}
/**
* Test that we are returning the correct model.
*/
public function testCorrectModelIsAssigned()
{
$this->assertEquals(Location::class, $this->repository->model());
}
/**
* Test that all locations with associated node and server counts are returned.
*/
public function testAllLocationsWithDetailsAreReturned()
{
$this->builder->shouldReceive('withCount')->with('nodes', 'servers')->once()->andReturnSelf()
->shouldReceive('get')->with(['*'])->once()->andReturnNull();
$this->assertNull($this->repository->getAllWithDetails());
}
/**
* Test that all locations with associated node are returned.
*/
public function testAllLocationsWithNodes()
{
$this->builder->shouldReceive('with')->with('nodes')->once()->andReturnSelf()
->shouldReceive('get')->with(['*'])->once()->andReturnNull();
$this->assertNull($this->repository->getAllWithNodes());
}
/**
* Test that a single location with associated node is returned.
*/
public function testLocationWithNodeIsReturned()
{
$model = factory(Location::class)->make();
$this->builder->shouldReceive('with')->with('nodes.servers')->once()->andReturnSelf()
->shouldReceive('find')->with(1, ['*'])->once()->andReturn($model);
$response = $this->repository->getWithNodes(1);
$this->assertInstanceOf(Location::class, $response);
$this->assertEquals($model, $response);
}
/**
* Test that an exception is thrown when getting location with nodes if no location is found.
*
* @expectedException \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function testExceptionIsThrownIfNoLocationIsFoundWithNodes()
{
$this->builder->shouldReceive('with')->with('nodes.servers')->once()->andReturnSelf()
->shouldReceive('find')->with(1, ['*'])->once()->andReturnNull();
$this->repository->getWithNodes(1);
}
}

View file

@ -25,6 +25,8 @@
namespace Tests\Unit\Services\Administrative; namespace Tests\Unit\Services\Administrative;
use Mockery as m; use Mockery as m;
use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface;
use Pterodactyl\Exceptions\DisplayException;
use Tests\TestCase; use Tests\TestCase;
use Illuminate\Database\DatabaseManager; use Illuminate\Database\DatabaseManager;
use Illuminate\Contracts\Encryption\Encrypter; use Illuminate\Contracts\Encryption\Encrypter;
@ -39,6 +41,11 @@ class DatabaseHostServiceTest extends TestCase
*/ */
protected $database; protected $database;
/**
* @var \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface
*/
protected $databaseRepository;
/** /**
* @var \Pterodactyl\Extensions\DynamicDatabaseConnection * @var \Pterodactyl\Extensions\DynamicDatabaseConnection
*/ */
@ -67,12 +74,14 @@ class DatabaseHostServiceTest extends TestCase
parent::setUp(); parent::setUp();
$this->database = m::mock(DatabaseManager::class); $this->database = m::mock(DatabaseManager::class);
$this->databaseRepository = m::mock(DatabaseRepositoryInterface::class);
$this->dynamic = m::mock(DynamicDatabaseConnection::class); $this->dynamic = m::mock(DynamicDatabaseConnection::class);
$this->encrypter = m::mock(Encrypter::class); $this->encrypter = m::mock(Encrypter::class);
$this->repository = m::mock(DatabaseHostRepositoryInterface::class); $this->repository = m::mock(DatabaseHostRepositoryInterface::class);
$this->service = new DatabaseHostService( $this->service = new DatabaseHostService(
$this->database, $this->database,
$this->databaseRepository,
$this->repository, $this->repository,
$this->dynamic, $this->dynamic,
$this->encrypter $this->encrypter
@ -82,7 +91,7 @@ class DatabaseHostServiceTest extends TestCase
/** /**
* Test that creating a host returns the correct data. * Test that creating a host returns the correct data.
*/ */
public function test_create_host_function() public function testHostIsCreated()
{ {
$data = [ $data = [
'password' => 'raw-password', 'password' => 'raw-password',
@ -130,7 +139,7 @@ class DatabaseHostServiceTest extends TestCase
/** /**
* Test that passing a password will store an encrypted version in the DB. * Test that passing a password will store an encrypted version in the DB.
*/ */
public function test_update_with_password() public function testHostIsUpdatedWithPasswordProvided()
{ {
$finalData = (object) ['password' => 'enc-pass', 'host' => '123.456.78.9']; $finalData = (object) ['password' => 'enc-pass', 'host' => '123.456.78.9'];
@ -158,7 +167,7 @@ class DatabaseHostServiceTest extends TestCase
/** /**
* Test that passing no or empty password will skip storing it. * Test that passing no or empty password will skip storing it.
*/ */
public function test_update_without_password() public function testHostIsUpdatedWithoutPassword()
{ {
$finalData = (object) ['host' => '123.456.78.9']; $finalData = (object) ['host' => '123.456.78.9'];
@ -182,12 +191,27 @@ class DatabaseHostServiceTest extends TestCase
/** /**
* Test that a database host can be deleted. * Test that a database host can be deleted.
*/ */
public function test_delete_function() public function testHostIsDeleted()
{ {
$this->repository->shouldReceive('deleteIfNoDatabases')->with(1)->once()->andReturn(true); $this->databaseRepository->shouldReceive('findCountWhere')->with([['database_host_id', '=', 1]])->once()->andReturn(0);
$this->repository->shouldReceive('delete')->with(1)->once()->andReturn(true);
$response = $this->service->delete(1); $response = $this->service->delete(1);
$this->assertTrue($response, 'Assert that response is true.'); $this->assertTrue($response, 'Assert that response is true.');
} }
/**
* Test exception is thrown when there are databases attached to a host.
*/
public function testExceptionIsThrownIfHostHasDatabases()
{
$this->databaseRepository->shouldReceive('findCountWhere')->with([['database_host_id', '=', 1]])->once()->andReturn(2);
try {
$this->service->delete(1);
} catch (DisplayException $exception) {
$this->assertEquals(trans('admin/exceptions.databases.delete_has_databases'), $exception->getMessage());
}
}
} }