Skip to content

Commit

Permalink
[8.x] Create getter for the middleware priority (laravel#37271)
Browse files Browse the repository at this point in the history
* Create getter for the middleware priority

This getter will help to create tests to ensure that middlewares are
registered in the right priority.

My use case for this is a middleware that I want to ensure gets
registered after the `StartSession` but right before the
`AuthenticatesRequests` one. With this getter I can use their indexes to
write a test for it.

* Update Kernel.php

Co-authored-by: Taylor Otwell <taylor@laravel.com>
  • Loading branch information
2 people authored and ibrasho committed May 8, 2021
1 parent c11ecea commit 4a9f917
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 54 deletions.
10 changes: 10 additions & 0 deletions src/Illuminate/Foundation/Http/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
181 changes: 127 additions & 54 deletions src/Illuminate/Testing/Concerns/TestDatabases.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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,
);
}
Expand All @@ -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;
}
}
16 changes: 16 additions & 0 deletions tests/Foundation/Http/KernelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down

0 comments on commit 4a9f917

Please sign in to comment.