Trying to run suite of tests
Failures
Provide console output if related. Use
-vvvmode for more details.
- ManagerTest: Check oem company monitor Destroying application
Starting application
[Fixtures] Loading fixtures
[yii\db\Connection::open] 'Opening DB connection: pgsql:host=localhost;port=5432;dbname=front_test'
[Fixtures] Opened database connection: pgsql:host=localhost;port=5432;dbname=front_test
[yii\db\Connection::open] 'Opening DB connection: pgsql:host=localhost;port=5432;dbname=back_test'
[Fixtures] Opened database connection: pgsql:host=localhost;port=5432;dbname=back_test
[Fixtures] Closing database connection: pgsql:host=localhost;port=5432;dbname=front_test
[Fixtures] Closing database connection: pgsql:host=localhost;port=5432;dbname=back_test
[Fixtures] Done
[yii\db\Connection::open] 'Opening DB connection: pgsql:host=localhost;port=5432;dbname=front_test'
[yii\web\Session::open] 'Session started'
[yii\web\User::login] 'User \'1256\' logged in from with duration 86400.'
Eventually get this
---------
300) ApiUserTesterCest: Test the forgot password request
Test tests/api/ApiUserTesterCest.php:ForgotPasswordRequest
[yii\db\Exception] SQLSTATE[08006] [7] FATAL: sorry, too many clients already
/srv/www/xyzweb/src/private/protected/vendor/yiisoft/yii2/db/Connection.php:624
/srv/www/xyzweb/src/private/protected/vendor/yiisoft/yii2/db/Connection.php:687
/srv/www/xyzweb/src/private/protected/vendor/yiisoft/yii2/db/Connection.php:613
/srv/www/xyzweb/src/private/protected/vendor/yiisoft/yii2/db/Connection.php:996
/srv/www/xyzweb/src/private/protected/vendor/yiisoft/yii2/db/Connection.php:983
/srv/www/xyzweb/src/private/protected/vendor/yiisoft/yii2/db/Schema.php:463
/srv/www/xyzweb/src/private/protected/vendor/yiisoft/yii2/db/Connection.php:881
/srv/www/xyzweb/src/private/protected/vendor/yiisoft/yii2/db/Command.php:209
/srv/www/xyzweb/src/private/protected/vendor/yiisoft/yii2/db/Command.php:1099
/srv/www/xyzweb/src/private/protected/vendor/yiisoft/yii2/db/Command.php:1120
/srv/www/xyzweb/src/private/protected/vendor/yiisoft/yii2/db/Command.php:442
/srv/www/xyzweb/src/private/protected/vendor/yiisoft/yii2/db/pgsql/Schema.php:182
/srv/www/xyzweb/src/private/protected/vendor/yiisoft/yii2/db/Schema.php:237
/srv/www/xyzweb/src/private/protected/vendor/yiisoft/yii2/db/pgsql/QueryBuilder.php:200
/srv/www/xyzweb/src/private/protected/vendor/yiisoft/yii2/db/Command.php:959
/srv/www/xyzweb/src/private/protected/vendor/yiisoft/yii2/test/InitDbFixture.php:96
/srv/www/xyzweb/src/private/protected/vendor/yiisoft/yii2/test/InitDbFixture.php:78
/srv/www/xyzweb/src/private/protected/vendor/yiisoft/yii2/test/FixtureTrait.php:117
/srv/www/xyzweb/src/private/protected/vendor/codeception/codeception/src/Codeception/Module/Yii2.php:467
/srv/www/xyzweb/src/private/protected/vendor/codeception/codeception/src/Codeception/Module/Yii2.php:285
/srv/www/xyzweb/src/private/protected/vendor/codeception/codeception/src/Codeception/Module/Yii2.php:259
/srv/www/xyzweb/src/private/protected/vendor/codeception/codeception/src/Codeception/Subscriber/Module.php:56
/srv/www/xyzweb/src/private/protected/vendor/symfony/event-dispatcher/EventDispatcher.php:212
/srv/www/xyzweb/src/private/protected/vendor/symfony/event-dispatcher/EventDispatcher.php:44
/srv/www/xyzweb/src/private/protected/vendor/codeception/phpunit-wrapper/src/Listener.php:133
/srv/www/xyzweb/src/private/protected/vendor/codeception/phpunit-wrapper/src/Listener.php:102
/srv/www/xyzweb/src/private/protected/vendor/phpunit/phpunit/src/Framework/TestResult.php:395
/srv/www/xyzweb/src/private/protected/vendor/codeception/codeception/src/Codeception/Test/Test.php:75
/srv/www/xyzweb/src/private/protected/vendor/phpunit/phpunit/src/Framework/TestSuite.php:755
/srv/www/xyzweb/src/private/protected/vendor/codeception/phpunit-wrapper/src/Runner.php:106
/srv/www/xyzweb/src/private/protected/vendor/codeception/codeception/src/Codeception/SuiteManager.php:157
/srv/www/xyzweb/src/private/protected/vendor/codeception/codeception/src/Codeception/Codecept.php:189
/srv/www/xyzweb/src/private/protected/vendor/codeception/codeception/src/Codeception/Codecept.php:158
/srv/www/xyzweb/src/private/protected/vendor/codeception/codeception/src/Codeception/Command/Run.php:466
/srv/www/xyzweb/src/private/protected/vendor/codeception/codeception/src/Codeception/Command/Run.php:361
/srv/www/xyzweb/src/private/protected/vendor/symfony/console/Command/Command.php:252
/srv/www/xyzweb/src/private/protected/vendor/symfony/console/Application.php:946
/srv/www/xyzweb/src/private/protected/vendor/symfony/console/Application.php:248
/srv/www/xyzweb/src/private/protected/vendor/symfony/console/Application.php:148
/srv/www/xyzweb/src/private/protected/vendor/codeception/codeception/src/Codeception/Application.php:108
/srv/www/xyzweb/src/private/protected/vendor/codeception/codeception/codecept:42
composer show)class_name: UnitTester
modules:
enabled:
- Yii2:
part: [orm, fixtures]
cleanup: true
transaction: false
coverage:
enabled: true
remote: false
include:
- models/*
- components/*
- forms/*
Okay I did some deep diving.
The current implementation reuses PDO connections only when transactions are enabled.
The old implementation only worked when the component was called 'db' and was defined in your application. (Modules can have components as well)
One solution would be to allow PDO reuse without using transactions (this is not hard from a technical perspective).
Another solution would be to always register all database connections in the test module and close them after a test.
For now several workarounds should fix it for you:
EVENT_AFTER_REQUEST.@SamMousa In my case transactions are enabled, component still called 'db'.
https://github.com/Codeception/Codeception/pull/4928 @StalkAlex your issue should be fixed
Thanks! I'll try after merge
Where would I add the trigger for the EVENT_AFTER_REQUEST?
The reason I had Transactions as False because we heavily use them in our app. So if something failed all the rest of the tests would fail and it would be difficult to find the problem.
@scottix if i correctly understand, in _before function you should do something like this:
Event::on(\yii\web\Application::class, \yii\web\Application::EVENT_AFTER_REQUEST, function (\yii\base\Event $event) {
\Yii::$app->db->close();
});
@SamMousa is it correct?
But seems it doesn't work for acceptance tests with webdriver.
Db connections doesn't close if '$I->haveFixtures(...)' called in _before or any test method, except _fixtures.
How it can be fixed?
@ilgiz-badamshin I think that would work yes, I would however check if the db component is initialized first.
If you have another issue please create a minimal test case as a PR to https://github.com/codeception/yii2-tests
That way your error can become part of the test suite and we can prevent future regressions.
@SamMousa Done: https://github.com/Codeception/yii2-tests/pull/1
Found problems with cleanup: false. Need to open a new issue?!
I'll look at the pr
After update from Codeception 2.4.0 to 2.4.2, for Yii2 it still has this error unfixed since 2.4.1:
[yii\db\Exception] SQLSTATE[HY000] [1040] Too many connections
The last stable version that did not have this error is 2.4.0.
@SamMousa, please reopen the ticket.
Agree - there is still a problem with 2.4.2 (I have reconnect: true in modules: enabled: Db:)
In 2.4.1 at the end of a test run there would be a sequence of lines saying "Destroying application" but in 2.4.2 this line at the end of each test run.
In any case the test runner is still running out of database connections.
Debug logs?
Part of debug log:
...
✔ PushNotificationSenderTest: Count pending | #14 (0.07s)
[Transaction] Rolling back 0 transactions
Destroying application
Destroying application
Starting application
[Fixtures] Loading fixtures
[Fixtures] Done
[yii\db\Connection::open] 'Opening DB connection: mysql:host=test_db;port=3306;dbname=klip_test'
✔ PushNotificationSenderTest: Count pending | #15 (0.07s)
[Transaction] Rolling back 0 transactions
Destroying application
Destroying application
Starting application
[Fixtures] Loading fixtures
[Fixtures] Done
[yii\db\Connection::open] 'Opening DB connection: mysql:host=test_db;port=3306;dbname=klip_test'
E BasePushNotificationCommandTest: Execute | "successful sending for android" (0.01s)
[Transaction] Rolling back 0 transactions
Destroying application
Suite done, restoring $_SERVER to original
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Time: 16.94 seconds, Memory: 72.00MB
There was 1 error:
---------
1) BasePushNotificationCommandTest: Execute | "successful sending for android"
Test tests/unit/components/notifications/commands/BasePushNotificationCommandTest.php:testExecute
[yii\db\Exception] SQLSTATE[HY000] [1040] Too many connections
#1 /app/vendor/yiisoft/yii2/db/Connection.php:624
#2 /app/vendor/yiisoft/yii2/db/Connection.php:996
#3 /app/vendor/yiisoft/yii2/db/Command.php:255
#4 /app/vendor/yiisoft/yii2/db/Command.php:1070
#5 /app/vendor/yiisoft/yii2/test/InitDbFixture.php:96
#6 /app/vendor/yiisoft/yii2/test/InitDbFixture.php:78
#7 /app/vendor/yiisoft/yii2/test/FixtureTrait.php:117
#8 Codeception\Module\Yii2->haveFixtures
#9 /app/tests/_support/_generated/UnitTesterActions.php:585
#10 /app/tests/unit/components/notifications/commands/BasePushNotificationCommandTest.php:33
ERRORS!
Tests: 180, Assertions: 285, Errors: 1.
/codeception.yml:
actor: Tester
paths:
tests: tests
log: tests/_output
data: tests/_data
helpers: tests/_support
settings:
bootstrap: _bootstrap.php
memory_limit: 1024M
colors: true
modules:
config:
Yii2:
configFile: 'config/test.php'
cleanup: false
/tests/unit.suite.yml:
class_name: UnitTester
modules:
enabled:
- Asserts
- Yii2:
part: [orm, fixtures]
Current quick workaround for this issue is to add to my test.php config file.
'on ' . \yii\web\Application::EVENT_AFTER_REQUEST => function (\yii\base\Event $event) {
\Yii::$app->db->close();
},
@scottix can you confirm this is still an issue on latest version from GIT? (ie 2.4 branch).
@SamMousa, the issues still exists :-(
Hmm, it has something to do with fixtures...
Could you by any chance share the source code of your fixture(s)?
(Specifically interested in the how, not the what, with respect to database interaction)
Some examples are below.
class AvatarCest
{
/**
* Initializes fixtures.
*
* @param \ApiTester $I Tester
*/
public function _before(\ApiTester $I)
{
$I->haveFixtures([
UserFixture::class,
TokenFixture::class,
]);
}
// ...
}
class UserExperimentTest extends \Codeception\Test\Unit
{
/**
* @var \UnitTester Tester
*/
protected $tester;
/**
* Declares the fixtures.
*/
protected function _before()
{
$this->tester->haveFixtures([
'experiments' => ExperimentFixture::class,
]);
}
// ...
}
#unit.suite.yml
class_name: UnitTester
modules:
enabled:
- Asserts
- Yii2:
part: [orm, fixtures]
#codeception.yml
actor: Tester
paths:
tests: tests
log: tests/_output
data: tests/_data
helpers: tests/_support
settings:
bootstrap: _bootstrap.php
memory_limit: 1024M
colors: true
modules:
config:
Yii2:
configFile: 'config/test.php'
cleanup: false
Note that some DB calls are transactional.
I have 1500+ tests in total.
I think I have fixed it here: https://github.com/Codeception/Codeception/pull/5045
Could you give this branch a try?
namespace app\tests\fixtures;
use yii\test\ActiveFixture;
/**
* Token fixture
*
* @author Oleksandr Roslov <[email protected]>
*/
class TokenFixture extends ActiveFixture
{
public $modelClass = 'app\\modules\\api\\v2\\models\\Token';
public $depends = [
'app\\tests\\fixtures\\AppKeyFixture',
'app\\tests\\fixtures\\OAuthFixture',
'app\\tests\\fixtures\\UserFixture',
];
}
# /tests/fixtures/data/token.php
return [
[
'user_id' => 1,
'app_key_id' => 1,
'oauth_id' => 1,
'token' => 'fjhdsidhgrlkruh974y5hghdfkghdfkg',
],
// ...
];
I downloaded https://github.com/SamMousa/Codeception/tree/yii2-event-handlers
But the issue still exists.
Debug output?
Looks like I found where the possible problem is.
The connections are not closed after each data provider test.
SET GLOBAL max_connections = 17;
SHOW VARIABLES LIKE "max_connections";
<?php
namespace app\tests\functional\admin;
use app\tests\fixtures\EventFixture;
use app\tests\fixtures\PermissionFixture;
use app\tests\fixtures\AdminUserFixture;
use Codeception\Example;
/**
* Tests Events page of admin panel.
*/
class EventsCest
{
/**
* Initializes fixtures.
*
* @param \FunctionalTester $I Tester
*/
public function _before(\FunctionalTester $I)
{
$I->haveFixtures([
'users' => AdminUserFixture::class,
'permissions' => PermissionFixture::class,
'events' => EventFixture::class,
]);
}
/**
* Tests available elements on pages
*
* @param \FunctionalTester $I Tester
* @param Example $example Data provider example
*
* @dataprovider dataProvider
*/
public function tryToFindButtons(\FunctionalTester $I, Example $example)
{
$I->amLoggedInAs($example['user']);
$route = $example['route'][0];
$params = $example['route'];
unset($params[0]);
$I->amOnRoute($route, $params);
if ($example['visible']) {
$I->see($example['text']);
} else {
$I->dontSee($example['text']);
}
}
/**
* User data provider
*
* @return array Data
*/
protected function dataProvider()
{
return [
'superadmin index visible button create' => [
'user' => 1,
'route' => ['admin/event'],
'text' => 'Create Event',
'visible' => true,
],
'superadmin view visible button update' => [
'user' => 1,
'route' => ['admin/event/1'],
'text' => 'Edit',
'visible' => true,
],
'superadmin view visible button delete' => [
'user' => 1,
'route' => ['admin/event/1'],
'text' => 'Delete',
'visible' => true,
],
'moderator index visible button create' => [
'user' => 2,
'route' => ['admin/event'],
'text' => 'Create Event',
'visible' => true,
],
'moderator view visible button update' => [
'user' => 2,
'route' => ['admin/event/1'],
'text' => 'Edit',
'visible' => true,
],
'moderator view visible button delete' => [
'user' => 2,
'route' => ['admin/event/1'],
'text' => 'Delete',
'visible' => false,
],
'analyst index visible button create' => [
'user' => 3,
'route' => ['admin/event'],
'text' => 'Create Event',
'visible' => false,
],
'analyst view visible button update' => [
'user' => 3,
'route' => ['admin/event/1'],
'text' => 'Edit',
'visible' => false,
],
'analyst view visible button delete' => [
'user' => 3,
'route' => ['admin/event/1'],
'text' => 'Delete',
'visible' => false,
],
'moderator analyst index visible button create' => [
'user' => 4,
'route' => ['admin/event'],
'text' => 'Create Event',
'visible' => true,
],
'moderator analyst view visible button update' => [
'user' => 4,
'route' => ['admin/event/1'],
'text' => 'Edit',
'visible' => true,
],
'moderator analyst view visible button delete' => [
'user' => 4,
'route' => ['admin/event/1'],
'text' => 'Delete',
'visible' => false,
],
'owner index visible button create' => [
'user' => 5,
'route' => ['admin/event'],
'text' => 'Create Event',
'visible' => true,
],
'owner view visible button update' => [
'user' => 5,
'route' => ['admin/event/1'],
'text' => 'Edit',
'visible' => true,
],
'owner view visible button delete' => [
'user' => 5,
'route' => ['admin/event/1'],
'text' => 'Delete',
'visible' => false,
],
];
}
}
Run tests with vendor/bin/codecept run functional admin/EventsCest -f.
Tests pass.
Then either decrease MySQL max_connections to 16 or add another test in data provider’s array:
'owner view visible button delete TEST' => [
'user' => 5,
'route' => ['admin/event/1'],
'text' => 'Delete',
'visible' => false,
],
Run tests with vendor/bin/codecept run functional admin/EventsCest -f.
You’ll get error [yii\db\Exception] SQLSTATE[HY000] [1040] Too many connections.
Strange, that is exactly the kind of test i'm using here: https://github.com/Codeception/yii2-tests/pull/2
Debug output of https://github.com/SamMousa/Codeception/tree/yii2-event-handlers
Hmm, it seems after connections are closed they get reopened.
Do you have cleanup of fixtures enabled or not?
Disabled (cleanup: false).
But the behavior is the same with cleanup equal to false or true — both have the same error.
Hmm, weird, if you look at this:
https://travis-ci.org/Codeception/yii2-tests/jobs/397764560
Those tests actually check if database connections are being closed properly... *-)
I found workaround using helper.
Create file: tests/_support/Helper/ConnectionClose.php
<?php
namespace Helper;
use Codeception\Module;
use Codeception\TestInterface;
class ConnectionClose extends Module
{
public function _after(TestInterface $test)
{
if (isset(\Yii::$app->db)) {
\Yii::$app->db->close();
}
parent::_after($test);
}
}
and add module to suite:
modules:
enabled:
- Helper\ConnectionClose
2.4.4 still does not close all connections:
Of course, not closed. Because:
https://github.com/Codeception/Codeception/blob/2.4/src/Codeception/Lib/Connector/Yii2.php#L93
Application destroyed without closing connection, without any destructors.
@m8rge destructors are called by PHP itself, it's called garbage collection...
Anyway, we watch all connections and close them after each test here:
https://github.com/Codeception/Codeception/blob/2.4/src/Codeception/Module/Yii2.php#L347
@SamMousa, looks like I found a fix.
Please check my PR #5172.
It’s in /src/Codeception/Module/Yii2.php.
Probably $this->client->getApplication() can reopen DB connections.
So I moved the closing of connections by ConnectionWatcher after session close.
So now all my 1.6K tests pass :-)
Nice, now we know the cause I think we can reproduce it as well right?
Creating an app that bootstraps the db component should do it. I'll try to make a test case in the test repo.
In my case It was reproducible in functional test where I used API calls and data providers with large list of cases.
Unfortunately I could not manage to run tests of Codeception/Codeception in my local environment.
Okay, I looked into it some more and feel there's some information still missing.
The conditions for this scenario are:
$this->client->getApplication() must re-initalize the application.getApplication() looks like this: public function getApplication()
{
if (!isset(Yii::$app)) {
$this->startApp();
}
return Yii::$app;
}
So I started looking for places where \Yii::$app is unset.
There's only a few places where this happens:
Module/Yii2::onReconfigure(), this resets the application and starts it again, so this is not the culprit.Module/Yii2::_after(), this happens after the getApplication() call so this is not the culprit.Module/Yii2::configureClient(), which is called indirectly via onReconfigure() and in _before(). This means this cannot be the culprit either...@roslov could you check all your code for anything that's unsetting \Yii::$app?
Also, I've created a PR that does some code cleanup. One of the things it changes is that it doesn't recreate the application to close the session. (If there's no application, there should be no session)
Could you try that branch to see if that also resolves your issue?
See https://github.com/SamMousa/Codeception/tree/yii2-cleanup
@SamMousa
\Yii::$app.I made tests with your branch and my PR:
2.4 without my PR — fails (Too many connections),2.4 with my PR — passes,yii2-cleanup without my PR — fails (Too many connections),yii2-cleanup with my PR — also fails (Too many connections).I don’t know why it is so.
Probably cleanup also broke something.
You put session close into resetApplication().
That’s why my PR does not work with your branch yii2-cleanup.
This means that
public function closeSession()
{
if (isset(\Yii::$app) && \Yii::$app->has('session', true)) {
\Yii::$app->session->close();
}
}
does initialize DB connections.
And as we are closing them before this code — we get Too many connections issue.
Most helpful comment
@SamMousa Done: https://github.com/Codeception/yii2-tests/pull/1
Found problems with cleanup: false. Need to open a new issue?!