diff options
author | LEDfan <LEDfan@users.noreply.github.com> | 2017-08-01 22:30:12 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-01 22:30:12 +0300 |
commit | e3793e3099c2d6e3b6750ab4b10aea89452e4054 (patch) | |
tree | 2d49d7743d281067e64a911318905cea80487c82 | |
parent | 9d7e9d87cf5db20c727e7166db1ba9d0e1bfa951 (diff) | |
parent | f32f47957ac98e8bfeab82c40657d1486804c831 (diff) |
Merge pull request #52 from nextcloud/refresh_roster_delete_users
Include deleted users in refresh roster + run on installation + fix current user in roster
-rw-r--r-- | appinfo/application.php | 19 | ||||
-rwxr-xr-x | appinfo/info.xml | 7 | ||||
-rw-r--r-- | lib/Migration/RefreshRoster.php | 75 | ||||
-rw-r--r-- | lib/command/refreshroster.php | 10 | ||||
-rw-r--r-- | lib/hooks.php | 4 | ||||
-rw-r--r-- | lib/rosterpush.php | 69 | ||||
-rw-r--r-- | lib/stanzahandlers/iq.php | 15 | ||||
-rw-r--r-- | phpunit.xml | 4 | ||||
-rw-r--r-- | tests/integration/db/IqRosterPushTest.php | 36 | ||||
-rw-r--r-- | tests/integration/db/PresenceMapperTest.php | 63 | ||||
-rw-r--r-- | tests/integration/db/StanzaMapperTest.php | 31 | ||||
-rw-r--r-- | tests/unit/HooksTest.php | 160 | ||||
-rw-r--r-- | tests/unit/RosterPushTest.php | 259 | ||||
-rw-r--r-- | tests/unit/stanzahandlers/IQTest.php | 14 |
14 files changed, 743 insertions, 23 deletions
diff --git a/appinfo/application.php b/appinfo/application.php index 55ffd3d..90cd530 100644 --- a/appinfo/application.php +++ b/appinfo/application.php @@ -13,6 +13,7 @@ use OCA\OJSXC\Db\MessageMapper; use OCA\OJSXC\Db\PresenceMapper; use OCA\OJSXC\Db\Stanza; use OCA\OJSXC\Db\StanzaMapper; +use OCA\OJSXC\Migration\RefreshRoster as RefreshRosterMigration; use OCA\OJSXC\NewContentContainer; use OCA\OJSXC\RosterPush; use OCA\OJSXC\StanzaHandlers\IQ; @@ -164,7 +165,8 @@ class Application extends App { return new IQ( $c->query('OJSXC_UserId'), $c->query('Host'), - $c->query('OCP\IUserManager') + $c->query('OCP\IUserManager'), + $c->query('OCP\IConfig') ); }); @@ -211,7 +213,8 @@ class Application extends App { $c->query('ServerContainer')->getUserManager(), $c->query('ServerContainer')->getUserSession(), $c->query('Host'), - $c->query('IQRosterPushMapper') + $c->query('IQRosterPushMapper'), + $c->query('ServerContainer')->getDatabaseConnection() ); }); @@ -243,17 +246,25 @@ class Application extends App { /** * Raw request body */ - $container->registerService('RawRequest', function($c) { + $container->registerService('RawRequest', function($c) { return new RawRequest(); }); /** * Data retriever */ - $container->registerService('DataRetriever', function($c) { + $container->registerService('DataRetriever', function($c) { return new DataRetriever(); }); + $container->registerService('OCA\OJSXC\Migration\RefreshRoster', function(IContainer $c) { + return new RefreshRosterMigration( + $c->query('RosterPush'), + $c->query('OCP\IConfig'), + $c->query('OCP\ILogger') + ); + }); + } /** diff --git a/appinfo/info.xml b/appinfo/info.xml index 4020ba7..9a94703 100755 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -53,4 +53,11 @@ <contactsmenu> <provider>OCA\OJSXC\ContactsMenu\Providers\ChatProvider</provider> </contactsmenu> + + <repair-steps> + <install> + <step>OCA\OJSXC\Migration\RefreshRoster</step> + </install> + </repair-steps> + </info> diff --git a/lib/Migration/RefreshRoster.php b/lib/Migration/RefreshRoster.php new file mode 100644 index 0000000..d31b988 --- /dev/null +++ b/lib/Migration/RefreshRoster.php @@ -0,0 +1,75 @@ +<?php + +namespace OCA\OJSXC\Migration; + +use OCA\OJSXC\RosterPush; +use OCP\IConfig; +use OCP\ILogger; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +class RefreshRoster implements IRepairStep +{ + + /** + * @var RosterPush + */ + private $rosterPush; + + /** + * @var IConfig + */ + private $config; + + /** + * @var ILogger + */ + private $logger; + + /** + * RefreshRoster constructor. + * + * @param RosterPush $rosterPush + * @param IConfig $config + * @param ILogger $logger + */ + public function __construct(RosterPush $rosterPush, IConfig $config, ILogger $logger) + { + $this->rosterPush = $rosterPush; + $this->config = $config; + $this->logger = $logger; + } + + /** + * Returns the step's name + * + * @return string + */ + public function getName() + { + return "Refresh the roster of all users when the app has been installed before."; + } + + /** + * Run repair step. + * Must throw exception on error. + * + * @param IOutput $output + * @throws \Exception in case of failure + */ + public function run(IOutput $output) + { + /** + * We want only to refresh the rosters if this app was installed before, + * since only then the rosters can be outdated. + */ + if ($this->config->getAppValue('ojsxc', 'installed_version', null) !== null + && $this->config->getAppValue('ojsxc', 'serverType', 'internal') === 'internal') { + $stats = $this->rosterPush->refreshRoster(); + $output->info("Updated " . $stats["updated"] . " roster items"); + $this->logger->info("Updated " . $stats["updated"] . " roster items", ["app" => "OJSXC"]); + $output->info("Removed " . $stats["removed"] . " roster items"); + $this->logger->info("Removed " . $stats["removed"] . " roster items", ["app" => "OJSXC"]); + } + } +} diff --git a/lib/command/refreshroster.php b/lib/command/refreshroster.php index b3f9522..e11c783 100644 --- a/lib/command/refreshroster.php +++ b/lib/command/refreshroster.php @@ -39,12 +39,8 @@ class RefreshRoster extends Command protected function execute(InputInterface $input, OutputInterface $output) { - $users = $this->userManager->search(''); - - foreach ($users as $user) { - $this->rosterPush->createOrUpdateRosterItem($user); - } - - $output->writeln("<info>Refreshed " . count($users) . " rosters. </info>"); + $stats = $this->rosterPush->refreshRoster(); + $output->writeln("Updated " . $stats["updated"] . " roster items"); + $output->writeln("Removed " . $stats["removed"] . " roster items"); } } diff --git a/lib/hooks.php b/lib/hooks.php index 4e731c1..c9ecba5 100644 --- a/lib/hooks.php +++ b/lib/hooks.php @@ -2,8 +2,6 @@ namespace OCA\OJSXC; -use OCA\OJSXC\Db\IQRosterPush; -use OCA\OJSXC\Db\IQRosterPushMapper; use OCA\OJSXC\Db\PresenceMapper; use OCA\OJSXC\Db\StanzaMapper; use OCP\IUserManager; @@ -80,7 +78,7 @@ class Hooks */ public function onDeleteUser(IUser $user) { - $this->rosterPush->removeRosterItem($user); + $this->rosterPush->removeRosterItem($user->getUID()); // delete the presence record of this user $this->presenceMapper->deletePresence($user->getUID()); diff --git a/lib/rosterpush.php b/lib/rosterpush.php index f15bfdf..4771dea 100644 --- a/lib/rosterpush.php +++ b/lib/rosterpush.php @@ -4,6 +4,7 @@ namespace OCA\OJSXC; use OCA\OJSXC\Db\IQRosterPush; use OCA\OJSXC\Db\IQRosterPushMapper; +use OCP\IDBConnection; use OCP\IUserManager; use OCP\IUser; @@ -29,16 +30,23 @@ class RosterPush */ private $userSession; + /** + * @var IDBConnection + */ + private $db; + public function __construct( IUserManager $userManager, IUserSession $userSession, $host, - IQRosterPushMapper $iqRosterPushMapper + IQRosterPushMapper $iqRosterPushMapper, + IDbConnection $db ) { $this->userManager = $userManager; $this->userSession = $userSession; $this->host = $host; $this->iqRosterPushMapper = $iqRosterPushMapper; + $this->db = $db; } /** @@ -64,22 +72,71 @@ class RosterPush /** * @see https://tools.ietf.org/html/rfc6121#section-2.1.6 - * @param IUser $user + * @param $userId */ - public function removeRosterItem(IUser $user) + public function removeRosterItem($userId) { $iq = new IQRosterPush(); - $iq->setJid($user->getUID()); - $iq->setName($user->getDisplayName()); + $iq->setJid($userId); $iq->setSubscription('remove'); $iq->setFrom(''); foreach ($this->userManager->search('') as $recipient) { - if ($recipient->getUID() !== $user->getUID()) { + if ($recipient->getUID() !== $userId) { $iq->setTo($recipient->getUID()); $this->iqRosterPushMapper->insert($iq); } } } + + /** + * @brief performs a completely roster fresh of all users. This will send + * a rosterPush for every existing user and a rosterPush for every + * user which was ever deleted. The deleted user is fetched from the + * `addressbookchanges` table. + */ + public function refreshRoster() + { + $stats = [ + "updated" => 0, + "removed" => 0 + ]; + + + foreach ($this->userManager->search('') as $user) { + $this->createOrUpdateRosterItem($user); + $stats["updated"]++; + } + + /** + * Here we look into the addressbookchanges table for deletions + * of "contacts" in the system addressbook. This are actual users of the + * Nextcloud instance. Because this is a private API of Nextcloud it's + * encapsulated in a try/catch block. + */ + try { + $query = "SELECT `id` FROM `*PREFIX*addressbooks` WHERE `principaluri`='principals/system/system' LIMIT 1"; + $addressbooks = $this->db->executeQuery($query)->fetchAll(); + $id = $addressbooks[0]['id']; + + $query = "SELECT `uri` FROM `*PREFIX*addressbookchanges` AS ac1 WHERE `addressbookid` = ? AND `operation` = 3 AND `id`=(SELECT MAX(id) FROM `*PREFIX*addressbookchanges` AS ac2 WHERE `uri`=ac1.uri)"; // we use the subquery to always fetch the latest change + + // Fetching all changes + $deletions = $this->db->executeQuery($query, [$id])->fetchAll(); + + foreach ($deletions as $deletion) { + $userid = $deletion['uri']; + $colonPlace = strpos($userid, ':'); + $dotPlace = strrpos($userid, '.'); + $userid = substr($userid, $colonPlace + 1, strlen($userid) - $dotPlace - $colonPlace); + $this->removeRosterItem($userid); + $stats["removed"]++; + } + } catch (\Exception $e) { + \OC::$server->getLogger()->logException($e); + } + + return $stats; + } } diff --git a/lib/stanzahandlers/iq.php b/lib/stanzahandlers/iq.php index 1d0aaba..9a7293c 100644 --- a/lib/stanzahandlers/iq.php +++ b/lib/stanzahandlers/iq.php @@ -3,6 +3,7 @@ namespace OCA\OJSXC\StanzaHandlers; use OCA\OJSXC\Db\IQRoster; +use OCP\IConfig; use OCP\IUserManager; use Sabre\Xml\Reader; use Sabre\Xml\Writer; @@ -21,16 +22,23 @@ class IQ extends StanzaHandler private $userManager; /** + * @var IConfig + */ + private $config; + + /** * IQ constructor. * * @param string $userId * @param string $host * @param IUserManager $userManager + * @param IConfig $config */ - public function __construct($userId, $host, IUserManager $userManager) + public function __construct($userId, $host, IUserManager $userManager, IConfig $config) { parent::__construct($userId, $host); $this->userManager = $userManager; + $this->config = $config; } @@ -42,6 +50,9 @@ class IQ extends StanzaHandler { $this->to = $this->getAttribute($stanza, 'to'); + // if in debug mode we show the own username in the roster for testing + $debugMode = $this->config->getSystemValue("debug"); + if ($stanza['value'][0]['name'] === '{jabber:iq:roster}query') { $id = $stanza['attributes']['id']; $iqRoster = new IQRoster(); @@ -49,7 +60,7 @@ class IQ extends StanzaHandler $iqRoster->setTo($this->from); $iqRoster->setQid($id); foreach ($this->userManager->search('') as $user) { - if ($user->getUID() !== $this->userId) { + if ($debugMode || (strtolower($user->getUID()) !== $this->userId)) { $iqRoster->addItem($user->getUID() . '@' . $this->host, $user->getDisplayName()); } } diff --git a/phpunit.xml b/phpunit.xml index 7ae3f53..b6bced8 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -14,9 +14,13 @@ <exclude> <directory suffix=".php">lib/ContactsMenu</directory> <directory suffix=".php">lib/db</directory> + <!-- The following three files are tested in the integration test suite --> <file>lib/ilock.php</file> <file>lib/memlock.php</file> <file>lib/dblock.php</file> + <!-- The following two files are simple wrappers around other code --> + <file>lib/command/refreshroster.php</file> + <file>lib/Migration/RefreshRoster.php</file> </exclude> </whitelist> </filter> diff --git a/tests/integration/db/IqRosterPushTest.php b/tests/integration/db/IqRosterPushTest.php new file mode 100644 index 0000000..e6e8c0d --- /dev/null +++ b/tests/integration/db/IqRosterPushTest.php @@ -0,0 +1,36 @@ +<?php +namespace OCA\OJSXC\Db; + +use Sabre\Xml\Writer; +use OCA\OJSXC\Utility\TestCase; + +class IqRosterPushTest extends TestCase +{ + public function testIqRoster() + { + $expected = '<body xmlns="http://jabber.org/protocol/httpbind"><iq to="jan@localhost" type="set" id="4"><query xmlns="jabber:iq:roster"><item jid="john@localhost" name="john" subscription="both"></item></query></iq></body>'; + + $writer = new Writer(); + $writer->openMemory(); + $writer->startElement('body'); + $writer->writeAttribute('xmlns', 'http://jabber.org/protocol/httpbind'); + + $iqRosterPush = new IQRosterPush(); + $iqRosterPush->setJid('john@localhost'); + $iqRosterPush->setTo('jan@localhost'); + $iqRosterPush->setName('john'); + $iqRosterPush->setSubscription('both'); + + $this->assertEquals($iqRosterPush->getJid(), 'john@localhost'); + $this->assertEquals($iqRosterPush->getTo(), 'jan@localhost'); + $this->assertEquals($iqRosterPush->getName(), 'john'); + $this->assertEquals($iqRosterPush->getSubscription(), 'both'); + + $writer->write($iqRosterPush); // needed to test the xmlSerialize function + + $writer->endElement(); + $result = $writer->outputMemory(); + + $this->assertEquals($expected, $result); + } +} diff --git a/tests/integration/db/PresenceMapperTest.php b/tests/integration/db/PresenceMapperTest.php index 11968c1..23b1624 100644 --- a/tests/integration/db/PresenceMapperTest.php +++ b/tests/integration/db/PresenceMapperTest.php @@ -480,4 +480,67 @@ class PresenceMapperTest extends MapperTestUtility $this->assertArrayDbResultsEqual($expected, $result, ['userid', 'last_active', 'presence']); } + + public function deletePresenceProvider() + { + $input1 = new PresenceEntity(); + $input1->setPresence('online'); + $input1->setUserid('admin'); + $input1->setLastActive(1000); + + $input2 = new PresenceEntity(); + $input2->setPresence('unavailable'); + $input2->setUserid('foo'); + $input2->setLastActive(1000); + + $input3 = new PresenceEntity(); + $input3->setPresence('xa'); + $input3->setUserid('derp'); + $input3->setLastActive(600); + + $input4 = new PresenceEntity(); + $input4->setPresence('chat'); + $input4->setUserid('derpina'); + $input4->setLastActive(400); + + return [ + [ + [$input1, $input2, $input3, $input4], + [ + [ + 'userid' => 'foo', + 'presence' => 'unavailable', + 'last_active' => '1000', + ], + [ + 'userid' => 'derp', + 'presence' => 'xa', + 'last_active' => '600', + ], + [ + 'userid' => 'derpina', + 'presence' => 'chat', + 'last_active' => '400', + ], + ] + ] + ]; + } + + /** + * @dataProvider deletePresenceProvider + */ + + public function testDeletePresence($inputs, $expected) + { + foreach ($inputs as $input) { + $this->mapper->setPresence($input); + } + + $this->mapper->deletePresence('admin'); + + $result = $this->fetchAllAsArray(); + + $this->assertArrayDbResultsEqual($expected, $result, ['userid', 'last_active', 'presence']); + } } diff --git a/tests/integration/db/StanzaMapperTest.php b/tests/integration/db/StanzaMapperTest.php index a2c09b0..279b2a1 100644 --- a/tests/integration/db/StanzaMapperTest.php +++ b/tests/integration/db/StanzaMapperTest.php @@ -111,4 +111,35 @@ class StanzaMapperTest extends MapperTestUtility $this->assertEquals($stanza2->getTo(), $result[0]->getTo()); $this->assertEquals($stanza2->getStanza(), $result[0]->getStanza()); } + + + public function testDeleteByTo() + { + $stanza1 = new Stanza(); + $stanza1->setFrom('jan@localhost'); + $stanza1->setTo('john@localhost'); + $stanza1->setStanza('abcd1'); + $this->mapper->insert($stanza1); + + $stanza2 = new Stanza(); + $stanza2->setFrom('thomas@localhost'); + $stanza2->setTo('jan@localhost'); + $stanza2->setStanza('abcd2'); + $this->mapper->insert($stanza2); + + // check if two elements are inserted + $result = $this->fetchAllAsArray(); + $this->assertArrayDbResultsEqual([ + ['from' => 'jan@localhost', 'to' => 'john@localhost', 'stanza' => 'abcd1'], + ['from' => 'thomas@localhost', 'to' => 'jan@localhost', 'stanza' => 'abcd2'] + ], $result, ['from', 'to', 'stanza']); + + + $this->mapper->deleteByTo('jan@localhost'); + + $result = $this->fetchAllAsArray(); + $this->assertArrayDbResultsEqual([ + ['from' => 'jan@localhost', 'to' => 'john@localhost', 'stanza' => 'abcd1'] + ], $result, ['from', 'to', 'stanza']); + } } diff --git a/tests/unit/HooksTest.php b/tests/unit/HooksTest.php new file mode 100644 index 0000000..f8a6f90 --- /dev/null +++ b/tests/unit/HooksTest.php @@ -0,0 +1,160 @@ +<?php + + +namespace OCA\OJSXC; + +use OCA\OJSXC\Db\Presence; +use OCA\OJSXC\Db\PresenceMapper; +use OCA\OJSXC\Db\StanzaMapper; +use OCP\IUserManager; +use OCP\IUserSession; +use PHPUnit_Framework_MockObject_MockObject; +use PHPUnit_Framework_TestCase; + +class HooksTest extends PHPUnit_Framework_TestCase +{ + + /** + * @var Hooks $hooks + */ + private $hooks; + + /** + * @var PHPUnit_Framework_MockObject_MockObject | IUserManager + */ + private $userManager; + + /** + * @var PHPUnit_Framework_MockObject_MockObject | IuserSession + */ + private $userSession; + + /** + * @var PHPUnit_Framework_MockObject_MockObject | RosterPush + */ + private $rosterPush; + + /** + * @var PHPUnit_Framework_MockObject_MockObject | PresenceMapper + */ + private $presenceMapper; + + /** + * @var PHPUnit_Framework_MockObject_MockObject | StanzaMapper + */ + private $stanzaMapper; + + public function setUp() + { + $this->userManager = $this->getMockBuilder('OCP\IUserManager')->setMethods(['listen', 'registerBackend', 'getBackends', 'removeBackend', 'clearBackends', 'get', 'userExists', 'checkPassword', 'search', 'searchDisplayName', 'createUser', 'createUserFromBackend', 'countUsers', 'callForAllUsers', 'countDisabledUsers', 'countSeenUsers', 'callForSeenUsers', 'getByEmail'])->getMock(); + + $this->userSession = $this->getMockBuilder('OCP\IUserSession')->setMethods(['listen', 'login', 'logout', 'setUser', 'getUser', 'isLoggedIn'])->getMock(); + + + $this->rosterPush = $this->getMockBuilder('OCA\OJSXC\RosterPush')->disableOriginalConstructor()->getMock(); + + $this->presenceMapper = $this->getMockBuilder('OCA\OJSXC\Db\PresenceMapper')->disableOriginalConstructor()->getMock(); + + $this->stanzaMapper = $this->getMockBuilder('OCA\OJSXC\Db\StanzaMapper')->disableOriginalConstructor()->getMock(); + + $this->hooks = new Hooks( + $this->userManager, + $this->userSession, + $this->rosterPush, + $this->presenceMapper, + $this->stanzaMapper + ); + } + + + public function testRegister() + { + $this->userManager->expects($this->at(0)) + ->method('listen') + ->with('\OC\User', 'postCreateUser', [$this->hooks, 'onCreateUser']); + + $this->userManager->expects($this->at(1)) + ->method('listen') + ->with('\OC\User', 'postDelete', [$this->hooks, 'onDeleteUser']); + + $this->userSession->expects($this->once()) + ->method('listen') + ->with('\OC\User', 'changeUser', [$this->hooks, 'onChangeUser']); + + $this->hooks->register(); + } + + public function testOnCreateUser() + { + $user = $this->getMockBuilder('OCP\IUser')->disableOriginalConstructor()->getMock(); + + $this->rosterPush->expects($this->once()) + ->method('createOrUpdateRosterItem') + ->with($user); + + $this->hooks->onCreateUser($user, 'abc'); + } + + public function testOnDeleteUser() + { + $user = $this->getMockBuilder('OCP\IUser')->disableOriginalConstructor()->getMock(); + + $user->expects($this->exactly(3)) + ->method('getUID') + ->willReturn('test'); + + $this->rosterPush->expects($this->once()) + ->method('removeRosterItem') + ->with('test'); + + $this->presenceMapper->expects($this->once()) + ->method('deletePresence') + ->with('test'); + + $this->stanzaMapper->expects($this->once()) + ->method('deleteByTo') + ->with('test'); + + $this->hooks->onDeleteUser($user); + } + + + public function testOnChangeUserEnabled() + { + $user = $this->getMockBuilder('OCP\IUser')->disableOriginalConstructor()->getMock(); + + $hooks = $this->getMockBuilder('OCA\OJSXC\Hooks')->disableOriginalConstructor()->setMethods(['onCreateUser'])->getMock(); + + $hooks->expects($this->once()) + ->method('onCreateUser') + ->with($user, ''); + + $hooks->onChangeUser($user, 'enabled', 'true'); + } + + public function testOnChangeUserDisabled() + { + $user = $this->getMockBuilder('OCP\IUser')->disableOriginalConstructor()->getMock(); + + $hooks = $this->getMockBuilder('OCA\OJSXC\Hooks')->disableOriginalConstructor()->setMethods(['onDeleteUser'])->getMock(); + + $hooks->expects($this->once()) + ->method('onDeleteUser') + ->with($user); + + $hooks->onChangeUser($user, 'enabled', 'false'); + } + + public function testOnChangeUserDisplayName() + { + $user = $this->getMockBuilder('OCP\IUser')->disableOriginalConstructor()->getMock(); + + $hooks = $this->getMockBuilder('OCA\OJSXC\Hooks')->disableOriginalConstructor()->setMethods(['onCreateUser'])->getMock(); + + $hooks->expects($this->once()) + ->method('onCreateUser') + ->with($user); + + $hooks->onChangeUser($user, 'displayName', 'abc'); + } +} diff --git a/tests/unit/RosterPushTest.php b/tests/unit/RosterPushTest.php new file mode 100644 index 0000000..1021a9f --- /dev/null +++ b/tests/unit/RosterPushTest.php @@ -0,0 +1,259 @@ +<?php + +namespace OCA\OJSXC; + +use OCA\OJSXC\Db\IQRosterPush; +use OCA\OJSXC\Db\IQRosterPushMapper; +use OCP\IDBConnection; +use OCP\IUserManager; +use OCP\IUserSession; +use PHPUnit_Framework_TestCase; + +class RosterPushTest extends PHPUnit_Framework_TestCase +{ + + /** + * @var RosterPush + */ + private $rosterPush; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject | IUserManager + */ + private $userManager; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject | IUserSession + */ + private $userSession; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject | IQRosterPushMapper + */ + private $iqRosterPushMapper; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject | IDBConnection + */ + private $db; + + public function setUp() + { + $this->userManager = $this->getMockBuilder('OCP\IUserManager') + ->disableOriginalConstructor()->getMock(); + + $this->userSession = $this->getMockBuilder('OCP\IUserSession') + ->disableOriginalConstructor()->getMock(); + + $this->iqRosterPushMapper = $this->getMockBuilder('OCA\OJSXC\Db\IQRosterPushMapper') + ->disableOriginalConstructor()->getMock(); + + $this->db = $this->getMockBuilder('OCP\IDbConnection') + ->disableOriginalConstructor()->getMock(); + + $this->rosterPush = new RosterPush( + $this->userManager, + $this->userSession, + 'localhost', + $this->iqRosterPushMapper, + $this->db + ); + } + + public function testRefreshRoster() + { + + /** @var \PHPUnit_Framework_MockObject_MockObject | RosterPush $rosterPush */ + $rosterPush = $this->getMockBuilder('OCA\OJSXC\RosterPush') + ->setConstructorArgs([$this->userManager, $this->userSession, 'host', $this->iqRosterPushMapper, $this->db]) + ->setMethods(['createOrUpdateRosterItem', 'removeRosterItem'])->getMock(); + + $user1 = $this->getMockBuilder('OCP\IUser')->getMock(); + $user2 = $this->getMockBuilder('OCP\IUser')->getMock(); + $user3 = $this->getMockBuilder('OCP\IUser')->getMock(); + + $this->userManager->expects($this->once()) + ->method('search') + ->willReturn([$user1, $user2, $user3]); + + $rosterPush->expects($this->at(0)) + ->method('createOrUpdateRosterItem') + ->with($user1); + + $rosterPush->expects($this->at(1)) + ->method('createOrUpdateRosterItem') + ->with($user2); + + $rosterPush->expects($this->at(2)) + ->method('createOrUpdateRosterItem') + ->with($user3); + + $resultStatement = $this->getMockBuilder('Doctrine\DBAL\Driver\ResultStatement')->getMock(); + + $resultStatement->expects($this->at(0)) + ->method('fetchAll') + ->willReturn([["id" => 10]]); + + $resultStatement->expects($this->at(1)) + ->method('fetchAll') + ->willReturn([ + ["uri" => 'Database:user1.vcf'], + ["uri" => 'Database:user2.vcf'], + ["uri" => 'Database:user3.vcf'], + ["uri" => 'Database:user4.vcf'] + ]); + + $this->db->expects($this->at(0)) + ->method('executeQuery') + ->with('SELECT `id` FROM `*PREFIX*addressbooks` WHERE `principaluri`=\'principals/system/system\' LIMIT 1') + ->willReturn($resultStatement); + + $this->db->expects($this->at(1)) + ->method('executeQuery') + ->with('SELECT `uri` FROM `*PREFIX*addressbookchanges` AS ac1 WHERE `addressbookid` = ? AND `operation` = 3 AND `id`=(SELECT MAX(id) FROM `*PREFIX*addressbookchanges` AS ac2 WHERE `uri`=ac1.uri)', [10]) + ->willReturn($resultStatement); + + + $rosterPush->expects($this->at(3)) + ->method('removeRosterItem') + ->with('user1'); + + $rosterPush->expects($this->at(4)) + ->method('removeRosterItem') + ->with('user2'); + + $rosterPush->expects($this->at(5)) + ->method('removeRosterItem') + ->with('user3'); + + $rosterPush->expects($this->at(6)) + ->method('removeRosterItem') + ->with('user4'); + + $stats = $rosterPush->refreshRoster(); + + $this->assertEquals($stats, ["removed" => 4, "updated" => 3]); + } + + public function testRefreshRosterThrowsDuringRemove() + { + + /** @var \PHPUnit_Framework_MockObject_MockObject | RosterPush $rosterPush */ + $rosterPush = $this->getMockBuilder('OCA\OJSXC\RosterPush') + ->setConstructorArgs([$this->userManager, $this->userSession, 'host', $this->iqRosterPushMapper, $this->db]) + ->setMethods(['createOrUpdateRosterItem', 'removeRosterItem'])->getMock(); + + $user1 = $this->getMockBuilder('OCP\IUser')->getMock(); + $user2 = $this->getMockBuilder('OCP\IUser')->getMock(); + $user3 = $this->getMockBuilder('OCP\IUser')->getMock(); + + $this->userManager->expects($this->once()) + ->method('search') + ->willReturn([$user1, $user2, $user3]); + + $rosterPush->expects($this->at(0)) + ->method('createOrUpdateRosterItem') + ->with($user1); + + $rosterPush->expects($this->at(1)) + ->method('createOrUpdateRosterItem') + ->with($user2); + + $rosterPush->expects($this->at(2)) + ->method('createOrUpdateRosterItem') + ->with($user3); + + $this->db->expects($this->at(0)) + ->method('executeQuery') + ->with('SELECT `id` FROM `*PREFIX*addressbooks` WHERE `principaluri`=\'principals/system/system\' LIMIT 1') + ->willThrowException(new \Exception("A random exception")); + + $stats = $rosterPush->refreshRoster(); + + $this->assertEquals($stats, ["removed" => 0, "updated" => 3]); + } + + public function testRemoveRosterItem() + { + $user1 = $this->getMockBuilder('OCP\IUser')->getMock(); + $user1->expects($this->once()) + ->method('getUID') + ->willReturn('user1'); + $user2 = $this->getMockBuilder('OCP\IUser')->getMock(); + $user2->expects($this->exactly(2)) + ->method('getUID') + ->willReturn('user2'); + $user3 = $this->getMockBuilder('OCP\IUser')->getMock(); + $user3->expects($this->exactly(2)) + ->method('getUID') + ->willReturn('user3'); + + $this->userManager->expects($this->once()) + ->method('search') + ->willReturn([$user1, $user2, $user3]); + + $stanza1 = new IQRosterPush(); + $stanza1->setJid('user1'); + $stanza1->setSubscription('remove'); + $stanza1->setFrom(''); + $stanza1->setTo('user2'); + + $stanza2 = new IQRosterPush(); + $stanza2->setJid('user1'); + $stanza2->setSubscription('remove'); + $stanza2->setFrom(''); + $stanza2->setTo('user3'); + + $this->iqRosterPushMapper->expects($this->at(0)) + ->method('insert') + ->with($stanza1); + + $this->iqRosterPushMapper->expects($this->at(1)) + ->method('insert') + ->with($stanza2); + + $this->rosterPush->removeRosterItem('user1'); + } + + public function testCreateOrUpdateRosterItem() + { + $user1 = $this->getMockBuilder('OCP\IUser')->getMock(); + $user1->expects($this->exactly(5)) + ->method('getUID') + ->willReturn('user1'); + $user2 = $this->getMockBuilder('OCP\IUser')->getMock(); + $user2->expects($this->exactly(2)) + ->method('getUID') + ->willReturn('user2'); + $user3 = $this->getMockBuilder('OCP\IUser')->getMock(); + $user3->expects($this->exactly(2)) + ->method('getUID') + ->willReturn('user3'); + + $this->userManager->expects($this->once()) + ->method('search') + ->willReturn([$user1, $user2, $user3]); + + $stanza1 = new IQRosterPush(); + $stanza1->setJid('user1'); + $stanza1->setSubscription('both'); + $stanza1->setFrom(''); + $stanza1->setTo('user2'); + + $stanza2 = new IQRosterPush(); + $stanza2->setJid('user1'); + $stanza2->setSubscription('both'); + $stanza2->setFrom(''); + $stanza2->setTo('user3'); + + $this->iqRosterPushMapper->expects($this->at(0)) + ->method('insert') + ->with($stanza1); + + $this->iqRosterPushMapper->expects($this->at(1)) + ->method('insert') + ->with($stanza2); + + $this->rosterPush->createOrUpdateRosterItem($user1); + } +} diff --git a/tests/unit/stanzahandlers/IQTest.php b/tests/unit/stanzahandlers/IQTest.php index 8ab22be..6c15c56 100644 --- a/tests/unit/stanzahandlers/IQTest.php +++ b/tests/unit/stanzahandlers/IQTest.php @@ -3,6 +3,7 @@ namespace OCA\OJSXC\StanzaHandlers; use OCA\OJSXC\Db\IQRoster; +use OCP\IConfig; use PHPUnit_Framework_MockObject_MockObject; use PHPUnit_Framework_TestCase; @@ -29,12 +30,18 @@ class IQTest extends PHPUnit_Framework_TestCase */ private $host; + /** + * @var PHPUnit_Framework_MockObject_MockObject | IConfig + */ + private $config; + public function setUp() { $this->host = 'localhost'; $this->userId = 'john'; $this->userManager = $this->getMockBuilder('OCP\IUserManager')->disableOriginalConstructor()->getMock(); - $this->iq = new IQ($this->userId, $this->host, $this->userManager); + $this->config = $this->getMockBuilder('OCP\IConfig')->disableOriginalConstructor()->getMock(); + $this->iq = new IQ($this->userId, $this->host, $this->userManager, $this->config); } public function iqRosterProvider() @@ -144,6 +151,11 @@ class IQTest extends PHPUnit_Framework_TestCase */ public function testIqRoster(array $stanza, array $users, $searchCount, $expected) { + $this->config->expects($this->once()) + ->method('getSystemValue') + ->with('debug') + ->will($this->returnValue(false)); + $this->userManager->expects($searchCount) ->method('search') ->with('') |