Add test cases for client servers endpoint
This commit is contained in:
parent
4a677aebae
commit
fc261fe20c
5 changed files with 178 additions and 37 deletions
|
@ -2,6 +2,16 @@
|
||||||
|
|
||||||
namespace Pterodactyl\Models;
|
namespace Pterodactyl\Models;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string $short
|
||||||
|
* @property string $long
|
||||||
|
* @property \Carbon\Carbon $created_at
|
||||||
|
* @property \Carbon\Carbon $updated_at
|
||||||
|
*
|
||||||
|
* @property \Pterodactyl\Models\Node[] $nodes
|
||||||
|
* @property \Pterodactyl\Models\Server[] $servers
|
||||||
|
*/
|
||||||
class Location extends Model
|
class Location extends Model
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,8 +20,6 @@ use Pterodactyl\Models\ApiKey;
|
||||||
|
|
||||||
$factory->define(Pterodactyl\Models\Server::class, function (Faker $faker) {
|
$factory->define(Pterodactyl\Models\Server::class, function (Faker $faker) {
|
||||||
return [
|
return [
|
||||||
'id' => $faker->unique()->randomNumber(),
|
|
||||||
'node_id' => $faker->randomNumber(),
|
|
||||||
'uuid' => $faker->unique()->uuid,
|
'uuid' => $faker->unique()->uuid,
|
||||||
'uuidShort' => str_random(8),
|
'uuidShort' => str_random(8),
|
||||||
'name' => $faker->firstName,
|
'name' => $faker->firstName,
|
||||||
|
@ -34,9 +32,6 @@ $factory->define(Pterodactyl\Models\Server::class, function (Faker $faker) {
|
||||||
'io' => 500,
|
'io' => 500,
|
||||||
'cpu' => 0,
|
'cpu' => 0,
|
||||||
'oom_disabled' => 0,
|
'oom_disabled' => 0,
|
||||||
'allocation_id' => $faker->randomNumber(),
|
|
||||||
'nest_id' => $faker->randomNumber(),
|
|
||||||
'egg_id' => $faker->randomNumber(),
|
|
||||||
'pack_id' => null,
|
'pack_id' => null,
|
||||||
'installed' => 1,
|
'installed' => 1,
|
||||||
'database_limit' => null,
|
'database_limit' => null,
|
||||||
|
@ -50,7 +45,6 @@ $factory->define(Pterodactyl\Models\User::class, function (Faker $faker) {
|
||||||
static $password;
|
static $password;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => $faker->unique()->randomNumber(),
|
|
||||||
'external_id' => $faker->unique()->isbn10,
|
'external_id' => $faker->unique()->isbn10,
|
||||||
'uuid' => $faker->uuid,
|
'uuid' => $faker->uuid,
|
||||||
'username' => $faker->userName,
|
'username' => $faker->userName,
|
||||||
|
@ -74,15 +68,13 @@ $factory->state(Pterodactyl\Models\User::class, 'admin', function () {
|
||||||
|
|
||||||
$factory->define(Pterodactyl\Models\Location::class, function (Faker $faker) {
|
$factory->define(Pterodactyl\Models\Location::class, function (Faker $faker) {
|
||||||
return [
|
return [
|
||||||
'id' => $faker->unique()->randomNumber(),
|
'short' => Str::random(8),
|
||||||
'short' => $faker->unique()->domainWord,
|
|
||||||
'long' => $faker->catchPhrase,
|
'long' => $faker->catchPhrase,
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
$factory->define(Pterodactyl\Models\Node::class, function (Faker $faker) {
|
$factory->define(Pterodactyl\Models\Node::class, function (Faker $faker) {
|
||||||
return [
|
return [
|
||||||
'id' => $faker->unique()->randomNumber(),
|
|
||||||
'uuid' => Uuid::uuid4()->toString(),
|
'uuid' => Uuid::uuid4()->toString(),
|
||||||
'public' => true,
|
'public' => true,
|
||||||
'name' => $faker->firstName,
|
'name' => $faker->firstName,
|
||||||
|
@ -104,7 +96,6 @@ $factory->define(Pterodactyl\Models\Node::class, function (Faker $faker) {
|
||||||
|
|
||||||
$factory->define(Pterodactyl\Models\Nest::class, function (Faker $faker) {
|
$factory->define(Pterodactyl\Models\Nest::class, function (Faker $faker) {
|
||||||
return [
|
return [
|
||||||
'id' => $faker->unique()->randomNumber(),
|
|
||||||
'uuid' => $faker->unique()->uuid,
|
'uuid' => $faker->unique()->uuid,
|
||||||
'author' => 'testauthor@example.com',
|
'author' => 'testauthor@example.com',
|
||||||
'name' => $faker->word,
|
'name' => $faker->word,
|
||||||
|
@ -114,9 +105,7 @@ $factory->define(Pterodactyl\Models\Nest::class, function (Faker $faker) {
|
||||||
|
|
||||||
$factory->define(Pterodactyl\Models\Egg::class, function (Faker $faker) {
|
$factory->define(Pterodactyl\Models\Egg::class, function (Faker $faker) {
|
||||||
return [
|
return [
|
||||||
'id' => $faker->unique()->randomNumber(),
|
|
||||||
'uuid' => $faker->unique()->uuid,
|
'uuid' => $faker->unique()->uuid,
|
||||||
'nest_id' => $faker->unique()->randomNumber(),
|
|
||||||
'name' => $faker->name,
|
'name' => $faker->name,
|
||||||
'description' => implode(' ', $faker->sentences(3)),
|
'description' => implode(' ', $faker->sentences(3)),
|
||||||
'startup' => 'java -jar test.jar',
|
'startup' => 'java -jar test.jar',
|
||||||
|
@ -125,7 +114,6 @@ $factory->define(Pterodactyl\Models\Egg::class, function (Faker $faker) {
|
||||||
|
|
||||||
$factory->define(Pterodactyl\Models\EggVariable::class, function (Faker $faker) {
|
$factory->define(Pterodactyl\Models\EggVariable::class, function (Faker $faker) {
|
||||||
return [
|
return [
|
||||||
'id' => $faker->unique()->randomNumber(),
|
|
||||||
'name' => $faker->firstName,
|
'name' => $faker->firstName,
|
||||||
'description' => $faker->sentence(),
|
'description' => $faker->sentence(),
|
||||||
'env_variable' => strtoupper(str_replace(' ', '_', $faker->words(2, true))),
|
'env_variable' => strtoupper(str_replace(' ', '_', $faker->words(2, true))),
|
||||||
|
@ -146,8 +134,6 @@ $factory->state(Pterodactyl\Models\EggVariable::class, 'editable', function () {
|
||||||
|
|
||||||
$factory->define(Pterodactyl\Models\Pack::class, function (Faker $faker) {
|
$factory->define(Pterodactyl\Models\Pack::class, function (Faker $faker) {
|
||||||
return [
|
return [
|
||||||
'id' => $faker->unique()->randomNumber(),
|
|
||||||
'egg_id' => $faker->randomNumber(),
|
|
||||||
'uuid' => $faker->uuid,
|
'uuid' => $faker->uuid,
|
||||||
'name' => $faker->word,
|
'name' => $faker->word,
|
||||||
'description' => null,
|
'description' => null,
|
||||||
|
@ -159,17 +145,11 @@ $factory->define(Pterodactyl\Models\Pack::class, function (Faker $faker) {
|
||||||
});
|
});
|
||||||
|
|
||||||
$factory->define(Pterodactyl\Models\Subuser::class, function (Faker $faker) {
|
$factory->define(Pterodactyl\Models\Subuser::class, function (Faker $faker) {
|
||||||
return [
|
return [];
|
||||||
'id' => $faker->unique()->randomNumber(),
|
|
||||||
'user_id' => $faker->randomNumber(),
|
|
||||||
'server_id' => $faker->randomNumber(),
|
|
||||||
];
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$factory->define(Pterodactyl\Models\Allocation::class, function (Faker $faker) {
|
$factory->define(Pterodactyl\Models\Allocation::class, function (Faker $faker) {
|
||||||
return [
|
return [
|
||||||
'id' => $faker->unique()->randomNumber(),
|
|
||||||
'node_id' => $faker->randomNumber(),
|
|
||||||
'ip' => $faker->ipv4,
|
'ip' => $faker->ipv4,
|
||||||
'port' => $faker->randomNumber(5),
|
'port' => $faker->randomNumber(5),
|
||||||
];
|
];
|
||||||
|
@ -177,13 +157,11 @@ $factory->define(Pterodactyl\Models\Allocation::class, function (Faker $faker) {
|
||||||
|
|
||||||
$factory->define(Pterodactyl\Models\DatabaseHost::class, function (Faker $faker) {
|
$factory->define(Pterodactyl\Models\DatabaseHost::class, function (Faker $faker) {
|
||||||
return [
|
return [
|
||||||
'id' => $faker->unique()->randomNumber(),
|
|
||||||
'name' => $faker->colorName,
|
'name' => $faker->colorName,
|
||||||
'host' => $faker->unique()->ipv4,
|
'host' => $faker->unique()->ipv4,
|
||||||
'port' => 3306,
|
'port' => 3306,
|
||||||
'username' => $faker->colorName,
|
'username' => $faker->colorName,
|
||||||
'password' => Crypt::encrypt($faker->word),
|
'password' => Crypt::encrypt($faker->word),
|
||||||
'node_id' => $faker->randomNumber(),
|
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -191,9 +169,6 @@ $factory->define(Pterodactyl\Models\Database::class, function (Faker $faker) {
|
||||||
static $password;
|
static $password;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => $faker->unique()->randomNumber(),
|
|
||||||
'server_id' => $faker->randomNumber(),
|
|
||||||
'database_host_id' => $faker->randomNumber(),
|
|
||||||
'database' => str_random(10),
|
'database' => str_random(10),
|
||||||
'username' => str_random(10),
|
'username' => str_random(10),
|
||||||
'remote' => '%',
|
'remote' => '%',
|
||||||
|
@ -205,16 +180,12 @@ $factory->define(Pterodactyl\Models\Database::class, function (Faker $faker) {
|
||||||
|
|
||||||
$factory->define(Pterodactyl\Models\Schedule::class, function (Faker $faker) {
|
$factory->define(Pterodactyl\Models\Schedule::class, function (Faker $faker) {
|
||||||
return [
|
return [
|
||||||
'id' => $faker->unique()->randomNumber(),
|
|
||||||
'server_id' => $faker->randomNumber(),
|
|
||||||
'name' => $faker->firstName(),
|
'name' => $faker->firstName(),
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
$factory->define(Pterodactyl\Models\Task::class, function (Faker $faker) {
|
$factory->define(Pterodactyl\Models\Task::class, function (Faker $faker) {
|
||||||
return [
|
return [
|
||||||
'id' => $faker->unique()->randomNumber(),
|
|
||||||
'schedule_id' => $faker->randomNumber(),
|
|
||||||
'sequence_id' => $faker->randomNumber(1),
|
'sequence_id' => $faker->randomNumber(1),
|
||||||
'action' => 'command',
|
'action' => 'command',
|
||||||
'payload' => 'test command',
|
'payload' => 'test command',
|
||||||
|
@ -225,9 +196,6 @@ $factory->define(Pterodactyl\Models\Task::class, function (Faker $faker) {
|
||||||
|
|
||||||
$factory->define(Pterodactyl\Models\DaemonKey::class, function (Faker $faker) {
|
$factory->define(Pterodactyl\Models\DaemonKey::class, function (Faker $faker) {
|
||||||
return [
|
return [
|
||||||
'id' => $faker->unique()->randomNumber(),
|
|
||||||
'server_id' => $faker->randomNumber(),
|
|
||||||
'user_id' => $faker->randomNumber(),
|
|
||||||
'secret' => 'i_' . str_random(40),
|
'secret' => 'i_' . str_random(40),
|
||||||
'expires_at' => \Carbon\Carbon::now()->addMinutes(10)->toDateTimeString(),
|
'expires_at' => \Carbon\Carbon::now()->addMinutes(10)->toDateTimeString(),
|
||||||
];
|
];
|
||||||
|
@ -237,8 +205,6 @@ $factory->define(Pterodactyl\Models\ApiKey::class, function (Faker $faker) {
|
||||||
static $token;
|
static $token;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => $faker->unique()->randomNumber(),
|
|
||||||
'user_id' => $faker->randomNumber(),
|
|
||||||
'key_type' => ApiKey::TYPE_APPLICATION,
|
'key_type' => ApiKey::TYPE_APPLICATION,
|
||||||
'identifier' => str_random(Pterodactyl\Models\ApiKey::IDENTIFIER_LENGTH),
|
'identifier' => str_random(Pterodactyl\Models\ApiKey::IDENTIFIER_LENGTH),
|
||||||
'token' => $token ?: $token = encrypt(str_random(Pterodactyl\Models\ApiKey::KEY_LENGTH)),
|
'token' => $token ?: $token = encrypt(str_random(Pterodactyl\Models\ApiKey::KEY_LENGTH)),
|
||||||
|
|
162
tests/Integration/Api/Client/ClientControllerTest.php
Normal file
162
tests/Integration/Api/Client/ClientControllerTest.php
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pterodactyl\Tests\Integration\Api\Client;
|
||||||
|
|
||||||
|
use Pterodactyl\Models\Node;
|
||||||
|
use Pterodactyl\Models\User;
|
||||||
|
use Pterodactyl\Models\Server;
|
||||||
|
use Pterodactyl\Models\Subuser;
|
||||||
|
use Pterodactyl\Models\Location;
|
||||||
|
use Pterodactyl\Models\Permission;
|
||||||
|
use Pterodactyl\Tests\Integration\IntegrationTestCase;
|
||||||
|
|
||||||
|
class ClientControllerTest extends IntegrationTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Cleanup after tests are run.
|
||||||
|
*/
|
||||||
|
protected function tearDown(): void
|
||||||
|
{
|
||||||
|
Server::query()->forceDelete();
|
||||||
|
User::query()->forceDelete();
|
||||||
|
Node::query()->forceDelete();
|
||||||
|
Location::query()->forceDelete();
|
||||||
|
|
||||||
|
parent::tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that only the servers a logged in user is assigned to are returned by the
|
||||||
|
* API endpoint. Obviously there are cases such as being an administrator or being
|
||||||
|
* a subuser, but for this test we just want to test a basic scenario and pretend
|
||||||
|
* subusers do not exist at all.
|
||||||
|
*/
|
||||||
|
public function testOnlyLoggedInUsersServersAreReturned()
|
||||||
|
{
|
||||||
|
/** @var \Pterodactyl\Models\User[] $users */
|
||||||
|
$users = factory(User::class)->times(3)->create();
|
||||||
|
|
||||||
|
/** @var \Pterodactyl\Models\Server[] $servers */
|
||||||
|
$servers = [
|
||||||
|
$this->createServerModel(['user_id' => $users[0]->id]),
|
||||||
|
$this->createServerModel(['user_id' => $users[1]->id]),
|
||||||
|
$this->createServerModel(['user_id' => $users[2]->id]),
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->actingAs($users[0])->getJson('/api/client');
|
||||||
|
|
||||||
|
$response->assertOk();
|
||||||
|
$response->assertJsonPath('object', 'list');
|
||||||
|
$response->assertJsonPath('data.0.object', Server::RESOURCE_NAME);
|
||||||
|
$response->assertJsonPath('data.0.attributes.identifier', $servers[0]->uuidShort);
|
||||||
|
$response->assertJsonPath('data.0.attributes.server_owner', true);
|
||||||
|
$response->assertJsonPath('meta.pagination.total', 1);
|
||||||
|
$response->assertJsonPath('meta.pagination.per_page', config('pterodactyl.paginate.frontend.servers'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that all of the servers on the system are returned when making the request as an
|
||||||
|
* administrator and including the ?filter=all parameter in the URL.
|
||||||
|
*/
|
||||||
|
public function testFilterIncludeAllServersWhenAdministrator()
|
||||||
|
{
|
||||||
|
/** @var \Pterodactyl\Models\User[] $users */
|
||||||
|
$users = factory(User::class)->times(3)->create();
|
||||||
|
$users[0]->root_admin = true;
|
||||||
|
|
||||||
|
$servers = [
|
||||||
|
$this->createServerModel(['user_id' => $users[0]->id]),
|
||||||
|
$this->createServerModel(['user_id' => $users[1]->id]),
|
||||||
|
$this->createServerModel(['user_id' => $users[2]->id]),
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->actingAs($users[0])->getJson('/api/client?filter=all');
|
||||||
|
|
||||||
|
$response->assertOk();
|
||||||
|
$response->assertJsonCount(3, 'data');
|
||||||
|
|
||||||
|
for ($i = 0; $i < 3; $i++) {
|
||||||
|
$response->assertJsonPath("data.{$i}.attributes.server_owner", $i === 0);
|
||||||
|
$response->assertJsonPath("data.{$i}.attributes.identifier", $servers[$i]->uuidShort);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that servers where the user is a subuser are returned by default in the API call.
|
||||||
|
*/
|
||||||
|
public function testServersUserIsASubuserOfAreReturned()
|
||||||
|
{
|
||||||
|
/** @var \Pterodactyl\Models\User[] $users */
|
||||||
|
$users = factory(User::class)->times(3)->create();
|
||||||
|
$servers = [
|
||||||
|
$this->createServerModel(['user_id' => $users[0]->id]),
|
||||||
|
$this->createServerModel(['user_id' => $users[1]->id]),
|
||||||
|
$this->createServerModel(['user_id' => $users[2]->id]),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Set user 0 as a subuser of server 1. Thus, we should get two servers
|
||||||
|
// back in the response when making the API call as user 0.
|
||||||
|
Subuser::query()->create([
|
||||||
|
'user_id' => $users[0]->id,
|
||||||
|
'server_id' => $servers[1]->id,
|
||||||
|
'permissions' => [Permission::ACTION_WEBSOCKET_CONNECT],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = $this->actingAs($users[0])->getJson('/api/client');
|
||||||
|
|
||||||
|
$response->assertOk();
|
||||||
|
$response->assertJsonCount(2, 'data');
|
||||||
|
$response->assertJsonPath('data.0.attributes.server_owner', true);
|
||||||
|
$response->assertJsonPath('data.0.attributes.identifier', $servers[0]->uuidShort);
|
||||||
|
$response->assertJsonPath('data.1.attributes.server_owner', false);
|
||||||
|
$response->assertJsonPath('data.1.attributes.identifier', $servers[1]->uuidShort);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns only servers that the user owns, not servers they are a subuser of.
|
||||||
|
*/
|
||||||
|
public function testFilterOnlyOwnerServers()
|
||||||
|
{
|
||||||
|
/** @var \Pterodactyl\Models\User[] $users */
|
||||||
|
$users = factory(User::class)->times(3)->create();
|
||||||
|
$servers = [
|
||||||
|
$this->createServerModel(['user_id' => $users[0]->id]),
|
||||||
|
$this->createServerModel(['user_id' => $users[1]->id]),
|
||||||
|
$this->createServerModel(['user_id' => $users[2]->id]),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Set user 0 as a subuser of server 1. Thus, we should get two servers
|
||||||
|
// back in the response when making the API call as user 0.
|
||||||
|
Subuser::query()->create([
|
||||||
|
'user_id' => $users[0]->id,
|
||||||
|
'server_id' => $servers[1]->id,
|
||||||
|
'permissions' => [Permission::ACTION_WEBSOCKET_CONNECT],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = $this->actingAs($users[0])->getJson('/api/client?filter=owner');
|
||||||
|
|
||||||
|
$response->assertOk();
|
||||||
|
$response->assertJsonCount(1, 'data');
|
||||||
|
$response->assertJsonPath('data.0.attributes.server_owner', true);
|
||||||
|
$response->assertJsonPath('data.0.attributes.identifier', $servers[0]->uuidShort);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that the permissions from the Panel are returned correctly.
|
||||||
|
*/
|
||||||
|
public function testPermissionsAreReturned()
|
||||||
|
{
|
||||||
|
/** @var \Pterodactyl\Models\User $user */
|
||||||
|
$user = factory(User::class)->create();
|
||||||
|
|
||||||
|
$this->actingAs($user)
|
||||||
|
->getJson('/api/client/permissions')
|
||||||
|
->assertOk()
|
||||||
|
->assertJson([
|
||||||
|
'object' => 'system_permissions',
|
||||||
|
'attributes' => [
|
||||||
|
'permissions' => Permission::permissions()->toArray(),
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,10 +5,13 @@ namespace Pterodactyl\Tests\Integration;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
use Cake\Chronos\Chronos;
|
use Cake\Chronos\Chronos;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Tests\Traits\Integration\CreatesTestModels;
|
||||||
use Pterodactyl\Transformers\Api\Application\BaseTransformer;
|
use Pterodactyl\Transformers\Api\Application\BaseTransformer;
|
||||||
|
|
||||||
abstract class IntegrationTestCase extends TestCase
|
abstract class IntegrationTestCase extends TestCase
|
||||||
{
|
{
|
||||||
|
use CreatesTestModels;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup base integration test cases.
|
* Setup base integration test cases.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue