You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

470 lines
13 KiB

  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @copyright Copyright (c) 2018, Joas Schilling <coding@schilljs.com>
  5. *
  6. * @author Joas Schilling <coding@schilljs.com>
  7. *
  8. * @license GNU AGPL version 3 or any later version
  9. *
  10. * This program is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Affero General Public License as
  12. * published by the Free Software Foundation, either version 3 of the
  13. * License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU Affero General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Affero General Public License
  21. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. *
  23. */
  24. namespace OCA\Talk\Tests\Unit;
  25. use OCA\Talk\Capabilities;
  26. use OCA\Talk\Chat\CommentsManager;
  27. use OCA\Talk\Config;
  28. use OCA\Talk\Participant;
  29. use OCA\Talk\Room;
  30. use OCP\App\IAppManager;
  31. use OCP\Capabilities\IPublicCapability;
  32. use OCP\ICache;
  33. use OCP\ICacheFactory;
  34. use OCP\IConfig;
  35. use OCP\IUser;
  36. use OCP\IUserSession;
  37. use OCP\Translation\ITranslationManager;
  38. use PHPUnit\Framework\MockObject\MockObject;
  39. use Test\TestCase;
  40. class CapabilitiesTest extends TestCase {
  41. protected IConfig|MockObject $serverConfig;
  42. protected Config|MockObject $talkConfig;
  43. protected CommentsManager|MockObject $commentsManager;
  44. protected IUserSession|MockObject $userSession;
  45. protected IAppManager|MockObject $appManager;
  46. protected ITranslationManager|MockObject $translationManager;
  47. protected ICacheFactory|MockObject $cacheFactory;
  48. protected ICache|MockObject $talkCache;
  49. protected ?array $baseFeatures = null;
  50. public function setUp(): void {
  51. parent::setUp();
  52. $this->serverConfig = $this->createMock(IConfig::class);
  53. $this->talkConfig = $this->createMock(Config::class);
  54. $this->commentsManager = $this->createMock(CommentsManager::class);
  55. $this->userSession = $this->createMock(IUserSession::class);
  56. $this->appManager = $this->createMock(IAppManager::class);
  57. $this->translationManager = $this->createMock(ITranslationManager::class);
  58. $this->cacheFactory = $this->createMock(ICacheFactory::class);
  59. $this->talkCache = $this->createMock(ICache::class);
  60. $this->cacheFactory->method('createLocal')
  61. ->with('talk::')
  62. ->willReturn($this->talkCache);
  63. $this->commentsManager->expects($this->any())
  64. ->method('supportReactions')
  65. ->willReturn(true);
  66. $this->appManager->expects($this->any())
  67. ->method('getAppVersion')
  68. ->with('spreed')
  69. ->willReturn('1.2.3');
  70. $this->baseFeatures = [
  71. 'audio',
  72. 'video',
  73. 'chat-v2',
  74. 'conversation-v4',
  75. 'guest-signaling',
  76. 'empty-group-room',
  77. 'guest-display-names',
  78. 'multi-room-users',
  79. 'favorites',
  80. 'last-room-activity',
  81. 'no-ping',
  82. 'system-messages',
  83. 'delete-messages',
  84. 'mention-flag',
  85. 'in-call-flags',
  86. 'conversation-call-flags',
  87. 'notification-levels',
  88. 'invite-groups-and-mails',
  89. 'locked-one-to-one-rooms',
  90. 'read-only-rooms',
  91. 'listable-rooms',
  92. 'chat-read-marker',
  93. 'chat-unread',
  94. 'webinary-lobby',
  95. 'start-call-flag',
  96. 'chat-replies',
  97. 'circles-support',
  98. 'force-mute',
  99. 'sip-support',
  100. 'sip-support-nopin',
  101. 'chat-read-status',
  102. 'phonebook-search',
  103. 'raise-hand',
  104. 'room-description',
  105. 'rich-object-sharing',
  106. 'temp-user-avatar-api',
  107. 'geo-location-sharing',
  108. 'voice-message-sharing',
  109. 'signaling-v3',
  110. 'publishing-permissions',
  111. 'clear-history',
  112. 'direct-mention-flag',
  113. 'notification-calls',
  114. 'conversation-permissions',
  115. 'rich-object-list-media',
  116. 'rich-object-delete',
  117. 'unified-search',
  118. 'chat-permission',
  119. 'silent-send',
  120. 'silent-call',
  121. 'send-call-notification',
  122. 'talk-polls',
  123. 'breakout-rooms-v1',
  124. 'recording-v1',
  125. 'avatar',
  126. 'chat-get-context',
  127. 'single-conversation-status',
  128. 'chat-keep-notifications',
  129. 'typing-privacy',
  130. 'remind-me-later',
  131. 'bots-v1',
  132. 'markdown-messages',
  133. 'media-caption',
  134. 'session-state',
  135. 'note-to-self',
  136. 'recording-consent',
  137. 'sip-support-dialout',
  138. 'delete-messages-unlimited',
  139. 'edit-messages',
  140. 'silent-send-state',
  141. 'message-expiration',
  142. 'reactions',
  143. ];
  144. }
  145. public function testGetCapabilitiesGuest(): void {
  146. $capabilities = new Capabilities(
  147. $this->serverConfig,
  148. $this->talkConfig,
  149. $this->commentsManager,
  150. $this->userSession,
  151. $this->appManager,
  152. $this->translationManager,
  153. $this->cacheFactory,
  154. );
  155. $this->userSession->expects($this->once())
  156. ->method('getUser')
  157. ->willReturn(null);
  158. $this->talkConfig->expects($this->never())
  159. ->method('isDisabledForUser');
  160. $this->talkConfig->expects($this->once())
  161. ->method('isBreakoutRoomsEnabled')
  162. ->willReturn(false);
  163. $this->serverConfig->expects($this->any())
  164. ->method('getAppValue')
  165. ->willReturnMap([
  166. ['spreed', 'has_reference_id', 'no', 'no'],
  167. ['spreed', 'max-gif-size', '3145728', '200000'],
  168. ['spreed', 'start_calls', (string) Room::START_CALL_EVERYONE, (string) Room::START_CALL_EVERYONE],
  169. ['spreed', 'session-ping-limit', '200', '200'],
  170. ['core', 'backgroundjobs_mode', 'ajax', 'cron'],
  171. ]);
  172. $this->assertInstanceOf(IPublicCapability::class, $capabilities);
  173. $this->assertSame([
  174. 'spreed' => [
  175. 'features' => $this->baseFeatures,
  176. 'config' => [
  177. 'attachments' => [
  178. 'allowed' => false,
  179. ],
  180. 'call' => [
  181. 'enabled' => true,
  182. 'breakout-rooms' => false,
  183. 'recording' => false,
  184. 'recording-consent' => 0,
  185. 'supported-reactions' => ['❤️', '🎉', '👏', '👍', '👎', '😂', '🤩', '🤔', '😲', '😥'],
  186. 'sip-enabled' => false,
  187. 'sip-dialout-enabled' => false,
  188. 'predefined-backgrounds' => [
  189. '1_office.jpg',
  190. '2_home.jpg',
  191. '3_abstract.jpg',
  192. '4_beach.jpg',
  193. '5_park.jpg',
  194. '6_theater.jpg',
  195. '7_library.jpg',
  196. '8_space_station.jpg',
  197. ],
  198. 'can-upload-background' => false,
  199. 'can-enable-sip' => false,
  200. ],
  201. 'chat' => [
  202. 'max-length' => 32000,
  203. 'read-privacy' => 0,
  204. 'has-translation-providers' => false,
  205. 'typing-privacy' => 0,
  206. ],
  207. 'conversations' => [
  208. 'can-create' => false,
  209. ],
  210. 'previews' => [
  211. 'max-gif-size' => 200000,
  212. ],
  213. 'signaling' => [
  214. 'session-ping-limit' => 200,
  215. ],
  216. ],
  217. 'version' => '1.2.3',
  218. ],
  219. ], $capabilities->getCapabilities());
  220. }
  221. public static function dataGetCapabilitiesUserAllowed(): array {
  222. return [
  223. [true, false, 'none', true, Participant::PRIVACY_PRIVATE],
  224. [false, true, '1 MB', true, Participant::PRIVACY_PUBLIC],
  225. [false, true, '0 B', false, Participant::PRIVACY_PUBLIC],
  226. ];
  227. }
  228. /**
  229. * @dataProvider dataGetCapabilitiesUserAllowed
  230. * @param bool $isNotAllowed
  231. * @param bool $canCreate
  232. * @param string $quota
  233. * @param bool $canUpload
  234. * @param int $readPrivacy
  235. */
  236. public function testGetCapabilitiesUserAllowed(bool $isNotAllowed, bool $canCreate, string $quota, bool $canUpload, int $readPrivacy): void {
  237. $capabilities = new Capabilities(
  238. $this->serverConfig,
  239. $this->talkConfig,
  240. $this->commentsManager,
  241. $this->userSession,
  242. $this->appManager,
  243. $this->translationManager,
  244. $this->cacheFactory,
  245. );
  246. $user = $this->createMock(IUser::class);
  247. $user->expects($this->atLeastOnce())
  248. ->method('getUID')
  249. ->willReturn('uid');
  250. $this->userSession->expects($this->once())
  251. ->method('getUser')
  252. ->willReturn($user);
  253. $this->talkConfig->expects($this->once())
  254. ->method('isDisabledForUser')
  255. ->with($user)
  256. ->willReturn(false);
  257. $this->talkConfig->expects($this->once())
  258. ->method('isBreakoutRoomsEnabled')
  259. ->willReturn(true);
  260. $this->talkConfig->expects($this->once())
  261. ->method('getAttachmentFolder')
  262. ->with('uid')
  263. ->willReturn('/Talk');
  264. $this->talkConfig->expects($this->once())
  265. ->method('isNotAllowedToCreateConversations')
  266. ->with($user)
  267. ->willReturn($isNotAllowed);
  268. $this->talkConfig->expects($this->once())
  269. ->method('getUserReadPrivacy')
  270. ->with('uid')
  271. ->willReturn($readPrivacy);
  272. $user->method('getQuota')
  273. ->willReturn($quota);
  274. $this->serverConfig->expects($this->any())
  275. ->method('getAppValue')
  276. ->willReturnMap([
  277. ['spreed', 'has_reference_id', 'no', 'yes'],
  278. ['spreed', 'max-gif-size', '3145728', '200000'],
  279. ['spreed', 'start_calls', (string) Room::START_CALL_EVERYONE, (string) Room::START_CALL_NOONE],
  280. ['spreed', 'session-ping-limit', '200', '50'],
  281. ['core', 'backgroundjobs_mode', 'ajax', 'cron'],
  282. ]);
  283. $this->assertInstanceOf(IPublicCapability::class, $capabilities);
  284. $data = $capabilities->getCapabilities();
  285. $this->assertSame([
  286. 'spreed' => [
  287. 'features' => array_merge(
  288. $this->baseFeatures, [
  289. 'chat-reference-id'
  290. ]
  291. ),
  292. 'config' => [
  293. 'attachments' => [
  294. 'allowed' => true,
  295. 'folder' => '/Talk',
  296. ],
  297. 'call' => [
  298. 'enabled' => false,
  299. 'breakout-rooms' => true,
  300. 'recording' => false,
  301. 'recording-consent' => 0,
  302. 'supported-reactions' => ['❤️', '🎉', '👏', '👍', '👎', '😂', '🤩', '🤔', '😲', '😥'],
  303. 'sip-enabled' => false,
  304. 'sip-dialout-enabled' => false,
  305. 'predefined-backgrounds' => [
  306. '1_office.jpg',
  307. '2_home.jpg',
  308. '3_abstract.jpg',
  309. '4_beach.jpg',
  310. '5_park.jpg',
  311. '6_theater.jpg',
  312. '7_library.jpg',
  313. '8_space_station.jpg',
  314. ],
  315. 'can-upload-background' => $canUpload,
  316. 'can-enable-sip' => false,
  317. ],
  318. 'chat' => [
  319. 'max-length' => 32000,
  320. 'read-privacy' => $readPrivacy,
  321. 'has-translation-providers' => false,
  322. 'typing-privacy' => 0,
  323. ],
  324. 'conversations' => [
  325. 'can-create' => $canCreate,
  326. ],
  327. 'previews' => [
  328. 'max-gif-size' => 200000,
  329. ],
  330. 'signaling' => [
  331. 'session-ping-limit' => 50,
  332. ],
  333. ],
  334. 'version' => '1.2.3',
  335. ],
  336. ], $data);
  337. foreach ($data['spreed']['features'] as $feature) {
  338. $this->assertCapabilityIsDocumented("`$feature`");
  339. }
  340. foreach ($data['spreed']['config'] as $feature => $configs) {
  341. foreach ($configs as $config => $data) {
  342. $this->assertCapabilityIsDocumented("`config => $feature => $config`");
  343. }
  344. }
  345. }
  346. protected function assertCapabilityIsDocumented(string $capability): void {
  347. $docs = file_get_contents(__DIR__ . '/../../docs/capabilities.md');
  348. self::assertStringContainsString($capability, $docs, 'Asserting that capability ' . $capability . ' is documented');
  349. }
  350. public function testGetCapabilitiesUserDisallowed(): void {
  351. $capabilities = new Capabilities(
  352. $this->serverConfig,
  353. $this->talkConfig,
  354. $this->commentsManager,
  355. $this->userSession,
  356. $this->appManager,
  357. $this->translationManager,
  358. $this->cacheFactory,
  359. );
  360. $user = $this->createMock(IUser::class);
  361. $this->userSession->expects($this->once())
  362. ->method('getUser')
  363. ->willReturn($user);
  364. $this->talkConfig->expects($this->once())
  365. ->method('isDisabledForUser')
  366. ->with($user)
  367. ->willReturn(true);
  368. $this->assertInstanceOf(IPublicCapability::class, $capabilities);
  369. $this->assertSame([], $capabilities->getCapabilities());
  370. }
  371. public function testCapabilitiesHelloV2Key(): void {
  372. $capabilities = new Capabilities(
  373. $this->serverConfig,
  374. $this->talkConfig,
  375. $this->commentsManager,
  376. $this->userSession,
  377. $this->appManager,
  378. $this->translationManager,
  379. $this->cacheFactory,
  380. );
  381. $this->talkConfig->expects($this->once())
  382. ->method('getSignalingTokenPublicKey')
  383. ->willReturn('this-is-the-key');
  384. $data = $capabilities->getCapabilities();
  385. $this->assertEquals('this-is-the-key', $data['spreed']['config']['signaling']['hello-v2-token-key']);
  386. }
  387. /**
  388. * @dataProvider dataTestConfigRecording
  389. */
  390. public function testConfigRecording(bool $enabled): void {
  391. $capabilities = new Capabilities(
  392. $this->serverConfig,
  393. $this->talkConfig,
  394. $this->commentsManager,
  395. $this->userSession,
  396. $this->appManager,
  397. $this->translationManager,
  398. $this->cacheFactory,
  399. );
  400. $this->talkConfig->expects($this->once())
  401. ->method('isRecordingEnabled')
  402. ->willReturn($enabled);
  403. $data = $capabilities->getCapabilities();
  404. $this->assertEquals($data['spreed']['config']['call']['recording'], $enabled);
  405. }
  406. public static function dataTestConfigRecording(): array {
  407. return [
  408. [true],
  409. [false],
  410. ];
  411. }
  412. public function testCapabilitiesTranslations(): void {
  413. $capabilities = new Capabilities(
  414. $this->serverConfig,
  415. $this->talkConfig,
  416. $this->commentsManager,
  417. $this->userSession,
  418. $this->appManager,
  419. $this->translationManager,
  420. $this->cacheFactory,
  421. );
  422. $this->translationManager->method('hasProviders')
  423. ->willReturn(true);
  424. $data = json_decode(json_encode($capabilities->getCapabilities(), JSON_THROW_ON_ERROR), true);
  425. $this->assertEquals(true, $data['spreed']['config']['chat']['has-translation-providers']);
  426. }
  427. }