Skip to content

Commit

Permalink
Merge pull request #2304 from flarum/fl/tests-in-transaction
Browse files Browse the repository at this point in the history
Run Backend Tests in Transactions
  • Loading branch information
askvortsov1 authored Jan 13, 2021
2 parents 925628c + e5f277e commit 85210ff
Show file tree
Hide file tree
Showing 41 changed files with 462 additions and 586 deletions.
20 changes: 16 additions & 4 deletions tests/integration/BuildsHttpRequests.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@

namespace Flarum\Tests\integration;

use Carbon\Carbon;
use Dflydev\FigCookies\SetCookie;
use Flarum\Http\AccessToken;
use Illuminate\Support\Str;
use Laminas\Diactoros\CallbackStream;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
Expand All @@ -33,10 +34,21 @@ protected function requestWithJsonBody(Request $req, array $json): Request

protected function requestAsUser(Request $req, int $userId): Request
{
$token = AccessToken::generate($userId);
$token->save();
$token = Str::random(40);

return $req->withAddedHeader('Authorization', "Token {$token->token}");
/**
* We insert this directly instead of via `prepareDatabase`
* so that requests can be created/sent after the app is booted.
*/
$this->database()->table('access_tokens')->insert([
'token' => $token,
'user_id' => $userId,
'created_at' => Carbon::now()->toDateTimeString(),
'last_activity_at' => Carbon::now()->toDateTimeString(),
'lifetime_seconds' => 3600
]);

return $req->withAddedHeader('Authorization', "Token {$token}");
}

protected function requestWithCookiesFrom(Request $req, Response $previous): Request
Expand Down
44 changes: 0 additions & 44 deletions tests/integration/RetrievesAuthorizedUsers.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,50 +11,6 @@

