From ee6413165c6fb404a81262df0c167324b29a8c8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Mon, 17 Jul 2017 12:24:42 +0200 Subject: [PATCH 1/2] [stable10] ActivityManager can be initialized with null for the session variable in the ctor This reverts commit 2cf02a0bb8adb103a6a8c4c57b1ca61e3901105a. --- lib/private/Activity/Manager.php | 6 +- .../lib/Activity/NullSession/ManagerTest.php | 526 ++++++++++++++++++ 2 files changed, 529 insertions(+), 3 deletions(-) create mode 100644 tests/lib/Activity/NullSession/ManagerTest.php diff --git a/lib/private/Activity/Manager.php b/lib/private/Activity/Manager.php index 050d442cda7d..4c2cca8c6007 100644 --- a/lib/private/Activity/Manager.php +++ b/lib/private/Activity/Manager.php @@ -59,7 +59,7 @@ class Manager implements IManager { * @param IConfig $config */ public function __construct(IRequest $request, - IUserSession $session, + IUserSession $session = null, IConfig $config) { $this->request = $request; $this->session = $session; @@ -177,7 +177,7 @@ public function publish(IEvent $event) { } if ($event->getAuthor() === null) { - if ($this->session->getUser() instanceof IUser) { + if ($this->session !== null && $this->session->getUser() instanceof IUser) { $event->setAuthor($this->session->getUser()->getUID()); } } @@ -501,7 +501,7 @@ public function setCurrentUserId($currentUserId) { public function getCurrentUserId() { if ($this->currentUserId !== null) { return $this->currentUserId; - } else if (!$this->session->isLoggedIn()) { + } else if ($this->session === null || !$this->session->isLoggedIn()) { return $this->getUserFromToken(); } else { return $this->session->getUser()->getUID(); diff --git a/tests/lib/Activity/NullSession/ManagerTest.php b/tests/lib/Activity/NullSession/ManagerTest.php new file mode 100644 index 000000000000..b0efc6abe837 --- /dev/null +++ b/tests/lib/Activity/NullSession/ManagerTest.php @@ -0,0 +1,526 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + * +*/ + +namespace Test\Activity\NullSession; + +use OC\Activity\Event; +use OCP\Activity\IConsumer; +use OCP\Activity\IEvent; +use OCP\Activity\IExtension; +use OCP\IConfig; +use OCP\IRequest; +use Test\TestCase; + +class ManagerTest extends TestCase { + + /** @var \OC\Activity\Manager */ + private $activityManager; + /** @var \OCP\IRequest|\PHPUnit_Framework_MockObject_MockObject */ + protected $request; + /** @var \OCP\IConfig|\PHPUnit_Framework_MockObject_MockObject */ + protected $config; + + protected function setUp() { + parent::setUp(); + + $this->request = $this->getMockBuilder(IRequest::class) + ->disableOriginalConstructor() + ->getMock(); + $this->config = $this->getMockBuilder(IConfig::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->activityManager = new \OC\Activity\Manager( + $this->request, + null, + $this->config + ); + + $this->assertSame([], $this->invokePrivate($this->activityManager, 'getConsumers')); + $this->assertSame([], $this->invokePrivate($this->activityManager, 'getExtensions')); + + $this->activityManager->registerConsumer(function() { + return new NoOpConsumer(); + }); + $this->activityManager->registerExtension(function() { + return new NoOpExtension(); + }); + $this->activityManager->registerExtension(function() { + return new SimpleExtension(); + }); + + $this->assertNotEmpty($this->invokePrivate($this->activityManager, 'getConsumers')); + $this->assertNotEmpty($this->invokePrivate($this->activityManager, 'getConsumers')); + $this->assertNotEmpty($this->invokePrivate($this->activityManager, 'getExtensions')); + $this->assertNotEmpty($this->invokePrivate($this->activityManager, 'getExtensions')); + } + + public function testGetConsumers() { + $consumers = $this->invokePrivate($this->activityManager, 'getConsumers'); + + $this->assertNotEmpty($consumers); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testGetConsumersInvalidConsumer() { + $this->activityManager->registerConsumer(function() { + return new \stdClass(); + }); + + $this->invokePrivate($this->activityManager, 'getConsumers'); + } + + public function testGetExtensions() { + $extensions = $this->invokePrivate($this->activityManager, 'getExtensions'); + + $this->assertNotEmpty($extensions); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testGetExtensionsInvalidExtension() { + $this->activityManager->registerExtension(function() { + return new \stdClass(); + }); + + $this->invokePrivate($this->activityManager, 'getExtensions'); + } + + public function testNotificationTypes() { + $result = $this->activityManager->getNotificationTypes('en'); + $this->assertTrue(is_array($result)); + $this->assertEquals(2, sizeof($result)); + } + + public function testDefaultTypes() { + $result = $this->activityManager->getDefaultTypes('stream'); + $this->assertTrue(is_array($result)); + $this->assertEquals(1, sizeof($result)); + + $result = $this->activityManager->getDefaultTypes('email'); + $this->assertTrue(is_array($result)); + $this->assertEquals(0, sizeof($result)); + } + + public function testTypeIcon() { + $result = $this->activityManager->getTypeIcon('NT1'); + $this->assertEquals('icon-nt-one', $result); + + $result = $this->activityManager->getTypeIcon('NT2'); + $this->assertEquals('', $result); + } + + public function testTranslate() { + $result = $this->activityManager->translate('APP0', '', [], false, false, 'en'); + $this->assertEquals('Stupid translation', $result); + + $result = $this->activityManager->translate('APP1', '', [], false, false, 'en'); + $this->assertFalse($result); + } + + public function testGetSpecialParameterList() { + $result = $this->activityManager->getSpecialParameterList('APP0', ''); + $this->assertEquals([0 => 'file', 1 => 'username'], $result); + + $result = $this->activityManager->getSpecialParameterList('APP1', ''); + $this->assertFalse($result); + } + + public function testGroupParameter() { + $result = $this->activityManager->getGroupParameter([]); + $this->assertEquals(5, $result); + } + + public function testNavigation() { + $result = $this->activityManager->getNavigation(); + $this->assertEquals(4, sizeof($result['apps'])); + $this->assertEquals(2, sizeof($result['top'])); + } + + public function testIsFilterValid() { + $result = $this->activityManager->isFilterValid('fv01'); + $this->assertTrue($result); + + $result = $this->activityManager->isFilterValid('InvalidFilter'); + $this->assertFalse($result); + } + + public function testFilterNotificationTypes() { + $result = $this->activityManager->filterNotificationTypes(['NT0', 'NT1', 'NT2', 'NT3'], 'fv01'); + $this->assertTrue(is_array($result)); + $this->assertEquals(3, sizeof($result)); + + $result = $this->activityManager->filterNotificationTypes(['NT0', 'NT1', 'NT2', 'NT3'], 'InvalidFilter'); + $this->assertTrue(is_array($result)); + $this->assertEquals(4, sizeof($result)); + } + + public function testQueryForFilter() { + // Register twice, to test the created sql part + $this->activityManager->registerExtension(function() { + return new SimpleExtension(); + }); + + $result = $this->activityManager->getQueryForFilter('fv01'); + $this->assertEquals( + [ + ' and ((`app` = ? and `message` like ?) or (`app` = ? and `message` like ?))', + ['mail', 'ownCloud%', 'mail', 'ownCloud%'] + ], $result + ); + + $result = $this->activityManager->getQueryForFilter('InvalidFilter'); + $this->assertEquals([null, null], $result); + } + + public function getUserFromTokenThrowInvalidTokenData() { + return [ + [null, []], + ['', []], + ['12345678901234567890123456789', []], + ['1234567890123456789012345678901', []], + ['123456789012345678901234567890', []], + ['123456789012345678901234567890', ['user1', 'user2']], + ]; + } + + /** + * @expectedException \UnexpectedValueException + * @dataProvider getUserFromTokenThrowInvalidTokenData + * + * @param string $token + * @param array $users + */ + public function testGetUserFromTokenThrowInvalidToken($token, $users) { + $this->mockRSSToken($token, $token, $users); + self::invokePrivate($this->activityManager, 'getUserFromToken'); + } + + public function getUserFromTokenData() { + return [ + ['123456789012345678901234567890', 'user1'], + ]; + } + + /** + * @dataProvider getUserFromTokenData + * + * @param string $token + * @param string $expected + */ + public function testGetUserFromToken($token, $expected) { + $this->mockRSSToken($token, '123456789012345678901234567890', ['user1']); + + $this->assertEquals($expected, $this->activityManager->getCurrentUserId()); + } + + protected function mockRSSToken($requestToken, $userToken, $users) { + if ($requestToken !== null) { + $this->request->expects($this->any()) + ->method('getParam') + ->with('token', '') + ->willReturn($requestToken); + } + + $this->config->expects($this->any()) + ->method('getUsersForUserValue') + ->with('activity', 'rsstoken', $userToken) + ->willReturn($users); + } + + /** + * @expectedException \BadMethodCallException + * @expectedExceptionMessage App not set + * @expectedExceptionCode 10 + */ + public function testPublishExceptionNoApp() { + $event = new Event(); + $this->activityManager->publish($event); + } + + /** + * @expectedException \BadMethodCallException + * @expectedExceptionMessage Type not set + * @expectedExceptionCode 11 + */ + public function testPublishExceptionNoType() { + $event = new Event(); + $event->setApp('test'); + $this->activityManager->publish($event); + } + + /** + * @expectedException \BadMethodCallException + * @expectedExceptionMessage Affected user not set + * @expectedExceptionCode 12 + */ + public function testPublishExceptionNoAffectedUser() { + $event = new Event(); + $event->setApp('test') + ->setType('test_type'); + $this->activityManager->publish($event); + } + + /** + * @expectedException \BadMethodCallException + * @expectedExceptionMessage Subject not set + * @expectedExceptionCode 13 + */ + public function testPublishExceptionNoSubject() { + $event = new Event(); + $event->setApp('test') + ->setType('test_type') + ->setAffectedUser('test_affected'); + $this->activityManager->publish($event); + } + + public function testPublish() { + $author = null; + $event = new Event(); + $event->setApp('test') + ->setType('test_type') + ->setSubject('test_subject', []) + ->setAffectedUser('test_affected'); + + $consumer = $this->getMockBuilder('OCP\Activity\IConsumer') + ->disableOriginalConstructor() + ->getMock(); + $consumer->expects($this->once()) + ->method('receive') + ->with($event) + ->willReturnCallback(function(IEvent $event) use ($author) { + $this->assertLessThanOrEqual(time() + 2, $event->getTimestamp(), 'Timestamp not set correctly'); + $this->assertGreaterThanOrEqual(time() - 2, $event->getTimestamp(), 'Timestamp not set correctly'); + $this->assertSame($author, $event->getAuthor(), 'Author name not set correctly'); + }); + $this->activityManager->registerConsumer(function () use ($consumer) { + return $consumer; + }); + + $this->activityManager->publish($event); + } + + public function testPublishAllManually() { + $event = new Event(); + $event->setApp('test_app') + ->setType('test_type') + ->setAffectedUser('test_affected') + ->setAuthor('test_author') + ->setTimestamp(1337) + ->setSubject('test_subject', ['test_subject_param']) + ->setMessage('test_message', ['test_message_param']) + ->setObject('test_object_type', 42, 'test_object_name') + ->setLink('test_link') + ; + + $consumer = $this->getMockBuilder('OCP\Activity\IConsumer') + ->disableOriginalConstructor() + ->getMock(); + $consumer->expects($this->once()) + ->method('receive') + ->willReturnCallback(function(IEvent $event) { + $this->assertSame('test_app', $event->getApp(), 'App not set correctly'); + $this->assertSame('test_type', $event->getType(), 'Type not set correctly'); + $this->assertSame('test_affected', $event->getAffectedUser(), 'Affected user not set correctly'); + $this->assertSame('test_author', $event->getAuthor(), 'Author not set correctly'); + $this->assertSame(1337, $event->getTimestamp(), 'Timestamp not set correctly'); + $this->assertSame('test_subject', $event->getSubject(), 'Subject not set correctly'); + $this->assertSame(['test_subject_param'], $event->getSubjectParameters(), 'Subject parameter not set correctly'); + $this->assertSame('test_message', $event->getMessage(), 'Message not set correctly'); + $this->assertSame(['test_message_param'], $event->getMessageParameters(), 'Message parameter not set correctly'); + $this->assertSame('test_object_type', $event->getObjectType(), 'Object type not set correctly'); + $this->assertSame(42, $event->getObjectId(), 'Object ID not set correctly'); + $this->assertSame('test_object_name', $event->getObjectName(), 'Object name not set correctly'); + $this->assertSame('test_link', $event->getLink(), 'Link not set correctly'); + }); + $this->activityManager->registerConsumer(function () use ($consumer) { + return $consumer; + }); + + $this->activityManager->publish($event); + } + + public function testDeprecatedPublishActivity() { + $event = new Event(); + $event->setApp('test_app') + ->setType('test_type') + ->setAffectedUser('test_affected') + ->setAuthor('test_author') + ->setTimestamp(1337) + ->setSubject('test_subject', ['test_subject_param']) + ->setMessage('test_message', ['test_message_param']) + ->setObject('test_object_type', 42, 'test_object_name') + ->setLink('test_link') + ; + + $consumer = $this->getMockBuilder('OCP\Activity\IConsumer') + ->disableOriginalConstructor() + ->getMock(); + $consumer->expects($this->once()) + ->method('receive') + ->willReturnCallback(function(IEvent $event) { + $this->assertSame('test_app', $event->getApp(), 'App not set correctly'); + $this->assertSame('test_type', $event->getType(), 'Type not set correctly'); + $this->assertSame('test_affected', $event->getAffectedUser(), 'Affected user not set correctly'); + $this->assertSame('test_subject', $event->getSubject(), 'Subject not set correctly'); + $this->assertSame(['test_subject_param'], $event->getSubjectParameters(), 'Subject parameter not set correctly'); + $this->assertSame('test_message', $event->getMessage(), 'Message not set correctly'); + $this->assertSame(['test_message_param'], $event->getMessageParameters(), 'Message parameter not set correctly'); + $this->assertSame('test_object_name', $event->getObjectName(), 'Object name not set correctly'); + $this->assertSame('test_link', $event->getLink(), 'Link not set correctly'); + + // The following values can not be used via publishActivity() + $this->assertLessThanOrEqual(time() + 2, $event->getTimestamp(), 'Timestamp not set correctly'); + $this->assertGreaterThanOrEqual(time() - 2, $event->getTimestamp(), 'Timestamp not set correctly'); + $this->assertSame(null, $event->getAuthor(), 'Author not set correctly'); + $this->assertSame('', $event->getObjectType(), 'Object type should not be set'); + $this->assertSame(0, $event->getObjectId(), 'Object ID should not be set'); + }); + $this->activityManager->registerConsumer(function () use ($consumer) { + return $consumer; + }); + + $this->activityManager->publishActivity( + $event->getApp(), + $event->getSubject(), $event->getSubjectParameters(), + $event->getMessage(), $event->getMessageParameters(), + $event->getObjectName(), + $event->getLink(), + $event->getAffectedUser(), + $event->getType(), + IExtension::PRIORITY_MEDIUM + ); + } +} + +class SimpleExtension implements IExtension { + + public function getNotificationTypes($languageCode) { + return ['NT1', 'NT2']; + } + + public function getDefaultTypes($method) { + if ($method === 'stream') { + return ['DT0']; + } + + return []; + } + + public function getTypeIcon($type) { + if ($type === 'NT1') { + return 'icon-nt-one'; + } + return ''; + } + + public function translate($app, $text, $params, $stripPath, $highlightParams, $languageCode) { + if ($app === 'APP0') { + return "Stupid translation"; + } + + return false; + } + + public function getSpecialParameterList($app, $text) { + if ($app === 'APP0') { + return [0 => 'file', 1 => 'username']; + } + + return false; + } + + public function getGroupParameter($activity) { + return 5; + } + + public function getNavigation() { + return [ + 'apps' => ['nav1', 'nav2', 'nav3', 'nav4'], + 'top' => ['top1', 'top2'] + ]; + } + + public function isFilterValid($filterValue) { + if ($filterValue === 'fv01') { + return true; + } + + return false; + } + + public function filterNotificationTypes($types, $filter) { + if ($filter === 'fv01') { + unset($types[0]); + } + return $types; + } + + public function getQueryForFilter($filter) { + if ($filter === 'fv01') { + return ['`app` = ? and `message` like ?', ['mail', 'ownCloud%']]; + } + + return false; + } +} + +class NoOpExtension implements IExtension { + + public function getNotificationTypes($languageCode) { + return false; + } + + public function getDefaultTypes($method) { + return false; + } + + public function getTypeIcon($type) { + return false; + } + + public function translate($app, $text, $params, $stripPath, $highlightParams, $languageCode) { + return false; + } + + public function getSpecialParameterList($app, $text) { + return false; + } + + public function getGroupParameter($activity) { + return false; + } + + public function getNavigation() { + return false; + } + + public function isFilterValid($filterValue) { + return false; + } + + public function filterNotificationTypes($types, $filter) { + return false; + } + + public function getQueryForFilter($filter) { + return false; + } +} + +class NoOpConsumer implements IConsumer { + + public function receive(IEvent $event) { + + } +} From 3bede3a681de2dec52e3b24450a542f991712166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Mon, 17 Jul 2017 12:25:01 +0200 Subject: [PATCH 2/2] When migrating an app should still be loaded .... This reverts commit 430aa2566c19cf4e4d1df9504bff2eda84fe4273. --- lib/private/DB/MigrationService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/private/DB/MigrationService.php b/lib/private/DB/MigrationService.php index fd1393fef187..d3cc5716b529 100644 --- a/lib/private/DB/MigrationService.php +++ b/lib/private/DB/MigrationService.php @@ -86,7 +86,7 @@ function __construct($appName, } // load the app so that app code can be used during migrations - \OC_App::loadApp($this->appName); + \OC_App::loadApp($this->appName, false); } private static function requireOnce($file) {