[Yii2] Functional tests fail after 2.2.5 => 2.2.6 upgrade with "[PDOException] There is no active transaction" #3696

Closed
ivokund opened this Issue Nov 7, 2016 · 8 comments

Projects

None yet

3 participants

@ivokund
Contributor
ivokund commented Nov 7, 2016 edited

What are you trying to achieve?

  1. Run a functional test that uses DB cleanup with transaction rollback (standard Yii2 module stuff)
  2. Throw a HttpException in a test

What do you get instead?

DB connection is closed during the logging process and the cleanup transaction will be implicitly rolled back before calling rollback(). Calling rollback() in \Codeception\Module\Yii2::_after will result in an error. It seems to me that the issue was caused by the fix to #3332 in here: 14438af#diff-94abe3ee46e86aa1477f9565b6d2f9f5R149.

Provide console output if related. Use -vvv mode for more details.

  [PDOException]
  There is no active transaction


Exception trace:
 () at <removed>/api-backend/vendor/yiisoft/yii2/db/Transaction.php:179
 PDO->rollBack() at <removed>/api-backend/vendor/yiisoft/yii2/db/Transaction.php:179
 yii\db\Transaction->rollBack() at <removed>/api-backend/vendor/codeception/codeception/src/Codeception/Module/Yii2.php:197
 Codeception\Module\Yii2->_after() at <removed>/api-backend/vendor/codeception/codeception/src/Codeception/Subscriber/Module.php:68
 Codeception\Subscriber\Module->after() at n/a:n/a
 call_user_func() at <removed>/api-backend/vendor/symfony/event-dispatcher/EventDispatcher.php:174
 Symfony\Component\EventDispatcher\EventDispatcher->doDispatch() at <removed>/api-backend/vendor/symfony/event-dispatcher/EventDispatcher.php:43
 Symfony\Component\EventDispatcher\EventDispatcher->dispatch() at <removed>/api-backend/vendor/codeception/codeception/src/Codeception/PHPUnit/Listener.php:124
 Codeception\PHPUnit\Listener->fire() at <removed>/api-backend/vendor/codeception/codeception/src/Codeception/PHPUnit/Listener.php:110
 Codeception\PHPUnit\Listener->endTest() at <removed>/api-backend/vendor/phpunit/phpunit/src/Framework/TestResult.php:401
 PHPUnit_Framework_TestResult->endTest() at <removed>/api-backend/vendor/codeception/codeception/src/Codeception/Test/Test.php:112
 Codeception\Test\Test->run() at <removed>/api-backend/vendor/phpunit/phpunit/src/Framework/TestSuite.php:753
 PHPUnit_Framework_TestSuite->run() at <removed>/api-backend/vendor/codeception/codeception/src/Codeception/PHPUnit/Runner.php:98
 Codeception\PHPUnit\Runner->doEnhancedRun() at <removed>/api-backend/vendor/codeception/codeception/src/Codeception/SuiteManager.php:162
 Codeception\SuiteManager->run() at <removed>/api-backend/vendor/codeception/codeception/src/Codeception/Codecept.php:209
 Codeception\Codecept->runSuite() at <removed>/api-backend/vendor/codeception/codeception/src/Codeception/Codecept.php:178
 Codeception\Codecept->run() at <removed>/api-backend/vendor/codeception/codeception/src/Codeception/Command/Run.php:281
 Codeception\Command\Run->execute() at <removed>/api-backend/vendor/symfony/console/Command/Command.php:256
 Symfony\Component\Console\Command\Command->run() at <removed>/api-backend/vendor/symfony/console/Application.php:818
 Symfony\Component\Console\Application->doRunCommand() at <removed>/api-backend/vendor/symfony/console/Application.php:186
 Symfony\Component\Console\Application->doRun() at <removed>/api-backend/vendor/symfony/console/Application.php:117
 Symfony\Component\Console\Application->run() at <removed>/api-backend/vendor/codeception/codeception/src/Codeception/Application.php:103
 Codeception\Application->run() at <removed>/api-backend/vendor/codeception/codeception/codecept:33

This is the trace to \yii\db\Connection::close that is executed during my test.

  Array
  (
      [0] => Array
          (
              [file] => /media/sf__SHARE/htdocs/ubik-ems/api-backend/vendor/yiisoft/yii2/db/Connection.php
              [line] => 975
              [function] => close
              [class] => yii\db\Connection
              [type] => ->
          )

      [1] => Array
          (
              [function] => __sleep
              [class] => yii\db\Connection
              [type] => ->
          )

      [2] => Array
          (
              [file] => /media/sf__SHARE/htdocs/ubik-ems/api-backend/vendor/yiisoft/yii2/helpers/BaseVarDumper.php
              [line] => 197
              [function] => serialize
          )

      [3] => Array
          (
              [file] => /media/sf__SHARE/htdocs/ubik-ems/api-backend/vendor/yiisoft/yii2/helpers/BaseVarDumper.php
              [line] => 158
              [function] => exportInternal
              [class] => yii\helpers\BaseVarDumper
              [type] => ::
          )

      [4] => Array
          (
              [file] => /media/sf__SHARE/htdocs/ubik-ems/api-backend/vendor/codeception/codeception/src/Codeception/Lib/Connector/Yii2/Logger.php
              [line] => 25
              [function] => export
              [class] => yii\helpers\BaseVarDumper
              [type] => ::
          )

      [5] => Array
          (
              [file] => /media/sf__SHARE/htdocs/ubik-ems/api-backend/vendor/yiisoft/yii2/BaseYii.php
              [line] => 400
              [function] => log
              [class] => Codeception\Lib\Connector\Yii2\Logger
              [type] => ->
          )

      [6] => Array
          (
              [file] => /media/sf__SHARE/htdocs/ubik-ems/api-backend/vendor/yiisoft/yii2/base/ErrorHandler.php
              [line] => 274
              [function] => error
              [class] => yii\BaseYii
              [type] => ::
          )

      [7] => Array
          (
              [file] => /media/sf__SHARE/htdocs/ubik-ems/api-backend/vendor/yiisoft/yii2/base/ErrorHandler.php
              [line] => 105
              [function] => logException
              [class] => yii\base\ErrorHandler
              [type] => ->
          )

      [8] => Array
          (
              [file] => /media/sf__SHARE/htdocs/ubik-ems/api-backend/vendor/codeception/codeception/src/Codeception/Lib/Connector/Yii2.php
              [line] => 151
              [function] => handleException
              [class] => yii\base\ErrorHandler
              [type] => ->
          )

      [9] => Array
          (
              [file] => /media/sf__SHARE/htdocs/ubik-ems/api-backend/vendor/symfony/browser-kit/Client.php
              [line] => 315
              [function] => doRequest
              [class] => Codeception\Lib\Connector\Yii2
              [type] => ->
          )
  )

