dmaicher / doctrine-test-bundle

Symfony bundle to isolate your app's doctrine database tests and improve the test performance
MIT License
1.08k stars 60 forks source link

SAVEPOINT can only be used in transaction blocks #190

Closed KDederichs closed 2 years ago

KDederichs commented 2 years ago

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?

dmaicher commented 2 years ago

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)

KDederichs commented 2 years ago

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

KDederichs commented 2 years ago

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

KDederichs commented 2 years ago

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