trait RetrievesAuthorizedUsers
{
protected function adminGroup(): array
{
return [
'id' => 1,
'name_singular' => 'Admin',
'name_plural' => 'Admins',
'color' => '#B72A2A',
'icon' => 'fas fa-wrench',
];
}

protected function guestGroup(): array
{
return [
'id' => 2,
'name_singular' => 'Guest',
'name_plural' => 'Guests',
'color' => null,
'icon' => null,
];
}

protected function memberGroup(): array
{
return [
'id' => 3,
'name_singular' => 'Member',
'name_plural' => 'Members',
'color' => null,
'icon' => null,
];
}

protected function adminUser(): array
{
return [
'id' => 1,
'username' => 'admin',
'password' => '$2y$10$HMOAe.XaQjOimA778VmFue1OCt7tj5j0wk5vfoL/CMSJq2BQlfBV2', // BCrypt hash for "password"
'email' => 'admin@machine.local',
'is_email_confirmed' => 1,
];
}

protected function normalUser(): array
{
return [
Expand Down
33 changes: 25 additions & 8 deletions tests/integration/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ abstract class TestCase extends \PHPUnit\Framework\TestCase
{
use BuildsHttpRequests;

/**
* @inheritDoc
*/
protected function tearDown(): void
{
parent::tearDown();

$this->database()->rollBack();
}

/**
* @var \Flarum\Foundation\InstalledApp
*/
Expand All @@ -47,6 +57,10 @@ protected function app()
$site->extendWith($this->extenders);

$this->app = $site->bootApp();

$this->database()->beginTransaction();

$this->populateDatabase();
}

return $this->app;
Expand Down Expand Up @@ -89,20 +103,23 @@ protected function database(): ConnectionInterface
return $this->database;
}

protected $databaseContent = [];

protected function prepareDatabase(array $tableData)
{
$this->databaseContent = array_merge_recursive(
$this->databaseContent,
$tableData
);
}

protected function populateDatabase()
{
// We temporarily disable foreign key checks to simplify this process.
$this->database()->getSchemaBuilder()->disableForeignKeyConstraints();

// First, truncate all referenced tables so that they are empty.
foreach (array_keys($tableData) as $table) {
if ($table !== 'settings') {
$this->database()->table($table)->truncate();
}
}

// Then, insert all rows required for this test case.
foreach ($tableData as $table => $rows) {
foreach ($this->databaseContent as $table => $rows) {
foreach ($rows as $row) {
if ($table === 'settings') {
$this->database()->table($table)->updateOrInsert(
Expand Down
25 changes: 25 additions & 0 deletions tests/integration/UsesSettings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/

namespace Flarum\Tests\integration;

use Flarum\Settings\SettingsRepositoryInterface;

trait UsesSettings
{
/**
* Removes the settings respository instance from the IoC container.
*
* This allows test cases that add/modify settings to refresh the in-memory settings cache.
*/
protected function purgeSettingsCache()
{
$this->app()->getContainer()->forgetInstance(SettingsRepositoryInterface::class);
}
}
42 changes: 13 additions & 29 deletions tests/integration/api/authentication/WithApiKeyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,39 +13,29 @@
use Flarum\Api\ApiKey;
use Flarum\Tests\integration\RetrievesAuthorizedUsers;
use Flarum\Tests\integration\TestCase;
use Illuminate\Support\Str;

class WithApiKeyTest extends TestCase
{
use RetrievesAuthorizedUsers;

/**
* @inheritDoc
*/
protected function setUp(): void
{
parent::setUp();

$this->prepareDatabase([
'users' => [
$this->adminUser(),
$this->normalUser(),
],
'group_permission' => [
['permission' => 'viewUserList', 'group_id' => 3]
],
'api_keys' => [],
'api_keys' => [
['key' => 'mastertoken', 'user_id' => null, 'created_at' => Carbon::now()->toDateTimeString()],
['key' => 'personaltoken', 'user_id' => 2, 'created_at' => Carbon::now()->toDateTimeString()],
]
]);
}

protected function key(int $user_id = null): ApiKey
{
return ApiKey::unguarded(function () use ($user_id) {
return ApiKey::query()->firstOrCreate([
'key' => Str::random(),
'user_id' => $user_id,
'created_at' => Carbon::now()
]);
});
}

/**
* @test
*/
Expand All @@ -64,18 +54,16 @@ public function cannot_authorize_without_key()
*/
public function master_token_can_authenticate_as_anyone()
{
$key = $this->key();

$response = $this->send(
$this->request('GET', '/api')
->withAddedHeader('Authorization', "Token {$key->key}; userId=1")
->withAddedHeader('Authorization', 'Token mastertoken; userId=1')
);

$data = json_decode($response->getBody(), true);
$this->assertTrue($data['data']['attributes']['canViewUserList']);
$this->assertArrayHasKey('adminUrl', $data['data']['attributes']);

$key->refresh();
$key = ApiKey::where('key', 'mastertoken')->first();

$this->assertNotNull($key->last_activity_at);
}
Expand All @@ -85,18 +73,16 @@ public function master_token_can_authenticate_as_anyone()
*/
public function personal_api_token_cannot_authenticate_as_anyone()
{
$key = $this->key(2);

$response = $this->send(
$this->request('GET', '/api')
->withAddedHeader('Authorization', "Token {$key->key}; userId=1")
->withAddedHeader('Authorization', 'Token personaltoken; userId=1')
);

$data = json_decode($response->getBody(), true);
$this->assertTrue($data['data']['attributes']['canViewUserList']);
$this->assertArrayNotHasKey('adminUrl', $data['data']['attributes']);

$key->refresh();
$key = ApiKey::where('key', 'personaltoken')->first();

$this->assertNotNull($key->last_activity_at);
}
Expand All @@ -106,18 +92,16 @@ public function personal_api_token_cannot_authenticate_as_anyone()
*/
public function personal_api_token_authenticates_user()
{
$key = $this->key(2);

$response = $this->send(
$this->request('GET', '/api')
->withAddedHeader('Authorization', "Token {$key->key}")
->withAddedHeader('Authorization', 'Token personaltoken')
);

$data = json_decode($response->getBody(), true);
$this->assertTrue($data['data']['attributes']['canViewUserList']);
$this->assertArrayNotHasKey('adminUrl', $data['data']['attributes']);

$key->refresh();
$key = ApiKey::where('key', 'personaltoken')->first();

$this->assertNotNull($key->last_activity_at);
}
Expand Down
3 changes: 3 additions & 0 deletions tests/integration/api/authentication/WithTokenTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ class WithTokenTest extends TestCase
{
use RetrievesAuthorizedUsers;

/**
* @inheritDoc
*/
protected function setUp(): void
{
parent::setUp();
Expand Down
15 changes: 3 additions & 12 deletions tests/integration/api/csrf_protection/RequireCsrfTokenTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,14 @@ class RequireCsrfTokenTest extends TestCase
{
use RetrievesAuthorizedUsers;

/**
* @inheritDoc
*/
protected function setUp(): void
{
parent::setUp();

$this->prepareDatabase([
'users' => [
$this->adminUser(),
],
'groups' => [
$this->adminGroup(),
],
'group_user' => [
['user_id' => 1, 'group_id' => 1],
],
'group_permission' => [
['permission' => 'viewUserList', 'group_id' => 3],
],
'api_keys' => [
['user_id' => 1, 'key' => 'superadmin'],
],
Expand Down
18 changes: 3 additions & 15 deletions tests/integration/api/discussions/CreateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,16 @@ class CreateTest extends TestCase
{
use RetrievesAuthorizedUsers;

/**
* @inheritDoc
*/
protected function setUp(): void
{
parent::setUp();

$this->prepareDatabase([
'discussions' => [],
'posts' => [],
'users' => [
$this->adminUser(),
$this->normalUser(),
],
'groups' => [
$this->adminGroup(),
$this->memberGroup(),
],
'group_user' => [
['user_id' => 1, 'group_id' => 1],
['user_id' => 2, 'group_id' => 3],
],
'group_permission' => [
['permission' => 'viewDiscussions', 'group_id' => 3],
['permission' => 'startDiscussion', 'group_id' => 3],
]
]);
}
Expand Down
10 changes: 3 additions & 7 deletions tests/integration/api/discussions/DeletionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ class DeletionTest extends TestCase
{
use RetrievesAuthorizedUsers;

/**
* @inheritDoc
*/
protected function setUp(): void
{
parent::setUp();
Expand All @@ -29,15 +32,8 @@ protected function setUp(): void
['id' => 1, 'discussion_id' => 1, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'type' => 'comment', 'content' => '<t><p>foo bar</p></t>'],
],
'users' => [
$this->adminUser(),
$this->normalUser(),
],
'groups' => [
$this->adminGroup(),
],
'group_user' => [
['user_id' => 1, 'group_id' => 1],
],
]);
}

Expand Down
Loading

0 comments on commit 85210ff

Please sign in to comment.