Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run Backend Tests in Transactions #2304

Merged
merged 13 commits into from
Jan 13, 2021
Merged
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' => '[email protected]',
'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