diff --git a/src/Illuminate/Foundation/Http/Kernel.php b/src/Illuminate/Foundation/Http/Kernel.php index 368bb5fa0471..adb11d008175 100644 --- a/src/Illuminate/Foundation/Http/Kernel.php +++ b/src/Illuminate/Foundation/Http/Kernel.php @@ -383,6 +383,16 @@ protected function syncMiddlewareToRouter() } } + /** + * Get the priority-sorted list of middleware. + * + * @return array + */ + public function getMiddlewarePriority() + { + return $this->middlewarePriority; + } + /** * Get the bootstrap classes for the application. * diff --git a/src/Illuminate/Testing/Concerns/TestDatabases.php b/src/Illuminate/Testing/Concerns/TestDatabases.php index f554f6d26be4..af9cbce20cdf 100644 --- a/src/Illuminate/Testing/Concerns/TestDatabases.php +++ b/src/Illuminate/Testing/Concerns/TestDatabases.php @@ -13,11 +13,32 @@ trait TestDatabases { /** - * Indicates if the test database schema is up to date. + * The connections to manage while parallel testing. * - * @var bool + * @var array */ - protected static $schemaIsUpToDate = false; + public static $connections = []; + + /** + * Indicates if the test database schema is up to date per connection. + * + * @var array + */ + protected static $schemaIsUpToDate = []; + + /** + * The callback used to setup every process. + * + * @var callable + */ + protected static $setUpProcessCallback; + + /** + * The callback used to setup every test case. + * + * @var callable + */ + protected static $setUpTestCaseCallback; /** * Boot a test database. @@ -26,140 +47,178 @@ trait TestDatabases */ protected function bootTestDatabase() { - ParallelTesting::setUpProcess(function () { - $this->whenNotUsingInMemoryDatabase(function ($database) { - if (ParallelTesting::option('recreate_databases')) { - Schema::dropDatabaseIfExists( - $this->testDatabase($database) - ); + ParallelTesting::setUpProcess(static::$setUpProcessCallback ?? function () { + if (! ParallelTesting::option('recreate_databases')) { + return; + } + + foreach ($this->connections() as $connection) { + $this->whenNotUsingInMemoryDatabase($connection, function ($connection, $database) { + dump($this->testDatabase($connection, $database)); + Schema::dropDatabaseIfExists( + $this->testDatabase($connection, $database) + ); + }); } }); - }); - ParallelTesting::setUpTestCase(function ($testCase) { - $uses = array_flip(class_uses_recursive(get_class($testCase))); + ParallelTesting::setUpTestCase(static::$setUpTestCaseCallback ?? function ($testCase) { + $uses = array_flip(class_uses_recursive(get_class($testCase))); - $databaseTraits = [ - Testing\DatabaseMigrations::class, - Testing\DatabaseTransactions::class, - Testing\RefreshDatabase::class, - ]; + $databaseTraits = [ + Testing\DatabaseMigrations::class, + Testing\DatabaseTransactions::class, + Testing\RefreshDatabase::class, + ]; - if (Arr::hasAny($uses, $databaseTraits)) { - $this->whenNotUsingInMemoryDatabase(function ($database) use ($uses) { - [$testDatabase, $created] = $this->ensureTestDatabaseExists($database); + if (Arr::hasAny($uses, $databaseTraits)) { + foreach ($this->connections() as $connection) { + $this->whenNotUsingInMemoryDatabase($connection, function ($connection, $database) use ($uses) { + [$testDatabase, $created] = $this->ensureTestDatabaseExists($connection, $database); - $this->switchToDatabase($testDatabase); + $this->switchToDatabase($connection, $testDatabase); - if (isset($uses[Testing\DatabaseTransactions::class])) { - $this->ensureSchemaIsUpToDate(); - } + if (isset($uses[Testing\DatabaseTransactions::class])) { + $this->ensureSchemaIsUpToDate($connection); + } - if ($created) { - ParallelTesting::callSetUpTestDatabaseCallbacks($testDatabase); + if ($created) { + ParallelTesting::callSetUpTestDatabaseCallbacks($testDatabase); + } + }); } - }); - } - }); + } + }); + } + + /** + * Specify a callback that should be used to setup every parallel testing process. + * + * @param callable $setUpCallback + */ + public static function setUpProcessUsing($setUpCallback) + { + static::$setUpProcessCallback = $setUpCallback; + } + + /** + * Specify a callback that should be used to setup test case while parallel testing. + * + * @param callable $setUpCallback + */ + public static function setUpTestCaseUsing($setUpCallback) + { + static::$setUpTestCaseCallback = $setUpCallback; } /** * Ensure a test database exists and returns its name. * + * @param string $connection * @param string $database * * @return array */ - protected function ensureTestDatabaseExists($database) + protected function ensureTestDatabaseExists($connection, $database) { - $testDatabase = $this->testDatabase($database); + $testDatabase = $this->testDatabase($connection, $database); try { - $this->usingDatabase($testDatabase, function () { - Schema::hasTable('dummy'); + $this->usingDatabase($connection, $testDatabase, function () use ($connection) { + Schema::connection($connection)->hasTable('dummy'); }); } catch (QueryException $e) { - $this->usingDatabase($database, function () use ($testDatabase) { + $this->usingDatabase($connection, $database, function () use ($testDatabase) { Schema::dropDatabaseIfExists($testDatabase); Schema::createDatabase($testDatabase); }); + dump([$testDatabase, true]); + return [$testDatabase, true]; } + dump([$testDatabase, false]); + return [$testDatabase, false]; } /** * Ensure the current database test schema is up to date. * + * @param string $connection + * * @return void */ - protected function ensureSchemaIsUpToDate() + protected function ensureSchemaIsUpToDate($connection) { - if (! static::$schemaIsUpToDate) { - Artisan::call('migrate'); + if (! isset(static::$schemaIsUpToDate) || ! static::$schemaIsUpToDate[$connection]) { + Artisan::call('migrate', ['--database' => $connection]); - static::$schemaIsUpToDate = true; + static::$schemaIsUpToDate[$connection] = true; } } /** * Runs the given callable using the given database. * + * @param string $connection * @param string $database * @param callable $callable + * * @return void */ - protected function usingDatabase($database, $callable) + protected function usingDatabase($connection, $database, $callable) { $original = DB::getConfig('database'); try { - $this->switchToDatabase($database); + $this->switchToDatabase($connection, $database); $callable(); } finally { - $this->switchToDatabase($original); + $this->switchToDatabase($connection, $original); } } /** * Apply the given callback when tests are not using in memory database. * + * @param string $connection * @param callable $callback + * * @return void */ - protected function whenNotUsingInMemoryDatabase($callback) + protected function whenNotUsingInMemoryDatabase($connection, $callback) { - $database = DB::getConfig('database'); + $database = DB::connection($connection)->getConfig('database'); if ($database !== ':memory:') { - $callback($database); + $callback($connection, $database); } } /** - * Switch to the given database. + * Switch the connection to the given database. * + * @param string $connection * @param string $database + * * @return void */ - protected function switchToDatabase($database) + protected function switchToDatabase($connection, $database) { - DB::purge(); - - $default = config('database.default'); + DB::purge($connection); - $url = config("database.connections.{$default}.url"); + $url = config("database.connections.{$connection}.url"); if ($url) { config()->set( - "database.connections.{$default}.url", + "database.connections.{$connection}.url", preg_replace('/^(.*)(\/[\w-]*)(\??.*)$/', "$1/{$database}$3", $url), ); } else { config()->set( - "database.connections.{$default}.database", + "database.connections.{$connection}.database", $database, ); } @@ -168,12 +227,26 @@ protected function switchToDatabase($database) /** * Returns the test database name. * + * @param string $connection + * @param string $database + * * @return string */ - protected function testDatabase($database) + protected function testDatabase($connection, $database) { $token = ParallelTesting::token(); - return "{$database}_test_{$token}"; + return "{$connection}_{$database}_test_{$token}"; + } + + /** + * The connections that should be updated while parallel testing. + * + * @return array + */ + protected function connections() + { + return empty(static::$connections) + ? [config('database.default')] : static::$connections; } } diff --git a/tests/Foundation/Http/KernelTest.php b/tests/Foundation/Http/KernelTest.php index 1e25bb7051ad..5354af5a4d39 100644 --- a/tests/Foundation/Http/KernelTest.php +++ b/tests/Foundation/Http/KernelTest.php @@ -24,6 +24,22 @@ public function testGetRouteMiddleware() $this->assertEquals([], $kernel->getRouteMiddleware()); } + public function testGetMiddlewarePriority() + { + $kernel = new Kernel($this->getApplication(), $this->getRouter()); + + $this->assertEquals([ + \Illuminate\Cookie\Middleware\EncryptCookies::class, + \Illuminate\Session\Middleware\StartSession::class, + \Illuminate\View\Middleware\ShareErrorsFromSession::class, + \Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class, + \Illuminate\Routing\Middleware\ThrottleRequests::class, + \Illuminate\Session\Middleware\AuthenticateSession::class, + \Illuminate\Routing\Middleware\SubstituteBindings::class, + \Illuminate\Auth\Middleware\Authorize::class, + ], $kernel->getMiddlewarePriority()); + } + /** * @return \Illuminate\Contracts\Foundation\Application */