Skip to content

Commit f1ef963

Browse files
SamMousasamdark
authored andcommitted
Support reconfiguration (#4918)
* Add support for reconfiguration during tests and fix issue with sqlite transactions * Fixed nitpick CS * Fixed docs, don't attempt to clear cookies since they won't get reloaded.
1 parent 5c2ea10 commit f1ef963

File tree

2 files changed

+78
-59
lines changed

2 files changed

+78
-59
lines changed

src/Codeception/Lib/Connector/Yii2.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,6 @@ protected function resetRequest(Application $app)
363363
break;
364364
case self::CLEAN_CLEAR:
365365
$request->getHeaders()->removeAll();
366-
$request->getCookies()->removeAll();
367366
$request->setBaseUrl(null);
368367
$request->setHostInfo(null);
369368
$request->setPathInfo(null);

src/Codeception/Module/Yii2.php

Lines changed: 78 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
* * `fixturesMethod` - (default: _fixtures) Name of the method used for creating fixtures.
4040
* * `responseCleanMethod` - (default: clear) Method for cleaning the response object. Note that this is only for multiple requests inside a single test case.
4141
* Between test casesthe whole application is always recreated
42-
* * `requestCleanMethod` - (default: clear) Method for cleaning the request object. Note that this is only for multiple requests inside a single test case.
42+
* * `requestCleanMethod` - (default: recreate) Method for cleaning the request object. Note that this is only for multiple requests inside a single test case.
4343
* Between test cases the whole application is always recreated
4444
* You can use this module by setting params in your functional.suite.yml:
4545
*
@@ -198,17 +198,16 @@ public function _initialize()
198198

199199
/**
200200
* Module configuration changed inside a test.
201-
* We might need to re-create the application.
201+
* We always re-create the application.
202202
*/
203203
protected function onReconfigure()
204204
{
205205
parent::onReconfigure();
206-
if (isset(\Yii::$app)) {
207-
$this->client->restart();
208-
}
206+
$this->client->resetApplication();
207+
$this->configureClient($this->config);
208+
$this->client->startApp();
209209
}
210210

211-
212211
/**
213212
* Adds the required server params.
214213
* Note this is done separately from the request cycle since someone might call
@@ -254,8 +253,22 @@ protected function validateConfig()
254253
}
255254
}
256255

256+
protected function configureClient(array $settings)
257+
{
258+
$settings['configFile'] = Configuration::projectDir() . $settings['configFile'];
257259

258-
public function _before(TestInterface $test)
260+
foreach ($settings as $key => $value) {
261+
if (property_exists($this->client, $key)) {
262+
$this->client->$key = $value;
263+
}
264+
}
265+
$this->client->resetApplication();
266+
}
267+
268+
/**
269+
* Instantiates the client based on module configuration
270+
*/
271+
protected function recreateClient()
259272
{
260273
$entryUrl = $this->config['entryUrl'];
261274
$entryFile = $this->config['entryScript'] ?: basename($entryUrl);
@@ -269,11 +282,13 @@ public function _before(TestInterface $test)
269282
'HTTPS' => parse_url($entryUrl, PHP_URL_SCHEME) === 'https'
270283
]);
271284

272-
$this->client->configFile = Configuration::projectDir() . $this->config['configFile'];
273-
$this->client->responseCleanMethod = $this->config['responseCleanMethod'];
285+
$this->configureClient($this->config);
286+
}
274287

