Files
piratepoet/mailpoet/tests/_support/CleanupExtension.php
Jan Jakes 200ea47926 Use mysqli to run test cleanups
[MAILPOET-6142]
2024-08-19 15:29:42 +02:00

111 lines
3.6 KiB
PHP

<?php declare(strict_types = 1);
use Codeception\Event\SuiteEvent;
use Codeception\Event\TestEvent;
use Codeception\Events;
use Codeception\Extension;
use MailPoet\Config\Env;
use MailPoet\DI\ContainerWrapper;
use MailPoetVendor\Doctrine\ORM\EntityManager;
// phpcs:ignore PSR1.Classes.ClassDeclaration
class CleanupExtension extends Extension {
const DB_BACKUP_PATH = __DIR__ . '/../_data/acceptanceBackup.sql';
const DB_HOST = 'mysql';
const DB_USERNAME = 'root';
const DB_PASSWORD = 'wordpress';
const DB_NAME = 'wordpress';
const MAILHOG_DATA_PATH = '/mailhog-data';
public static $events = [
Events::SUITE_BEFORE => 'backupDatabase',
Events::TEST_BEFORE => 'cleanupEnvironment',
];
/** @var mysqli */
private $rootConnection;
public function __construct(
$config,
$options
) {
parent::__construct($config, $options);
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$this->rootConnection = new mysqli(self::DB_HOST, self::DB_USERNAME, self::DB_PASSWORD, self::DB_NAME);
}
public function backupDatabase(SuiteEvent $event) {
exec($this->createMysqlDumpCommand());
$sql = file_get_contents(self::DB_BACKUP_PATH);
// wrap dump with SQL preserving user session ($I->login() reuses session snapshot for performance)
$sql = "
SELECT meta_value
INTO @mp_meta_value
FROM mp_usermeta
WHERE user_id = 1
AND meta_key = 'session_tokens';
$sql
DELETE FROM mp_usermeta WHERE meta_key = 'session_tokens';
INSERT INTO mp_usermeta (user_id, meta_key, meta_value) VALUES (1, 'session_tokens', @mp_meta_value);
";
// set current plugin version to prevent executing Changelog.php setup for every test
$version = Env::$version;
$sql .= "
\n\n
INSERT INTO mp_mailpoet_settings (name, value) VALUES ('version', '$version')
ON DUPLICATE KEY UPDATE value = '$version';
";
// wrap SQL with serializable transaction (to avoid other connections like WP-CLI seeing wrong state)
$sql = "
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
$sql
COMMIT;
";
file_put_contents(self::DB_BACKUP_PATH, $sql);
}
public function cleanupEnvironment(TestEvent $event) {
$backupSql = file_get_contents(self::DB_BACKUP_PATH);
if (!is_string($backupSql)) {
throw new \RuntimeException('Missing or empty DB backup file: ' . self::DB_BACKUP_PATH);
}
$result = $this->rootConnection->multi_query($backupSql);
if ($result === false) {
throw new \RuntimeException('Failed to restore DB backup: ' . $this->rootConnection->error);
}
while ($this->rootConnection->next_result()) {
// flush all multi_query results
}
exec('rm -rf ' . self::MAILHOG_DATA_PATH . '/*', $output);
// cleanup EntityManager for data factories that are using it
ContainerWrapper::getInstance()->get(EntityManager::class)->clear();
// reset settings controller cache
ContainerWrapper::getInstance()->get(\MailPoet\Settings\SettingsController::class)->resetCache();
// Without clearing the cache WordPress will think data exist that doesn't, e.g. users created in previous tests
global $wp_object_cache;
if ($wp_object_cache) {
$wp_object_cache->flush();
}
}
private function createMysqlDumpCommand() {
return sprintf(
'mysqldump --host=%s --user=%s --password=%s %s > %s',
escapeshellarg(self::DB_HOST),
escapeshellarg(self::DB_USERNAME),
escapeshellarg(self::DB_PASSWORD),
escapeshellarg(self::DB_NAME),
escapeshellarg(self::DB_BACKUP_PATH)
);
}
}