jenkins-bot has submitted this change and it was merged. ( https://gerrit.wikimedia.org/r/394728 )
Change subject: Add maintenance script for populating DB with test data ...................................................................... Add maintenance script for populating DB with test data Change-Id: Ia9e81b2021fd03e1dc78b8d1083773eb4c34bf51 --- A maintenance/populateWithTestData.php 1 file changed, 195 insertions(+), 0 deletions(-) Approvals: jenkins-bot: Verified Mholloway: Looks good to me, approved diff --git a/maintenance/populateWithTestData.php b/maintenance/populateWithTestData.php new file mode 100644 index 0000000..8af4f32 --- /dev/null +++ b/maintenance/populateWithTestData.php @@ -0,0 +1,195 @@ +<?php + +namespace MediaWiki\Extensions\ReadingLists\Maintenance; + +use Maintenance; +use MediaWiki\Extensions\ReadingLists\ReadingListRepository; +use MediaWiki\Extensions\ReadingLists\ReadingListRepositoryException; +use MediaWiki\Extensions\ReadingLists\Utils; +use MediaWiki\MediaWikiServices; +use Wikimedia\Rdbms\DBConnRef; +use Wikimedia\Rdbms\LBFactory; + +require_once getenv( 'MW_INSTALL_PATH' ) !== false + ? getenv( 'MW_INSTALL_PATH' ) . '/maintenance/Maintenance.php' + : __DIR__ . '/../../../maintenance/Maintenance.php'; + +/** + * Fill the database with test data, or remove it. + */ +class PopulateWithTestData extends Maintenance { + + /** @var LBFactory */ + private $loadBalancerFactory; + + /** @var DBConnRef */ + private $dbw; + + /** @var DBConnRef */ + private $dbr; + + public function __construct() { + parent::__construct(); + $this->addDescription( 'Fill the database with test data, or remove it.' ); + $this->addOption( 'users', 'Number of users', false, true ); + $this->addOption( 'lists', 'Lists per user (number or stats distribution)', false, true ); + $this->addOption( 'entries', 'Entries per list (number or stats distribution)', false, true ); + $this->addOption( 'cleanup', 'Delete lists which look like test data' ); + if ( !extension_loaded( 'stats' ) ) { + $this->error( 'Requires the stats PHP extension', 1 ); + } + } + + private function setupServices() { + // Can't do this in the constructor, initialization not done yet. + $services = MediaWikiServices::getInstance(); + $this->loadBalancerFactory = $services->getDBLoadBalancerFactory(); + $this->dbw = Utils::getDB( DB_MASTER, $services ); + $this->dbr = Utils::getDB( DB_REPLICA, $services ); + } + + /** + * @inheritDoc + */ + public function execute() { + $this->setupServices(); + $this->assertOptions(); + if ( $this->getOption( 'cleanup' ) ) { + $this->cleanupTestData(); + return; + } + + $projects = $this->dbw->selectFieldValues( 'reading_list_project', 'rlp_id' ); + if ( !$projects ) { + $this->error( 'No projects! Please set up some', 1 ); + } + $totalLists = $totalEntries = 0; + stats_rand_setall( mt_rand(), mt_rand() ); + $users = $this->getOption( 'users' ); + for ( $i = 0; $i < $users; $i++ ) { + // The test data is for performance testing so we don't care whether the user exists. + $centralId = 1000 + $i; + $repository = new ReadingListRepository( $centralId, $this->dbw, $this->dbr, + $this->loadBalancerFactory ); + try { + $repository->setupForUser(); + $i++; + // HACK mark default list so it will be deleted together with the rest + $this->dbw->update( + 'reading_list', + [ 'rl_description' => __FILE__ ], + [ + 'rl_user_id' => $centralId, + 'rl_is_default' => 1, + ] + ); + } catch ( ReadingListRepositoryException $e ) { + // Instead of trying to find a user ID that's not used yet, we'll be lazy + // and just ignore "already set up" errors. + } + $lists = $this->getRandomValueFromDistribution( $this->getOption( 'lists' ) ); + for ( $j = 0; $j < $lists; $j++, $totalLists++ ) { + $listId = $repository->addList( "test_$j", __FILE__ ); + $entries = $this->getRandomValueFromDistribution( $this->getOption( 'entries' ) ); + $rows = []; + for ( $k = 0; $k < $entries; $k++, $totalEntries++ ) { + $project = $projects[array_rand( $projects )]; + // Calling addListEntry for each row separately would be a bit slow. + $rows[] = [ + 'rle_rl_id' => $listId, + 'rle_user_id' => $centralId, + 'rle_rlp_id' => $project, + 'rle_title' => "Test_$k", + ]; + } + $this->dbw->insert( + 'reading_list_entry', + $rows + ); + } + $this->output( '.' ); + } + $this->output( "\nAdded $totalLists lists and $totalEntries entries for $users users\n" ); + } + + private function cleanupTestData() { + $services = MediaWikiServices::getInstance(); + $dbw = Utils::getDB( DB_MASTER, $services ); + $ids = $dbw->selectFieldValues( + 'reading_list', + 'rl_id', + [ 'rl_description' => __FILE__ ] + ); + if ( !$ids ) { + $this->output( "Noting to clean up\n" ); + return; + } + $dbw->delete( + 'reading_list_entry', + [ 'rle_rl_id' => $ids ] + ); + $entries = $dbw->affectedRows(); + $dbw->delete( + 'reading_list', + [ 'rl_description' => __FILE__ ] + ); + $lists = $dbw->affectedRows(); + $this->output( "Deleted $lists lists and $entries entries\n" ); + } + + /** + * Get a random value according to some distribution. The parameter is either a constant + * (in which case it will be returned) or a distribution descriptor in the form of + * '<dist>,<param1>,<param2>,...' (no spaces) where <dist> refers to one of the stats_rand_gen_* + * methods (e.g. 'exponential,1' for an exponential distribution with λ=1, or 'normal,0,1' for + * a normal distribution with µ=0, ρ=1). + * The result is normalized to be a nonnegative integer. + * @param string $distribution + * @return int + */ + private function getRandomValueFromDistribution( $distribution ) { + $params = explode( ',', $distribution ); + $type = trim( array_shift( $params ) ); + if ( is_numeric( $type ) ) { + return (int)$type; + } + $function = "stats_rand_gen_$type"; + if ( + !preg_match( '/[a-z_]+/', $type ) + || !function_exists( $function ) + ) { + $this->error( "invalid distribution: $distribution (could not parse '$type')" ); + } + $params = array_map( function ( $param ) use ( $distribution ) { + if ( !is_numeric( $param ) ) { + $this->error( "invalid distribution: $distribution (could not parse '$param')" ); + } + return (float)$param; + }, $params ); + return max( (int)call_user_func_array( $function, $params ), 0 ); + } + + private function assertOptions() { + if ( $this->hasOption( 'cleanup' ) ) { + if ( + $this->hasOption( 'users' ) + || $this->hasOption( 'lists' ) + || $this->hasOption( 'entries' ) + ) { + $this->error( "'cleanup' cannot be used together with other options", 1 ); + } + } else { + if ( + !$this->hasOption( 'users' ) + || !$this->hasOption( 'lists' ) + || !$this->hasOption( 'entries' ) + ) { + $this->error( "'users', 'lists' and 'entries' are required in non-cleanup mode", 1 ); + } + } + } + +} + +$maintClass = PopulateWithTestData::class; +require_once RUN_MAINTENANCE_IF_MAIN; -- To view, visit https://gerrit.wikimedia.org/r/394728 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ia9e81b2021fd03e1dc78b8d1083773eb4c34bf51 Gerrit-PatchSet: 3 Gerrit-Project: mediawiki/extensions/ReadingLists Gerrit-Branch: master Gerrit-Owner: Gergő Tisza <gti...@wikimedia.org> Gerrit-Reviewer: Mholloway <mhollo...@wikimedia.org> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits