MediaWiki
REL1_19
|
00001 <?php 00002 00003 abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { 00004 public $suite; 00005 public $regex = ''; 00006 public $runDisabled = false; 00007 00011 protected $db; 00012 protected $oldTablePrefix; 00013 protected $useTemporaryTables = true; 00014 protected $reuseDB = false; 00015 protected $tablesUsed = array(); // tables with data 00016 00017 private static $dbSetup = false; 00018 00022 const DB_PREFIX = 'unittest_'; 00023 const ORA_DB_PREFIX = 'ut_'; 00024 00025 protected $supportedDBs = array( 00026 'mysql', 00027 'sqlite', 00028 'postgres', 00029 'oracle' 00030 ); 00031 00032 function __construct( $name = null, array $data = array(), $dataName = '' ) { 00033 parent::__construct( $name, $data, $dataName ); 00034 00035 $this->backupGlobals = false; 00036 $this->backupStaticAttributes = false; 00037 } 00038 00039 function run( PHPUnit_Framework_TestResult $result = NULL ) { 00040 /* Some functions require some kind of caching, and will end up using the db, 00041 * which we can't allow, as that would open a new connection for mysql. 00042 * Replace with a HashBag. They would not be going to persist anyway. 00043 */ 00044 ObjectCache::$instances[CACHE_DB] = new HashBagOStuff; 00045 00046 if( $this->needsDB() ) { 00047 global $wgDBprefix; 00048 00049 $this->useTemporaryTables = !$this->getCliArg( 'use-normal-tables' ); 00050 $this->reuseDB = $this->getCliArg('reuse-db'); 00051 00052 $this->db = wfGetDB( DB_MASTER ); 00053 00054 $this->checkDbIsSupported(); 00055 00056 $this->oldTablePrefix = $wgDBprefix; 00057 00058 if( !self::$dbSetup ) { 00059 $this->initDB(); 00060 self::$dbSetup = true; 00061 } 00062 00063 $this->addCoreDBData(); 00064 $this->addDBData(); 00065 00066 parent::run( $result ); 00067 00068 $this->resetDB(); 00069 } else { 00070 parent::run( $result ); 00071 } 00072 } 00073 00074 function dbPrefix() { 00075 return $this->db->getType() == 'oracle' ? self::ORA_DB_PREFIX : self::DB_PREFIX; 00076 } 00077 00078 function needsDB() { 00079 $rc = new ReflectionClass( $this ); 00080 return strpos( $rc->getDocComment(), '@group Database' ) !== false; 00081 } 00082 00087 function addDBData() {} 00088 00089 private function addCoreDBData() { 00090 # disabled for performance 00091 #$this->tablesUsed[] = 'page'; 00092 #$this->tablesUsed[] = 'revision'; 00093 00094 if ( $this->db->getType() == 'oracle' ) { 00095 00096 # Insert 0 user to prevent FK violations 00097 # Anonymous user 00098 $this->db->insert( 'user', array( 00099 'user_id' => 0, 00100 'user_name' => 'Anonymous' ), __METHOD__, array( 'IGNORE' ) ); 00101 00102 # Insert 0 page to prevent FK violations 00103 # Blank page 00104 $this->db->insert( 'page', array( 00105 'page_id' => 0, 00106 'page_namespace' => 0, 00107 'page_title' => ' ', 00108 'page_restrictions' => NULL, 00109 'page_counter' => 0, 00110 'page_is_redirect' => 0, 00111 'page_is_new' => 0, 00112 'page_random' => 0, 00113 'page_touched' => $this->db->timestamp(), 00114 'page_latest' => 0, 00115 'page_len' => 0 ), __METHOD__, array( 'IGNORE' ) ); 00116 00117 } 00118 00119 User::resetIdByNameCache(); 00120 00121 //Make sysop user 00122 $user = User::newFromName( 'UTSysop' ); 00123 00124 if ( $user->idForName() == 0 ) { 00125 $user->addToDatabase(); 00126 $user->setPassword( 'UTSysopPassword' ); 00127 00128 $user->addGroup( 'sysop' ); 00129 $user->addGroup( 'bureaucrat' ); 00130 $user->saveSettings(); 00131 } 00132 00133 00134 //Make 1 page with 1 revision 00135 $page = WikiPage::factory( Title::newFromText( 'UTPage' ) ); 00136 if ( !$page->getId() == 0 ) { 00137 $page->doEdit( 'UTContent', 00138 'UTPageSummary', 00139 EDIT_NEW, 00140 false, 00141 User::newFromName( 'UTSysop' ) ); 00142 } 00143 } 00144 00145 private function initDB() { 00146 global $wgDBprefix; 00147 if ( $wgDBprefix === $this->dbPrefix() ) { 00148 throw new MWException( 'Cannot run unit tests, the database prefix is already "unittest_"' ); 00149 } 00150 00151 $tablesCloned = $this->listTables(); 00152 $dbClone = new CloneDatabase( $this->db, $tablesCloned, $this->dbPrefix() ); 00153 $dbClone->useTemporaryTables( $this->useTemporaryTables ); 00154 00155 if ( ( $this->db->getType() == 'oracle' || !$this->useTemporaryTables ) && $this->reuseDB ) { 00156 CloneDatabase::changePrefix( $this->dbPrefix() ); 00157 $this->resetDB(); 00158 return; 00159 } else { 00160 $dbClone->cloneTableStructure(); 00161 } 00162 00163 if ( $this->db->getType() == 'oracle' ) { 00164 $this->db->query( 'BEGIN FILL_WIKI_INFO; END;' ); 00165 } 00166 } 00167 00171 private function resetDB() { 00172 if( $this->db ) { 00173 if ( $this->db->getType() == 'oracle' ) { 00174 if ( $this->useTemporaryTables ) { 00175 wfGetLB()->closeAll(); 00176 $this->db = wfGetDB( DB_MASTER ); 00177 } else { 00178 foreach( $this->tablesUsed as $tbl ) { 00179 if( $tbl == 'interwiki') continue; 00180 $this->db->query( 'TRUNCATE TABLE '.$this->db->tableName($tbl), __METHOD__ ); 00181 } 00182 } 00183 } else { 00184 foreach( $this->tablesUsed as $tbl ) { 00185 if( $tbl == 'interwiki' || $tbl == 'user' ) continue; 00186 $this->db->delete( $tbl, '*', __METHOD__ ); 00187 } 00188 } 00189 } 00190 } 00191 00192 function __call( $func, $args ) { 00193 static $compatibility = array( 00194 'assertInternalType' => 'assertType', 00195 'assertNotInternalType' => 'assertNotType', 00196 'assertInstanceOf' => 'assertType', 00197 'assertEmpty' => 'assertEmpty2', 00198 ); 00199 00200 if ( method_exists( $this->suite, $func ) ) { 00201 return call_user_func_array( array( $this->suite, $func ), $args); 00202 } elseif ( isset( $compatibility[$func] ) ) { 00203 return call_user_func_array( array( $this, $compatibility[$func] ), $args); 00204 } else { 00205 throw new MWException( "Called non-existant $func method on " 00206 . get_class( $this ) ); 00207 } 00208 } 00209 00210 private function assertEmpty2( $value, $msg ) { 00211 return $this->assertTrue( $value == '', $msg ); 00212 } 00213 00214 static private function unprefixTable( $tableName ) { 00215 global $wgDBprefix; 00216 return substr( $tableName, strlen( $wgDBprefix ) ); 00217 } 00218 00219 static private function isNotUnittest( $table ) { 00220 return strpos( $table, 'unittest_' ) !== 0; 00221 } 00222 00223 protected function listTables() { 00224 global $wgDBprefix; 00225 00226 $tables = $this->db->listTables( $wgDBprefix, __METHOD__ ); 00227 $tables = array_map( array( __CLASS__, 'unprefixTable' ), $tables ); 00228 00229 // Don't duplicate test tables from the previous fataled run 00230 $tables = array_filter( $tables, array( __CLASS__, 'isNotUnittest' ) ); 00231 00232 if ( $this->db->getType() == 'sqlite' ) { 00233 $tables = array_flip( $tables ); 00234 // these are subtables of searchindex and don't need to be duped/dropped separately 00235 unset( $tables['searchindex_content'] ); 00236 unset( $tables['searchindex_segdir'] ); 00237 unset( $tables['searchindex_segments'] ); 00238 $tables = array_flip( $tables ); 00239 } 00240 return $tables; 00241 } 00242 00243 protected function checkDbIsSupported() { 00244 if( !in_array( $this->db->getType(), $this->supportedDBs ) ) { 00245 throw new MWException( $this->db->getType() . " is not currently supported for unit testing." ); 00246 } 00247 } 00248 00249 public function getCliArg( $offset ) { 00250 00251 if( isset( MediaWikiPHPUnitCommand::$additionalOptions[$offset] ) ) { 00252 return MediaWikiPHPUnitCommand::$additionalOptions[$offset]; 00253 } 00254 00255 } 00256 00257 public function setCliArg( $offset, $value ) { 00258 00259 MediaWikiPHPUnitCommand::$additionalOptions[$offset] = $value; 00260 00261 } 00262 00263 public static function disableInterwikis( $prefix, &$data ) { 00264 return false; 00265 } 00266 00273 function hideDeprecated( $function ) { 00274 wfSuppressWarnings(); 00275 wfDeprecated( $function ); 00276 wfRestoreWarnings(); 00277 } 00278 }