aboutsummaryrefslogtreecommitdiffstats
path: root/tests/phpunit/integration
diff options
context:
space:
mode:
authorTim Starling <tstarling@wikimedia.org>2025-01-15 15:25:49 +1100
committerTim Starling <tstarling@wikimedia.org>2025-02-19 11:18:41 +1100
commitc0dd3afe639260f05b89db1e1191adba9e22ac46 (patch)
treef012264484f33b826e8fe577629591483f967e9a /tests/phpunit/integration
parent8210d146e1ac8fa22586bf8412df39059631efa2 (diff)
downloadmediawikicore-c0dd3afe639260f05b89db1e1191adba9e22ac46.tar.gz
mediawikicore-c0dd3afe639260f05b89db1e1191adba9e22ac46.zip
block: Add a BlockTarget class hierarchy
Main change: * Add a class hierarchy representing block targets, representing a target and type. * Add BlockTargetFactory, replacing BlockUtils. * Add CrossWikiBlockTargetFactory, replacing BlockUtilsFactory. * Construct a BlockTarget object early in the request flow and pass it down through the layers, instead of having every layer interpret UserIdentity|string target specifications. Also: * Remove Block::TYPE_ID. Nothing uses it in code search, so there's no point in porting it to the new system. * Stop using the type constants as specificity scores. Add BlockTarget::getSpecificity(). * Add DatabaseBlockStore::newUnsaved() to replace direct construction of DatabaseBlock in insertBlock() callers. There are many such callers in tests. This is part of the effort to remove the service container usage in DatabaseBlock::__construct(). * Make DatabaseBlock::getRangeStart() and getRangeEnd() return null if the block is not a range, since that is convenient for their only caller following the resolution of T51504. * Add DatabaseBlock::getIpHex() which similarly maps to a DB field in the new schema. * In ApiBlock and ApiUnblock, have ParamValidator provide UserIdentity objects instead of converting to a string and back to a UserIdentity again. Bug: T382106 Change-Id: I2ce1a82f3fbb3cf18aa2d17986d46dbdcc70c761
Diffstat (limited to 'tests/phpunit/integration')
-rw-r--r--tests/phpunit/integration/includes/block/BlockTargetFactoryTest.php216
-rw-r--r--tests/phpunit/integration/includes/block/DatabaseBlockStoreTest.php2
2 files changed, 217 insertions, 1 deletions
diff --git a/tests/phpunit/integration/includes/block/BlockTargetFactoryTest.php b/tests/phpunit/integration/includes/block/BlockTargetFactoryTest.php
new file mode 100644
index 000000000000..6eded3e76258
--- /dev/null
+++ b/tests/phpunit/integration/includes/block/BlockTargetFactoryTest.php
@@ -0,0 +1,216 @@
+<?php
+
+use MediaWiki\Block\AnonIpBlockTarget;
+use MediaWiki\Block\AutoBlockTarget;
+use MediaWiki\Block\BlockTargetFactory;
+use MediaWiki\Block\RangeBlockTarget;
+use MediaWiki\Block\UserBlockTarget;
+use MediaWiki\Config\ServiceOptions;
+use MediaWiki\MainConfigNames;
+use MediaWiki\User\UserIdentity;
+use MediaWiki\User\UserIdentityLookup;
+use MediaWiki\User\UserIdentityValue;
+use MediaWiki\User\UserSelectQueryBuilder;
+use Wikimedia\Rdbms\IDBAccessObject;
+
+/**
+ * @covers \MediaWiki\Block\BlockTargetFactory
+ */
+class BlockTargetFactoryTest extends \MediaWikiIntegrationTestCase {
+ private function getBlockTargetFactory( $wikiId = false ) {
+ return new BlockTargetFactory(
+ new ServiceOptions(
+ BlockTargetFactory::CONSTRUCTOR_OPTIONS,
+ [
+ MainConfigNames::BlockCIDRLimit => [
+ 'IPv4' => 16,
+ 'IPv6' => 19,
+ ],
+ ]
+ ),
+ $this->getMockUserIdentityLookup(),
+ $this->getServiceContainer()->getUserNameUtils(),
+ $wikiId
+ );
+ }
+
+ private function getMockUserIdentityLookup() {
+ return new class implements UserIdentityLookup {
+ public function getUserIdentityByName(
+ string $name, int $queryFlags = IDBAccessObject::READ_NORMAL
+ ): ?UserIdentity {
+ if ( $name === 'Exists' ) {
+ return new UserIdentityValue( 1, $name );
+ } else {
+ return null;
+ }
+ }
+
+ public function getUserIdentityByUserId(
+ int $userId, int $queryFlags = IDBAccessObject::READ_NORMAL
+ ): ?UserIdentity {
+ if ( $userId === 1 ) {
+ return new UserIdentityValue( 1, 'Exists' );
+ } else {
+ return null;
+ }
+ }
+
+ public function newSelectQueryBuilder( $dbOrQueryFlags = IDBAccessObject::READ_NORMAL
+ ): UserSelectQueryBuilder {
+ throw new RuntimeException( 'unimplemented' );
+ }
+ };
+ }
+
+ public function testGetWikiId() {
+ $this->assertSame( 'enwiki',
+ $this->getBlockTargetFactory( 'enwiki' )->getWikiId() );
+ }
+
+ public static function provideNewFromString() {
+ return [
+ [ '1.2.3.4', AnonIpBlockTarget::class ],
+ [ '::1', AnonIpBlockTarget::class, '0:0:0:0:0:0:0:1' ],
+ [ ' 1.2.3.4', AnonIpBlockTarget::class, '1.2.3.4' ],
+ [ '1.2.3.0/24', RangeBlockTarget::class ],
+ [ '::1/64', RangeBlockTarget::class, '0:0:0:0:0:0:0:0/64' ],
+ [ 'Exists', UserBlockTarget::class ],
+ [ 'Nonexistent', UserBlockTarget::class ],
+ [ '#1234', AutoBlockTarget::class ],
+ [ '__', null ],
+ [ '', null ],
+ [ null, null ]
+ ];
+ }
+
+ /**
+ * @dataProvider provideNewFromString
+ * @param string $input
+ * @param string $class
+ * @param string|null $serialized
+ */
+ public function testNewFromString( $input, $class, $serialized = null ) {
+ $target = $this->getBlockTargetFactory()->newFromString( $input );
+ if ( $class === null ) {
+ $this->assertNull( $target );
+ return;
+ }
+ $this->assertInstanceOf( $class, $target );
+ // Confirm round trip
+ $this->assertSame( $serialized ?? $input, $target->toString() );
+ }
+
+ /**
+ * @covers \MediaWiki\Block\UserBlockTarget::validateForCreation
+ */
+ public function testNoSuchUser() {
+ $target = $this->getBlockTargetFactory()->newFromString( 'Nonexistent' );
+ $status = $target->validateForCreation();
+ $this->assertStatusError( 'nosuchusershort', $status );
+ $this->assertSame( '<text>Nonexistent</text>',
+ $status->getMessages()[0]->getParams()[0]->dump() );
+ }
+
+ public static function provideNewFromUser() {
+ return [
+ [ 1, 'Alice', UserBlockTarget::class ],
+ [ 5, 'Exists', UserBlockTarget::class ],
+ [ 0, 'Nonexistent', UserBlockTarget::class ],
+ [ 0, '127.0.0.1', AnonIpBlockTarget::class ],
+ [ 0, '1.2.3.0/24', RangeBlockTarget::class ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideNewFromUser
+ * @param int $id
+ * @param string $name
+ * @param string $class
+ */
+ public function testNewFromUser( $id, $name, $class ) {
+ $user = new UserIdentityValue( $id, $name );
+ $target = $this->getBlockTargetFactory()->newFromUser( $user );
+ $this->assertInstanceOf( $class, $target );
+ $this->assertSame( $name, $target->toString() );
+ }
+
+ public static function provideNewFromRow() {
+ $default = [
+ 'bt_auto' => '0',
+ 'bt_address' => '127.0.0.1',
+ 'bt_user' => null,
+ 'bt_user_text' => null,
+ 'bl_id' => 5,
+ ];
+ return [
+ 'IP block' => [
+ $default,
+ false,
+ AnonIpBlockTarget::class,
+ '127.0.0.1',
+ ],
+ 'Autoblock exposed' => [
+ [ 'bt_auto' => '1' ] + $default,
+ false,
+ AnonIpBlockTarget::class,
+ '127.0.0.1',
+ ],
+ 'Autoblock redacted' => [
+ [ 'bt_auto' => '1' ] + $default,
+ true,
+ AutoBlockTarget::class,
+ '#5',
+ ],
+ 'Range block' => [
+ [ 'bt_address' => '127.0.0.0/24' ] + $default,
+ false,
+ RangeBlockTarget::class,
+ '127.0.0.0/24',
+ ],
+ 'IPv6 range block' => [
+ [ 'bt_address' => '2001:0:0:0:0:0:0:0/19' ] + $default,
+ false,
+ RangeBlockTarget::class,
+ '2001:0:0:0:0:0:0:0/19',
+ ],
+ 'User block' => [
+ [ 'bt_user' => 2, 'bt_user_text' => 'Bob' ] + $default,
+ false,
+ UserBlockTarget::class,
+ 'Bob'
+ ],
+ 'Error case 1' => [
+ [ 'bt_address' => null ] + $default,
+ false,
+ null,
+ ''
+ ],
+ 'Error case 2' => [
+ [ 'bt_address' => 'Some invalid string' ] + $default,
+ false,
+ null,
+ ''
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideNewFromRow
+ * @param array $data
+ * @param bool $redact
+ * @param string|null $class
+ * @param string $serialized
+ */
+ public function testNewFromRow( $data, $redact, $class, $serialized ) {
+ $factory = $this->getBlockTargetFactory();
+ $target = $redact ? $factory->newFromRowRedacted( (object)$data )
+ : $factory->newFromRowRaw( (object)$data );
+ if ( $class === null ) {
+ $this->assertNull( $target );
+ return;
+ }
+ $this->assertInstanceOf( $class, $target );
+ $this->assertSame( $serialized, $target->toString() );
+ }
+}
diff --git a/tests/phpunit/integration/includes/block/DatabaseBlockStoreTest.php b/tests/phpunit/integration/includes/block/DatabaseBlockStoreTest.php
index 93fb77007b9f..c2e51ff01ea2 100644
--- a/tests/phpunit/integration/includes/block/DatabaseBlockStoreTest.php
+++ b/tests/phpunit/integration/includes/block/DatabaseBlockStoreTest.php
@@ -75,7 +75,7 @@ class DatabaseBlockStoreTest extends MediaWikiIntegrationTestCase {
'readOnlyMode' => $readOnlyMode,
'userFactory' => $services->getUserFactory(),
'tempUserConfig' => $services->getTempUserConfig(),
- 'blockUtils' => $services->getBlockUtils(),
+ 'blockTargetFactory' => $services->getBlockTargetFactory(),
'autoblockExemptionList' => $services->getAutoblockExemptionList(),
];
$constructorArgs = array_merge( $defaultConstructorArgs, $overrideConstructorArgs );