Skip to content

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

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

Merged
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,24 @@

class DatabaseTransactionsManager extends BaseManager
{
/**
* The names of the connections transacting during tests.
*/
protected array $connectionsTransacting;

/**
* Create a new database transaction manager instance.
*
* @param array $connectionsTransacting
* @return void
*/
public function __construct(array $connectionsTransacting)
{
parent::__construct();

$this->connectionsTransacting = $connectionsTransacting;
}

/**
* Register a transaction callback.
*
Expand All @@ -31,7 +49,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