275-
$this->client->resetApplication();
276-
$app = $this->client->getApplication();
288+
public function _before(TestInterface $test)
289+
{
290+
$this->recreateClient();
291+
$this->client->startApp();
277292

278293
// load fixtures before db transaction
279294
if ($test instanceof \Codeception\Test\Cest) {
@@ -336,68 +351,73 @@ public function _after(TestInterface $test)
336351
if ($this->client->getApplication()->has('session', true)) {
337352
$this->client->getApplication()->session->close();
338353
}
339-
340354
parent::_after($test);
341355
}
342356

343-
protected function startTransactions()
344-
{
345-
if ($this->config['transaction']) {
346-
// This should register handlers that start a transaction whenever a connection opens and add it to the transactions array.
347-
Event::on(Connection::class, Connection::EVENT_AFTER_OPEN, function (Event $event) {
348-
if ($event->sender instanceof Connection) {
349-
$connection = $event->sender;
350-
/*
351-
* We should check if the known PDO objects are the same, in which case we should reuse the PDO
352-
* object so only 1 transaction is started and multiple connections to the same database see the
353-
* same data (due to writes inside a transaction not being visible from the outside).
354-
*
355-
*/
356-
$key = md5(json_encode([
357-
'dsn' => $connection->dsn,
358-
'user' => $connection->username,
359-
'pass' => $connection->password,
360-
'attributes' => $connection->attributes,
361-
'emulatePrepare' => $connection->emulatePrepare,
362-
'charset' => $connection->charset
363-
]));
364-
365-
/*
366-
* If keys match we assume connections are "similar enough".
367-
*/
368-
if (isset($this->pdoCache[$key])) {
369-
$connection->pdo = $this->pdoCache[$key];
370-
}
371-
372-
if (isset($this->dsnCache[$connection->dsn])
373-
&& $this->dsnCache[$connection->dsn] !== $key
374-
&& !$this->config['ignoreCollidingDSN']
375-
) {
376-
377-
$this->debugSection('WARNING', <<<TEXT
357+
public function connectionOpenHandler(Event $event)
358+
{
359+
if ($event->sender instanceof Connection) {
360+
$connection = $event->sender;
361+
/*
362+
* We should check if the known PDO objects are the same, in which case we should reuse the PDO
363+
* object so only 1 transaction is started and multiple connections to the same database see the
364+
* same data (due to writes inside a transaction not being visible from the outside).
365+
*
366+
*/
367+
$key = md5(json_encode([
368+
'dsn' => $connection->dsn,
369+
'user' => $connection->username,
370+
'pass' => $connection->password,
371+
'attributes' => $connection->attributes,
372+
'emulatePrepare' => $connection->emulatePrepare,
373+
'charset' => $connection->charset
374+
]));
375+
376+
/*
377+
* If keys match we assume connections are "similar enough".
378+
*/
379+
if (isset($this->pdoCache[$key])) {
380+
$connection->pdo = $this->pdoCache[$key];
381+
}
382+
383+
if (isset($this->dsnCache[$connection->dsn])
384+
&& $this->dsnCache[$connection->dsn] !== $key
385+
&& !$this->config['ignoreCollidingDSN']
386+
) {
387+
$this->debugSection('WARNING', <<<TEXT
378388
You use multiple connections to the same DSN ({$connection->dsn}) with different configuration.
379389
These connections will not see the same database state since we cannot share a transaction between different PDO
380390
instances.
381391
You can remove this message by adding 'ignoreCollidingDSN = true' in the module configuration.
382392
TEXT
383-
);
384-
Debug::pause();
385-
}
393+
);
394+
Debug::pause();
395+
}
386396

387-
if (isset($this->transactions[$key])) {
388-
$this->debugSection('Database', 'Reusing PDO, so no need for a new transaction');
389-
return;
390-
}
397+
if (isset($this->transactions[$key])) {
398+
$this->debugSection('Database', 'Reusing PDO, so no need for a new transaction');
399+
return;
400+
}
391401

392-
$this->debugSection('Database', 'Transaction started for: ' . $connection->dsn);
393-
$this->transactions[$key] = $connection->beginTransaction();
394-
}
395-
});
402+
$this->debugSection('Database', 'Transaction started for: ' . $connection->dsn);
403+
$this->transactions[$key] = $connection->beginTransaction();
404+
}
405+
406+
}
407+
408+
protected function startTransactions()
409+
{
410+
if ($this->config['transaction']) {
411+
// This should register handlers that start a transaction whenever a connection opens and add it to the transactions array.
412+
$this->debug('Transaction', 'Registering connection event handler');
413+
Event::on(Connection::class, Connection::EVENT_AFTER_OPEN, [$this, 'connectionOpenHandler']);
396414
}
397415
}
398416

399417
protected function rollbackTransactions()
400418
{
419+
$this->debugSection('Transaction', 'Rolling back ' . count($this->transactions) . ' transactions');
420+
Event::off(Connection::class, Connection::EVENT_AFTER_OPEN, [$this, 'connectionOpenHandler']);
401421
/** @var Transaction $transaction */
402422
foreach ($this->transactions as $transaction) {
403423
$transaction->rollBack();

0 commit comments

Comments
 (0)