You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

369 lines
13 KiB

<?php
/** @noinspection ALL */
// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
//
// All Rights Reserved. See copyright.txt for details and a complete list of authors.
// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
// $Id$
/*
* Created on Apr 7, 2009
*
* To change the template for this generated file go to
* Window - Preferences - PHPeclipse - PHP - Code Templates
*/
use Tiki\Installer\Installer;
require_once('installer/installlib.php');
abstract class TikiAcceptanceTestDBRestorer
/*
* This class is invoked between automated tests, in order to restore the Tiki DB
* to a given starting state. This avoids side effects between tests, which could
* happen if a given test put data into the DB which would affect the success/failure
* of subsequent tests.
*
* There are currently two subclasses that use different approaches for dumping the DB
* and restoring it. We keep both of them for now, until we decide which of the two
* is most appropriate.
*
* The SQLDumps approach uses files containing SQL statements that can be used to restore
* the DB. It is slower, but possibly more reliable.
*
* The BinaryDumps approach uses the actual binary files of the DB. It is faster, but possibly
* less reliable.
*/
{
const EMPTY_DB = 'emptyDb.sql';
protected $host = "localhost";
protected $tiki_test_db = "tiki_db_for_acceptance_tests";
protected $tiki_test_db_user = "tiki_automated_test_user";
protected $tiki_test_db_pwd = "tiki_automated_test_user";
protected $tiki_test_db_dump = "tiki_db_for_acceptance_tests_dump.sql";
protected $mysql_data_dir = "";
protected $tiki_schema_file_start = "dump_schema_tiki_start.txt";
protected $tiki_restore_db_file_name = "tiki_testdb_restore_file.sql";
protected $tiki_bare_bones_db_dump = "bareBonesDBDump.sql";
public function __construct()
{
if (getenv('MYSQL_HOST')) {
$this->host = getenv('MYSQL_HOST');
}
if (getenv('MYSQL_DATABASE')) {
$this->tiki_test_db = getenv('MYSQL_DATABASE');
}
if (getenv('MYSQL_USER')) {
$this->tiki_test_db_user = getenv('MYSQL_USER');
}
if (getenv('MYSQL_PASSWORD')) {
$this->tiki_test_db_pwd = getenv('MYSQL_PASSWORD');
}
$this->current_dir = getcwd();
$this->mysql_data_dir = $this->setMysqlDataDir();
}
//This method can be called to create any dump file from a db.
//Useful for creating dumps for diffent test db configurations
abstract public function createDumpFile($dump_file);
public function setMysqlDataDir()
{
$conn = mysqli_connect($this->host, $this->tiki_test_db_user, $this->tiki_test_db_pwd) or die(mysqli_error($conn));
$result = mysqli_query($conn, "select @@datadir;");
while ($array = mysqli_fetch_array($result)) {
$datadir = $array[0];
}
return $datadir;
}
abstract public function checkIfDumpExists($dump_file);
public function restoreDB($tiki_test_db_dump, $save_schema = false)
{
$begTime = microtime(true);
$this->restoreDBDump($tiki_test_db_dump, $save_schema);
$this->reinitializeInternalValuesAndClearCaches();
echo "<pre>" . __METHOD__ . " DB restored in " . (microtime(true) - $begTime) . " seconds</pre>\n";
}
abstract public function restoreDBDump($tiki_test_db_dump, $save_schema = false);
public function reinitializeInternalValuesAndClearCaches()
{
global $prefs;
$tikilib = TikiLib::lib('tiki');
$cachelib = TikiLib::lib('cache');
initialize_prefs();
$tikilib->cache_page_info = [];
$cachelib->empty_cache();
}
public function printCallStack()
{
// Can't believe this is not standard in PHP!
$backtrace = debug_backtrace();
// Remove printCallStack() element from the stack, and print just the rest.
array_shift($backtrace);
foreach ($backtrace as $backtraceElement) {
$line = "In File: " . $backtraceElement['file'] . ", at line: " . $backtraceElement['line'] . "\n";
if (isset($backtraceElement['class'])) {
$line .= $backtraceElement['class'] . "::";
}
$line .= $backtraceElement['function'] . "\n";
echo $line;
}
}
}
class TikiAcceptanceTestDBRestorerSQLDumps extends TikiAcceptanceTestDBRestorer
{
/*
* This subclass uses SQL dumps of the DB to create DB snapshots and restore them.
* It tries to only restore those tables that have changed since the last time
* the snapshot was restored.
*/
public function __construct()
{
parent::__construct();
// enable this to run from the tiki temp folder as a cache dir
if (realpath(__DIR__ . '/../../temp')) {
$this->mysql_data_dir = realpath(__DIR__ . '/../../temp') . '/testcache/';
if (! is_dir($this->mysql_data_dir)) {
mkdir($this->mysql_data_dir);
}
}
}
public function checkIfDumpAndSchemaStartFilesExist($dump_file)
{
if (
checkIfDumpExists($dump_file) &&
checkIfDumpExists($dump_file . "_" . $this->tiki_schema_file_start)
) {
return true;
}
}
public function checkIfDumpExists($dump_file)
{
chdir($this->mysql_data_dir);
if (file_exists($dump_file)) {
return true;
}
}
//This method can be called to create any dump file from a db.
//Useful for creating dumps for diffent test db configurations
public function createDumpFile($dump_file)
{
chdir($this->mysql_data_dir);
// echo "\nDumping the whole tiki database: ";
// $begTime = microtime(true);
$mysqldump_command_line = "MYSQL_PWD=$this->tiki_test_db_pwd mysqldump --host=$this->host --user=$this->tiki_test_db_user $this->tiki_test_db > $dump_file";
shell_exec($mysqldump_command_line);
// echo (microtime(true) -$begTime)." sec\n";
chdir($this->current_dir);
return true;
}
//Creates start schema files from the test db
public function createStartSchemaFiles()
{
chdir($this->mysql_data_dir);
// echo "\n\rDumping start tables and times from information_schema: ";
// $begTime = microtime(true);
$mysql_select_from_schema_command = "echo select TABLE_NAME,UPDATE_TIME from information_schema.TABLES WHERE TABLE_SCHEMA=\'$this->tiki_test_db\' | MYSQL_PWD=$this->tiki_test_db_pwd mysql --host=$this->host --user=$this->tiki_test_db_user > $this->tiki_schema_file_start";
exec($mysql_select_from_schema_command);
// echo (microtime(true) - $begTime)." sec\n";
chdir($this->current_dir);
return true;
}
public function createTestdbDumpAndStartSchemaFiles()
{
$this->createDumpFile($this->tiki_test_db_dump);
$this->createStartSchemaFiles();
}
public function restoreDBDump($tiki_test_db_dump, $save_schema = false)
{
$begTime = microtime(true);
global $last_restored;
$error_msg = null;
chdir($this->mysql_data_dir);
if (! file_exists($tiki_test_db_dump)) {
$error_msg =
"\nTried to run an acceptance test without an initial database dump. " .
"Run script lib/core/test/create_dump_db_file.php to create it.\n";
return $error_msg;
}
if ($last_restored == $tiki_test_db_dump) {
//restore only the changed tables
$tiki_schema_file_end = "dump_schema_tiki_end.txt";
//GET THE CURRENT TABLES
// echo "\n\rDumping end tables and times from information_schema: ";
// $begTime = microtime(true);
$mysql_select_from_schema_command = "echo select TABLE_NAME,UPDATE_TIME from information_schema.TABLES WHERE TABLE_SCHEMA=\'$this->tiki_test_db\' | MYSQL_PWD=$this->tiki_test_db_pwd mysql --host=$this->host --user=$this->tiki_test_db_user > $tiki_schema_file_end";
shell_exec($mysql_select_from_schema_command);
// echo (microtime(true) -$begTime)." sec";
//COMPARE THE START AND END DUMPS
// echo "\n\rCompare start and end tables and times from information_schema: ";
// $begTime = microtime(true);
$start_file_lines = file($this->tiki_schema_file_start, FILE_IGNORE_NEW_LINES);
$end_file_lines = file($tiki_schema_file_end, FILE_IGNORE_NEW_LINES);
$diff = array_diff($start_file_lines, $end_file_lines);
//GET ONLY TABLE_NAMES THAT CHANGED
array_walk($diff, [$this,'getTableName']);
// echo (microtime(true) -$begTime)." sec";
// echo "\n\rCreate restore sql file: ";
// $begTime = microtime(true);
$tiki_test_db_dump_as_string = file_get_contents($tiki_test_db_dump);
//CREATE SQL FILE THAT WILL RESTORE ONLY THE CHANGED TABLES
$tiki_restore_db_file = fopen($this->tiki_restore_db_file_name, 'w') or die("can't open file for restoring DB" . $this->tiki_restore_db_file_name);/**/
fwrite($tiki_restore_db_file, "-- Nothing\n\n");
foreach ($diff as $table_name) {
$match_this = "/(LOCK TABLES `" . $table_name . "`.+UNLOCK TABLES;)/Us";
$is_matched = preg_match($match_this, $tiki_test_db_dump_as_string, $matches);
fwrite($tiki_restore_db_file, "TRUNCATE TABLE `" . $table_name . "`;\n\n");
fwrite($tiki_restore_db_file, $matches[0]);
fwrite($tiki_restore_db_file, "\n\n\n");
}
fclose($tiki_restore_db_file);
// echo (microtime(true) -$begTime)." sec";
// echo "\n\rRestore original database: ";
// $begTime = microtime(true);
//RESTORE THE ORIGINAL DATABASE
$installer = Installer::getInstance();
$installer->runFile($this->tiki_restore_db_file_name);
// echo (microtime(true) -$begTime)." sec";
$last_restored = $tiki_test_db_dump;
// $this->reinitializeInternalValuesAndClearCaches();
} else {
//restore the whole database
$this->restoreDBDumpFromScratch($tiki_test_db_dump);
$last_restored = $tiki_test_db_dump;
$this->createStartSchemaFiles();
}
chdir($this->current_dir);
return null;
}
public function getTableName(&$table_name_date_time)
{
preg_match('/([a-zA-Z-_]+)(\s+)/', $table_name_date_time, $matches);
$table_name_date_time = $matches[1];
}
public function restoreBareBonesDB()
{
chdir($this->mysql_data_dir);
$mysql_restore_db_command = "MYSQL_PWD=$this->tiki_test_db_pwd mysql --host=$this->host --user=$this->tiki_test_db_user $this->tiki_test_db < $this->tiki_bare_bones_db_dump";
shell_exec($mysql_restore_db_command);
chdir($this->current_dir);
}
public function restoreDBDumpFromScratch($dump_file)
{
$dump_file_with_path = $this->mysql_data_dir . $dump_file;
$installer = Installer::getInstance();
$installer->runFile($dump_file_with_path);
}
}
class TikiAcceptanceTestDBRestorerBinaryDumps extends TikiAcceptanceTestDBRestorer
{
/*
* This subclass uses binary files of the SQL database, instead of
* files containing SQL statements to restore the DB.
* It is faster, but possibly less robust than the SQLDumps approach.
* We keep both approaches for now, until we decide which of the
* two makes most sense.
*/
private $dump_file_extension = 'binary';
public function __construct()
{
parent::__construct();
}
public function createDumpFile($dump_name)
{
$tiki_test_db_data_directory =
$this->mysql_data_dir . DIRECTORY_SEPARATOR .
$this->tiki_test_db;
$this->copyDir($tiki_test_db_data_directory, $this->dumpFilePath($dump_name));
}
private function dumpFilePath($dump_name)
{
return $this->mysql_data_dir . DIRECTORY_SEPARATOR .
$dump_name .
"." . $this->dump_file_extension;
}
public function checkIfDumpExists($dump_file)
{
}
public function restoreDBDump($tiki_test_db_dump, $save_schema = false)
{
}
private function copyDir($source, $target)
{
if (is_dir($source)) {
@mkdir($target);
$d = dir($source);
while (false !== ($entry = $d->read())) {
if ($entry == '.' || $entry == '..') {
continue;
}
$Entry = $source . '/' . $entry;
if (is_dir($Entry)) {
full_copy($Entry, $target . '/' . $entry);
continue;
}
copy($Entry, $target . '/' . $entry);
}
$d->close();
} else {
copy($source, $target);
}
}
}