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.
*
$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 ] );
$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' );
}
$wgRequest = new FauxRequest();
MediaWiki\Session\SessionManager::resetCache();
+ MediaWiki\Auth\AuthManager::resetCache();
$phpErrorLevel = intval( ini_get( 'error_reporting' ) );
}
}
+ /**
+ * 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()
*
// 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];
+ }
}
}
}
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...?
# 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' ) );
// 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' ] );
}
}
- /**
- * 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.