Files
portal/app/tests/Concerns/SharesSupplierPdo.php
T

54 lines
2.7 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
namespace Tests\Concerns;
use Illuminate\Database\Connection;
use Illuminate\Support\Facades\DB;
/**
* Share PDO between pgsql и pgsql_supplier connections в тестах.
*
* Зачем: Laravel DatabaseTransactions trait оборачивает каждый connection в
* свою транзакцию. Записи через default Project::factory() ($pgsql) не видны
* с pgsql_supplier connection до commit'а. Sharing PDO означает — обе
* connection'ы используют ту же PDO session → одну транзакцию.
*
* На production обе connection'ы реальные separate PDO, и видимость
* обеспечивается READ COMMITTED после commit'а webhook-handler'а перед
* dispatch'ом supplier-flow job'а. Этот trait — только для test-окружения.
*
* Использование: `uses(SharesSupplierPdo::class)` в Pest test-файле, где
* нужна cross-connection visibility (например, tests/Feature/Supplier/*).
*/
trait SharesSupplierPdo
{
protected function setUpSharesSupplierPdo(): void
{
if (! config()->has('database.connections.pgsql_supplier')) {
return;
}
$defaultConnection = DB::connection('pgsql');
$supplierConnection = DB::connection('pgsql_supplier');
$supplierConnection->setPdo($defaultConnection->getPdo());
$supplierConnection->setReadPdo($defaultConnection->getReadPdo());
// Шарим не только PDO, но и уровень вложенности транзакции. DatabaseTransactions
// уже открыл транзакцию на pgsql (этот же PDO) к моменту setUp этого трейта.
// Без синхронизации supplier-connection считает transactions=0 и при
// DB::connection('pgsql_supplier')->transaction() зовёт PDO->beginTransaction()
// на уже активной транзакции → PDOException "There is already an active transaction"
// (например AdminIncidentsController::notifyRkn). С синхронизацией вложенный
// transaction() делает SAVEPOINT внутри внешней транзакции (Postgres поддерживает),
// запись видна последующим чтениям и откатывается общим rollback'ом в teardown.
$level = $defaultConnection->transactionLevel();
if ($level > 0) {
$prop = new \ReflectionProperty(Connection::class, 'transactions');
$prop->setAccessible(true);
$prop->setValue($supplierConnection, $level);
}
}
}