Details

  • Codeception version: 2.2.6
  • PHP Version: 7.0.4
  • Operating System: Ubuntu Trusty
  • Installation type: Composer
  • Suite configuration:
class_name: FunctionalTester
modules:
    enabled:
        - Filesystem
        - Yii2:
            parts: init
        - Asserts
        - tests\codeception\common\_support\FixtureHelper
        - tests\codeception\common\_support\MailHelper
        - REST:
            isFunctional: true
            depends: Yii2
        - tests\codeception\common\_support\AuthHelper
    config:
        Yii2:
            configFile: 'codeception/config/functional.php'
            cleanup: true
error_level: "E_ALL"
@DavertMik
Member

Thanks. Looks like you should set:

        - Yii2:
            parts: init
            cleanup: false

To fix that

@ivokund
Contributor
ivokund commented Nov 8, 2016

But I need to use cleanup, are you saying cleanup does not work anymore in 2.2.6? Please note that everything was fine and working up until 2.2.6.

Thanks

@samdark samdark added the Yii label Nov 8, 2016
@DavertMik
Member

Yes, sorry my suggestion looks unrelated.

As you pointed that to 14438af#diff-94abe3ee46e86aa1477f9565b6d2f9f5R149 I'm not sure I understand what happens there and why error happens. Looks like by handling exception Yii closes transaction it didn't open, right?

@samdark your expertise required )

@samdark samdark was assigned by DavertMik Nov 8, 2016
@samdark
Collaborator
samdark commented Nov 8, 2016

@ivokund first of all, can you try removing $e instanceof HttpException block from connector to see if it works?

@samdark
Collaborator
samdark commented Nov 8, 2016

@DavertMik after exception is handled to Yii, this method is executed:

https://github.com/yiisoft/yii2/blob/master/framework/base/ErrorHandler.php#L89

I guess @ivokund refers to https://github.com/yiisoft/yii2/blob/master/framework/base/ErrorHandler.php#L113 since the rest of the method has nothing to do with database at all. If DbTarget is configured as log target, export method is called but, again, there's nothing inside to affect transactions:

https://github.com/yiisoft/yii2/blob/master/framework/log/DbTarget.php#L61

@ivokund
Contributor
ivokund commented Nov 9, 2016 edited

I did some digging and yes, my initial idea was wrong. The problem is caused by https://github.com/Codeception/Codeception/blob/2.2/src/Codeception/Lib/Connector/Yii2/Logger.php#L25 when VarDumper::export tries to serialize a HttpException which in turn somehow causes yii\db\Connection::__sleep() to be called during serialization. This was introduced by 8b5cb22

The stacktrace from my initial post is still valid (redacted for readability)

#0  yii\db\Connection->close() called at [/vendor/yiisoft/yii2/db/Connection.php:973]
#1  yii\db\Connection->__sleep()
#2  serialize() called at [/vendor/yiisoft/yii2/helpers/BaseVarDumper.php:197]
#3  yii\helpers\BaseVarDumper::exportInternal() called at [/vendor/yiisoft/yii2/helpers/BaseVarDumper.php:158]
#4  yii\helpers\BaseVarDumper::export() called at [/vendor/codeception/codeception/src/Codeception/Lib/Connector/Yii2/Logger.php:25]
#5  Codeception\Lib\Connector\Yii2\Logger->log() called at [/vendor/yiisoft/yii2/BaseYii.php:400]
#6  yii\BaseYii::error() called at [/vendor/yiisoft/yii2/base/ErrorHandler.php:274]
#7  yii\base\ErrorHandler->logException() called at [/vendor/yiisoft/yii2/base/ErrorHandler.php:105]
#8  yii\base\ErrorHandler->handleException() called at [/vendor/codeception/codeception/src/Codeception/Lib/Connector/Yii2.php:149]
#9  Codeception\Lib\Connector\Yii2->doRequest() called at [/vendor/symfony/browser-kit/Client.php:315]

It may have something to do with parameters in exception trace log (which can contain \Yii::$app or \Yii::$app->db). Adding this to \Codeception\Lib\Connector\Yii2\Logger::log just before the last line seems to solve the problem:

        if ($message instanceof \yii\base\Exception) {
            $message = $message->__toString();
        }

If this looks like a reasonable fix I can send in a pull request.

@DavertMik
Member

Thanks for investigation. That was a good catch. I had some doubts about this dumper thing but I didn't think it will affect code this way. Please send PR with your suggested fix.

@ivokund
Contributor
ivokund commented Nov 9, 2016 edited

Here you go #3708

@DavertMik DavertMik closed this in #3708 Nov 10, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment