jenkins-bot has submitted this change and it was merged.
Change subject: Replace EchoBatchRowUpdate with BatchRowUpdate
......................................................................
Replace EchoBatchRowUpdate with BatchRowUpdate
Also removes tests for the class.
Bug: T119253
Change-Id: I4c0d7187c2b847297dd0867faecba26185cfba37
Depends-On: Iccafbbdb06711463fee0f30a11326c7771df30e2
---
M autoload.php
D includes/BatchRowUpdate.php
M includes/UserLocator.php
M includes/iterator/FilteredSequentialIterator.php
M includes/schemaUpdate.php
M maintenance/updateEchoSchemaForSuppression.php
D tests/phpunit/BatchRowUpdateTest.php
7 files changed, 7 insertions(+), 715 deletions(-)
Approvals:
Catrope: Looks good to me, approved
jenkins-bot: Verified
diff --git a/autoload.php b/autoload.php
index ae40880..1a0fa7d 100644
--- a/autoload.php
+++ b/autoload.php
@@ -9,7 +9,6 @@
'ApiEchoMarkSeen' => __DIR__ . '/includes/api/ApiEchoMarkSeen.php',
'ApiEchoNotifications' => __DIR__ .
'/includes/api/ApiEchoNotifications.php',
'ApiEchoNotificationsTest' => __DIR__ .
'/tests/phpunit/api/ApiEchoNotificationsTest.php',
- 'BatchRowUpdateTest' => __DIR__ .
'/tests/phpunit/BatchRowUpdateTest.php',
'CallbackFilterIterator' => __DIR__ .
'/includes/iterator/CallbackFilterIterator.php',
'ContainmentSetTest' => __DIR__ .
'/tests/phpunit/ContainmentSetTest.php',
'EchoAbstractEntity' => __DIR__ . '/includes/model/AbstractEntity.php',
@@ -20,9 +19,6 @@
'EchoAttributeManager' => __DIR__ . '/includes/AttributeManager.php',
'EchoAttributeManagerTest' => __DIR__ .
'/tests/phpunit/AttributeManagerTest.php',
'EchoBasicFormatter' => __DIR__ .
'/includes/formatters/BasicFormatter.php',
- 'EchoBatchRowIterator' => __DIR__ . '/includes/BatchRowUpdate.php',
- 'EchoBatchRowUpdate' => __DIR__ . '/includes/BatchRowUpdate.php',
- 'EchoBatchRowWriter' => __DIR__ . '/includes/BatchRowUpdate.php',
'EchoCachedList' => __DIR__ . '/includes/ContainmentSet.php',
'EchoCallbackIterator' => __DIR__ .
'/includes/iterator/CallbackIterator.php',
'EchoCatchableFatalErrorException' => __DIR__ .
'/includes/exception/CatchableFatalErrorException.php',
@@ -80,7 +76,6 @@
'EchoPageLinkedPresentationModel' => __DIR__ .
'/includes/formatters/PageLinkedPresentationModel.php',
'EchoRevertedPresentationModel' => __DIR__ .
'/includes/formatters/RevertedPresentationModel.php',
'EchoRevisionLocalCache' => __DIR__ .
'/includes/cache/RevisionLocalCache.php',
- 'EchoRowUpdateGenerator' => __DIR__ . '/includes/BatchRowUpdate.php',
'EchoSeenTime' => __DIR__ . '/includes/SeenTime.php',
'EchoSuppressionRowUpdateGenerator' => __DIR__ .
'/includes/schemaUpdate.php',
'EchoTalkPageFunctionalTest' => __DIR__ .
'/tests/phpunit/TalkPageFunctionalTest.php',
diff --git a/includes/BatchRowUpdate.php b/includes/BatchRowUpdate.php
deleted file mode 100644
index 1a92b93..0000000
--- a/includes/BatchRowUpdate.php
+++ /dev/null
@@ -1,455 +0,0 @@
-<?php
-/**
- * Provides components to update a tables rows via a batching process
- *
- * 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
- *
- * @file
- * @ingroup Maintenance
- */
-
-/**
- * Ties together the batch update components to provide a composable method
- * of batch updating rows in a database. To use create a class implementing
- * the EchoRowUpdateGenerator interface and configure the EchoBatchRowIterator
and
- * EchoBatchRowWriter for access to the correct table. The components will
- * handle reading, writing, and waiting for slaves while the generator
implementation
- * handles generating update arrays for singular rows.
- *
- * Instantiate:
- * $updater = new EchoBatchRowUpdate(
- * new EchoBatchRowIterator( $dbr, 'some_table', 'primary_key_column',
500 ),
- * new EchoBatchRowWriter( $dbw, 'some_table', 'clusterName' ),
- * new MyImplementationOfEchoRowUpdateGenerator
- * );
- *
- * Run:
- * $updater->execute();
- *
- * An example maintenance script utilizing the EchoBatchRowUpdate can be
located in the Echo
- * extension file maintenance/updateSchema.php
- *
- * @ingroup Maintenance
- */
-class EchoBatchRowUpdate {
- /**
- * @var EchoBatchRowIterator $reader Iterator that returns an array of
database rows
- */
- protected $reader;
-
- /**
- * @var EchoBatchRowWriter $writer Writer capable of pushing row
updates to the database
- */
- protected $writer;
-
- /**
- * @var EchoRowUpdateGenerator $generator Generates single row updates
based on the rows content
- */
- protected $generator;
-
- /**
- * @var callable $output Output callback
- */
- protected $output;
-
- /**
- * @param EchoBatchRowIterator $reader Iterator that returns an array
of database rows
- * @param EchoBatchRowWriter $writer Writer capable of pushing row
updates to the database
- * @param EchoRowUpdateGenerator $generator Generates single row
updates based on the rows content
- */
- public function __construct( EchoBatchRowIterator $reader,
EchoBatchRowWriter $writer, EchoRowUpdateGenerator $generator ) {
- $this->reader = $reader;
- $this->writer = $writer;
- $this->generator = $generator;
- $this->output = function () {
- }; // nop
- }
-
- /**
- * Runs the batch update process
- */
- public function execute() {
- foreach ( $this->reader as $rows ) {
- $updates = array();
- foreach ( $rows as $row ) {
- $update = $this->generator->update( $row );
- if ( $update ) {
- $updates[] = array(
- 'primaryKey' =>
$this->reader->extractPrimaryKeys( $row ),
- 'changes' => $update,
- );
- }
- }
-
- if ( $updates ) {
- $this->output( "Processing " . count( $updates
) . " rows\n" );
- $this->writer->write( $updates );
- }
- }
-
- $this->output( "Completed\n" );
- }
-
- /**
- * Accepts a callable which will receive a single parameter containing
- * string status updates
- *
- * @param callable $output A callback taking a single string parameter
to output
- *
- * @throws MWException
- */
- public function setOutput( $output ) {
- if ( !is_callable( $output ) ) {
- throw new MWException( 'Provided $output param is
required to be callable.' );
- }
- $this->output = $output;
- }
-
- /**
- * Write out a status update
- *
- * @param string $text The value to print
- */
- protected function output( $text ) {
- call_user_func( $this->output, $text );
- }
-}
-
-/**
- * Interface for generating updates to single rows in the database.
- *
- * @ingroup Maintenance
- */
-interface EchoRowUpdateGenerator {
-
- /**
- * Given a database row, generates an array mapping column names to
updated value within the database row
- *
- * Sample Response:
- * return array(
- * 'some_col' => 'new value',
- * 'other_col' => 99,
- * );
- *
- * @param stdClass $row A row from the database
- * @return array Map of column names to updated value within the
database row. When no update is required
- * returns an empty array.
- */
- public function update( $row );
-}
-
-/**
- * Updates database rows by primary key in batches. There are two options for
writing to tables
- * with a composite primary key.
- *
- * @ingroup Maintenance
- */
-class EchoBatchRowWriter {
- /**
- * @var DatabaseBase $db The database to write to
- */
- protected $db;
-
- /**
- * @var string $table The name of the table to update
- */
- protected $table;
-
- /**
- * @var string $clusterName A cluster name valid for use with LBFactory
- */
- protected $clusterName;
-
- /**
- * @param DatabaseBase $db The database to write to
- * @param string $table The name of the table to update
- * @param string|bool $clusterName A cluster name valid for use with
LBFactory
- */
- public function __construct( DatabaseBase $db, $table, $clusterName =
false ) {
- $this->db = $db;
- $this->table = $table;
- $this->clusterName = $clusterName;
- }
-
- /**
- * @param array $updates Array of arrays each containing two keys,
'primaryKey' and 'changes'.
- * primaryKey must contain a map of column names to values sufficient
to uniquely identify the row
- * changes must contain a map of column names to update values to
apply to the row
- */
- public function write( array $updates ) {
- $this->db->begin();
-
- foreach ( $updates as $update ) {
- // echo "Updating: ";var_dump( $update['primaryKey'] );
- // echo "With values: ";var_dump( $update['changes'] );
- $this->db->update(
- $this->table,
- $update['changes'],
- $update['primaryKey'],
- __METHOD__
- );
- }
-
- $this->db->commit();
- wfWaitForSlaves( false, false, $this->clusterName );
- }
-}
-
-/**
- * Fetches rows batched into groups from the database in ascending order of
the primary key(s).
- *
- * @ingroup Maintenance
- */
-class EchoBatchRowIterator implements RecursiveIterator {
-
- /**
- * @var DatabaseBase $db The database to read from
- */
- protected $db;
-
- /**
- * @var string $table The name of the table to read from
- */
- protected $table;
-
- /**
- * @var array $primaryKey The name of the primary key(s)
- */
- protected $primaryKey;
-
- /**
- * @var integer $batchSize The number of rows to fetch per iteration
- */
- protected $batchSize;
-
- /**
- * @var array $conditions Array of strings containing SQL conditions to
add to the query
- */
- protected $conditions = array();
-
- /**
- * @var array $joinConditions
- */
- protected $joinConditions = array();
-
- /**
- * @var array $fetchColumns List of column names to select from the
table suitable for use with DatabaseBase::select()
- */
- protected $fetchColumns;
-
- /**
- * @var string $orderBy SQL Order by condition generated from
$this->primaryKey
- */
- protected $orderBy;
-
- /**
- * @var array $current The current iterator value
- */
- private $current = array();
-
- /**
- * @var integer key 0-indexed number of pages fetched since
self::reset()
- */
- private $key;
-
- /**
- * @param DatabaseBase $db The database to read from
- * @param string $table The name of the table to read from
- * @param string|array $primaryKey The name or names of the primary key
columns
- * @param integer $batchSize The number of rows to fetch per iteration
- *
- * @throws MWException
- */
- public function __construct( DatabaseBase $db, $table, $primaryKey,
$batchSize ) {
- if ( $batchSize < 1 ) {
- throw new MWException( 'Batch size must be at least 1
row.' );
- }
- $this->db = $db;
- $this->table = $table;
- $this->primaryKey = (array)$primaryKey;
- $this->fetchColumns = $this->primaryKey;
- $this->orderBy = implode( ' ASC,', $this->primaryKey ) . ' ASC';
- $this->batchSize = $batchSize;
- }
-
- /**
- * @param string $condition Query conditions suitable for use with
DatabaseBase::select
- */
- public function addConditions( array $conditions ) {
- $this->conditions = array_merge( $this->conditions, $conditions
);
- }
-
- public function addJoinConditions( array $conditions ) {
- $this->joinConditions = array_merge( $this->joinConditions,
$conditions );
- }
-
- /**
- * @param array $columns List of column names to select from the table
suitable for use with DatabaseBase::select()
- */
- public function setFetchColumns( array $columns ) {
- // If it's not the all column selector merge in the primary
keys we need
- if ( count( $columns ) === 1 && reset( $columns ) === '*' ) {
- $this->fetchColumns = $columns;
- } else {
- $this->fetchColumns = array_unique( array_merge(
$this->primaryKey, $columns ) );
- }
- }
-
- /**
- * Extracts the primary key(s) from a database row.
- *
- * @param stdClass $row An individual database row from this iterator
- * @return array Map of primary key column to value within the row
- */
- public function extractPrimaryKeys( $row ) {
- $pk = array();
- foreach ( $this->primaryKey as $column ) {
- $pk[$column] = $row->$column;
- }
-
- return $pk;
- }
-
- /**
- * @return array The most recently fetched set of rows from the database
- */
- public function current() {
- return $this->current;
- }
-
- /**
- * @return integer 0-indexed count of the page number fetched
- */
- public function key() {
- return $this->key;
- }
-
- /**
- * Reset the iterator to the begining of the table.
- */
- public function rewind() {
- $this->key = -1; // self::next() will turn this into 0
- $this->current = array();
- $this->next();
- }
-
- /**
- * @return boolean True when the iterator is in a valid state
- */
- public function valid() {
- return (bool)$this->current;
- }
-
- /**
- * @return boolean True when this result set has rows
- */
- public function hasChildren() {
- return $this->current && count( $this->current );
- }
-
- /**
- * @return RecursiveIterator
- */
- public function getChildren() {
- return new EchoNotRecursiveIterator( new ArrayIterator(
$this->current ) );
- }
-
- /**
- * Fetch the next set of rows from the database.
- */
- public function next() {
- $res = $this->db->select(
- $this->table,
- $this->fetchColumns,
- $this->buildConditions(),
- __METHOD__,
- array(
- 'LIMIT' => $this->batchSize,
- 'ORDER BY' => $this->orderBy,
- ),
- $this->joinConditions
- );
-
- // The iterator is converted to an array because in addition to
returning it
- // in self::current() we need to use the end value in
self::buildConditions()
- $this->current = iterator_to_array( $res );
- $this->key++;
- }
-
- /**
- * Uses the primary key list and the maximal result row from the
previous iteration to build
- * an SQL condition sufficient for selecting the next page of results.
All except the final
- * key use `=` conditions while the final key uses a `>` condition
- *
- * Example output:
- * array( '( foo = 42 AND bar > 7 ) OR ( foo > 42 )' )
- *
- * @return array The SQL conditions necessary to select the next set of
rows in the batched query
- */
- protected function buildConditions() {
- if ( !$this->current ) {
- return $this->conditions;
- }
-
- $maxRow = end( $this->current );
- $maximumValues = array();
- foreach ( $this->primaryKey as $column ) {
- $maximumValues[$column] = $this->db->addQuotes(
$maxRow->$column );
- }
-
- $pkConditions = array();
- // For example: If we have 3 primary keys
- // first run through will generate
- // col1 = 4 AND col2 = 7 AND col3 > 1
- // second run through will generate
- // col1 = 4 AND col2 > 7
- // and the final run through will generate
- // col1 > 4
- while ( $maximumValues ) {
- $pkConditions[] = $this->buildGreaterThanCondition(
$maximumValues );
- array_pop( $maximumValues );
- }
-
- $conditions = $this->conditions;
- $conditions[] = sprintf( '( %s )', implode( ' ) OR ( ',
$pkConditions ) );
-
- return $conditions;
- }
-
- /**
- * Given an array of column names and their maximum value generate an
SQL
- * condition where all keys except the last match $quotedMaximumValues
- * exactly and the last column is greater than the matching value in
$quotedMaximumValues
- *
- * @param array $quotedMaximumValues The maximum values quoted with
$this->db->addQuotes()
- * @return string An SQL condition that will select rows where all
columns match the
- * maximum value exactly except the last column which must be greater
than the provided
- * maximum value
- */
- protected function buildGreaterThanCondition( array
$quotedMaximumValues ) {
- $keys = array_keys( $quotedMaximumValues );
- $lastColumn = end( $keys );
- $lastValue = array_pop( $quotedMaximumValues );
- $conditions = array();
- foreach ( $quotedMaximumValues as $column => $value ) {
- $conditions[] = "$column = $value";
- }
- $conditions[] = "$lastColumn > $lastValue";
-
- return implode( ' AND ', $conditions );
- }
-}
-
diff --git a/includes/UserLocator.php b/includes/UserLocator.php
index f0b3e37..81e086e 100644
--- a/includes/UserLocator.php
+++ b/includes/UserLocator.php
@@ -16,7 +16,7 @@
return array();
}
- $it = new EchoBatchRowIterator(
+ $it = new BatchRowIterator(
wfGetDB( DB_SLAVE, 'watchlist' ),
/* $table = */ 'watchlist',
/* $primaryKeys = */ array( 'wl_user' ),
diff --git a/includes/iterator/FilteredSequentialIterator.php
b/includes/iterator/FilteredSequentialIterator.php
index 24f46b1..4fae0bf 100644
--- a/includes/iterator/FilteredSequentialIterator.php
+++ b/includes/iterator/FilteredSequentialIterator.php
@@ -13,7 +13,7 @@
* $users = new EchoFilteredSequentialIterator;
* $users->add( array( $userA, $userB, $userC ) );
*
- * $it = new EchoBatchRowIterator( ... );
+ * $it = new BatchRowIterator( ... );
* ...
* $it = new RecursiveIteratorIterator( $it );
* $users->add( new EchoCallbackIterator( $it, function( $row ) {
@@ -25,7 +25,7 @@
* ...
* }
*
- * By default the EchoBatchRowIterator returns an array of rows, this class
+ * By default the BatchRowIterator returns an array of rows, this class
* expects a stream of user objects. To bridge that gap the
* RecursiveIteratorIterator is used to flatten and the EchoCallbackIterator
* is used to transform each database $row into a User object.
diff --git a/includes/schemaUpdate.php b/includes/schemaUpdate.php
index ee02ce1..5c20e43 100644
--- a/includes/schemaUpdate.php
+++ b/includes/schemaUpdate.php
@@ -5,7 +5,7 @@
* Updates event_page_id based on event_page_title and event_page_namespace
* Updates extra data for page-linked events to contain page id's
*/
-class EchoSuppressionRowUpdateGenerator implements EchoRowUpdateGenerator {
+class EchoSuppressionRowUpdateGenerator implements RowUpdateGenerator {
/**
* @var callable Hack to allow replacing Title::newFromText in tests
*/
diff --git a/maintenance/updateEchoSchemaForSuppression.php
b/maintenance/updateEchoSchemaForSuppression.php
index 7feb863..0dd9123 100644
--- a/maintenance/updateEchoSchemaForSuppression.php
+++ b/maintenance/updateEchoSchemaForSuppression.php
@@ -34,15 +34,15 @@
public function execute() {
global $wgEchoCluster;
- $reader = new EchoBatchRowIterator( MWEchoDbFactory::getDB(
DB_SLAVE ), $this->table, $this->idField, $this->mBatchSize );
+ $reader = new BatchRowIterator( MWEchoDbFactory::getDB(
DB_SLAVE ), $this->table, $this->idField, $this->mBatchSize );
$reader->addConditions( array(
"event_page_title IS NOT NULL",
"event_page_id" => null,
) );
- $updater = new EchoBatchRowUpdate(
+ $updater = new BatchRowUpdate(
$reader,
- new EchoBatchRowWriter( MWEchoDbFactory::getDB(
DB_MASTER ), $this->table, $wgEchoCluster ),
+ new BatchRowWriter( MWEchoDbFactory::getDB( DB_MASTER
), $this->table, $wgEchoCluster ),
new EchoSuppressionRowUpdateGenerator
);
$updater->setOutput( array( $this, '__internalOutput' ) );
diff --git a/tests/phpunit/BatchRowUpdateTest.php
b/tests/phpunit/BatchRowUpdateTest.php
deleted file mode 100644
index ecb2360..0000000
--- a/tests/phpunit/BatchRowUpdateTest.php
+++ /dev/null
@@ -1,248 +0,0 @@
-<?php
-
-require_once __DIR__ . "/../../includes/BatchRowUpdate.php";
-
-/**
- * Tests for BatchRowUpdate and its components
- * @group Echo
- */
-class BatchRowUpdateTest extends MediaWikiTestCase {
-
- public function testWriterBasicFunctionality() {
- $db = $this->mockDb();
- $writer = new EchoBatchRowWriter( $db, 'echo_event' );
-
- $updates = array(
- self::mockUpdate( array( 'something' => 'changed' ) ),
- self::mockUpdate( array( 'otherthing' => 'changed' ) ),
- self::mockUpdate( array( 'and' => 'something', 'else'
=> 'changed' ) ),
- );
-
- $db->expects( $this->exactly( count( $updates ) ) )
- ->method( 'update' );
-
- $writer->write( $updates );
- }
-
- protected static function mockUpdate( array $changes ) {
- static $i = 0;
-
- return array(
- 'primaryKey' => array( 'event_id' => $i++ ),
- 'changes' => $changes,
- );
- }
-
- public function testReaderBasicIterate() {
- $db = $this->mockDb();
- $batchSize = 2;
- $reader = new EchoBatchRowIterator( $db, 'some_table',
'id_field', $batchSize );
-
- $response = $this->genSelectResult( $batchSize, /*numRows*/ 5,
function() {
- static $i = 0;
-
- return array( 'id_field' => ++$i );
- } );
- $db->expects( $this->exactly( count( $response ) ) )
- ->method( 'select' )
- ->will( $this->consecutivelyReturnFromSelect( $response
) );
-
- $pos = 0;
- foreach ( $reader as $rows ) {
- $this->assertEquals( $response[$pos], $rows, "Testing
row in position $pos" );
- $pos++;
- }
- // -1 is because the final array() marks the end and isnt
included
- $this->assertEquals( count( $response ) - 1, $pos );
- }
-
- public static function provider_readerGetPrimaryKey() {
- $row = array(
- 'id_field' => 42,
- 'some_col' => 'dvorak',
- 'other_col' => 'samurai',
- );
-
- return array(
-
- array(
- 'Must return single column pk when requested',
- array( 'id_field' => 42 ),
- $row
- ),
-
- array(
- 'Must return multiple column pks when
requested',
- array( 'id_field' => 42, 'other_col' =>
'samurai' ),
- $row
- ),
-
- );
- }
-
- /**
- * @dataProvider provider_readerGetPrimaryKey
- */
- public function testReaderGetPrimaryKey( $message, array $expected,
array $row ) {
- $reader = new EchoBatchRowIterator( $this->mockDb(),
'some_table', array_keys( $expected ), 8675309 );
- $this->assertEquals( $expected, $reader->extractPrimaryKeys(
(object)$row ), $message );
- }
-
- public static function provider_readerSetFetchColumns() {
- return array(
-
- array(
- 'Must merge primary keys into select
conditions',
- // Expected column select
- array( 'foo', 'bar' ),
- // primary keys
- array( 'foo' ),
- // setFetchColumn
- array( 'bar' )
- ),
-
- array(
- 'Must not merge primary keys into the all
columns selector',
- // Expected column select
- array( '*' ),
- // primary keys
- array( 'foo' ),
- // setFetchColumn
- array( '*' ),
- ),
-
- array(
- 'Must not duplicate primary keys into column
selector',
- // Expected column select.
- // TODO: figure out how to only assert the
array_values portion and not the keys
- array( 0 => 'foo', 1 => 'bar', 3 => 'baz' ),
- // primary keys
- array( 'foo', 'bar', ),
- // setFetchColumn
- array( 'bar', 'baz' ),
- ),
- );
- }
-
- /**
- * @dataProvider provider_readerSetFetchColumns
- */
- public function testReaderSetFetchColumns( $message, array $columns,
array $primaryKeys, array $fetchColumns ) {
- $db = $this->mockDb();
- $db->expects( $this->once() )
- ->method( 'select' )
- ->with( 'some_table', $columns )// only testing second
parameter of DatabaseBase::select
- ->will( $this->returnValue( new ArrayIterator( array()
) ) );
-
- $reader = new EchoBatchRowIterator( $db, 'some_table',
$primaryKeys, 22 );
- $reader->setFetchColumns( $fetchColumns );
- // triggers first database select
- $reader->rewind();
- }
-
- public static function provider_readerSelectConditions() {
- return array(
-
- array(
- "With single primary key must generate id >
'value'",
- // Expected second iteration
- array( "( id_field > '3' )" ),
- // Primary key(s)
- 'id_field',
- ),
-
- array(
- 'With multiple primary keys the first
conditions must use >= and the final condition must use >',
- // Expected second iteration
- array( "( id_field = '3' AND foo > '103' ) OR (
id_field > '3' )" ),
- // Primary key(s)
- array( 'id_field', 'foo' ),
- ),
-
- );
- }
-
- /**
- * Slightly hackish to use reflection, but asserting different
parameters
- * to consecutive calls of DatabaseBase::select in phpunit is error
prone
- *
- * @dataProvider provider_readerSelectConditions
- */
- public function testReaderSelectConditionsMultiplePrimaryKeys(
$message, $expectedSecondIteration, $primaryKeys, $batchSize = 3 ) {
- $results = $this->genSelectResult( $batchSize, $batchSize * 3,
function () {
- static $i = 0, $j = 100, $k = 1000;
-
- return array( 'id_field' => ++$i, 'foo' => ++$j, 'bar'
=> ++$k );
- } );
- $db = $this->mockDbConsecutiveSelect( $results );
-
- $conditions = array( 'bar' => 42, 'baz' => 'hai' );
- $reader = new EchoBatchRowIterator( $db, 'some_table',
$primaryKeys, $batchSize );
- $reader->addConditions( $conditions );
-
- $buildConditions = new ReflectionMethod( $reader,
'buildConditions' );
- $buildConditions->setAccessible( true );
-
- // On first iteration only the passed conditions must be used
- $this->assertEquals( $conditions, $buildConditions->invoke(
$reader ),
- 'First iteration must return only the conditions passed
in addConditions' );
- $reader->rewind();
-
- // Second iteration must use the maximum primary key of last set
- $this->assertEquals(
- $conditions + $expectedSecondIteration,
- $buildConditions->invoke( $reader ),
- $message
- );
- }
-
- protected function mockDbConsecutiveSelect( array $retvals ) {
- $db = $this->mockDb();
- $db->expects( $this->any() )
- ->method( 'select' )
- ->will( $this->consecutivelyReturnFromSelect( $retvals
) );
- $db->expects( $this->any() )
- ->method( 'addQuotes' )
- ->will( $this->returnCallback( function ( $value ) {
- return "'$value'"; // not real quoting: doesn't
matter in test
- } ) );
-
- return $db;
- }
-
- protected function consecutivelyReturnFromSelect( array $results ) {
- $retvals = array();
- foreach ( $results as $rows ) {
- // The DatabaseBase::select method returns iterators,
so we do too.
- $retvals[] = $this->returnValue( new ArrayIterator(
$rows ) );
- }
-
- return call_user_func_array( array( $this, 'onConsecutiveCalls'
), $retvals );
- }
-
- protected function genSelectResult( $batchSize, $numRows, $rowGenerator
) {
- $res = array();
- for ( $i = 0; $i < $numRows; $i += $batchSize ) {
- $rows = array();
- for ( $j = 0; $j < $batchSize && $i + $j < $numRows;
$j++ ) {
- $rows [] = (object)call_user_func(
$rowGenerator );
- }
- $res[] = $rows;
- }
- $res[] = array(); // termination condition requires empty
result for last row
- return $res;
- }
-
- protected function mockDb() {
- // Cant mock from DatabaseType or DatabaseBase, they dont
- // have the full gamut of methods
- $databaseMysql = $this->getMockBuilder( 'DatabaseMysql' )
- ->disableOriginalConstructor()
- ->getMock();
- $databaseMysql->expects( $this->any() )
- ->method( 'isOpen' )
- ->will( $this->returnValue( true ) );
-
- return $databaseMysql;
- }
-}
--
To view, visit https://gerrit.wikimedia.org/r/259397
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I4c0d7187c2b847297dd0867faecba26185cfba37
Gerrit-PatchSet: 6
Gerrit-Project: mediawiki/extensions/Echo
Gerrit-Branch: master
Gerrit-Owner: Sn1per <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Legoktm <[email protected]>
Gerrit-Reviewer: Mattflaschen <[email protected]>
Gerrit-Reviewer: Sn1per <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits