mediawiki-extensions-Echo/tests/phpunit/controller/NotificationControllerTest.php
Matthew Flaschen 5ecc6aa7c8 BREAKING CHANGE: Change $wgEchoDefaultNotificationTypes to be logical
Merge and deploy at the *same time* as:
* BounceHandler - I3c669945080d8e1f67880bd8a31af7f88a70904d
* mediawiki-config - I13817c139967ed9e230cfb0c87c5de66da793c96

Despite claiming to be about categories, $wgEchoDefaultNotificationTypes
was actually configuring both categories and types (which go inside
categories).

For example, 'thank-you-edit' is a type, but 'emailuser' is both
a category and a type (when used as a category, this has special
effects at Special:Preferences).

Since types and categories can and sometimes do have the same names,
this leaves no way to properly and clearly configure them.  It also
makes it difficult to document what is going on (as required by
T132127).

Split into three variables:

$wgDefaultNotifyTypeAvailability - Applies unless overriden

$wgNotifyTypeAvailabilityByCategory - By category; this can be and is
displayed at Special:Preferences

$wgNotifyTypeAvailabilityByNotificationType - By type; this cannot
be displayed at Special:Preferences. To avoid confusing the user,
we introduce a restriction (which was previously followed in practice,
AFAICT) that types can only be overridden if the category is not
displayed in preferences.

Otherwise, it can look to the user like a category is on/off, but the
types within might have the opposite state.

Due to this configuration change, this is a breaking change, and needs
coordinated deployments.

This also lays the groundwork for T132127

Also change terminology to consistently use "notify type" for web/email.

It was mixing between that and output format (which unfortunately
sounds like the API format, e.g. 'model').

Bug: T132820
Bug: T132127
Change-Id: I09f39f5fc5f13f3253af9f7819bca81f1601da93
2016-04-22 19:08:12 -07:00

252 lines
6.1 KiB
PHP

<?php
class NotificationControllerTest extends MediaWikiTestCase {
public function evaluateUserLocatorsProvider() {
return array(
array(
'With no options no users are notified',
// expected result
array(),
// event user locator config
array(),
),
array(
'Does not error when given non-existant user-locator',
// expected result
array(),
// event user locator config
array( 'not-callable' ),
),
array(
'Calls selected locator and returns result',
// expected result
array( array( 123 ) ),
// event user locator config
function () {
return array( 123 => 123 );
}
),
array(
'evaluates multiple locators',
// expected result
array( array( 123 ), array( 456 ) ),
// event user locator config
array(
function () {
return array( 123 => 123 );
},
function () {
return array( 456 => 456 );
},
),
),
array(
'Passes parameters to locateFromEventExtra in expected manner',
// expected result
array( array( 123 ) ),
// event user locator config
array(
array( 'EchoUserLocator::locateFromEventExtra', array( 'other-user' ) ),
),
// additional setup
function ( $test, $event ) {
$event->expects( $test->any() )
->method( 'getExtraParam' )
->with( 'other-user' )
->will( $test->returnValue( 123 ) );
}
),
);
}
/**
* @dataProvider evaluateUserLocatorsProvider
*/
public function testEvaluateUserLocators( $message, $expect, $locatorConfigForEventType, $setup = null ) {
$this->setMwGlobals( array(
'wgEchoNotifications' => array(
'unit-test' => array(
EchoAttributeManager::ATTR_LOCATORS => $locatorConfigForEventType
),
),
) );
$event = $this->getMockBuilder( 'EchoEvent' )
->disableOriginalConstructor()
->getMock();
$event->expects( $this->any() )
->method( 'getType' )
->will( $this->returnValue( 'unit-test' ) );
if ( $setup !== null ) {
$setup( $this, $event );
}
$result = EchoNotificationController::evaluateUserCallable( $event, EchoAttributeManager::ATTR_LOCATORS );
$this->assertEquals( $expect, array_map( 'array_keys', $result ), $message );
}
public function testEvaluateUserLocatorPassesParameters() {
$test = $this;
$callback = function ( $event, $firstOption, $secondOption ) use ( $test ) {
$test->assertInstanceOf( 'EchoEvent', $event );
$test->assertEquals( 'first', $firstOption );
$test->assertEquals( 'second', $secondOption );
return array();
};
self::testEvaluateUserLocators(
__FUNCTION__,
array( array() ),
array( array( $callback, 'first', 'second' ) )
);
}
public function getUsersToNotifyForEventProvider() {
return array(
array(
'Filters anonymous users',
// expected result
array(),
// users returned from locator
array( User::newFromName( '4.5.6.7', false ) ),
),
array(
'Filters duplicate users',
// expected result
array( 123 ),
// users returned from locator
array( User::newFromId( 123 ), User::newFromId( 123 ) ),
),
array(
'Filters non-user objects',
// expected result
array( 123 ),
// users returned from locator
array( null, 'foo', User::newFromId( 123 ), new stdClass, 456 ),
),
);
}
/**
* @dataProvider getUsersToNotifyForEventProvider
*/
public function testGetUsersToNotifyForEvent(
$message,
$expect,
$users
) {
$this->setMwGlobals( array(
'wgEchoNotifications' => array(
'unit-test' => array(
EchoAttributeManager::ATTR_LOCATORS => function () use ( $users ) {
return $users;
},
),
),
) );
$event = $this->getMockBuilder( 'EchoEvent' )
->disableOriginalConstructor()
->getMock();
$event->expects( $this->any() )
->method( 'getType' )
->will( $this->returnValue( 'unit-test' ) );
$result = EchoNotificationController::getUsersToNotifyForEvent( $event );
$ids = array();
foreach ( $result as $user ) {
$ids[] = $user->getId();
}
$this->assertEquals( $expect, $ids, $message );
}
public function testDoesNotDeliverDisabledEvent() {
$event = $this->getMockBuilder( 'EchoEvent' )
->disableOriginalConstructor()
->getMock();
$event->expects( $this->any() )
->method( 'isEnabledEvent' )
->will( $this->returnValue( false ) );
// Assume it would have to check the event type to
// determine how to deliver
$event->expects( $this->never() )
->method( 'getType' );
EchoNotificationController::notify( $event, false );
}
public static function getEventNotifyTypesProvider() {
return array(
array(
'Selects the `all` configuration by default',
// expected result
array( 'web' ),
// event type
'bar',
// default notification types configuration
array( 'web' => true ),
// type-specific
array(
'foo' => array(
'notify-type-availability' => array( 'email' => true ),
),
),
),
array(
'Overrides `all` configuration with event type configuration',
// expected result
array( 'web' ),
// event type
'foo',
// default notification types configuration
array( 'web' => true, 'email' => true ),
// type-specific
array(
'foo' => array(
'notify-type-availability' => array( 'email' => false ),
),
'bar' => array(
'notify-type-availability' => array( 'sms' => true ),
),
),
),
array(
'Uses all configuration when notify-type-availability not set at all',
// expected result
array( 'web', 'email' ),
// event type
'baz',
// default notification types configuration
array( 'web' => true, 'email' => true ),
// type-specific
array(
'baz' => array(),
),
)
);
}
/**
* @dataProvider getEventNotifyTypesProvider
*/
public function testGetEventNotifyTypes( $message, $expect, $type, array $defaultNotifyTypeAvailability, array $notifications ) {
$this->setMwGlobals( array(
'wgDefaultNotifyTypeAvailability' => $defaultNotifyTypeAvailability,
'wgEchoNotifications' => $notifications,
) );
$result = EchoNotificationController::getEventNotifyTypes( $type );
$this->assertEquals( $expect, $result, $message );
}
}