mirror of
https://github.com/pelican-dev/panel.git
synced 2025-05-19 17:34:45 +02:00
Use PestPHP (#962)
* Install Pest * Don’t use bootstrap file anymore * Fix comment * Think this is needed * Reset this * Switch dataproviders to attributes * Fix these * Support in memory databases * Fix this migration * Switch this back for now * Add missing import * Truncate and reseed database * These are replaced now * Switch ci to use pest
This commit is contained in:
parent
635cc6a029
commit
f8ad9a1805
12
.github/workflows/ci.yaml
vendored
12
.github/workflows/ci.yaml
vendored
@ -69,13 +69,13 @@ jobs:
|
||||
run: composer install --no-interaction --no-suggest --prefer-dist
|
||||
|
||||
- name: Unit tests
|
||||
run: vendor/bin/phpunit tests/Unit
|
||||
run: vendor/bin/pest tests/Unit
|
||||
env:
|
||||
DB_HOST: UNIT_NO_DB
|
||||
SKIP_MIGRATIONS: true
|
||||
|
||||
- name: Integration tests
|
||||
run: vendor/bin/phpunit tests/Integration
|
||||
run: vendor/bin/pest tests/Integration
|
||||
env:
|
||||
DB_PORT: ${{ job.services.database.ports[3306] }}
|
||||
DB_USERNAME: root
|
||||
@ -142,13 +142,13 @@ jobs:
|
||||
run: composer install --no-interaction --no-suggest --prefer-dist
|
||||
|
||||
- name: Unit tests
|
||||
run: vendor/bin/phpunit tests/Unit
|
||||
run: vendor/bin/pest tests/Unit
|
||||
env:
|
||||
DB_HOST: UNIT_NO_DB
|
||||
SKIP_MIGRATIONS: true
|
||||
|
||||
- name: Integration tests
|
||||
run: vendor/bin/phpunit tests/Integration
|
||||
run: vendor/bin/pest tests/Integration
|
||||
env:
|
||||
DB_PORT: ${{ job.services.database.ports[3306] }}
|
||||
DB_USERNAME: root
|
||||
@ -206,10 +206,10 @@ jobs:
|
||||
run: touch database/testing.sqlite
|
||||
|
||||
- name: Unit tests
|
||||
run: vendor/bin/phpunit tests/Unit
|
||||
run: vendor/bin/pest tests/Unit
|
||||
env:
|
||||
DB_HOST: UNIT_NO_DB
|
||||
SKIP_MIGRATIONS: true
|
||||
|
||||
- name: Integration tests
|
||||
run: vendor/bin/phpunit tests/Integration
|
||||
run: vendor/bin/pest tests/Integration
|
||||
|
@ -6,9 +6,6 @@ use App\Models\Server;
|
||||
use App\Contracts\Http\ClientPermissionsRequest;
|
||||
use App\Http\Requests\Api\Application\ApplicationApiRequest;
|
||||
|
||||
/**
|
||||
* @method \App\Models\User user($guard = null)
|
||||
*/
|
||||
class ClientApiRequest extends ApplicationApiRequest
|
||||
{
|
||||
/**
|
||||
@ -23,7 +20,7 @@ class ClientApiRequest extends ApplicationApiRequest
|
||||
return $this->user()->can($this->permission(), $server);
|
||||
}
|
||||
|
||||
// If there is no server available on the reqest, trigger a failure since
|
||||
// If there is no server available on the request, trigger a failure since
|
||||
// we expect there to be one at this point.
|
||||
return false;
|
||||
}
|
||||
|
@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use NunoMaduro\Collision\Provider;
|
||||
use Illuminate\Contracts\Console\Kernel;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$app = require __DIR__ . '/app.php';
|
||||
|
||||
/** @var \App\Console\Kernel $kernel */
|
||||
$kernel = $app->make(Kernel::class);
|
||||
|
||||
/*
|
||||
* Bootstrap the kernel and prepare application for testing.
|
||||
*/
|
||||
$kernel->bootstrap();
|
||||
|
||||
// Register the collision service provider so that errors during the test
|
||||
// setup process are output nicely.
|
||||
(new Provider())->register();
|
||||
|
||||
$output = new ConsoleOutput();
|
||||
|
||||
$prefix = 'database.connections.' . config('database.default');
|
||||
if (!Str::contains(config("$prefix.database"), 'test')) {
|
||||
$output->writeln(PHP_EOL . '<error>Cannot run test process against non-testing database.</error>');
|
||||
$output->writeln(PHP_EOL . '<error>Environment is currently pointed at: "' . config("$prefix.database") . '".</error>');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform database migrations and reseeding before continuing with
|
||||
* running the tests.
|
||||
*/
|
||||
if (!env('SKIP_MIGRATIONS')) {
|
||||
$output->writeln(PHP_EOL . '<info>Refreshing database for Integration tests...</info>');
|
||||
$kernel->call('migrate:fresh');
|
||||
|
||||
$output->writeln('<info>Seeding database for Integration tests...</info>' . PHP_EOL);
|
||||
$kernel->call('db:seed');
|
||||
} else {
|
||||
$output->writeln(PHP_EOL . '<comment>Skipping database migrations...</comment>' . PHP_EOL);
|
||||
}
|
@ -54,7 +54,7 @@
|
||||
"laravel/sail": "^1.29.1",
|
||||
"mockery/mockery": "^1.6.11",
|
||||
"nunomaduro/collision": "^8.1.1",
|
||||
"phpunit/phpunit": "^10.5.20",
|
||||
"pestphp/pest": "^3.7",
|
||||
"spatie/laravel-ignition": "^2.7"
|
||||
},
|
||||
"autoload": {
|
||||
@ -89,7 +89,10 @@
|
||||
"config": {
|
||||
"optimize-autoloader": true,
|
||||
"preferred-install": "dist",
|
||||
"sort-packages": true
|
||||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
"pestphp/pest-plugin": true
|
||||
}
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"prefer-stable": true
|
||||
|
1198
composer.lock
generated
1198
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,8 @@
|
||||
|
||||
$database = env('DB_DATABASE', 'database.sqlite');
|
||||
$datapasePath = database_path($database);
|
||||
if (str($database)->startsWith('/')) {
|
||||
|
||||
if (str_starts_with($database, '/') || $database === ':memory:') {
|
||||
$databasePath = $database;
|
||||
}
|
||||
|
||||
|
@ -23,8 +23,8 @@ return new class extends Migration
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->addColumn('varchar', 'name_first');
|
||||
$table->addColumn('varchar', 'name_last');
|
||||
$table->string('name_first')->nullable();
|
||||
$table->string('name_last')->nullable();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
60
phpunit.xml
60
phpunit.xml
@ -1,32 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd"
|
||||
bootstrap="bootstrap/tests.php"
|
||||
colors="true"
|
||||
displayDetailsOnSkippedTests="true"
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
|
||||
bootstrap="vendor/autoload.php"
|
||||
colors="true"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Integration">
|
||||
<directory>./tests/Integration</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Unit">
|
||||
<directory>./tests/Unit</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<php>
|
||||
<env name="APP_ENV" value="testing"/>
|
||||
<env name="BCRYPT_ROUNDS" value="4"/>
|
||||
<env name="DB_DATABASE" value="testing.sqlite"/>
|
||||
<env name="CACHE_STORE" value="array"/>
|
||||
<env name="GUZZLE_CONNECT_TIMEOUT" value="1"/>
|
||||
<env name="MAIL_MAILER" value="array"/>
|
||||
<env name="SESSION_DRIVER" value="array"/>
|
||||
<env name="QUEUE_CONNECTION" value="sync"/>
|
||||
</php>
|
||||
<source>
|
||||
<include>
|
||||
<directory suffix=".php">./app</directory>
|
||||
</include>
|
||||
</source>
|
||||
<testsuites>
|
||||
<testsuite name="Integration">
|
||||
<directory>./tests/Integration</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Unit">
|
||||
<directory>./tests/Unit</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<php>
|
||||
<env name="APP_ENV" value="testing"/>
|
||||
<env name="APP_MAINTENANCE_DRIVER" value="file"/>
|
||||
<env name="BCRYPT_ROUNDS" value="4"/>
|
||||
<env name="CACHE_STORE" value="array"/>
|
||||
<env name="DB_CONNECTION" value="sqlite"/>
|
||||
<env name="DB_DATABASE" value="testing.sqlite"/>
|
||||
<env name="GUZZLE_CONNECT_TIMEOUT" value="1"/>
|
||||
<env name="MAIL_MAILER" value="array"/>
|
||||
<env name="PULSE_ENABLED" value="false"/>
|
||||
<env name="QUEUE_CONNECTION" value="sync"/>
|
||||
<env name="SESSION_DRIVER" value="array"/>
|
||||
<env name="TELESCOPE_ENABLED" value="false"/>
|
||||
</php>
|
||||
<source>
|
||||
<include>
|
||||
<directory>app</directory>
|
||||
</include>
|
||||
</source>
|
||||
</phpunit>
|
||||
|
@ -16,7 +16,6 @@ use App\Models\Server;
|
||||
use App\Models\Role;
|
||||
use App\Services\Acl\Api\AdminAcl;
|
||||
use App\Tests\Integration\IntegrationTestCase;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use App\Tests\Traits\Integration\CreatesTestModels;
|
||||
use App\Transformers\Api\Application\BaseTransformer;
|
||||
use App\Transformers\Api\Client\BaseClientTransformer;
|
||||
@ -25,7 +24,6 @@ use App\Tests\Traits\Http\IntegrationJsonRequestAssertions;
|
||||
abstract class ApplicationApiIntegrationTestCase extends IntegrationTestCase
|
||||
{
|
||||
use CreatesTestModels;
|
||||
use DatabaseTransactions;
|
||||
use IntegrationJsonRequestAssertions;
|
||||
|
||||
private ApiKey $key;
|
||||
|
@ -9,6 +9,7 @@ use App\Services\Acl\Api\AdminAcl;
|
||||
use App\Transformers\Api\Application\UserTransformer;
|
||||
use App\Transformers\Api\Application\ServerTransformer;
|
||||
use App\Tests\Integration\Api\Application\ApplicationApiIntegrationTestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class UserControllerTest extends ApplicationApiIntegrationTestCase
|
||||
{
|
||||
@ -272,9 +273,8 @@ class UserControllerTest extends ApplicationApiIntegrationTestCase
|
||||
/**
|
||||
* Test that an API key without write permissions cannot create, update, or
|
||||
* delete a user model.
|
||||
*
|
||||
* @dataProvider userWriteEndpointsDataProvider
|
||||
*/
|
||||
#[DataProvider('userWriteEndpointsDataProvider')]
|
||||
public function testApiKeyWithoutWritePermissions(string $method, string $url): void
|
||||
{
|
||||
$this->createNewDefaultApiKey($this->getApiUser(), [User::RESOURCE_NAME => AdminAcl::READ]);
|
||||
|
@ -7,6 +7,7 @@ use Illuminate\Http\Response;
|
||||
use App\Models\ApiKey;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use App\Events\ActivityLogged;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class ApiKeyControllerTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
@ -44,9 +45,8 @@ class ApiKeyControllerTest extends ClientApiIntegrationTestCase
|
||||
* Test that an API key can be created for the client account. This also checks that the
|
||||
* API key secret is returned as metadata in the response since it will not be returned
|
||||
* after that point.
|
||||
*
|
||||
* @dataProvider validIPAddressDataProvider
|
||||
*/
|
||||
#[DataProvider('validIPAddressDataProvider')]
|
||||
public function testApiKeyCanBeCreatedForAccount(array $data): void
|
||||
{
|
||||
/** @var \App\Models\User $user */
|
||||
|
@ -2,17 +2,13 @@
|
||||
|
||||
namespace App\Tests\Integration\Api\Client;
|
||||
|
||||
use App\Models\Node;
|
||||
use App\Models\Task;
|
||||
use App\Models\User;
|
||||
use App\Models\Model;
|
||||
use App\Models\Backup;
|
||||
use App\Models\Server;
|
||||
use App\Models\Database;
|
||||
use App\Models\Schedule;
|
||||
use Illuminate\Support\Collection;
|
||||
use App\Models\Allocation;
|
||||
use App\Models\DatabaseHost;
|
||||
use App\Tests\Integration\TestResponse;
|
||||
use App\Tests\Integration\IntegrationTestCase;
|
||||
use Illuminate\Database\Eloquent\Model as EloquentModel;
|
||||
@ -20,21 +16,6 @@ use App\Transformers\Api\Client\BaseClientTransformer;
|
||||
|
||||
abstract class ClientApiIntegrationTestCase extends IntegrationTestCase
|
||||
{
|
||||
/**
|
||||
* Cleanup after running tests.
|
||||
*/
|
||||
protected function tearDown(): void
|
||||
{
|
||||
Database::query()->forceDelete();
|
||||
DatabaseHost::query()->forceDelete();
|
||||
Backup::query()->forceDelete();
|
||||
Server::query()->forceDelete();
|
||||
Node::query()->forceDelete();
|
||||
User::query()->forceDelete();
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the default createTestResponse from Illuminate so that we can
|
||||
* just dump 500-level errors to the screen in the tests without having
|
||||
|
@ -8,6 +8,7 @@ use App\Models\Subuser;
|
||||
use App\Models\Allocation;
|
||||
use App\Models\Permission;
|
||||
use App\Models\Role;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class ClientControllerTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
@ -286,9 +287,8 @@ class ClientControllerTest extends ClientApiIntegrationTestCase
|
||||
/**
|
||||
* Test that no servers get returned if the user requests all admin level servers by using
|
||||
* ?type=admin or ?type=admin-all in the request.
|
||||
*
|
||||
* @dataProvider filterTypeDataProvider
|
||||
*/
|
||||
#[DataProvider('filterTypeDataProvider')]
|
||||
public function testNoServersAreReturnedIfAdminFilterIsPassedByRegularUser(string $type): void
|
||||
{
|
||||
/** @var \App\Models\User[] $users */
|
||||
|
@ -5,12 +5,11 @@ namespace App\Tests\Integration\Api\Client\Server\Allocation;
|
||||
use App\Models\Subuser;
|
||||
use App\Models\Allocation;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class AllocationAuthorizationTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider methodDataProvider
|
||||
*/
|
||||
#[DataProvider('methodDataProvider')]
|
||||
public function testAccessToAServersAllocationsIsRestrictedProperly(string $method, string $endpoint): void
|
||||
{
|
||||
// The API $user is the owner of $server1.
|
||||
|
@ -6,6 +6,7 @@ use Illuminate\Http\Response;
|
||||
use App\Models\Allocation;
|
||||
use App\Models\Permission;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class CreateNewAllocationTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
@ -23,9 +24,8 @@ class CreateNewAllocationTest extends ClientApiIntegrationTestCase
|
||||
|
||||
/**
|
||||
* Tests that a new allocation can be properly assigned to a server.
|
||||
*
|
||||
* @dataProvider permissionDataProvider
|
||||
*/
|
||||
#[DataProvider('permissionDataProvider')]
|
||||
public function testNewAllocationCanBeAssignedToServer(array $permission): void
|
||||
{
|
||||
/** @var \App\Models\Server $server */
|
||||
|
@ -6,15 +6,15 @@ use Illuminate\Http\Response;
|
||||
use App\Models\Allocation;
|
||||
use App\Models\Permission;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class DeleteAllocationTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
/**
|
||||
* Test that an allocation is deleted from the server and the notes are properly reset
|
||||
* to an empty value on assignment.
|
||||
*
|
||||
* @dataProvider permissionDataProvider
|
||||
*/
|
||||
#[DataProvider('permissionDataProvider')]
|
||||
public function testAllocationCanBeDeletedFromServer(array $permission): void
|
||||
{
|
||||
/** @var \App\Models\Server $server */
|
||||
|
@ -7,12 +7,11 @@ use App\Models\Backup;
|
||||
use App\Models\Subuser;
|
||||
use App\Services\Backups\DeleteBackupService;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class BackupAuthorizationTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider methodDataProvider
|
||||
*/
|
||||
#[DataProvider('methodDataProvider')]
|
||||
public function testAccessToAServersBackupIsRestrictedProperly(string $method, string $endpoint): void
|
||||
{
|
||||
// The API $user is the owner of $server1.
|
||||
|
@ -8,12 +8,11 @@ use App\Models\DatabaseHost;
|
||||
use App\Services\Databases\DatabasePasswordService;
|
||||
use App\Services\Databases\DatabaseManagementService;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class DatabaseAuthorizationTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider methodDataProvider
|
||||
*/
|
||||
#[DataProvider('methodDataProvider')]
|
||||
public function testAccessToAServersDatabasesIsRestrictedProperly(string $method, string $endpoint): void
|
||||
{
|
||||
// The API $user is the owner of $server1.
|
||||
|
@ -7,6 +7,7 @@ use Illuminate\Http\Response;
|
||||
use App\Models\Allocation;
|
||||
use App\Models\Permission;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class NetworkAllocationControllerTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
@ -48,9 +49,8 @@ class NetworkAllocationControllerTest extends ClientApiIntegrationTestCase
|
||||
|
||||
/**
|
||||
* Tests that notes on an allocation can be set correctly.
|
||||
*
|
||||
* @dataProvider updatePermissionsDataProvider
|
||||
*/
|
||||
#[DataProvider('updatePermissionsDataProvider')]
|
||||
public function testAllocationNotesCanBeUpdated(array $permissions): void
|
||||
{
|
||||
[$user, $server] = $this->generateTestAccount($permissions);
|
||||
@ -96,9 +96,7 @@ class NetworkAllocationControllerTest extends ClientApiIntegrationTestCase
|
||||
$this->actingAs($user)->postJson($this->link($server->allocation))->assertForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider updatePermissionsDataProvider
|
||||
*/
|
||||
#[DataProvider('updatePermissionsDataProvider')]
|
||||
public function testPrimaryAllocationCanBeModified(array $permissions): void
|
||||
{
|
||||
[$user, $server] = $this->generateTestAccount($permissions);
|
||||
|
@ -6,6 +6,7 @@ use Illuminate\Http\Response;
|
||||
use App\Models\Permission;
|
||||
use App\Repositories\Daemon\DaemonPowerRepository;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class PowerControllerTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
@ -15,9 +16,8 @@ class PowerControllerTest extends ClientApiIntegrationTestCase
|
||||
* the command to the server.
|
||||
*
|
||||
* @param string[] $permissions
|
||||
*
|
||||
* @dataProvider invalidPermissionDataProvider
|
||||
*/
|
||||
#[DataProvider('invalidPermissionDataProvider')]
|
||||
public function testSubuserWithoutPermissionsReceivesError(string $action, array $permissions): void
|
||||
{
|
||||
[$user, $server] = $this->generateTestAccount($permissions);
|
||||
@ -45,9 +45,8 @@ class PowerControllerTest extends ClientApiIntegrationTestCase
|
||||
|
||||
/**
|
||||
* Test that sending a valid power actions works.
|
||||
*
|
||||
* @dataProvider validPowerActionDataProvider
|
||||
*/
|
||||
#[DataProvider('validPowerActionDataProvider')]
|
||||
public function testActionCanBeSentToServer(string $action, string $permission): void
|
||||
{
|
||||
$service = \Mockery::mock(DaemonPowerRepository::class);
|
||||
|
@ -6,14 +6,14 @@ use Illuminate\Http\Response;
|
||||
use App\Models\Schedule;
|
||||
use App\Models\Permission;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class CreateServerScheduleTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
/**
|
||||
* Test that a schedule can be created for the server.
|
||||
*
|
||||
* @dataProvider permissionsDataProvider
|
||||
*/
|
||||
#[DataProvider('permissionsDataProvider')]
|
||||
public function testScheduleCanBeCreatedForServer(array $permissions): void
|
||||
{
|
||||
[$user, $server] = $this->generateTestAccount($permissions);
|
||||
|
@ -7,14 +7,14 @@ use Illuminate\Http\Response;
|
||||
use App\Models\Schedule;
|
||||
use App\Models\Permission;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class DeleteServerScheduleTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
/**
|
||||
* Test that a schedule can be deleted from the system.
|
||||
*
|
||||
* @dataProvider permissionsDataProvider
|
||||
*/
|
||||
#[DataProvider('permissionsDataProvider')]
|
||||
public function testScheduleCanBeDeleted(array $permissions): void
|
||||
{
|
||||
[$user, $server] = $this->generateTestAccount($permissions);
|
||||
|
@ -9,14 +9,14 @@ use App\Models\Permission;
|
||||
use Illuminate\Support\Facades\Bus;
|
||||
use App\Jobs\Schedule\RunTaskJob;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class ExecuteScheduleTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
/**
|
||||
* Test that a schedule can be executed and is updated in the database correctly.
|
||||
*
|
||||
* @dataProvider permissionsDataProvider
|
||||
*/
|
||||
#[DataProvider('permissionsDataProvider')]
|
||||
public function testScheduleIsExecutedRightAway(array $permissions): void
|
||||
{
|
||||
[$user, $server] = $this->generateTestAccount($permissions);
|
||||
|
@ -6,6 +6,7 @@ use App\Models\Task;
|
||||
use App\Models\Schedule;
|
||||
use App\Models\Permission;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class GetServerSchedulesTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
@ -22,9 +23,8 @@ class GetServerSchedulesTest extends ClientApiIntegrationTestCase
|
||||
|
||||
/**
|
||||
* Test that schedules for a server are returned.
|
||||
*
|
||||
* @dataProvider permissionsDataProvider
|
||||
*/
|
||||
#[DataProvider('permissionsDataProvider')]
|
||||
public function testServerSchedulesAreReturned(array $permissions, bool $individual): void
|
||||
{
|
||||
[$user, $server] = $this->generateTestAccount($permissions);
|
||||
|
@ -5,6 +5,7 @@ namespace App\Tests\Integration\Api\Client\Server\Schedule;
|
||||
use App\Models\Subuser;
|
||||
use App\Models\Schedule;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class ScheduleAuthorizationTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
@ -16,9 +17,8 @@ class ScheduleAuthorizationTest extends ClientApiIntegrationTestCase
|
||||
*
|
||||
* The comments within the test code itself are better at explaining exactly what is
|
||||
* being tested and protected against.
|
||||
*
|
||||
* @dataProvider methodDataProvider
|
||||
*/
|
||||
#[DataProvider('methodDataProvider')]
|
||||
public function testAccessToAServersSchedulesIsRestrictedProperly(string $method, string $endpoint): void
|
||||
{
|
||||
// The API $user is the owner of $server1.
|
||||
|
@ -6,6 +6,7 @@ use App\Models\Schedule;
|
||||
use App\Helpers\Utilities;
|
||||
use App\Models\Permission;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class UpdateServerScheduleTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
@ -24,9 +25,8 @@ class UpdateServerScheduleTest extends ClientApiIntegrationTestCase
|
||||
|
||||
/**
|
||||
* Test that a schedule can be updated.
|
||||
*
|
||||
* @dataProvider permissionsDataProvider
|
||||
*/
|
||||
#[DataProvider('permissionsDataProvider')]
|
||||
public function testScheduleCanBeUpdated(array $permissions): void
|
||||
{
|
||||
[$user, $server] = $this->generateTestAccount($permissions);
|
||||
|
@ -7,14 +7,14 @@ use Illuminate\Http\Response;
|
||||
use App\Models\Schedule;
|
||||
use App\Models\Permission;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class CreateServerScheduleTaskTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
/**
|
||||
* Test that a task can be created.
|
||||
*
|
||||
* @dataProvider permissionsDataProvider
|
||||
*/
|
||||
#[DataProvider('permissionsDataProvider')]
|
||||
public function testTaskCanBeCreated(array $permissions): void
|
||||
{
|
||||
[$user, $server] = $this->generateTestAccount($permissions);
|
||||
|
@ -8,14 +8,14 @@ use App\Models\Server;
|
||||
use App\Models\Permission;
|
||||
use App\Repositories\Daemon\DaemonServerRepository;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class SettingsControllerTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
/**
|
||||
* Test that the server's name can be changed.
|
||||
*
|
||||
* @dataProvider renamePermissionsDataProvider
|
||||
*/
|
||||
#[DataProvider('renamePermissionsDataProvider')]
|
||||
public function testServerNameCanBeChanged(array $permissions): void
|
||||
{
|
||||
/** @var \App\Models\Server $server */
|
||||
@ -69,9 +69,8 @@ class SettingsControllerTest extends ClientApiIntegrationTestCase
|
||||
/**
|
||||
* Test that a server can be reinstalled. Honestly this test doesn't do much of anything other
|
||||
* than make sure the endpoint works since.
|
||||
*
|
||||
* @dataProvider reinstallPermissionsDataProvider
|
||||
*/
|
||||
#[DataProvider('reinstallPermissionsDataProvider')]
|
||||
public function testServerCanBeReinstalled(array $permissions): void
|
||||
{
|
||||
/** @var \App\Models\Server $server */
|
||||
|
@ -6,15 +6,15 @@ use App\Models\User;
|
||||
use App\Models\Permission;
|
||||
use App\Models\EggVariable;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class GetStartupAndVariablesTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
/**
|
||||
* Test that the startup command and variables are returned for a server, but only the variables
|
||||
* that can be viewed by a user (e.g. user_viewable=true).
|
||||
*
|
||||
* @dataProvider permissionsDataProvider
|
||||
*/
|
||||
#[DataProvider('permissionsDataProvider')]
|
||||
public function testStartupVariablesAreReturnedForServer(array $permissions): void
|
||||
{
|
||||
/** @var \App\Models\Server $server */
|
||||
|
@ -7,14 +7,14 @@ use Illuminate\Http\Response;
|
||||
use App\Models\Permission;
|
||||
use App\Models\EggVariable;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class UpdateStartupVariableTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
/**
|
||||
* Test that a startup variable can be edited successfully for a server.
|
||||
*
|
||||
* @dataProvider permissionsDataProvider
|
||||
*/
|
||||
#[DataProvider('permissionsDataProvider')]
|
||||
public function testStartupVariableCanBeUpdated(array $permissions): void
|
||||
{
|
||||
/** @var \App\Models\Server $server */
|
||||
@ -47,9 +47,8 @@ class UpdateStartupVariableTest extends ClientApiIntegrationTestCase
|
||||
/**
|
||||
* Test that variables that are either not user_viewable, or not user_editable, cannot be
|
||||
* updated via this endpoint.
|
||||
*
|
||||
* @dataProvider permissionsDataProvider
|
||||
*/
|
||||
#[DataProvider('permissionsDataProvider')]
|
||||
public function testStartupVariableCannotBeUpdatedIfNotUserViewableOrEditable(array $permissions): void
|
||||
{
|
||||
/** @var \App\Models\Server $server */
|
||||
|
@ -9,6 +9,7 @@ use App\Models\Subuser;
|
||||
use App\Models\Permission;
|
||||
use Illuminate\Foundation\Testing\WithFaker;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class CreateServerSubuserTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
@ -16,9 +17,8 @@ class CreateServerSubuserTest extends ClientApiIntegrationTestCase
|
||||
|
||||
/**
|
||||
* Test that a subuser can be created for a server.
|
||||
*
|
||||
* @dataProvider permissionsDataProvider
|
||||
*/
|
||||
#[DataProvider('permissionsDataProvider')]
|
||||
public function testSubuserCanBeCreated(array $permissions): void
|
||||
{
|
||||
[$user, $server] = $this->generateTestAccount($permissions);
|
||||
|
@ -6,14 +6,14 @@ use App\Models\User;
|
||||
use App\Models\Subuser;
|
||||
use App\Repositories\Daemon\DaemonServerRepository;
|
||||
use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class SubuserAuthorizationTest extends ClientApiIntegrationTestCase
|
||||
{
|
||||
/**
|
||||
* Test that mismatched subusers are not accessible to a server.
|
||||
*
|
||||
* @dataProvider methodDataProvider
|
||||
*/
|
||||
#[DataProvider('methodDataProvider')]
|
||||
public function testUserCannotAccessResourceBelongingToOtherServers(string $method): void
|
||||
{
|
||||
// Generic subuser, the specific resource we're trying to access.
|
||||
|
@ -6,6 +6,7 @@ use App\Http\Middleware\Api\Daemon\DaemonAuthenticate;
|
||||
use App\Models\Node;
|
||||
use App\Tests\Unit\Http\Middleware\MiddlewareTestCase;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
@ -45,9 +46,8 @@ class DaemonAuthenticateTest extends MiddlewareTestCase
|
||||
/**
|
||||
* Test that passing in an invalid node daemon secret will result in a bad request
|
||||
* exception being returned.
|
||||
*
|
||||
* @dataProvider badTokenDataProvider
|
||||
*/
|
||||
#[DataProvider('badTokenDataProvider')]
|
||||
public function testResponseShouldFailIfTokenFormatIsIncorrect(string $token): void
|
||||
{
|
||||
$this->expectException(BadRequestHttpException::class);
|
||||
|
@ -10,6 +10,7 @@ use App\Models\Permission;
|
||||
use App\Models\Role;
|
||||
use App\Models\UserSSHKey;
|
||||
use App\Tests\Integration\IntegrationTestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class SftpAuthenticationControllerTest extends IntegrationTestCase
|
||||
{
|
||||
@ -95,9 +96,8 @@ class SftpAuthenticationControllerTest extends IntegrationTestCase
|
||||
/**
|
||||
* Test that providing an invalid key and/or invalid username triggers the throttle on
|
||||
* the endpoint.
|
||||
*
|
||||
* @dataProvider authorizationTypeDataProvider
|
||||
*/
|
||||
#[DataProvider('authorizationTypeDataProvider')]
|
||||
public function testUserIsThrottledIfInvalidCredentialsAreProvided(): void
|
||||
{
|
||||
for ($i = 0; $i <= 10; $i++) {
|
||||
@ -113,9 +113,8 @@ class SftpAuthenticationControllerTest extends IntegrationTestCase
|
||||
/**
|
||||
* Test that a request is rejected if the credentials are valid but the username indicates
|
||||
* a server on a different node.
|
||||
*
|
||||
* @dataProvider authorizationTypeDataProvider
|
||||
*/
|
||||
#[DataProvider('authorizationTypeDataProvider')]
|
||||
public function testRequestIsRejectedIfServerBelongsToDifferentNode(string $type): void
|
||||
{
|
||||
$node2 = $this->createServerModel()->node;
|
||||
@ -150,9 +149,7 @@ class SftpAuthenticationControllerTest extends IntegrationTestCase
|
||||
->assertJsonPath('errors.0.detail', 'You do not have permission to access SFTP for this server.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider serverStateDataProvider
|
||||
*/
|
||||
#[DataProvider('serverStateDataProvider')]
|
||||
public function testInvalidServerStateReturnsConflictError(string $status): void
|
||||
{
|
||||
$this->server->update(['status' => $status]);
|
||||
|
@ -5,6 +5,7 @@ namespace App\Tests\Integration;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Carbon\CarbonInterface;
|
||||
use App\Tests\TestCase;
|
||||
use Illuminate\Foundation\Testing\DatabaseTruncation;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use App\Events\ActivityLogged;
|
||||
use App\Tests\Assertions\AssertsActivityLogged;
|
||||
@ -16,6 +17,9 @@ abstract class IntegrationTestCase extends TestCase
|
||||
{
|
||||
use AssertsActivityLogged;
|
||||
use CreatesTestModels;
|
||||
use DatabaseTruncation;
|
||||
|
||||
protected $seed = true;
|
||||
|
||||
protected $defaultHeaders = [
|
||||
'Accept' => 'application/json',
|
||||
|
@ -13,6 +13,7 @@ use App\Jobs\Schedule\RunTaskJob;
|
||||
use App\Tests\Integration\IntegrationTestCase;
|
||||
use App\Repositories\Daemon\DaemonPowerRepository;
|
||||
use Illuminate\Http\Client\ConnectionException;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class RunTaskJobTest extends IntegrationTestCase
|
||||
{
|
||||
@ -62,9 +63,7 @@ class RunTaskJobTest extends IntegrationTestCase
|
||||
Bus::dispatchSync($job);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider isManualRunDataProvider
|
||||
*/
|
||||
#[DataProvider('isManualRunDataProvider')]
|
||||
public function testJobIsExecuted(bool $isManualRun): void
|
||||
{
|
||||
$server = $this->createServerModel();
|
||||
@ -103,9 +102,7 @@ class RunTaskJobTest extends IntegrationTestCase
|
||||
$this->assertTrue(CarbonImmutable::now()->isSameAs(\DateTimeInterface::ATOM, $schedule->last_run_at));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider isManualRunDataProvider
|
||||
*/
|
||||
#[DataProvider('isManualRunDataProvider')]
|
||||
public function testExceptionDuringRunIsHandledCorrectly(bool $continueOnFailure): void
|
||||
{
|
||||
$server = $this->createServerModel();
|
||||
|
@ -9,6 +9,7 @@ use App\Services\Databases\DatabaseManagementService;
|
||||
use App\Exceptions\Repository\DuplicateDatabaseNameException;
|
||||
use App\Exceptions\Service\Database\TooManyDatabasesException;
|
||||
use App\Exceptions\Service\Database\DatabaseClientFeatureNotEnabledException;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class DatabaseManagementServiceTest extends IntegrationTestCase
|
||||
{
|
||||
@ -63,9 +64,8 @@ class DatabaseManagementServiceTest extends IntegrationTestCase
|
||||
|
||||
/**
|
||||
* Test that a missing or invalid database name format causes an exception to be thrown.
|
||||
*
|
||||
* @dataProvider invalidDataDataProvider
|
||||
*/
|
||||
#[DataProvider('invalidDataDataProvider')]
|
||||
public function testEmptyDatabaseNameOrInvalidNameTriggersAnException(array $data): void
|
||||
{
|
||||
$server = $this->createServerModel();
|
||||
|
@ -10,6 +10,7 @@ use App\Tests\Integration\IntegrationTestCase;
|
||||
use App\Services\Databases\DatabaseManagementService;
|
||||
use App\Services\Databases\DeployServerDatabaseService;
|
||||
use App\Exceptions\Service\Database\NoSuitableDatabaseHostException;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class DeployServerDatabaseServiceTest extends IntegrationTestCase
|
||||
{
|
||||
@ -41,9 +42,8 @@ class DeployServerDatabaseServiceTest extends IntegrationTestCase
|
||||
|
||||
/**
|
||||
* Test that an error is thrown if either the database name or the remote host are empty.
|
||||
*
|
||||
* @dataProvider invalidDataProvider
|
||||
*/
|
||||
#[DataProvider('invalidDataProvider')]
|
||||
public function testErrorIsThrownIfDatabaseNameIsEmpty(array $data): void
|
||||
{
|
||||
$server = $this->createServerModel();
|
||||
|
@ -12,6 +12,7 @@ use App\Jobs\Schedule\RunTaskJob;
|
||||
use App\Exceptions\DisplayException;
|
||||
use App\Tests\Integration\IntegrationTestCase;
|
||||
use App\Services\Schedules\ProcessScheduleService;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class ProcessScheduleServiceTest extends IntegrationTestCase
|
||||
{
|
||||
@ -55,9 +56,8 @@ class ProcessScheduleServiceTest extends IntegrationTestCase
|
||||
|
||||
/**
|
||||
* Test that a job is dispatched as expected using the initial delay.
|
||||
*
|
||||
* @dataProvider dispatchNowDataProvider
|
||||
*/
|
||||
#[DataProvider('dispatchNowDataProvider')]
|
||||
public function testJobCanBeDispatchedWithExpectedInitialDelay(bool $now): void
|
||||
{
|
||||
Bus::fake();
|
||||
|
45
tests/Pest.php
Normal file
45
tests/Pest.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Test Case
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The closure you provide to your test functions is always bound to a specific PHPUnit test
|
||||
| case class. By default, that class is "PHPUnit\Framework\TestCase". Of course, you may
|
||||
| need to change it using the "pest()" function to bind a different classes or traits.
|
||||
|
|
||||
*/
|
||||
|
||||
// pest()->extend(Tests\TestCase::class)->in('Feature');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Expectations
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When you're writing tests, you often need to check that values meet certain conditions. The
|
||||
| "expect()" function gives you access to a set of "expectations" methods that you can use
|
||||
| to assert different things. Of course, you may extend the Expectation API at any time.
|
||||
|
|
||||
*/
|
||||
|
||||
expect()->extend('toBeOne', function () {
|
||||
return $this->toBe(1);
|
||||
});
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Functions
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| While Pest is very powerful out-of-the-box, you may have some testing code specific to your
|
||||
| project that you don't want to repeat in every file. Here you can also expose helpers as
|
||||
| global functions to help you to reduce the number of lines of code in your test files.
|
||||
|
|
||||
*/
|
||||
|
||||
function something()
|
||||
{
|
||||
// ..
|
||||
}
|
@ -48,7 +48,7 @@ abstract class TestCase extends BaseTestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the known UUID handling in certain unit tests. Use the "KnownUuid" trait
|
||||
* Handles the known UUID handling in certain unit tests. Use the "MocksUuid" trait
|
||||
* in order to enable this ability.
|
||||
*/
|
||||
public function setKnownUuidFactory()
|
||||
|
@ -4,12 +4,11 @@ namespace App\Tests\Unit\Helpers;
|
||||
|
||||
use App\Tests\TestCase;
|
||||
use App\Traits\EnvironmentWriterTrait;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class EnvironmentWriterTraitTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider variableDataProvider
|
||||
*/
|
||||
#[DataProvider('variableDataProvider')]
|
||||
public function testVariableIsEscapedProperly($input, $expected): void
|
||||
{
|
||||
$output = (new FooClass())->escapeEnvironmentValue($input);
|
||||
|
@ -3,14 +3,14 @@
|
||||
namespace App\Tests\Unit\Helpers;
|
||||
|
||||
use App\Tests\TestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class IsDigitTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Test the is_digit helper.
|
||||
*
|
||||
* @dataProvider helperDataProvider
|
||||
*/
|
||||
#[DataProvider('helperDataProvider')]
|
||||
public function testHelper($value, $response): void
|
||||
{
|
||||
$this->assertSame($response, is_digit($value));
|
||||
|
@ -4,6 +4,7 @@ namespace App\Tests\Unit\Rules;
|
||||
|
||||
use App\Rules\Username;
|
||||
use App\Tests\TestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class UsernameTest extends TestCase
|
||||
{
|
||||
@ -17,9 +18,8 @@ class UsernameTest extends TestCase
|
||||
|
||||
/**
|
||||
* Test valid usernames.
|
||||
*
|
||||
* @dataProvider validUsernameDataProvider
|
||||
*/
|
||||
#[DataProvider('validUsernameDataProvider')]
|
||||
public function testValidUsernames(string $username): void
|
||||
{
|
||||
$this->assertTrue((new Username())->passes('test', $username), 'Assert username is valid.');
|
||||
@ -27,9 +27,8 @@ class UsernameTest extends TestCase
|
||||
|
||||
/**
|
||||
* Test invalid usernames return false.
|
||||
*
|
||||
* @dataProvider invalidUsernameDataProvider
|
||||
*/
|
||||
#[DataProvider('invalidUsernameDataProvider')]
|
||||
public function testInvalidUsernames(string $username): void
|
||||
{
|
||||
$this->assertFalse((new Username())->passes('test', $username), 'Assert username is not valid.');
|
||||
|
@ -6,14 +6,14 @@ use App\Models\ApiKey;
|
||||
use App\Tests\TestCase;
|
||||
use App\Services\Acl\Api\AdminAcl;
|
||||
use App\Models\Server;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class AdminAclTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Test that permissions return the expects values.
|
||||
*
|
||||
* @dataProvider permissionsDataProvider
|
||||
*/
|
||||
#[DataProvider('permissionsDataProvider')]
|
||||
public function testPermissions(int $permission, int $check, bool $outcome): void
|
||||
{
|
||||
$this->assertSame($outcome, AdminAcl::can($permission, $check));
|
||||
|
Loading…
x
Reference in New Issue
Block a user