'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) ); } }