From 86df2d275521184e42f30254724da2b0483ad421 Mon Sep 17 00:00:00 2001 From: X! Date: Tue, 28 Dec 2010 17:15:50 +0000 Subject: [PATCH] It's here! It's finally here! The skies are falling, pigs have sprouted wings, and it's pretty cold in hell! -Add a working PHPUnit test that instantiates a new DB, adds set data, and deleted when done. -Add listTables() to the Database classes (only MySql and SQLite use it, and only MySQL is tested) --- includes/db/Database.php | 10 ++ includes/db/DatabaseMysql.php | 23 +++++ includes/db/DatabaseSqlite.php | 28 ++++++ tests/phpunit/bootstrap.php | 137 +++++++++++++++++++++++++++ tests/phpunit/includes/NewDBTest.php | 37 ++++++++ 5 files changed, 235 insertions(+) create mode 100644 tests/phpunit/includes/NewDBTest.php diff --git a/includes/db/Database.php b/includes/db/Database.php index 0f9065cf53..1ab7f51746 100644 --- a/includes/db/Database.php +++ b/includes/db/Database.php @@ -2288,6 +2288,16 @@ abstract class DatabaseBase implements DatabaseType { function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = 'DatabaseBase::duplicateTableStructure' ) { throw new MWException( 'DatabaseBase::duplicateTableStructure is not implemented in descendant class' ); } + + /** + * List all tables on the database + * + * @param $prefix Only show tables with this prefix, e.g. mw_ + * @param $fname String: calling function name + */ + function listTables( $prefix = null, $fname = 'DatabaseBase::listTables' ) { + throw new MWException( 'DatabaseBase::listTables is not implemented in descendant class' ); + } /** * Return MW-style timestamp used for MySQL schema diff --git a/includes/db/DatabaseMysql.php b/includes/db/DatabaseMysql.php index 24e522f1a4..2eee6cf352 100644 --- a/includes/db/DatabaseMysql.php +++ b/includes/db/DatabaseMysql.php @@ -530,6 +530,29 @@ class DatabaseMysql extends DatabaseBase { } $this->query( $query, $fname ); } + + /** + * List all tables on the database + * + * @param $prefix Only show tables with this prefix, e.g. mw_ + * @param $fname String: calling function name + */ + function listTables( $prefix = null, $fname = 'DatabaseMysql::listTables' ) { + $result = $this->query( "SHOW TABLES", $fname); + + $endArray = array(); + + foreach( $result as $table ) { + $vars = get_object_vars($table); + $table = array_pop( $vars ); + + if( strpos( $table, $prefix ) === 0 || is_null( $prefix ) ) { + $endArray[] = $table; + } + } + + return $endArray; + } public function dropTable( $tableName, $fName = 'DatabaseMysql::dropTable' ) { if( !$this->tableExists( $tableName ) ) { diff --git a/includes/db/DatabaseSqlite.php b/includes/db/DatabaseSqlite.php index 52637a23a9..4dc2e4d03a 100644 --- a/includes/db/DatabaseSqlite.php +++ b/includes/db/DatabaseSqlite.php @@ -608,6 +608,34 @@ class DatabaseSqlite extends DatabaseBase { $sql = preg_replace( '/\b' . preg_quote( $oldName ) . '\b/', $newName, $sql, 1 ); return $this->query( $sql, $fname ); } + + + /** + * List all tables on the database + * + * @param $prefix Only show tables with this prefix, e.g. mw_ + * @param $fname String: calling function name + */ + function listTables( $prefix = null, $fname = 'DatabaseSqlite::listTables' ) { + $result = $this->select( + 'sqlite_master', + 'name', + "type='TABLE'" + ); + + $endArray = array(); + + foreach( $result as $table ) { + $vars = get_object_vars($table); + $table = array_pop( $vars ); + + if( strpos( $table, $prefix ) === 0 || is_null( $prefix ) ) { + $endArray[] = $table; + } + } + + return $endArray; + } } // end DatabaseSqlite class diff --git a/tests/phpunit/bootstrap.php b/tests/phpunit/bootstrap.php index 81beb2bc4a..94ec6d6102 100644 --- a/tests/phpunit/bootstrap.php +++ b/tests/phpunit/bootstrap.php @@ -46,11 +46,139 @@ abstract class MediaWikiTestSetup extends PHPUnit_Framework_TestCase { protected $suite; public $regex = ''; public $runDisabled = false; + + protected static $databaseSetupDone = false; + protected $db; + protected $dbClone; + protected $oldTablePrefix; + protected $useTemporaryTables = true; function __construct( PHPUnit_Framework_TestSuite $suite = null ) { if ( null !== $suite ) { $this->suite = $suite; } + parent::__construct(); + + if( $this->needsDB() && !is_object( $this->dbClone ) ) { + $this->initDB(); + $this->addCoreDBData(); + $this->addDBData(); + } + } + + function __destruct() { + if( $this->needsDB() && is_object( $this->dbClone ) && $this->dbClone instanceof CloneDatabase ) { + $this->destroyDB(); + } + } + + function needsDB() { return false; } + + function addDBData() {} + + private function addCoreDBData() { + + //Make sysop user + $user = User::newFromName( 'UTSysop' ); + if ( $user->idForName() == 0 ) { + $user->addToDatabase(); + $user->setPassword( 'UTSysopPassword' ); + + $user->addGroup( 'sysop' ); + $user->addGroup( 'bureaucrat' ); + $user->saveSettings(); + } + + + //Make 1 page with 1 revision + $article = new Article( Title::newFromText( 'UTPage' ) ); + $article->doEdit( 'UTContent', + 'UTPageSummary', + EDIT_NEW, + false, + User::newFromName( 'UTSysop' ) ); + } + + private function initDB() { + global $wgDBprefix; + + if ( self::$databaseSetupDone ) { + return; + } + + $this->db = wfGetDB( DB_MASTER ); + $dbType = $this->db->getType(); + + if ( $wgDBprefix === 'unittest_' || ( $dbType == 'oracle' && $wgDBprefix === 'ut_' ) ) { + throw new MWException( 'Cannot run unit tests, the database prefix is already "unittest_"' ); + } + + self::$databaseSetupDone = true; + $this->oldTablePrefix = $wgDBprefix; + + # SqlBagOStuff broke when using temporary tables on r40209 (bug 15892). + # It seems to have been fixed since (r55079?). + # If it fails, $wgCaches[CACHE_DB] = new HashBagOStuff(); should work around it. + + # CREATE TEMPORARY TABLE breaks if there is more than one server + if ( wfGetLB()->getServerCount() != 1 ) { + $this->useTemporaryTables = false; + } + + $temporary = $this->useTemporaryTables || $dbType == 'postgres'; + + $tables = $this->listTables(); + + $prefix = $dbType != 'oracle' ? 'unittest_' : 'ut_'; + + $this->dbClone = new CloneDatabase( $this->db, $tables, $prefix ); + $this->dbClone->useTemporaryTables( $temporary ); + $this->dbClone->cloneTableStructure(); + + if ( $dbType == 'oracle' ) + $this->db->query( 'BEGIN FILL_WIKI_INFO; END;' ); + + if ( $dbType == 'oracle' ) { + # Insert 0 user to prevent FK violations + + # Anonymous user + $this->db->insert( 'user', array( + 'user_id' => 0, + 'user_name' => 'Anonymous' ) ); + } + + } + + private function destroyDB() { + if ( !self::$databaseSetupDone ) { + return; + } + + $this->dbClone->destroy(); + self::$databaseSetupDone = false; + + if ( $this->useTemporaryTables ) { + # Don't need to do anything + //return; + //Temporary tables seem to be broken ATM, delete anyway + } + + if( $this->db->getType() == 'oracle' ) { + $tables = $this->db->listTables( 'ut_', __METHOD__ ); + } + else { + $tables = $this->db->listTables( 'unittest_', __METHOD__ ); + } + + foreach ( $tables as $table ) { + $sql = $this->db->getType() == 'oracle' ? "DROP TABLE $table DROP CONSTRAINTS" : "DROP TABLE `$table`"; + $this->db->query( $sql ); + } + + if ( $this->db->getType() == 'oracle' ) + $this->db->query( 'BEGIN FILL_WIKI_INFO; END;' ); + + } function __call( $func, $args ) { @@ -61,5 +189,14 @@ abstract class MediaWikiTestSetup extends PHPUnit_Framework_TestCase { . get_class( $this ) ); } } + + protected function listTables() { + global $wgDBprefix; + + $tables = $this->db->listTables( $wgDBprefix, __METHOD__ ); + $tables = array_map( create_function( '$table', 'global $wgDBprefix; return substr( $table, strlen( $wgDBprefix ) );' ), $tables ); + return $tables; + + } } diff --git a/tests/phpunit/includes/NewDBTest.php b/tests/phpunit/includes/NewDBTest.php new file mode 100644 index 0000000000..070f048d33 --- /dev/null +++ b/tests/phpunit/includes/NewDBTest.php @@ -0,0 +1,37 @@ +doEdit( 'FoobarContent', + '', + EDIT_NEW, + false, + User::newFromName( 'UTSysop' ) ); + } + + function needsDB() { return true; } + + function testBootstrapCreation() { + + $article = new Article( Title::newFromText("UTPage") ); + + $this->assertEquals("UTContent", $article->fetchContent(), "Automatic main page creation"); + + $article = new Article( Title::newFromText("Foobar") ); + + $this->assertEquals("FoobarContent", $article->fetchContent(), "addDBData() adds to the database"); + + } + +} + -- 2.20.1