summaryrefslogtreecommitdiff
path: root/www/wiki/tests/phpunit/includes/auth/ThrottlerTest.php
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/tests/phpunit/includes/auth/ThrottlerTest.php')
-rw-r--r--www/wiki/tests/phpunit/includes/auth/ThrottlerTest.php238
1 files changed, 238 insertions, 0 deletions
diff --git a/www/wiki/tests/phpunit/includes/auth/ThrottlerTest.php b/www/wiki/tests/phpunit/includes/auth/ThrottlerTest.php
new file mode 100644
index 00000000..f963ad9c
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/auth/ThrottlerTest.php
@@ -0,0 +1,238 @@
+<?php
+
+namespace MediaWiki\Auth;
+
+use BagOStuff;
+use HashBagOStuff;
+use Psr\Log\AbstractLogger;
+use Psr\Log\LoggerInterface;
+use Psr\Log\NullLogger;
+use Wikimedia\TestingAccessWrapper;
+
+/**
+ * @group AuthManager
+ * @covers MediaWiki\Auth\Throttler
+ */
+class ThrottlerTest extends \MediaWikiTestCase {
+ public function testConstructor() {
+ $cache = new \HashBagOStuff();
+ $logger = $this->getMockBuilder( AbstractLogger::class )
+ ->setMethods( [ 'log' ] )
+ ->getMockForAbstractClass();
+
+ $throttler = new Throttler(
+ [ [ 'count' => 123, 'seconds' => 456 ] ],
+ [ 'type' => 'foo', 'cache' => $cache ]
+ );
+ $throttler->setLogger( $logger );
+ $throttlerPriv = TestingAccessWrapper::newFromObject( $throttler );
+ $this->assertSame( [ [ 'count' => 123, 'seconds' => 456 ] ], $throttlerPriv->conditions );
+ $this->assertSame( 'foo', $throttlerPriv->type );
+ $this->assertSame( $cache, $throttlerPriv->cache );
+ $this->assertSame( $logger, $throttlerPriv->logger );
+
+ $throttler = new Throttler( [ [ 'count' => 123, 'seconds' => 456 ] ] );
+ $throttler->setLogger( new NullLogger() );
+ $throttlerPriv = TestingAccessWrapper::newFromObject( $throttler );
+ $this->assertSame( [ [ 'count' => 123, 'seconds' => 456 ] ], $throttlerPriv->conditions );
+ $this->assertSame( 'custom', $throttlerPriv->type );
+ $this->assertInstanceOf( BagOStuff::class, $throttlerPriv->cache );
+ $this->assertInstanceOf( LoggerInterface::class, $throttlerPriv->logger );
+
+ $this->setMwGlobals( [ 'wgPasswordAttemptThrottle' => [ [ 'count' => 321,
+ 'seconds' => 654 ] ] ] );
+ $throttler = new Throttler();
+ $throttler->setLogger( new NullLogger() );
+ $throttlerPriv = TestingAccessWrapper::newFromObject( $throttler );
+ $this->assertSame( [ [ 'count' => 321, 'seconds' => 654 ] ], $throttlerPriv->conditions );
+ $this->assertSame( 'password', $throttlerPriv->type );
+ $this->assertInstanceOf( BagOStuff::class, $throttlerPriv->cache );
+ $this->assertInstanceOf( LoggerInterface::class, $throttlerPriv->logger );
+
+ try {
+ new Throttler( [], [ 'foo' => 1, 'bar' => 2, 'baz' => 3 ] );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \InvalidArgumentException $ex ) {
+ $this->assertSame( 'unrecognized parameters: foo, bar, baz', $ex->getMessage() );
+ }
+ }
+
+ /**
+ * @dataProvider provideNormalizeThrottleConditions
+ */
+ public function testNormalizeThrottleConditions( $condition, $normalized ) {
+ $throttler = new Throttler( $condition );
+ $throttler->setLogger( new NullLogger() );
+ $throttlerPriv = TestingAccessWrapper::newFromObject( $throttler );
+ $this->assertSame( $normalized, $throttlerPriv->conditions );
+ }
+
+ public function provideNormalizeThrottleConditions() {
+ return [
+ [
+ [],
+ [],
+ ],
+ [
+ [ 'count' => 1, 'seconds' => 2 ],
+ [ [ 'count' => 1, 'seconds' => 2 ] ],
+ ],
+ [
+ [ [ 'count' => 1, 'seconds' => 2 ], [ 'count' => 2, 'seconds' => 3 ] ],
+ [ [ 'count' => 1, 'seconds' => 2 ], [ 'count' => 2, 'seconds' => 3 ] ],
+ ],
+ ];
+ }
+
+ public function testNormalizeThrottleConditions2() {
+ $priv = TestingAccessWrapper::newFromClass( Throttler::class );
+ $this->assertSame( [], $priv->normalizeThrottleConditions( null ) );
+ $this->assertSame( [], $priv->normalizeThrottleConditions( 'bad' ) );
+ }
+
+ public function testIncrease() {
+ $cache = new \HashBagOStuff();
+ $throttler = new Throttler( [
+ [ 'count' => 2, 'seconds' => 10, ],
+ [ 'count' => 4, 'seconds' => 15, 'allIPs' => true ],
+ ], [ 'cache' => $cache ] );
+ $throttler->setLogger( new NullLogger() );
+
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle' );
+
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle' );
+
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertSame( [ 'throttleIndex' => 0, 'count' => 2, 'wait' => 10 ], $result );
+
+ $result = $throttler->increase( 'OtherUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle' );
+
+ $result = $throttler->increase( 'SomeUser', '2.3.4.5' );
+ $this->assertFalse( $result, 'should not throttle' );
+
+ $result = $throttler->increase( 'SomeUser', '3.4.5.6' );
+ $this->assertFalse( $result, 'should not throttle' );
+
+ $result = $throttler->increase( 'SomeUser', '3.4.5.6' );
+ $this->assertSame( [ 'throttleIndex' => 1, 'count' => 4, 'wait' => 15 ], $result );
+ }
+
+ public function testZeroCount() {
+ $cache = new \HashBagOStuff();
+ $throttler = new Throttler( [ [ 'count' => 0, 'seconds' => 10 ] ], [ 'cache' => $cache ] );
+ $throttler->setLogger( new NullLogger() );
+
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle, count=0 is ignored' );
+
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle, count=0 is ignored' );
+
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle, count=0 is ignored' );
+ }
+
+ public function testNamespacing() {
+ $cache = new \HashBagOStuff();
+ $throttler1 = new Throttler( [ [ 'count' => 1, 'seconds' => 10 ] ],
+ [ 'cache' => $cache, 'type' => 'foo' ] );
+ $throttler2 = new Throttler( [ [ 'count' => 1, 'seconds' => 10 ] ],
+ [ 'cache' => $cache, 'type' => 'foo' ] );
+ $throttler3 = new Throttler( [ [ 'count' => 1, 'seconds' => 10 ] ],
+ [ 'cache' => $cache, 'type' => 'bar' ] );
+ $throttler1->setLogger( new NullLogger() );
+ $throttler2->setLogger( new NullLogger() );
+ $throttler3->setLogger( new NullLogger() );
+
+ $throttled = [ 'throttleIndex' => 0, 'count' => 1, 'wait' => 10 ];
+
+ $result = $throttler1->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle' );
+
+ $result = $throttler1->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertEquals( $throttled, $result, 'should throttle' );
+
+ $result = $throttler2->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertEquals( $throttled, $result, 'should throttle, same namespace' );
+
+ $result = $throttler3->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle, different namespace' );
+ }
+
+ public function testExpiration() {
+ $cache = $this->getMockBuilder( HashBagOStuff::class )
+ ->setMethods( [ 'add' ] )->getMock();
+ $throttler = new Throttler( [ [ 'count' => 3, 'seconds' => 10 ] ], [ 'cache' => $cache ] );
+ $throttler->setLogger( new NullLogger() );
+
+ $cache->expects( $this->once() )->method( 'add' )->with( $this->anything(), 1, 10 );
+ $throttler->increase( 'SomeUser' );
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testException() {
+ $throttler = new Throttler( [ [ 'count' => 3, 'seconds' => 10 ] ] );
+ $throttler->setLogger( new NullLogger() );
+ $throttler->increase();
+ }
+
+ public function testLog() {
+ $cache = new \HashBagOStuff();
+ $throttler = new Throttler( [ [ 'count' => 1, 'seconds' => 10 ] ], [ 'cache' => $cache ] );
+
+ $logger = $this->getMockBuilder( AbstractLogger::class )
+ ->setMethods( [ 'log' ] )
+ ->getMockForAbstractClass();
+ $logger->expects( $this->never() )->method( 'log' );
+ $throttler->setLogger( $logger );
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle' );
+
+ $logger = $this->getMockBuilder( AbstractLogger::class )
+ ->setMethods( [ 'log' ] )
+ ->getMockForAbstractClass();
+ $logger->expects( $this->once() )->method( 'log' )->with( $this->anything(), $this->anything(), [
+ 'throttle' => 'custom',
+ 'index' => 0,
+ 'ip' => '1.2.3.4',
+ 'username' => 'SomeUser',
+ 'count' => 1,
+ 'expiry' => 10,
+ 'method' => 'foo',
+ ] );
+ $throttler->setLogger( $logger );
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4', 'foo' );
+ $this->assertSame( [ 'throttleIndex' => 0, 'count' => 1, 'wait' => 10 ], $result );
+ }
+
+ public function testClear() {
+ $cache = new \HashBagOStuff();
+ $throttler = new Throttler( [ [ 'count' => 1, 'seconds' => 10 ] ], [ 'cache' => $cache ] );
+ $throttler->setLogger( new NullLogger() );
+
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle' );
+
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertSame( [ 'throttleIndex' => 0, 'count' => 1, 'wait' => 10 ], $result );
+
+ $result = $throttler->increase( 'OtherUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle' );
+
+ $result = $throttler->increase( 'OtherUser', '1.2.3.4' );
+ $this->assertSame( [ 'throttleIndex' => 0, 'count' => 1, 'wait' => 10 ], $result );
+
+ $throttler->clear( 'SomeUser', '1.2.3.4' );
+
+ $result = $throttler->increase( 'SomeUser', '1.2.3.4' );
+ $this->assertFalse( $result, 'should not throttle' );
+
+ $result = $throttler->increase( 'OtherUser', '1.2.3.4' );
+ $this->assertSame( [ 'throttleIndex' => 0, 'count' => 1, 'wait' => 10 ], $result );
+ }
+}