Merge pull request #3751 from BookStackApp/parallel_testing
Parallel Testing Support
This commit is contained in:
		
						commit
						67d7534d4f
					
				| 
						 | 
				
			
			@ -44,6 +44,7 @@
 | 
			
		|||
        "ssddanbrown/htmldiff": "^1.0.2"
 | 
			
		||||
    },
 | 
			
		||||
    "require-dev": {
 | 
			
		||||
        "brianium/paratest": "^6.6",
 | 
			
		||||
        "fakerphp/faker": "^1.16",
 | 
			
		||||
        "itsgoingd/clockwork": "^5.1",
 | 
			
		||||
        "mockery/mockery": "^1.4",
 | 
			
		||||
| 
						 | 
				
			
			@ -73,6 +74,8 @@
 | 
			
		|||
        "format": "phpcbf",
 | 
			
		||||
        "lint": "phpcs",
 | 
			
		||||
        "test": "phpunit",
 | 
			
		||||
        "t": "@php artisan test --parallel",
 | 
			
		||||
        "t-reset": "@php artisan test --recreate-databases",
 | 
			
		||||
        "post-autoload-dump": [
 | 
			
		||||
            "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
 | 
			
		||||
            "@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.
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
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.
 | 
			
		||||
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`.
 | 
			
		||||
 | 
			
		||||
### 📜 Code Standards
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,10 +22,12 @@ use GuzzleHttp\Client;
 | 
			
		|||
use GuzzleHttp\Handler\MockHandler;
 | 
			
		||||
use GuzzleHttp\HandlerStack;
 | 
			
		||||
use GuzzleHttp\Middleware;
 | 
			
		||||
use Illuminate\Contracts\Console\Kernel;
 | 
			
		||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
 | 
			
		||||
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
 | 
			
		||||
use Illuminate\Http\JsonResponse;
 | 
			
		||||
use Illuminate\Support\Env;
 | 
			
		||||
use Illuminate\Support\Facades\DB;
 | 
			
		||||
use Illuminate\Support\Facades\Log;
 | 
			
		||||
use Illuminate\Testing\Assert as PHPUnit;
 | 
			
		||||
use Monolog\Handler\TestHandler;
 | 
			
		||||
| 
						 | 
				
			
			@ -47,6 +49,21 @@ abstract class TestCase extends BaseTestCase
 | 
			
		|||
     */
 | 
			
		||||
    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.
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -299,6 +316,8 @@ abstract class TestCase extends BaseTestCase
 | 
			
		|||
    /**
 | 
			
		||||
     * Run a set test with the given env variable.
 | 
			
		||||
     * 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)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -311,7 +330,12 @@ abstract class TestCase extends BaseTestCase
 | 
			
		|||
            $_SERVER[$name] = $value;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $database = config('database.connections.mysql_testing.database');
 | 
			
		||||
        $this->refreshApplication();
 | 
			
		||||
 | 
			
		||||
        DB::purge();
 | 
			
		||||
        config()->set('database.connections.mysql_testing.database', $database);
 | 
			
		||||
 | 
			
		||||
        $callback();
 | 
			
		||||
 | 
			
		||||
        if (is_null($originalVal)) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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()
 | 
			
		||||
    {
 | 
			
		||||
        $bodyStartStr = 'barry-fought-against-the-panther';
 | 
			
		||||
        $bodyEndStr = 'barry-lost-his-fight-with-grace';
 | 
			
		||||
        $bodyStartStr = 'garry-fought-against-the-panther';
 | 
			
		||||
        $bodyEndStr = 'garry-lost-his-fight-with-grace';
 | 
			
		||||
        /** @var Page $page */
 | 
			
		||||
        $page = Page::query()->first();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -342,18 +342,18 @@ class ThemeTest extends TestCase
 | 
			
		|||
    protected function usingThemeFolder(callable $callback)
 | 
			
		||||
    {
 | 
			
		||||
        // 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);
 | 
			
		||||
        $themeFolderPath = theme_path('');
 | 
			
		||||
 | 
			
		||||
        // Create theme folder and clean it up on application tear-down
 | 
			
		||||
        File::makeDirectory($themeFolderPath);
 | 
			
		||||
        $this->beforeApplicationDestroyed(fn() => File::deleteDirectory($themeFolderPath));
 | 
			
		||||
 | 
			
		||||
        // Run provided callback with theme env option set
 | 
			
		||||
        $this->runWithEnv('APP_THEME', $themeFolderName, function () use ($callback, $themeFolderName) {
 | 
			
		||||
            call_user_func($callback, $themeFolderName);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Cleanup the custom theme folder we created
 | 
			
		||||
        File::deleteDirectory($themeFolderPath);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue