Merge "Use independent stats for emergency disable"

This commit is contained in:
jenkins-bot 2021-02-26 18:06:16 +00:00 committed by Gerrit Code Review
commit 34a2660ad2
12 changed files with 369 additions and 64 deletions

View file

@ -99,6 +99,13 @@ class AbuseFilterServices {
return MediaWikiServices::getInstance()->getService( FilterLookup::SERVICE_NAME );
}
/**
* @return EmergencyCache
*/
public static function getEmergencyCache() : EmergencyCache {
return MediaWikiServices::getInstance()->getService( EmergencyCache::SERVICE_NAME );
}
/**
* @return EmergencyWatcher
*/

140
includes/EmergencyCache.php Normal file
View file

@ -0,0 +1,140 @@
<?php
namespace MediaWiki\Extension\AbuseFilter;
use BagOStuff;
/**
* Helper class for EmergencyWatcher. Wrapper around cache which tracks hits of recently
* modified filters.
*/
class EmergencyCache {
public const SERVICE_NAME = 'AbuseFilterEmergencyCache';
/** @var BagOStuff */
private $stash;
/** @var int[] */
private $ttlPerGroup;
/**
* @param BagOStuff $stash
* @param int[] $ttlPerGroup
*/
public function __construct( BagOStuff $stash, array $ttlPerGroup ) {
$this->stash = $stash;
$this->ttlPerGroup = $ttlPerGroup;
}
/**
* Get recently modified filters in the group. Thanks to this, performance can be improved,
* because only a small subset of filters will need an update.
*
* @param string $group
* @return int[]
*/
public function getFiltersToCheckInGroup( string $group ) : array {
$filterToExpiry = $this->stash->get( $this->createGroupKey( $group ) );
if ( $filterToExpiry === false ) {
return [];
}
$time = (int)round( $this->stash->getCurrentTime() );
return array_keys( array_filter(
$filterToExpiry,
static function ( $exp ) use ( $time ) {
return $exp > $time;
}
) );
}
/**
* Create a new entry in cache for a filter and update the entry for the group.
* This method is usually called after the filter has been updated.
*
* @param int $filter
* @param string $group
* @return bool
*/
public function setNewForFilter( int $filter, string $group ) : bool {
$ttl = $this->ttlPerGroup[$group] ?? $this->ttlPerGroup['default'];
$expiry = (int)round( $this->stash->getCurrentTime() + $ttl );
$this->stash->merge(
$this->createGroupKey( $group ),
function ( $cache, $key, $value ) use ( $filter, $expiry ) {
if ( $value === false ) {
$value = [];
}
// note that some filters may have already had their keys expired
// we are currently filtering them out in getFiltersToCheckInGroup
// but if necessary, it can be done here
$value[$filter] = $expiry;
return $value;
},
$expiry
);
return $this->stash->set(
$this->createFilterKey( $filter ),
[ 'total' => 0, 'matches' => 0, 'expiry' => $expiry ],
$expiry
);
}
/**
* Increase the filter's 'total' value by one and possibly also the 'matched' value.
*
* @param int $filter
* @param bool $matched Whether the filter matched the action
* @return bool
*/
public function incrementForFilter( int $filter, bool $matched ) : bool {
return $this->stash->merge(
$this->createFilterKey( $filter ),
static function ( $cache, $key, $value, &$expiry ) use ( $matched ) {
if ( $value === false ) {
return false;
}
$value['total']++;
if ( $matched ) {
$value['matches']++;
}
// enforce the prior TTL
$expiry = $value['expiry'];
return $value;
}
);
}
/**
* Get the cache entry for the filter. Returns false when the key has already expired.
* Otherwise it returns the entry formatted as [ 'total' => number of actions,
* 'matches' => number of hits ] (since the last filter modification).
*
* @param int $filter
* @return array|false
*/
public function getForFilter( int $filter ) {
$value = $this->stash->get( $this->createFilterKey( $filter ) );
if ( $value !== false ) {
unset( $value['expiry'] );
}
return $value;
}
/**
* @param string $group
* @return string
*/
private function createGroupKey( string $group ) : string {
return $this->stash->makeKey( 'abusefilter', 'emergency', 'group', $group );
}
/**
* @param int $filter
* @return string
*/
private function createFilterKey( int $filter ) : string {
return $this->stash->makeKey( 'abusefilter', 'emergency', 'filter', $filter );
}
}

View file

@ -3,6 +3,7 @@
namespace MediaWiki\Extension\AbuseFilter;
use BadMethodCallException;
use DeferredUpdates;
use IBufferingStatsdDataFactory;
use InvalidArgumentException;
use MediaWiki\Config\ServiceOptions;
@ -51,6 +52,8 @@ class FilterRunner {
private $consExecutorFactory;
/** @var AbuseLoggerFactory */
private $abuseLoggerFactory;
/** @var EmergencyCache */
private $emergencyCache;
/** @var Watcher[] */
private $watchers;
/** @var EditStashCache */
@ -103,6 +106,7 @@ class FilterRunner {
* @param AbuseLoggerFactory $abuseLoggerFactory
* @param VariablesManager $varManager
* @param VariableGeneratorFactory $varGeneratorFactory
* @param EmergencyCache $emergencyCache
* @param Watcher[] $watchers
* @param EditStashCache $stashCache
* @param LoggerInterface $logger
@ -124,6 +128,7 @@ class FilterRunner {
AbuseLoggerFactory $abuseLoggerFactory,
VariablesManager $varManager,
VariableGeneratorFactory $varGeneratorFactory,
EmergencyCache $emergencyCache,
array $watchers,
EditStashCache $stashCache,
LoggerInterface $logger,
@ -143,6 +148,7 @@ class FilterRunner {
$this->abuseLoggerFactory = $abuseLoggerFactory;
$this->varManager = $varManager;
$this->varGeneratorFactory = $varGeneratorFactory;
$this->emergencyCache = $emergencyCache;
$this->watchers = $watchers;
$this->stashCache = $stashCache;
$this->logger = $logger;
@ -226,6 +232,14 @@ class FilterRunner {
}
$this->profileExecution( $runnerData );
// hack until DI for DeferredUpdates is possible (T265749)
if ( defined( 'MW_PHPUNIT_TEST' ) ) {
$this->updateEmergencyCache( $runnerData->getMatchesMap() );
} else {
DeferredUpdates::addCallableUpdate( function () use ( $runnerData ) {
$this->updateEmergencyCache( $runnerData->getMatchesMap() );
} );
}
// Tag the action if the condition limit was hit
if ( $runnerData->getTotalConditions() > $this->options->get( 'AbuseFilterConditionLimit' ) ) {
@ -395,6 +409,18 @@ class FilterRunner {
);
}
/**
* @param bool[] $matches
*/
protected function updateEmergencyCache( array $matches ) : void {
$filters = $this->emergencyCache->getFiltersToCheckInGroup( $this->group );
foreach ( $filters as $filter ) {
if ( array_key_exists( "$filter", $matches ) ) {
$this->emergencyCache->incrementForFilter( $filter, $matches["$filter"] );
}
}
}
/**
* @return array
*/

View file

@ -40,6 +40,8 @@ class FilterRunnerFactory {
private $varManager;
/** @var VariableGeneratorFactory */
private $varGeneratorFactory;
/** @var EmergencyCache */
private $emergencyCache;
/** @var UpdateHitCountWatcher */
private $updateHitCountWatcher;
/** @var EmergencyWatcher */
@ -65,6 +67,7 @@ class FilterRunnerFactory {
* @param AbuseLoggerFactory $abuseLoggerFactory
* @param VariablesManager $varManager
* @param VariableGeneratorFactory $varGeneratorFactory
* @param EmergencyCache $emergencyCache
* @param UpdateHitCountWatcher $updateHitCountWatcher
* @param EmergencyWatcher $emergencyWatcher
* @param BagOStuff $localCache
@ -83,6 +86,7 @@ class FilterRunnerFactory {
AbuseLoggerFactory $abuseLoggerFactory,
VariablesManager $varManager,
VariableGeneratorFactory $varGeneratorFactory,
EmergencyCache $emergencyCache,
UpdateHitCountWatcher $updateHitCountWatcher,
EmergencyWatcher $emergencyWatcher,
BagOStuff $localCache,
@ -100,6 +104,7 @@ class FilterRunnerFactory {
$this->abuseLoggerFactory = $abuseLoggerFactory;
$this->varManager = $varManager;
$this->varGeneratorFactory = $varGeneratorFactory;
$this->emergencyCache = $emergencyCache;
$this->updateHitCountWatcher = $updateHitCountWatcher;
$this->emergencyWatcher = $emergencyWatcher;
$this->localCache = $localCache;
@ -134,6 +139,7 @@ class FilterRunnerFactory {
$this->abuseLoggerFactory,
$this->varManager,
$this->varGeneratorFactory,
$this->emergencyCache,
$watchers,
new EditStashCache(
$this->localCache,

View file

@ -39,6 +39,9 @@ class FilterStore {
/** @var FilterCompare */
private $filterCompare;
/** @var EmergencyCache */
private $emergencyCache;
/**
* @param ConsequencesRegistry $consequencesRegistry
* @param ILoadBalancer $loadBalancer
@ -47,6 +50,7 @@ class FilterStore {
* @param ChangeTagsManager $tagsManager
* @param FilterValidator $filterValidator
* @param FilterCompare $filterCompare
* @param EmergencyCache $emergencyCache
*/
public function __construct(
ConsequencesRegistry $consequencesRegistry,
@ -55,7 +59,8 @@ class FilterStore {
FilterLookup $filterLookup,
ChangeTagsManager $tagsManager,
FilterValidator $filterValidator,
FilterCompare $filterCompare
FilterCompare $filterCompare,
EmergencyCache $emergencyCache
) {
$this->consequencesRegistry = $consequencesRegistry;
$this->loadBalancer = $loadBalancer;
@ -64,6 +69,7 @@ class FilterStore {
$this->tagsManager = $tagsManager;
$this->filterValidator = $filterValidator;
$this->filterCompare = $filterCompare;
$this->emergencyCache = $emergencyCache;
}
/**
@ -213,13 +219,15 @@ class FilterStore {
$dbw->endAtomic( __METHOD__ );
// TODO: isset() shouldn't be necessary,
// invalid values should also be discarded upstream
$group = 'default';
if ( isset( $newRow['af_group'] ) && $newRow['af_group'] !== '' ) {
$group = $newRow['af_group'];
}
// Invalidate cache if this was a global rule
if ( $wasGlobal || $newRow['af_global'] ) {
$group = 'default';
if ( isset( $newRow['af_group'] ) && $newRow['af_group'] !== '' ) {
$group = $newRow['af_group'];
}
$this->filterLookup->purgeGroupWANCache( $group );
}
@ -241,6 +249,9 @@ class FilterStore {
}
$this->filterProfiler->resetFilterProfile( $newID );
if ( $newRow['af_enabled'] ) {
$this->emergencyCache->setNewForFilter( $newID, $group );
}
return [ $newID, $historyID ];
}

View file

@ -18,6 +18,7 @@ use MediaWiki\Extension\AbuseFilter\Consequences\ConsequencesRegistry;
use MediaWiki\Extension\AbuseFilter\EchoNotifier;
use MediaWiki\Extension\AbuseFilter\EditBox\EditBoxBuilderFactory;
use MediaWiki\Extension\AbuseFilter\EditRevUpdater;
use MediaWiki\Extension\AbuseFilter\EmergencyCache;
use MediaWiki\Extension\AbuseFilter\FilterCompare;
use MediaWiki\Extension\AbuseFilter\FilterImporter;
use MediaWiki\Extension\AbuseFilter\FilterLookup;
@ -127,9 +128,15 @@ return [
$services->get( CentralDBManager::SERVICE_NAME )
);
},
EmergencyCache::SERVICE_NAME => function ( MediaWikiServices $services ): EmergencyCache {
return new EmergencyCache(
$services->getMainObjectStash(),
$services->getMainConfig()->get( 'AbuseFilterEmergencyDisableAge' )
);
},
EmergencyWatcher::SERVICE_NAME => function ( MediaWikiServices $services ): EmergencyWatcher {
return new EmergencyWatcher(
$services->getService( FilterProfiler::SERVICE_NAME ),
$services->getService( EmergencyCache::SERVICE_NAME ),
$services->getDBLoadBalancer(),
$services->getService( FilterLookup::SERVICE_NAME ),
$services->getService( EchoNotifier::SERVICE_NAME ),
@ -176,7 +183,8 @@ return [
$services->get( FilterLookup::SERVICE_NAME ),
$services->get( ChangeTagsManager::SERVICE_NAME ),
$services->get( FilterValidator::SERVICE_NAME ),
$services->get( FilterCompare::SERVICE_NAME )
$services->get( FilterCompare::SERVICE_NAME ),
$services->get( EmergencyCache::SERVICE_NAME )
);
},
ConsequencesFactory::SERVICE_NAME => function ( MediaWikiServices $services ): ConsequencesFactory {
@ -277,6 +285,7 @@ return [
$services->get( AbuseLoggerFactory::SERVICE_NAME ),
$services->get( VariablesManager::SERVICE_NAME ),
$services->get( VariableGeneratorFactory::SERVICE_NAME ),
$services->get( EmergencyCache::SERVICE_NAME ),
$services->get( UpdateHitCountWatcher::SERVICE_NAME ),
$services->get( EmergencyWatcher::SERVICE_NAME ),
ObjectCache::getLocalClusterInstance(),

View file

@ -7,8 +7,8 @@ use DeferredUpdates;
use InvalidArgumentException;
use MediaWiki\Config\ServiceOptions;
use MediaWiki\Extension\AbuseFilter\EchoNotifier;
use MediaWiki\Extension\AbuseFilter\EmergencyCache;
use MediaWiki\Extension\AbuseFilter\FilterLookup;
use MediaWiki\Extension\AbuseFilter\FilterProfiler;
use Wikimedia\Rdbms\IDatabase;
use Wikimedia\Rdbms\ILoadBalancer;
@ -27,8 +27,8 @@ class EmergencyWatcher implements Watcher {
'AbuseFilterEmergencyDisableThreshold',
];
/** @var FilterProfiler */
private $profiler;
/** @var EmergencyCache */
private $cache;
/** @var ILoadBalancer */
private $loadBalancer;
@ -43,21 +43,21 @@ class EmergencyWatcher implements Watcher {
private $options;
/**
* @param FilterProfiler $profiler
* @param EmergencyCache $cache
* @param ILoadBalancer $loadBalancer
* @param FilterLookup $filterLookup
* @param EchoNotifier $notifier
* @param ServiceOptions $options
*/
public function __construct(
FilterProfiler $profiler,
EmergencyCache $cache,
ILoadBalancer $loadBalancer,
FilterLookup $filterLookup,
EchoNotifier $notifier,
ServiceOptions $options
) {
$options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
$this->profiler = $profiler;
$this->cache = $cache;
$this->loadBalancer = $loadBalancer;
$this->filterLookup = $filterLookup;
$this->notifier = $notifier;
@ -73,12 +73,11 @@ class EmergencyWatcher implements Watcher {
* @return int[] Array of filters to be throttled
*/
public function getFiltersToThrottle( array $filters, string $group ) : array {
$groupProfile = $this->profiler->getGroupProfile( $group );
// @ToDo this is an amount between 1 and AbuseFilterProfileActionsCap, which means that the
// reliability of this number may strongly vary. We should instead use a fixed one.
$totalActions = $groupProfile['total'];
if ( $totalActions === 0 ) {
$filters = array_intersect(
$filters,
$this->cache->getFiltersToCheckInGroup( $group )
);
if ( $filters === [] ) {
return [];
}
@ -91,6 +90,8 @@ class EmergencyWatcher implements Watcher {
$throttleFilters = [];
foreach ( $filters as $filter ) {
$filterObj = $this->filterLookup->getFilter( $filter, false );
// TODO: consider removing the filter from the group key
// after throttling
if ( $filterObj->isThrottled() ) {
continue;
}
@ -99,13 +100,20 @@ class EmergencyWatcher implements Watcher {
$exemptTime = $filterAge + $maxAge;
// Optimize for the common case when filters are well-established
// This check somewhat duplicates the role of cache entry's TTL
// and could as well be removed
if ( $exemptTime <= $time ) {
continue;
}
// TODO: this value might be stale, there is no guarantee the match
// has actually been recorded now
$matchCount = $this->profiler->getFilterProfile( $filter )['matches'];
$cacheValue = $this->cache->getForFilter( $filter );
if ( $cacheValue === false ) {
continue;
}
[ 'total' => $totalActions, 'matches' => $matchCount ] = $cacheValue;
if ( $matchCount > $hitCountLimit && ( $matchCount / $totalActions ) > $threshold ) {
// More than AbuseFilterEmergencyDisableCount matches, constituting more than

View file

@ -0,0 +1,107 @@
<?php
namespace MediaWiki\Extension\AbuseFilter\Tests\Unit;
use HashBagOStuff;
use MediaWiki\Extension\AbuseFilter\EmergencyCache;
use MediaWikiUnitTestCase;
/**
* @coversDefaultClass \MediaWiki\Extension\AbuseFilter\EmergencyCache
*/
class EmergencyCacheTest extends MediaWikiUnitTestCase {
/**
* @covers ::__construct
* @covers ::getFiltersToCheckInGroup
* @covers ::getForFilter
*/
public function testEmptyCache() {
$cache = new EmergencyCache( new HashBagOStuff(), [ 'default' => 86400 ] );
$this->assertSame( [], $cache->getFiltersToCheckInGroup( 'default' ) );
$this->assertFalse( $cache->getForFilter( 1 ) );
}
/**
* @covers ::setNewForFilter
* @covers ::getFiltersToCheckInGroup
* @covers ::getForFilter
* @covers ::createGroupKey
* @covers ::createFilterKey
*/
public function testSetNewForFilter() {
$time = microtime( true );
$stash = new HashBagOStuff();
$stash->setMockTime( $time );
$cache = new EmergencyCache( $stash, [ 'default' => 86400, 'other' => 3600 ] );
$cache->setNewForFilter( 2, 'other' );
$this->assertSame(
[ 'total' => 0, 'matches' => 0 ],
$cache->getForFilter( 2 )
);
$this->assertSame(
[ 2 ],
$cache->getFiltersToCheckInGroup( 'other' )
);
$this->assertSame(
[],
$cache->getFiltersToCheckInGroup( 'default' )
);
$time += 3599;
$this->assertNotFalse( $cache->getForFilter( 2 ) );
$time += 2;
$this->assertFalse( $cache->getForFilter( 2 ) );
$this->assertSame( [], $cache->getFiltersToCheckInGroup( 'other' ) );
}
/**
* @covers ::incrementForFilter
* @covers ::getForFilter
* @covers ::setNewForFilter
*/
public function testIncrementForFilter() {
$time = microtime( true );
$stash = new HashBagOStuff();
$stash->setMockTime( $time );
$cache = new EmergencyCache( $stash, [ 'default' => 86400 ] );
$cache->setNewForFilter( 1, 'default' );
$cache->incrementForFilter( 1, false );
$this->assertSame(
[ 'total' => 1, 'matches' => 0 ],
$cache->getForFilter( 1 )
);
$cache->incrementForFilter( 1, true );
$this->assertSame(
[ 'total' => 2, 'matches' => 1 ],
$cache->getForFilter( 1 )
);
$time += 86401;
$cache->incrementForFilter( 1, true );
$this->assertFalse( $cache->getForFilter( 1 ) );
}
/**
* @covers ::getFiltersToCheckInGroup
*/
public function testGetFiltersToCheckInGroup() {
$time = microtime( true );
$stash = new HashBagOStuff();
$stash->setMockTime( $time );
$cache = new EmergencyCache( $stash, [ 'default' => 3600 ] );
$cache->setNewForFilter( 1, 'default' );
$time += 1000;
$cache->setNewForFilter( 2, 'default' );
$this->assertArrayEquals(
[ 1, 2 ],
$cache->getFiltersToCheckInGroup( 'default' )
);
$time += 2601;
$this->assertArrayEquals(
[ 2 ],
$cache->getFiltersToCheckInGroup( 'default' )
);
}
}

View file

@ -8,6 +8,7 @@ use MediaWiki\Config\ServiceOptions;
use MediaWiki\Extension\AbuseFilter\AbuseLoggerFactory;
use MediaWiki\Extension\AbuseFilter\ChangeTags\ChangeTagger;
use MediaWiki\Extension\AbuseFilter\Consequences\ConsequencesExecutorFactory;
use MediaWiki\Extension\AbuseFilter\EmergencyCache;
use MediaWiki\Extension\AbuseFilter\FilterLookup;
use MediaWiki\Extension\AbuseFilter\FilterProfiler;
use MediaWiki\Extension\AbuseFilter\FilterRunner;
@ -54,6 +55,7 @@ class FilterRunnerFactoryTest extends MediaWikiUnitTestCase {
$this->createMock( AbuseLoggerFactory::class ),
$this->createMock( VariablesManager::class ),
$this->createMock( VariableGeneratorFactory::class ),
$this->createMock( EmergencyCache::class ),
$this->createMock( UpdateHitCountWatcher::class ),
$this->createMock( EmergencyWatcher::class ),
new HashBagOStuff(),

View file

@ -9,6 +9,7 @@ use MediaWiki\Extension\AbuseFilter\AbuseLoggerFactory;
use MediaWiki\Extension\AbuseFilter\ChangeTags\ChangeTagger;
use MediaWiki\Extension\AbuseFilter\Consequences\ConsequencesExecutorFactory;
use MediaWiki\Extension\AbuseFilter\EditStashCache;
use MediaWiki\Extension\AbuseFilter\EmergencyCache;
use MediaWiki\Extension\AbuseFilter\FilterLookup;
use MediaWiki\Extension\AbuseFilter\FilterProfiler;
use MediaWiki\Extension\AbuseFilter\FilterRunner;
@ -67,6 +68,7 @@ class FilterRunnerTest extends MediaWikiUnitTestCase {
$this->createMock( AbuseLoggerFactory::class ),
$this->createMock( VariablesManager::class ),
$this->createMock( VariableGeneratorFactory::class ),
$this->createMock( EmergencyCache::class ),
[],
$cache,
new NullLogger(),

View file

@ -4,6 +4,7 @@ namespace MediaWiki\Extension\AbuseFilter\Tests\Unit;
use MediaWiki\Extension\AbuseFilter\ChangeTags\ChangeTagsManager;
use MediaWiki\Extension\AbuseFilter\Consequences\ConsequencesRegistry;
use MediaWiki\Extension\AbuseFilter\EmergencyCache;
use MediaWiki\Extension\AbuseFilter\FilterCompare;
use MediaWiki\Extension\AbuseFilter\FilterLookup;
use MediaWiki\Extension\AbuseFilter\FilterProfiler;
@ -32,7 +33,8 @@ class FilterStoreTest extends MediaWikiUnitTestCase {
$this->createMock( FilterLookup::class ),
$this->createMock( ChangeTagsManager::class ),
$this->createMock( FilterValidator::class ),
$this->createMock( FilterCompare::class )
$this->createMock( FilterCompare::class ),
$this->createMock( EmergencyCache::class )
)
);
}

View file

@ -4,9 +4,9 @@ namespace MediaWiki\Extension\AbuseFilter\Tests\Unit\Watcher;
use MediaWiki\Config\ServiceOptions;
use MediaWiki\Extension\AbuseFilter\EchoNotifier;
use MediaWiki\Extension\AbuseFilter\EmergencyCache;
use MediaWiki\Extension\AbuseFilter\Filter\ExistingFilter;
use MediaWiki\Extension\AbuseFilter\FilterLookup;
use MediaWiki\Extension\AbuseFilter\FilterProfiler;
use MediaWiki\Extension\AbuseFilter\Watcher\EmergencyWatcher;
use MediaWikiUnitTestCase;
use MWTimestamp;
@ -36,15 +36,15 @@ class EmergencyWatcherTest extends MediaWikiUnitTestCase {
);
}
private function getFilterProfiler( array $profilerData ) : FilterProfiler {
$profiler = $this->createMock( FilterProfiler::class );
$profiler->method( 'getGroupProfile' )
->willReturnCallback( function ( $group ) use ( $profilerData ) {
return [ 'total' => $profilerData['total'][$group] ];
} );
$profiler->method( 'getFilterProfile' )
->willReturn( [ 'matches' => $profilerData['matches'] ] );
return $profiler;
private function getEmergencyCache( array $cacheData, string $group ) : EmergencyCache {
$cache = $this->createMock( EmergencyCache::class );
$cache->method( 'getForFilter' )
->with( 1 )
->willReturn( $cacheData );
$cache->method( 'getFiltersToCheckInGroup' )
->with( $group )
->willReturn( [ 1 ] );
return $cache;
}
private function getFilterLookup( array $filterData ) : FilterLookup {
@ -67,10 +67,8 @@ class EmergencyWatcherTest extends MediaWikiUnitTestCase {
/* filterData */ [
'timestamp' => '20201016000000'
],
/* profilerData */ [
'total' => [
'default' => 100,
],
/* cacheData */ [
'total' => 100,
'matches' => 10
],
/* willThrottle */ true
@ -80,11 +78,8 @@ class EmergencyWatcherTest extends MediaWikiUnitTestCase {
/* filterData */ [
'timestamp' => '20201016000000'
],
/* profilerData */ [
'total' => [
'default' => 200,
'other' => 100
],
/* cacheData */ [
'total' => 100,
'matches' => 5
],
/* willThrottle */ true,
@ -96,10 +91,8 @@ class EmergencyWatcherTest extends MediaWikiUnitTestCase {
'timestamp' => '20201016000000',
'throttled' => true,
],
/* profilerData */ [
'total' => [
'default' => 100,
],
/* cacheData */ [
'total' => 100,
'matches' => 10
],
/* willThrottle */ false
@ -109,10 +102,8 @@ class EmergencyWatcherTest extends MediaWikiUnitTestCase {
/* filterData */ [
'timestamp' => '20201016000000'
],
/* profilerData */ [
'total' => [
'default' => 5,
],
/* cacheData */ [
'total' => 5,
'matches' => 2
],
/* willThrottle */ false
@ -122,10 +113,8 @@ class EmergencyWatcherTest extends MediaWikiUnitTestCase {
/* filterData */ [
'timestamp' => '20201016000000'
],
/* profilerData */ [
'total' => [
'default' => 100,
],
/* cacheData */ [
'total' => 100,
'matches' => 5
],
/* willThrottle */ false
@ -135,10 +124,8 @@ class EmergencyWatcherTest extends MediaWikiUnitTestCase {
/* filterData */ [
'timestamp' => '20201016000000'
],
/* profilerData */ [
'total' => [
'default' => 1000,
],
/* cacheData */ [
'total' => 1000,
'matches' => 100
],
/* willThrottle */ false
@ -148,10 +135,8 @@ class EmergencyWatcherTest extends MediaWikiUnitTestCase {
/* filterData */ [
'timestamp' => '20201016000000'
],
/* profilerData */ [
'total' => [
'default' => 0,
],
/* cacheData */ [
'total' => 0,
'matches' => 0
],
/* willThrottle */ false
@ -167,13 +152,13 @@ class EmergencyWatcherTest extends MediaWikiUnitTestCase {
public function testGetFiltersToThrottle(
string $timestamp,
array $filterData,
array $profilerData,
array $cacheData,
bool $willThrottle,
string $group = 'default'
) {
MWTimestamp::setFakeTime( $timestamp );
$watcher = new EmergencyWatcher(
$this->getFilterProfiler( $profilerData ),
$this->getEmergencyCache( $cacheData, $group ),
$this->createMock( ILoadBalancer::class ),
$this->getFilterLookup( $filterData ),
$this->createMock( EchoNotifier::class ),
@ -194,7 +179,7 @@ class EmergencyWatcherTest extends MediaWikiUnitTestCase {
*/
public function testConstruct() {
$watcher = new EmergencyWatcher(
$this->createMock( FilterProfiler::class ),
$this->createMock( EmergencyCache::class ),
$this->createMock( ILoadBalancer::class ),
$this->createMock( FilterLookup::class ),
$this->createMock( EchoNotifier::class ),