use 'EditPageGetCheckboxesDefinition' instead.
* Linker::getLinkColour() and DummyLinker::getLinkColour(), deprecated since
1.28, were removed. LinkRenderer::getLinkClasses() should be used instead.
+* Wikimedia\Rdbms\LoadBalancer::getLaggedSlaveMode(), deprecated in 1.28, has
+ been removed. Use Wikimedia\Rdbms\LoadBalancer::getLaggedReplicaMode()
+ instead.
* mw.widgets.CategoryMultiselectWidget now uses TagMultiselectWidget instead of
CapsuleMultiselectWidget. The following methods may no longer be used:
* setItemsFromData: Use setValue instead
} else {
// If we receive the last parameter of the request, we can fairly
// claim the POST request has not been truncated.
-
- // TODO: softened the check for cutover. Once we determine
- // that it is safe, we should complete the transition by
- // removing the "edittime" clause.
- $this->incompleteForm = ( !$request->getVal( 'wpUltimateParam' )
- && is_null( $this->edittime ) );
+ $this->incompleteForm = !$request->getVal( 'wpUltimateParam' );
}
if ( $this->incompleteForm ) {
# If the form is incomplete, force to preview.
use MediaWiki\Storage\RevisionFactory;
use MediaWiki\Storage\RevisionLookup;
use MediaWiki\Storage\RevisionStore;
-use MediaWiki\Storage\RevisionStoreFactory;
use OldRevisionImporter;
use UploadRevisionImporter;
use Wikimedia\Rdbms\LBFactory;
return $this->getService( 'RevisionStore' );
}
- /**
- * @since 1.32
- * @return RevisionStoreFactory
- */
- public function getRevisionStoreFactory() {
- return $this->getService( 'RevisionStoreFactory' );
- }
-
/**
* @since 1.31
* @return RevisionLookup
use MediaWiki\Shell\CommandFactory;
use MediaWiki\Storage\BlobStoreFactory;
use MediaWiki\Storage\NameTableStore;
-use MediaWiki\Storage\RevisionStoreFactory;
+use MediaWiki\Storage\RevisionStore;
use MediaWiki\Storage\SqlBlobStore;
use Wikimedia\ObjectFactory;
},
'RevisionStore' => function ( MediaWikiServices $services ) {
- return $services->getRevisionStoreFactory()->getRevisionStore();
- },
-
- 'RevisionStoreFactory' => function ( MediaWikiServices $services ) {
/** @var SqlBlobStore $blobStore */
$blobStore = $services->getService( '_SqlBlobStore' );
- $config = $services->getMainConfig();
- $store = new RevisionStoreFactory(
+ $store = new RevisionStore(
$services->getDBLoadBalancer(),
$blobStore,
$services->getMainWANObjectCache(),
$services->getContentModelStore(),
$services->getSlotRoleStore(),
$services->getMainConfig()->get( 'MultiContentRevisionSchemaMigrationStage' ),
- $services->getActorMigration(),
- LoggerFactory::getInstance( 'RevisionStore' ),
- $config->get( 'ContentHandlerUseDB' )
+ $services->getActorMigration()
);
+ $store->setLogger( LoggerFactory::getInstance( 'RevisionStore' ) );
+
+ $config = $services->getMainConfig();
+ $store->setContentHandlerUseDB( $config->get( 'ContentHandlerUseDB' ) );
+
return $store;
},
+++ /dev/null
-<?php
-
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * Attribution notice: when this file was created, much of its content was taken
- * from the Revision.php file as present in release 1.30. Refer to the history
- * of that file for original authorship.
- *
- * @file
- */
-
-namespace MediaWiki\Storage;
-
-use ActorMigration;
-use CommentStore;
-use Psr\Log\LoggerInterface;
-use WANObjectCache;
-use Wikimedia\Assert\Assert;
-use Wikimedia\Rdbms\LoadBalancer;
-
-/**
- * @since 1.32
- */
-class RevisionStoreFactory {
-
- /** @var SqlBlobStore */
- private $blobStore;
-
- /** @var LoadBalancer */
- private $loadBalancer;
-
- /** @var WANObjectCache */
- private $cache;
-
- /** @var CommentStore */
- private $commentStore;
-
- /** @var ActorMigration */
- private $actorMigration;
-
- /** @var NameTableStore */
- private $contentModelStore;
-
- /** @var NameTableStore */
- private $slotRoleStore;
-
- /** @var int One of the MIGRATION_* constants */
- private $mcrMigrationStage;
-
- /**
- * @var bool
- * @see $wgContentHandlerUseDB
- */
- private $contentHandlerUseDB;
-
- /** @var LoggerInterface */
- private $logger;
-
- /**
- * @todo $blobStore should be allowed to be any BlobStore!
- *
- * @param LoadBalancer $loadBalancer
- * @param SqlBlobStore $blobStore
- * @param WANObjectCache $cache
- * @param CommentStore $commentStore
- * @param NameTableStore $contentModelStore
- * @param NameTableStore $slotRoleStore
- * @param int $migrationStage
- * @param ActorMigration $actorMigration
- * @param LoggerInterface $logger
- * @param bool $contentHandlerUseDB see {@link $wgContentHandlerUseDB}
- */
- public function __construct(
- LoadBalancer $loadBalancer,
- SqlBlobStore $blobStore,
- WANObjectCache $cache,
- CommentStore $commentStore,
- NameTableStore $contentModelStore,
- NameTableStore $slotRoleStore,
- $migrationStage,
- ActorMigration $actorMigration,
- LoggerInterface $logger,
- $contentHandlerUseDB
- ) {
- Assert::parameterType( 'integer', $migrationStage, '$migrationStage' );
-
- $this->loadBalancer = $loadBalancer;
- $this->blobStore = $blobStore;
- $this->cache = $cache;
- $this->commentStore = $commentStore;
- $this->contentModelStore = $contentModelStore;
- $this->slotRoleStore = $slotRoleStore;
- $this->mcrMigrationStage = $migrationStage;
- $this->actorMigration = $actorMigration;
- $this->logger = $logger;
- $this->contentHandlerUseDB = $contentHandlerUseDB;
- }
-
- /**
- * @since 1.32
- *
- * @param bool|string $wikiId false for the current domain / wikid
- *
- * @return RevisionStore for the given wikiId with all necessary services and a logger
- */
- public function getRevisionStore( $wikiId = false ) {
- Assert::parameterType( 'string|boolean', $wikiId, '$wikiId' );
-
- $store = new RevisionStore(
- $this->loadBalancer,
- $this->blobStore,
- $this->cache,
- $this->commentStore,
- $this->contentModelStore,
- $this->slotRoleStore,
- $this->mcrMigrationStage,
- $this->actorMigration,
- $wikiId
- );
-
- $store->setLogger( $this->logger );
- $store->setContentHandlerUseDB( $this->contentHandlerUseDB );
-
- return $store;
- }
-
-}
const LOCK_TTL = 30;
/**
- * Process local cache of loaded messages that are defined in
- * MediaWiki namespace. First array level is a language code,
- * second level is message key and the values are either message
- * content prefixed with space, or !NONEXISTENT for negative
- * caching.
- * @var array $mCache
+ * Process cache of loaded messages that are defined in MediaWiki namespace
+ *
+ * @var MapCacheLRU Map of (language code => key => " <MESSAGE>" or "!TOO BIG")
*/
- protected $mCache;
+ protected $cache;
/**
* @var bool[] Map of (language code => boolean)
/** @var Parser */
protected $mParser;
- /**
- * Variable for tracking which variables are already loaded
- * @var array $mLoadedLanguages
- */
- protected $mLoadedLanguages = [];
-
/**
* @var bool $mInParser
*/
$this->clusterCache = $clusterCache;
$this->srvCache = $serverCache;
+ $this->cache = new MapCacheLRU( 5 ); // limit size for sanity
+
$this->mDisable = !$useDB;
$this->mExpiry = $expiry;
}
*
* @param string $code Language to which load messages
* @param int $mode Use MessageCache::FOR_UPDATE to skip process cache [optional]
- * @throws MWException
+ * @throws InvalidArgumentException
* @return bool
*/
protected function load( $code, $mode = null ) {
}
# Don't do double loading...
- if ( isset( $this->mLoadedLanguages[$code] ) && $mode != self::FOR_UPDATE ) {
+ if ( $this->cache->has( $code ) && $mode != self::FOR_UPDATE ) {
return true;
}
$staleCache = $cache;
} else {
$where[] = 'got from local cache';
+ $this->cache->set( $code, $cache );
$success = true;
- $this->mCache[$code] = $cache;
}
if ( !$success ) {
$staleCache = $cache;
} else {
$where[] = 'got from global cache';
- $this->mCache[$code] = $cache;
+ $this->cache->set( $code, $cache );
$this->saveToCaches( $cache, 'local-only', $code );
$success = true;
}
} elseif ( $staleCache ) {
# Use the stale cache while some other thread constructs the new one
$where[] = 'using stale cache';
- $this->mCache[$code] = $staleCache;
+ $this->cache->set( $code, $staleCache );
$success = true;
break;
} elseif ( $failedAttempts > 0 ) {
if ( !$success ) {
$where[] = 'loading FAILED - cache is disabled';
$this->mDisable = true;
- $this->mCache = false;
+ $this->cache->set( $code, null );
wfDebugLog( 'MessageCacheError', __METHOD__ . ": Failed to load $code\n" );
# This used to throw an exception, but that led to nasty side effects like
# the whole wiki being instantly down if the memcached server died
- } else {
- # All good, just record the success
- $this->mLoadedLanguages[$code] = true;
+ }
+
+ if ( !$this->cache->has( $code ) ) { // sanity
+ throw new LogicException( "Process cache for '$code' should be set by now." );
}
$info = implode( ', ', $where );
}
$cache = $this->loadFromDB( $code, $mode );
- $this->mCache[$code] = $cache;
+ $this->cache->set( $code, $cache );
$saveSuccess = $this->saveToCaches( $cache, 'all', $code );
if ( !$saveSuccess ) {
$mostused = [];
if ( $wgAdaptiveMessageCache && $code !== $wgLanguageCode ) {
- if ( !isset( $this->mCache[$wgLanguageCode] ) ) {
+ if ( !$this->cache->has( $wgLanguageCode ) ) {
$this->load( $wgLanguageCode );
}
- $mostused = array_keys( $this->mCache[$wgLanguageCode] );
+ $mostused = array_keys( $this->cache->get( $wgLanguageCode ) );
foreach ( $mostused as $key => $value ) {
$mostused[$key] = "$value/$code";
}
// (a) Update the process cache with the new message text
if ( $text === false ) {
// Page deleted
- $this->mCache[$code][$title] = '!NONEXISTENT';
+ $this->cache->setField( $code, $title, '!NONEXISTENT' );
} else {
// Ignore $wgMaxMsgCacheEntrySize so the process cache is up to date
- $this->mCache[$code][$title] = ' ' . $text;
+ $this->cache->setField( $code, $title, ' ' . $text );
}
// (b) Update the shared caches in a deferred update with a fresh DB snapshot
}
// Load the messages from the master DB to avoid race conditions
$cache = $this->loadFromDB( $code, self::FOR_UPDATE );
- $this->mCache[$code] = $cache;
- // Load the process cache values and set the per-title cache keys
+ // Check if an individual cache key should exist and update cache accordingly
$page = WikiPage::factory( Title::makeTitle( NS_MEDIAWIKI, $title ) );
$page->loadPageData( $page::READ_LATEST );
$text = $this->getMessageTextFromContent( $page->getContent() );
- // Check if an individual cache key should exist and update cache accordingly
if ( is_string( $text ) && strlen( $text ) > $wgMaxMsgCacheEntrySize ) {
- $titleKey = $this->bigMessageCacheKey( $this->mCache[$code]['HASH'], $title );
- $this->wanCache->set( $titleKey, ' ' . $text, $this->mExpiry );
+ $this->wanCache->set(
+ $this->bigMessageCacheKey( $cache['HASH'], $title ),
+ ' ' . $text,
+ $this->mExpiry
+ );
}
// Mark this cache as definitely being "latest" (non-volatile) so
- // load() calls do try to refresh the cache with replica DB data
- $this->mCache[$code]['LATEST'] = time();
+ // load() calls do not try to refresh the cache with replica DB data
+ $cache['LATEST'] = time();
+ // Update the process cache
+ $this->cache->set( $code, $cache );
// Pre-emptively update the local datacenter cache so things like edit filter and
// blacklist changes are reflected immediately; these often use MediaWiki: pages.
// The datacenter handling replace() calls should be the same one handling edits
// as they require HTTP POST.
- $this->saveToCaches( $this->mCache[$code], 'all', $code );
+ $this->saveToCaches( $cache, 'all', $code );
// Release the lock now that the cache is saved
ScopedCallback::consume( $scopedLock );
public function getMsgFromNamespace( $title, $code ) {
$this->load( $code );
- if ( isset( $this->mCache[$code][$title] ) ) {
- $entry = $this->mCache[$code][$title];
+ if ( $this->cache->hasField( $code, $title ) ) {
+ $entry = $this->cache->getField( $code, $title );
if ( substr( $entry, 0, 1 ) === ' ' ) {
// The message exists and is not '!TOO BIG'
return (string)substr( $entry, 1 );
$message = false;
Hooks::run( 'MessagesPreLoad', [ $title, &$message, $code ] );
if ( $message !== false ) {
- $this->mCache[$code][$title] = ' ' . $message;
+ $this->cache->setField( $code, $title, ' ' . $message );
} else {
- $this->mCache[$code][$title] = '!NONEXISTENT';
+ $this->cache->setField( $code, $title, '!NONEXISTENT' );
}
return $message;
}
// Individual message cache key
- $titleKey = $this->bigMessageCacheKey( $this->mCache[$code]['HASH'], $title );
+ $bigKey = $this->bigMessageCacheKey( $this->cache->getField( $code, 'HASH' ), $title );
if ( $this->mCacheVolatile[$code] ) {
$entry = false;
// Make sure that individual keys respect the WAN cache holdoff period too
LoggerFactory::getInstance( 'MessageCache' )->debug(
__METHOD__ . ': loading volatile key \'{titleKey}\'',
- [ 'titleKey' => $titleKey, 'code' => $code ] );
+ [ 'titleKey' => $bigKey, 'code' => $code ] );
} else {
// Try the individual message cache
- $entry = $this->wanCache->get( $titleKey );
+ $entry = $this->wanCache->get( $bigKey );
}
if ( $entry !== false ) {
if ( substr( $entry, 0, 1 ) === ' ' ) {
- $this->mCache[$code][$title] = $entry;
+ $this->cache->setField( $code, $title, $entry );
// The message exists, so make sure a string is returned
return (string)substr( $entry, 1 );
} elseif ( $entry === '!NONEXISTENT' ) {
- $this->mCache[$code][$title] = '!NONEXISTENT';
+ $this->cache->setField( $code, $title, '!NONEXISTENT' );
return false;
} else {
// Corrupt/obsolete entry, delete it
- $this->wanCache->delete( $titleKey );
+ $this->wanCache->delete( $bigKey );
}
}
if ( $content ) {
$message = $this->getMessageTextFromContent( $content );
if ( is_string( $message ) ) {
- $this->mCache[$code][$title] = ' ' . $message;
- $this->wanCache->set( $titleKey, ' ' . $message, $this->mExpiry, $cacheOpts );
+ $this->cache->setField( $code, $title, ' ' . $message );
+ $this->wanCache->set( $bigKey, ' ' . $message, $this->mExpiry, $cacheOpts );
}
} else {
// A possibly temporary loading failure
LoggerFactory::getInstance( 'MessageCache' )->warning(
__METHOD__ . ': failed to load message page text for \'{titleKey}\'',
- [ 'titleKey' => $titleKey, 'code' => $code ] );
+ [ 'titleKey' => $bigKey, 'code' => $code ] );
$message = null; // no negative caching
}
} else {
if ( $message === false ) {
// Negative caching in case a "too big" message is no longer available (deleted)
- $this->mCache[$code][$title] = '!NONEXISTENT';
- $this->wanCache->set( $titleKey, '!NONEXISTENT', $this->mExpiry, $cacheOpts );
+ $this->cache->setField( $code, $title, '!NONEXISTENT' );
+ $this->wanCache->set( $bigKey, '!NONEXISTENT', $this->mExpiry, $cacheOpts );
}
return $message;
*
* Mainly used after a mass rebuild
*/
- function clear() {
+ public function clear() {
$langs = Language::fetchLanguageNames( null, 'mw' );
foreach ( array_keys( $langs ) as $code ) {
$this->wanCache->touchCheckKey( $this->getCheckKey( $code ) );
}
-
- $this->mLoadedLanguages = [];
+ $this->cache->clear();
}
/**
global $wgContLang;
$this->load( $code );
- if ( !isset( $this->mCache[$code] ) ) {
+ if ( !$this->cache->has( $code ) ) {
// Apparently load() failed
return null;
}
// Remove administrative keys
- $cache = $this->mCache[$code];
+ $cache = $this->cache->get( $code );
unset( $cache['VERSION'] );
unset( $cache['EXPIRY'] );
unset( $cache['EXCESSIVE'] );
# works correctly across DB engines, we need to change the pre-
# fix back and forth so tableName() works right.
- self::changePrefix( $this->oldTablePrefix );
+ $this->db->tablePrefix( $this->oldTablePrefix );
$oldTableName = $this->db->tableName( $tbl, 'raw' );
- self::changePrefix( $this->newTablePrefix );
+ $this->db->tablePrefix( $this->newTablePrefix );
$newTableName = $this->db->tableName( $tbl, 'raw' );
// Postgres: Temp tables are automatically deleted upon end of session
*/
public function destroy( $dropTables = false ) {
if ( $dropTables ) {
- self::changePrefix( $this->newTablePrefix );
+ $this->db->tablePrefix( $this->newTablePrefix );
foreach ( $this->tablesToClone as $tbl ) {
$this->db->dropTable( $tbl );
}
}
- self::changePrefix( $this->oldTablePrefix );
+ $this->db->tablePrefix( $this->oldTablePrefix );
}
/**
$dbw = $this->lbFactory->getMainLB()->getConnection( DB_MASTER );
$sleep = (int)$this->getOption( 'sleep', 10 );
$lastId = 0;
- $this->output( "Starting to add ct_tag_id = {$tagId} for ct_tag = {$tagName}" );
+ $this->output( "Starting to add ct_tag_id = {$tagId} for ct_tag = {$tagName}\n" );
while ( true ) {
// Given that indexes might not be there, it's better to use replica
$ids = $dbr->selectFieldValues(
);
continue;
} else {
- $this->output( "Updating ct_tag_id = {$tagId} up to row ct_id = {$lastId}" );
+ $this->output( "Updating ct_tag_id = {$tagId} up to row ct_id = {$lastId}\n" );
}
$dbw->update(
}
}
- $this->output( "Finished adding ct_tag_id = {$tagId} for ct_tag = {$tagName}" );
+ $this->output( "Finished adding ct_tag_id = {$tagId} for ct_tag = {$tagName}\n" );
}
}
* @since 1.18
*/
public function dbPrefix() {
- return $this->db->getType() == 'oracle' ? self::ORA_DB_PREFIX : self::DB_PREFIX;
+ return self::getTestPrefixFor( $this->db );
+ }
+
+ /**
+ * @param IDatabase $db
+ * @return string
+ * @since 1.32
+ */
+ public static function getTestPrefixFor( IDatabase $db ) {
+ return $db->getType() == 'oracle' ? self::ORA_DB_PREFIX : self::DB_PREFIX;
}
/**
}
/**
- * Setups a database with the given prefix.
+ * Prepares the given database connection for usage in the context of usage tests.
+ * This sets up clones database tables and changes the table prefix as appropriate.
+ * If the database connection already has cloned tables, calling this method has no
+ * effect. The tables are not re-cloned or reset in that case.
+ *
+ * @param IMaintainableDatabase $db
+ */
+ protected function prepareConnectionForTesting( IMaintainableDatabase $db ) {
+ if ( !self::$dbSetup ) {
+ throw new LogicException(
+ 'Cannot use prepareConnectionForTesting()'
+ . ' if the test case is not defined to use the database!'
+ );
+ }
+
+ if ( isset( $db->_originalTablePrefix ) ) {
+ // The DB connection was already prepared for testing.
+ return;
+ }
+
+ $testPrefix = self::getTestPrefixFor( $db );
+ $oldPrefix = $db->tablePrefix();
+
+ $tablesCloned = self::listTables( $db );
+
+ if ( $oldPrefix === $testPrefix ) {
+ // The database connection already has the test prefix, but presumably not
+ // the cloned tables. This is the typical case, since the LBFactory will
+ // have the prefix set during testing, but LoadBalancers will still return
+ // connections that don't have the cloned table structure.
+ $oldPrefix = self::$oldTablePrefix;
+ }
+
+ $dbClone = new CloneDatabase( $db, $tablesCloned, $testPrefix, $oldPrefix );
+ $dbClone->useTemporaryTables( self::$useTemporaryTables );
+
+ $db->_originalTablePrefix = $oldPrefix;
+
+ if ( ( $db->getType() == 'oracle' || !self::$useTemporaryTables ) && self::$reuseDB ) {
+ throw new LogicException( 'Cannot clone database tables' );
+ } else {
+ $dbClone->cloneTableStructure();
+ }
+ }
+
+ /**
+ * Setups a database with cloned tables using the given prefix.
*
* If reuseDB is true and certain conditions apply, it will just change the prefix.
* Otherwise, it will clone the tables and change the prefix.
*
- * Clones all tables in the given database (whatever database that connection has
- * open), to versions with the test prefix.
- *
* @param IMaintainableDatabase $db Database to use
- * @param string $prefix Prefix to use for test tables
+ * @param string $prefix Prefix to use for test tables. If not given, the prefix is determined
+ * automatically for $db.
* @return bool True if tables were cloned, false if only the prefix was changed
*/
- protected static function setupDatabaseWithTestPrefix( IMaintainableDatabase $db, $prefix ) {
- $tablesCloned = self::listTables( $db );
- $dbClone = new CloneDatabase( $db, $tablesCloned, $prefix );
- $dbClone->useTemporaryTables( self::$useTemporaryTables );
-
- $db->_originalTablePrefix = $db->tablePrefix();
+ protected static function setupDatabaseWithTestPrefix(
+ IMaintainableDatabase $db,
+ $prefix = null
+ ) {
+ if ( $prefix === null ) {
+ $prefix = self::getTestPrefixFor( $db );
+ }
if ( ( $db->getType() == 'oracle' || !self::$useTemporaryTables ) && self::$reuseDB ) {
- CloneDatabase::changePrefix( $prefix );
-
+ $db->tablePrefix( $prefix );
return false;
- } else {
+ }
+
+ if ( !isset( $db->_originalTablePrefix ) ) {
+ $oldPrefix = $db->tablePrefix();
+
+ if ( $oldPrefix === $prefix ) {
+ // table already has the correct prefix, but presumably no cloned tables
+ $oldPrefix = self::$oldTablePrefix;
+ }
+
+ $db->tablePrefix( $oldPrefix );
+ $tablesCloned = self::listTables( $db );
+ $dbClone = new CloneDatabase( $db, $tablesCloned, $prefix, $oldPrefix );
+ $dbClone->useTemporaryTables( self::$useTemporaryTables );
+
$dbClone->cloneTableStructure();
- return true;
+
+ $db->tablePrefix( $prefix );
+ $db->_originalTablePrefix = $oldPrefix;
}
+
+ return true;
}
/**
if ( self::isUsingExternalStoreDB() ) {
self::setupExternalStoreTestDBs( $testPrefix );
}
+
+ // NOTE: Change the prefix in the LBFactory and $wgDBprefix, to prevent
+ // *any* database connections to operate on live data.
+ CloneDatabase::changePrefix( $testPrefix );
}
/**
/**
* Clones the External Store database(s) for testing
*
- * @param string $testPrefix Prefix for test tables
+ * @param string|null $testPrefix Prefix for test tables. Will be determined automatically
+ * if not given.
*/
- protected static function setupExternalStoreTestDBs( $testPrefix ) {
+ protected static function setupExternalStoreTestDBs( $testPrefix = null ) {
$connections = self::getExternalStoreDatabaseConnections();
foreach ( $connections as $dbw ) {
- // Hack: cloneTableStructure sets $wgDBprefix to the unit test
- // prefix,. Even though listTables now uses tablePrefix, that
- // itself is populated from $wgDBprefix by default.
-
- // We have to set it back, or we won't find the original 'blobs'
- // table to copy.
-
- $dbw->tablePrefix( self::$oldTablePrefix );
self::setupDatabaseWithTestPrefix( $dbw, $testPrefix );
}
}
return $tables;
}
+ /**
+ * Copy test data from one database connection to another.
+ *
+ * This should only be used for small data sets.
+ *
+ * @param IDatabase $source
+ * @param IDatabase $target
+ */
+ public function copyTestData( IDatabase $source, IDatabase $target ) {
+ $tables = self::listOriginalTables( $source, 'unprefixed' );
+
+ foreach ( $tables as $table ) {
+ $res = $source->select( $table, '*', [], __METHOD__ );
+ $allRows = [];
+
+ foreach ( $res as $row ) {
+ $allRows[] = (array)$row;
+ }
+
+ $target->insert( $table, $allRows, __METHOD__, [ 'IGNORE' ] );
+ }
+ }
+
/**
* @throws MWException
* @since 1.18
use MediaWiki\Storage\RevisionFactory;
use MediaWiki\Storage\RevisionLookup;
use MediaWiki\Storage\RevisionStore;
-use MediaWiki\Storage\RevisionStoreFactory;
use MediaWiki\Storage\SqlBlobStore;
/**
'BlobStore' => [ 'BlobStore', BlobStore::class ],
'_SqlBlobStore' => [ '_SqlBlobStore', SqlBlobStore::class ],
'RevisionStore' => [ 'RevisionStore', RevisionStore::class ],
- 'RevisionStoreFactory' => [ 'RevisionStoreFactory', RevisionStoreFactory::class ],
'RevisionLookup' => [ 'RevisionLookup', RevisionLookup::class ],
'RevisionFactory' => [ 'RevisionFactory', RevisionFactory::class ],
'ContentModelStore' => [ 'ContentModelStore', NameTableStore::class ],
+++ /dev/null
-<?php
-
-namespace MediaWiki\Tests\Storage;
-
-use ActorMigration;
-use CommentStore;
-use MediaWiki\Logger\LoggerFactory;
-use MediaWiki\Storage\NameTableStore;
-use MediaWiki\Storage\RevisionStore;
-use MediaWiki\Storage\RevisionStoreFactory;
-use MediaWiki\Storage\SqlBlobStore;
-use MediaWikiTestCase;
-use WANObjectCache;
-use Wikimedia\Rdbms\LoadBalancer;
-use Wikimedia\TestingAccessWrapper;
-
-class RevisionStoreFactoryTest extends MediaWikiTestCase {
-
- public function testValidConstruction_doesntCauseErrors() {
- new RevisionStoreFactory(
- $this->getMockLoadBalancer(),
- $this->getMockSqlBlobStore(),
- $this->getHashWANObjectCache(),
- $this->getMockCommentStore(),
- $this->getMockNameTableStore(),
- $this->getMockNameTableStore(),
- MIGRATION_OLD,
- ActorMigration::newMigration(),
- LoggerFactory::getInstance( 'someInstance' ),
- true
- );
- $this->assertTrue( true );
- }
-
- public function provideWikiIds() {
- yield [ true ];
- yield [ false ];
- yield [ 'somewiki' ];
- yield [ 'somewiki', MIGRATION_OLD , false ];
- yield [ 'somewiki', MIGRATION_NEW , true ];
- }
-
- /**
- * @dataProvider provideWikiIds
- */
- public function testGetRevisionStore(
- $wikiId,
- $mcrMigrationStage = MIGRATION_OLD,
- $contentHandlerUseDb = true
- ) {
- $lb = $this->getMockLoadBalancer();
- $blobStore = $this->getMockSqlBlobStore();
- $cache = $this->getHashWANObjectCache();
- $commentStore = $this->getMockCommentStore();
- $contentModelStore = $this->getMockNameTableStore();
- $slotRoleStore = $this->getMockNameTableStore();
- $actorMigration = ActorMigration::newMigration();
- $logger = LoggerFactory::getInstance( 'someInstance' );
-
- $factory = new RevisionStoreFactory(
- $lb,
- $blobStore,
- $cache,
- $commentStore,
- $contentModelStore,
- $slotRoleStore,
- $mcrMigrationStage,
- $actorMigration,
- $logger,
- $contentHandlerUseDb
- );
-
- $store = $factory->getRevisionStore( $wikiId );
- $wrapper = TestingAccessWrapper::newFromObject( $store );
-
- // ensure the correct object type is returned
- $this->assertInstanceOf( RevisionStore::class, $store );
-
- // ensure the RevisionStore is for the given wikiId
- $this->assertSame( $wikiId, $wrapper->wikiId );
-
- // ensure all other required services are correctly set
- $this->assertSame( $lb, $wrapper->loadBalancer );
- $this->assertSame( $blobStore, $wrapper->blobStore );
- $this->assertSame( $cache, $wrapper->cache );
- $this->assertSame( $commentStore, $wrapper->commentStore );
- $this->assertSame( $contentModelStore, $wrapper->contentModelStore );
- $this->assertSame( $slotRoleStore, $wrapper->slotRoleStore );
- $this->assertSame( $mcrMigrationStage, $wrapper->mcrMigrationStage );
- $this->assertSame( $actorMigration, $wrapper->actorMigration );
- $this->assertSame( $logger, $wrapper->logger );
- $this->assertSame( $contentHandlerUseDb, $store->getContentHandlerUseDB() );
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject|NameTableStore
- */
- private function getMockNameTableStore() {
- return $this->getMockBuilder( NameTableStore::class )
- ->disableOriginalConstructor()->getMock();
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject|LoadBalancer
- */
- private function getMockLoadBalancer() {
- return $this->getMockBuilder( LoadBalancer::class )
- ->disableOriginalConstructor()->getMock();
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject|SqlBlobStore
- */
- private function getMockSqlBlobStore() {
- return $this->getMockBuilder( SqlBlobStore::class )
- ->disableOriginalConstructor()->getMock();
- }
-
- /**
- * @return \PHPUnit_Framework_MockObject_MockObject|CommentStore
- */
- private function getMockCommentStore() {
- return $this->getMockBuilder( CommentStore::class )
- ->disableOriginalConstructor()->getMock();
- }
-
- private function getHashWANObjectCache() {
- return new WANObjectCache( [ 'cache' => new \HashBagOStuff() ] );
- }
-
-}