dmaicher/doctrine-test-bundle

SAVEPOINT can only be used in transaction blocks

KDederichs opened this issue · 4 comments

Hey,

I'm trying to use this to speed up my tests and the first test class runs pretty well.
The problem is once it gets to the next one it's throwing me this:

PDOException: SQLSTATE[25P01]: No active sql transaction: 7 ERROR:  SAVEPOINT can only be used in transaction blocks in /Users/my/path/to/project/vendor/doctrine/dbal/src/Driver/PDO/Connection.php:34

I'm using the liip/test-fixtures-bundle in version 2.2.1 and I'm currently loading my fixtures in setUpBeforeClass like this:

        self::$databaseTool = static::getContainer()->get(DatabaseToolCollection::class)->get();
        self::$fixtures = self::$databaseTool->loadFixtures(array_merge(
            [
                   // Fixture List
            ],
            $testFixtures
        ))->getReferenceRepository();
        StaticDriver::commit();

I added the commit cause I'll get the There is already an active transaction thing otherwise.

Any idea what might be causing this?

Is the code from liip/test-fixtures-bundle doing any DDL queries? such as DROP/ALTER/CREATE/TRUNCATE table? (those cannot be executed within transactions with most RDBMS)

Doesn't seem like it no.
Upon further debugging it seems it's caused by the actual fixture loading part of the code as well on this part:

$executor->execute($loader->getFixtures(), true);

which passes it to this:

    /** @inheritDoc */
    public function execute(array $fixtures, $append = false)
    {
        $executor = $this;
        $this->em->transactional(static function (EntityManagerInterface $em) use ($executor, $fixtures, $append) {
            if ($append === false) {
                $executor->purge();
            }
            foreach ($fixtures as $fixture) {
                $executor->load($em, $fixture);
            }
        });
    }

(https://github.com/doctrine/data-fixtures/blob/1e08b4d76c54c0d85ee8ea28ecb1fd8cc33bc7f7/lib/Doctrine/Common/DataFixtures/Executor/ORMExecutor.php#L65)

So I guess it's actually the Doctrine Datafixtures that's the issue

It's also worth mentioning that all tests run perfectly fine on their own. It's just a problem when you run the whole suit for some reason and it switches between test classes....

#0 /Users/my/path/to/project/vendor/doctrine/dbal/src/Driver/PDO/Connection.php(34): PDO->exec('SAVEPOINT DOCTR...')
#1 /Users/my/path/to/project/vendor/dama/doctrine-test-bundle/src/DAMA/DoctrineTestBundle/Doctrine/DBAL/AbstractStaticConnectionV3.php(25): Doctrine\DBAL\Driver\PDO\Connection->exec('SAVEPOINT DOCTR...')
#2 /Users/my/path/to/project/vendor/doctrine/dbal/src/Connection.php(1145): DAMA\DoctrineTestBundle\Doctrine\DBAL\AbstractStaticConnectionV3->exec('SAVEPOINT DOCTR...')
#3 /Users/my/path/to/project/vendor/doctrine/dbal/src/Connection.php(1450): Doctrine\DBAL\Connection->executeStatement('SAVEPOINT DOCTR...')
#4 /Users/my/path/to/project/vendor/doctrine/dbal/src/Connection.php(1295): Doctrine\DBAL\Connection->createSavepoint('DOCTRINE2_SAVEP...')
#5 /Users/my/path/to/project/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php(232): Doctrine\DBAL\Connection->beginTransaction()
#6 /Users/my/path/to/project/var/cache/test/ContainerHO0heoZ/EntityManager_9a5be93.php(66): Doctrine\ORM\EntityManager->transactional(Object(Closure))
#7 /Users/my/path/to/project/vendor/doctrine/data-fixtures/lib/Doctrine/Common/DataFixtures/Executor/ORMExecutor.php(74): ContainerHO0heoZ\EntityManager_9a5be93->transactional(Object(Closure))
#8 /Users/my/path/to/project/vendor/liip/test-fixtures-bundle/src/Services/DatabaseTools/ORMDatabaseTool.php(122): Doctrine\Common\DataFixtures\Executor\ORMExecutor->execute(Array, true)
#9 /Users/my/path/to/project/tests/BaseWebTestCase.php(53): Liip\TestFixturesBundle\Services\DatabaseTools\ORMDatabaseTool->loadFixtures(Array)
#10 /Users/my/path/to/project/tests/UserLoginControllerTest.php(20): App\Tests\BaseWebTestCase::fixtureSetup(Array)
#11 /Users/my/path/to/project/bin/.phpunit/phpunit-9-0/src/Framework/TestSuite.php(622): App\Tests\UserLoginControllerTest::setUpBeforeClass()
#12 /Users/my/path/to/project/bin/.phpunit/phpunit-9-0/src/Framework/TestSuite.php(678): PHPUnit\Framework\TestSuite->run(Object(PHPUnit\Framework\TestResult))
#13 /Users/my/path/to/project/bin/.phpunit/phpunit-9-0/src/Framework/TestSuite.php(678): PHPUnit\Framework\TestSuite->run(Object(PHPUnit\Framework\TestResult))
#14 /Users/my/path/to/project/bin/.phpunit/phpunit-9-0/src/TextUI/TestRunner.php(670): PHPUnit\Framework\TestSuite->run(Object(PHPUnit\Framework\TestResult))
#15 /Users/my/path/to/project/bin/.phpunit/phpunit-9-0/src/TextUI/Command.php(143): PHPUnit\TextUI\TestRunner->run(Object(PHPUnit\Framework\TestSuite), Array, Array, true)
#16 /Users/my/path/to/project/bin/.phpunit/phpunit-9-0/src/TextUI/Command.php(96): PHPUnit\TextUI\Command->run(Array, true)
#17 /Users/my/path/to/project/bin/.phpunit/phpunit-9-0/phpunit(22): PHPUnit\TextUI\Command::main()

Also here's a stack trace if that helps

Seems like it works when you explicitly Wrap it in
StaticDriver::beginTransaction();
/// Load fixtures
StaticDriver::commit();

strange, well closing this since it seems to fix the issue