mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-05-02 15:30:06 +00:00
Merge pull request #3751 from BookStackApp/parallel_testing
Parallel Testing Support
This commit is contained in:
commit
67d7534d4f
5 changed files with 61 additions and 13 deletions
|
@ -44,6 +44,7 @@
|
||||||
"ssddanbrown/htmldiff": "^1.0.2"
|
"ssddanbrown/htmldiff": "^1.0.2"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
"brianium/paratest": "^6.6",
|
||||||
"fakerphp/faker": "^1.16",
|
"fakerphp/faker": "^1.16",
|
||||||
"itsgoingd/clockwork": "^5.1",
|
"itsgoingd/clockwork": "^5.1",
|
||||||
"mockery/mockery": "^1.4",
|
"mockery/mockery": "^1.4",
|
||||||
|
@ -73,6 +74,8 @@
|
||||||
"format": "phpcbf",
|
"format": "phpcbf",
|
||||||
"lint": "phpcs",
|
"lint": "phpcs",
|
||||||
"test": "phpunit",
|
"test": "phpunit",
|
||||||
|
"t": "@php artisan test --parallel",
|
||||||
|
"t-reset": "@php artisan test --recreate-databases",
|
||||||
"post-autoload-dump": [
|
"post-autoload-dump": [
|
||||||
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
||||||
"@php artisan package:discover --ansi"
|
"@php artisan package:discover --ansi"
|
||||||
|
|
|
@ -108,14 +108,9 @@ npm run dev
|
||||||
|
|
||||||
BookStack has many integration tests that use Laravel's built-in testing capabilities which makes use of PHPUnit. There is a `mysql_testing` database defined within the app config which is what is used by PHPUnit. This database is set with the database name, user name and password all defined as `bookstack-test`. You will have to create that database and that set of credentials before testing.
|
BookStack has many integration tests that use Laravel's built-in testing capabilities which makes use of PHPUnit. There is a `mysql_testing` database defined within the app config which is what is used by PHPUnit. This database is set with the database name, user name and password all defined as `bookstack-test`. You will have to create that database and that set of credentials before testing.
|
||||||
|
|
||||||
The testing database will also need migrating and seeding beforehand. This can be done with the following commands:
|
The testing database will also need migrating and seeding beforehand. This can be done by running `composer refresh-test-database`.
|
||||||
|
|
||||||
``` bash
|
Once done you can run `composer test` in the application root directory to run all tests. Tests can be ran in parallel by running them via `composer t`. This will use Laravel's built-in parallel testing functionality, and attempt to create and seed a database instance for each testing thread. If required these parallel testing instances can be reset, before testing again, by running `composer t-reset`.
|
||||||
php artisan migrate --database=mysql_testing
|
|
||||||
php artisan db:seed --class=DummyContentSeeder --database=mysql_testing
|
|
||||||
```
|
|
||||||
|
|
||||||
Once done you can run `composer test` in the application root directory to run all tests.
|
|
||||||
|
|
||||||
### 📜 Code Standards
|
### 📜 Code Standards
|
||||||
|
|
||||||
|
|
|
@ -22,10 +22,12 @@ use GuzzleHttp\Client;
|
||||||
use GuzzleHttp\Handler\MockHandler;
|
use GuzzleHttp\Handler\MockHandler;
|
||||||
use GuzzleHttp\HandlerStack;
|
use GuzzleHttp\HandlerStack;
|
||||||
use GuzzleHttp\Middleware;
|
use GuzzleHttp\Middleware;
|
||||||
|
use Illuminate\Contracts\Console\Kernel;
|
||||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
|
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Support\Env;
|
use Illuminate\Support\Env;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Testing\Assert as PHPUnit;
|
use Illuminate\Testing\Assert as PHPUnit;
|
||||||
use Monolog\Handler\TestHandler;
|
use Monolog\Handler\TestHandler;
|
||||||
|
@ -47,6 +49,21 @@ abstract class TestCase extends BaseTestCase
|
||||||
*/
|
*/
|
||||||
protected string $baseUrl = 'http://localhost';
|
protected string $baseUrl = 'http://localhost';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the application.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Foundation\Application
|
||||||
|
*/
|
||||||
|
public function createApplication()
|
||||||
|
{
|
||||||
|
/** @var \Illuminate\Foundation\Application $app */
|
||||||
|
$app = require __DIR__ . '/../bootstrap/app.php';
|
||||||
|
$app->register(TestServiceProvider::class);
|
||||||
|
$app->make(Kernel::class)->bootstrap();
|
||||||
|
|
||||||
|
return $app;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the current user context to be an admin.
|
* Set the current user context to be an admin.
|
||||||
*/
|
*/
|
||||||
|
@ -299,6 +316,8 @@ abstract class TestCase extends BaseTestCase
|
||||||
/**
|
/**
|
||||||
* Run a set test with the given env variable.
|
* Run a set test with the given env variable.
|
||||||
* Remembers the original and resets the value after test.
|
* Remembers the original and resets the value after test.
|
||||||
|
* Database config is juggled so the value can be restored when
|
||||||
|
* parallel testing are used, where multiple databases exist.
|
||||||
*/
|
*/
|
||||||
protected function runWithEnv(string $name, $value, callable $callback)
|
protected function runWithEnv(string $name, $value, callable $callback)
|
||||||
{
|
{
|
||||||
|
@ -311,7 +330,12 @@ abstract class TestCase extends BaseTestCase
|
||||||
$_SERVER[$name] = $value;
|
$_SERVER[$name] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$database = config('database.connections.mysql_testing.database');
|
||||||
$this->refreshApplication();
|
$this->refreshApplication();
|
||||||
|
|
||||||
|
DB::purge();
|
||||||
|
config()->set('database.connections.mysql_testing.database', $database);
|
||||||
|
|
||||||
$callback();
|
$callback();
|
||||||
|
|
||||||
if (is_null($originalVal)) {
|
if (is_null($originalVal)) {
|
||||||
|
|
26
tests/TestServiceProvider.php
Normal file
26
tests/TestServiceProvider.php
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Artisan;
|
||||||
|
use Illuminate\Support\Facades\ParallelTesting;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
|
class TestServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Bootstrap services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot()
|
||||||
|
{
|
||||||
|
// Tell Laravel's parallel testing functionality to seed the test
|
||||||
|
// databases with the DummyContentSeeder upon creation.
|
||||||
|
// This is only done for initial database creation. Seeding
|
||||||
|
// won't occur on every run.
|
||||||
|
ParallelTesting::setUpTestDatabase(function ($database, $token) {
|
||||||
|
Artisan::call('db:seed --class=DummyContentSeeder');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -322,8 +322,8 @@ class ThemeTest extends TestCase
|
||||||
|
|
||||||
public function test_export_body_start_and_end_template_files_can_be_used()
|
public function test_export_body_start_and_end_template_files_can_be_used()
|
||||||
{
|
{
|
||||||
$bodyStartStr = 'barry-fought-against-the-panther';
|
$bodyStartStr = 'garry-fought-against-the-panther';
|
||||||
$bodyEndStr = 'barry-lost-his-fight-with-grace';
|
$bodyEndStr = 'garry-lost-his-fight-with-grace';
|
||||||
/** @var Page $page */
|
/** @var Page $page */
|
||||||
$page = Page::query()->first();
|
$page = Page::query()->first();
|
||||||
|
|
||||||
|
@ -342,18 +342,18 @@ class ThemeTest extends TestCase
|
||||||
protected function usingThemeFolder(callable $callback)
|
protected function usingThemeFolder(callable $callback)
|
||||||
{
|
{
|
||||||
// Create a folder and configure a theme
|
// Create a folder and configure a theme
|
||||||
$themeFolderName = 'testing_theme_' . rtrim(base64_encode(time()), '=');
|
$themeFolderName = 'testing_theme_' . str_shuffle(rtrim(base64_encode(time()), '='));
|
||||||
config()->set('view.theme', $themeFolderName);
|
config()->set('view.theme', $themeFolderName);
|
||||||
$themeFolderPath = theme_path('');
|
$themeFolderPath = theme_path('');
|
||||||
|
|
||||||
|
// Create theme folder and clean it up on application tear-down
|
||||||
File::makeDirectory($themeFolderPath);
|
File::makeDirectory($themeFolderPath);
|
||||||
|
$this->beforeApplicationDestroyed(fn() => File::deleteDirectory($themeFolderPath));
|
||||||
|
|
||||||
// Run provided callback with theme env option set
|
// Run provided callback with theme env option set
|
||||||
$this->runWithEnv('APP_THEME', $themeFolderName, function () use ($callback, $themeFolderName) {
|
$this->runWithEnv('APP_THEME', $themeFolderName, function () use ($callback, $themeFolderName) {
|
||||||
call_user_func($callback, $themeFolderName);
|
call_user_func($callback, $themeFolderName);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Cleanup the custom theme folder we created
|
|
||||||
File::deleteDirectory($themeFolderPath);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue