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

[11.x] Skip the number of connections transacting while testing to run callbacks #53377

Open
wants to merge 9 commits into
base: 11.x
Choose a base branch
from
6 changes: 4 additions & 2 deletions src/Illuminate/Foundation/Testing/DatabaseTransactions.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ public function beginDatabaseTransaction()
{
$database = $this->app->make('db');

$this->app->instance('db.transactions', $transactionsManager = new DatabaseTransactionsManager);
$connections = $this->connectionsToTransact();

foreach ($this->connectionsToTransact() as $name) {
$this->app->instance('db.transactions', $transactionsManager = new DatabaseTransactionsManager($connections));

foreach ($connections as $name) {
$connection = $database->connection($name);
$connection->setTransactionManager($transactionsManager);
$dispatcher = $connection->getEventDispatcher();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@

class DatabaseTransactionsManager extends BaseManager
{
/**
* A list with the names of connections transacting on tests to be skiped and run the callbacks correctly.
*/
protected array $connectionsTransacting;

/**
* @param array $connectionsTransacting The name of the connections transacting on tests (to skip for callbacks).
*/
public function __construct(array $connectionsTransacting)
{
parent::__construct();

$this->connectionsTransacting = $connectionsTransacting;
}

/**
* Register a transaction callback.
*
Expand All @@ -31,7 +46,7 @@ public function addCallback($callback)
*/
public function callbackApplicableTransactions()
{
return $this->pendingTransactions->skip(1)->values();
return $this->pendingTransactions->skip(count($this->connectionsTransacting))->values();
}

/**
Expand Down
6 changes: 4 additions & 2 deletions src/Illuminate/Foundation/Testing/RefreshDatabase.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,11 @@ public function beginDatabaseTransaction()
{
$database = $this->app->make('db');

$this->app->instance('db.transactions', $transactionsManager = new DatabaseTransactionsManager);
$connections = $this->connectionsToTransact();

foreach ($this->connectionsToTransact() as $name) {
$this->app->instance('db.transactions', $transactionsManager = new DatabaseTransactionsManager($connections));

foreach ($connections as $name) {
$connection = $database->connection($name);

$connection->setTransactionManager($transactionsManager);
Expand Down
25 changes: 18 additions & 7 deletions tests/Foundation/Testing/DatabaseTransactionsManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ class DatabaseTransactionsManagerTest extends TestCase
{
public function testItExecutesCallbacksImmediatelyIfThereIsOnlyOneTransaction()
{
$testObject = new TestingDatabaseTransactionsManagerTestObject();
$manager = new DatabaseTransactionsManager;
$testObject = new TestingDatabaseTransactionsManagerTestObject;
$manager = new DatabaseTransactionsManager([null]);

$manager->begin('foo', 1);

Expand All @@ -22,7 +22,7 @@ public function testItExecutesCallbacksImmediatelyIfThereIsOnlyOneTransaction()

public function testItIgnoresTheBaseTransactionForCallbackApplicableTransactions()
{
$manager = new DatabaseTransactionsManager;
$manager = new DatabaseTransactionsManager([null]);

$manager->begin('foo', 1);
$manager->begin('foo', 2);
Expand All @@ -33,7 +33,7 @@ public function testItIgnoresTheBaseTransactionForCallbackApplicableTransactions

public function testCommittingDoesNotRemoveTheBasePendingTransaction()
{
$manager = new DatabaseTransactionsManager;
$manager = new DatabaseTransactionsManager([null]);

$manager->begin('foo', 1);

Expand All @@ -50,8 +50,8 @@ public function testCommittingDoesNotRemoveTheBasePendingTransaction()

public function testItExecutesCallbacksForTheSecondTransaction()
{
$testObject = new TestingDatabaseTransactionsManagerTestObject();
$manager = new DatabaseTransactionsManager;
$testObject = new TestingDatabaseTransactionsManagerTestObject;
$manager = new DatabaseTransactionsManager([null]);
$manager->begin('foo', 1);
$manager->begin('foo', 2);

Expand All @@ -67,17 +67,28 @@ public function testItExecutesCallbacksForTheSecondTransaction()

public function testItExecutesTransactionCallbacksAtLevelOne()
{
$manager = new DatabaseTransactionsManager;
$manager = new DatabaseTransactionsManager([null]);

$this->assertFalse($manager->afterCommitCallbacksShouldBeExecuted(0));
$this->assertTrue($manager->afterCommitCallbacksShouldBeExecuted(1));
$this->assertFalse($manager->afterCommitCallbacksShouldBeExecuted(2));
}

public function testSkipsTheNumberOfConnectionsTransacting()
{
$manager = new DatabaseTransactionsManager([null]);

$manager->begin('foo', 1);
$manager->begin('foo', 2);

$this->assertCount(1, $manager->callbackApplicableTransactions());
}
}

class TestingDatabaseTransactionsManagerTestObject
{
public $ran = false;

public $runs = 0;

public function handle()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace Illuminate\Tests\Integration\Database;

use Illuminate\Support\Facades\DB;
use Orchestra\Testbench\Attributes\WithConfig;

use function Orchestra\Testbench\artisan;

#[WithConfig('database.connections.second', ['driver' => 'sqlite', 'database' => ':memory:', 'foreign_key_constraints' => false])]
class EloquentTransactionWithAfterCommitUsingRefreshDatabaseOnMultipleConnectionsTest extends EloquentTransactionWithAfterCommitUsingRefreshDatabaseTest
{
/** {@inheritDoc} */
protected function connectionsToTransact()
{
return [null, 'second'];
}

/** {@inheritDoc} */
protected function afterRefreshingDatabase()
{
artisan($this, 'migrate', ['--database' => 'second']);
}

public function testAfterCommitCallbacksAreCalledCorrectlyWhenNoAppTransaction()
{
$called = false;

DB::afterCommit(function () use (&$called) {
$called = true;
});

$this->assertTrue($called);
}

public function testAfterCommitCallbacksAreCalledWithWrappingTransactionsCorrectly()
{
$calls = [];

DB::transaction(function () use (&$calls) {
DB::afterCommit(function () use (&$calls) {
$calls[] = 'first transaction callback';
});

DB::connection('second')->transaction(function () use (&$calls) {
DB::connection('second')->afterCommit(function () use (&$calls) {
$calls[] = 'second transaction callback';
});
});
});

$this->assertEquals([
'second transaction callback',
'first transaction callback',
], $calls);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class EloquentTransactionWithAfterCommitUsingRefreshDatabaseTest extends TestCas
*/
protected $driver;

/** {@inheritDoc} */
protected function setUp(): void
{
$this->beforeApplicationDestroyed(function () {
Expand All @@ -28,7 +29,8 @@ protected function setUp(): void
parent::setUp();
}

protected function getEnvironmentSetUp($app)
/** {@inheritDoc} */
protected function defineEnvironment($app)
{
$connection = $app['config']->get('database.default');

Expand Down