X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=tests%2Fphpunit%2FMediaWikiTestCase.php;h=27f1454dca2472bc0d06ebedf9bfabd67131641d;hb=356b3420d6908f91510aa0cd94f3a363be7f8999;hp=9f3aa11a7ca462a98972a86b2e671b1b5af2ae96;hpb=5b38b28cddf5c00ad31208cf82fcb0911eb9ba32;p=lhc%2Fweb%2Fwiklou.git diff --git a/tests/phpunit/MediaWikiTestCase.php b/tests/phpunit/MediaWikiTestCase.php index 9f3aa11a7c..27f1454dca 100644 --- a/tests/phpunit/MediaWikiTestCase.php +++ b/tests/phpunit/MediaWikiTestCase.php @@ -127,6 +127,42 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { self::prepareServices( new GlobalVarConfig() ); } + /** + * Convenience method for getting an immutable test user + * + * @since 1.28 + * + * @param string[] $groups Groups the test user should be in. + * @return TestUser + */ + public static function getTestUser( $groups = [] ) { + return TestUserRegistry::getImmutableTestUser( $groups ); + } + + /** + * Convenience method for getting a mutable test user + * + * @since 1.28 + * + * @param string[] $groups Groups the test user should be added in. + * @return TestUser + */ + public static function getMutableTestUser( $groups = [] ) { + return TestUserRegistry::getMutableTestUser( __CLASS__, $groups ); + } + + /** + * Convenience method for getting an immutable admin test user + * + * @since 1.28 + * + * @param string[] $groups Groups the test user should be added to. + * @return TestUser + */ + public static function getTestSysop() { + return self::getTestUser( [ 'sysop', 'bureaucrat' ] ); + } + /** * Prepare service configuration for unit testing. * @@ -221,6 +257,9 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { $defaultOverrides->set( 'ObjectCaches', $objectCaches ); $defaultOverrides->set( 'MainCacheType', CACHE_NONE ); + // Use a fast hash algorithm to hash passwords. + $defaultOverrides->set( 'PasswordDefault', 'A' ); + $testConfig = $customOverrides ? new MultiConfig( [ $customOverrides, $defaultOverrides, $baseConfig ] ) : new MultiConfig( [ $defaultOverrides, $baseConfig ] ); @@ -302,7 +341,6 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { // TODO: move global state into MediaWikiServices RequestContext::resetMain(); - MediaHandler::resetCache(); if ( session_id() !== '' ) { session_write_close(); session_id( '' ); @@ -318,7 +356,7 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { $needsResetDB = false; - if ( $this->needsDB() ) { + if ( !self::$dbSetup || $this->needsDB() ) { // set up a DB connection for this test to use self::$useTemporaryTables = !$this->getCliArg( 'use-normal-tables' ); @@ -491,7 +529,6 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { // TODO: move global state into MediaWikiServices RequestContext::resetMain(); - MediaHandler::resetCache(); if ( session_id() !== '' ) { session_write_close(); session_id( '' ); @@ -597,6 +634,29 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { } } + /** + * Check if we can back up a value by performing a shallow copy. + * Values which fail this test are copied recursively. + * + * @param mixed $value + * @return bool True if a shallow copy will do; false if a deep copy + * is required. + */ + private static function canShallowCopy( $value ) { + if ( is_scalar( $value ) || $value === null ) { + return true; + } + if ( is_array( $value ) ) { + foreach ( $value as $subValue ) { + if ( !is_scalar( $subValue ) && $subValue !== null ) { + return false; + } + } + return true; + } + return false; + } + /** * Stashes the global, will be restored in tearDown() * @@ -632,13 +692,22 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { // NOTE: we serialize then unserialize the value in case it is an object // this stops any objects being passed by reference. We could use clone // and if is_object but this does account for objects within objects! - try { - $this->mwGlobals[$globalKey] = unserialize( serialize( $GLOBALS[$globalKey] ) ); - } - // NOTE; some things such as Closures are not serializable - // in this case just set the value! - catch ( Exception $e ) { + if ( self::canShallowCopy( $GLOBALS[$globalKey] ) ) { $this->mwGlobals[$globalKey] = $GLOBALS[$globalKey]; + } elseif ( + // Many MediaWiki types are safe to clone. These are the + // ones that are most commonly stashed. + $GLOBALS[$globalKey] instanceof Language || + $GLOBALS[$globalKey] instanceof User || + $GLOBALS[$globalKey] instanceof FauxRequest + ) { + $this->mwGlobals[$globalKey] = clone $GLOBALS[$globalKey]; + } else { + try { + $this->mwGlobals[$globalKey] = unserialize( serialize( $GLOBALS[$globalKey] ) ); + } catch ( Exception $e ) { + $this->mwGlobals[$globalKey] = $GLOBALS[$globalKey]; + } } } } @@ -848,7 +917,7 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { protected function insertPage( $pageName, $text = 'Sample page for unit test.' ) { $title = Title::newFromText( $pageName, 0 ); - $user = User::newFromName( 'UTSysop' ); + $user = static::getTestSysop()->getUser(); $comment = __METHOD__ . ': Sample page for unit test.'; // Avoid memory leak...? @@ -899,36 +968,33 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { # Insert 0 user to prevent FK violations # Anonymous user - $this->db->insert( 'user', [ - 'user_id' => 0, - 'user_name' => 'Anonymous' ], __METHOD__, [ 'IGNORE' ] ); + if ( !$this->db->selectField( 'user', '1', [ 'user_id' => 0 ] ) ) { + $this->db->insert( 'user', [ + 'user_id' => 0, + 'user_name' => 'Anonymous' ], __METHOD__, [ 'IGNORE' ] ); + } # Insert 0 page to prevent FK violations # Blank page - $this->db->insert( 'page', [ - 'page_id' => 0, - 'page_namespace' => 0, - 'page_title' => ' ', - 'page_restrictions' => null, - 'page_is_redirect' => 0, - 'page_is_new' => 0, - 'page_random' => 0, - 'page_touched' => $this->db->timestamp(), - 'page_latest' => 0, - 'page_len' => 0 ], __METHOD__, [ 'IGNORE' ] ); + if ( !$this->db->selectField( 'page', '1', [ 'page_id' => 0 ] ) ) { + $this->db->insert( 'page', [ + 'page_id' => 0, + 'page_namespace' => 0, + 'page_title' => ' ', + 'page_restrictions' => null, + 'page_is_redirect' => 0, + 'page_is_new' => 0, + 'page_random' => 0, + 'page_touched' => $this->db->timestamp(), + 'page_latest' => 0, + 'page_len' => 0 ], __METHOD__, [ 'IGNORE' ] ); + } } User::resetIdByNameCache(); // Make sysop user - $user = User::newFromName( 'UTSysop' ); - - if ( $user->idForName() == 0 ) { - $user->addToDatabase(); - TestUser::setPasswordForUser( $user, 'UTSysopPassword' ); - $user->addGroup( 'sysop' ); - $user->addGroup( 'bureaucrat' ); - } + $user = static::getTestSysop()->getUser(); // Make 1 page with 1 revision $page = WikiPage::factory( Title::newFromText( 'UTPage' ) ); @@ -1147,11 +1213,7 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { // If any of the user tables were marked as used, we should clear all of them. if ( array_intersect( $tablesUsed, $userTables ) ) { $tablesUsed = array_unique( array_merge( $tablesUsed, $userTables ) ); - - // Totally clear User class in-process cache to avoid CAS errors - TestingAccessWrapper::newFromClass( 'User' ) - ->getInProcessCache() - ->clear(); + TestUserRegistry::clear(); } $truncate = in_array( $db->getType(), [ 'oracle', 'mysql' ] ); @@ -1586,32 +1648,6 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { } } - /** - * Check whether we have the 'gzip' commandline utility, will skip - * the test whenever "gzip -V" fails. - * - * Result is cached at the process level. - * - * @return bool - * - * @since 1.21 - */ - protected function checkHasGzip() { - static $haveGzip; - - if ( $haveGzip === null ) { - $retval = null; - wfShellExec( 'gzip -V', $retval ); - $haveGzip = ( $retval === 0 ); - } - - if ( !$haveGzip ) { - $this->markTestSkipped( "Skip test, requires the gzip utility in PATH" ); - } - - return $haveGzip; - } - /** * Check if $extName is a loaded PHP extension, will skip the * test whenever it is not loaded. @@ -1737,4 +1773,15 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { return $buffer; } + /** + * Create a temporary hook handler which will be reset by tearDown. + * This replaces other handlers for the same hook. + * @param string $hookName Hook name + * @param mixed $handler Value suitable for a hook handler + * @since 1.28 + */ + protected function setTemporaryHook( $hookName, $handler ) { + $this->mergeMwGlobalArrayValue( 'wgHooks', [ $hookName => [ $handler ] ] ); + } + }