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.
490 lines
15 KiB
490 lines
15 KiB
<?php
|
|
|
|
declare(strict_types=1);
|
|
/**
|
|
* SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
|
|
namespace OCA\Talk\Tests\Unit;
|
|
|
|
use OCA\Talk\Capabilities;
|
|
use OCA\Talk\Chat\CommentsManager;
|
|
use OCA\Talk\Config;
|
|
use OCA\Talk\Participant;
|
|
use OCA\Talk\Room;
|
|
use OCP\App\IAppManager;
|
|
use OCP\AppFramework\Services\IAppConfig;
|
|
use OCP\Capabilities\IPublicCapability;
|
|
use OCP\ICache;
|
|
use OCP\ICacheFactory;
|
|
use OCP\IConfig;
|
|
use OCP\IUser;
|
|
use OCP\IUserSession;
|
|
use OCP\TaskProcessing\IManager as ITaskProcessingManager;
|
|
use OCP\TaskProcessing\TaskTypes\TextToTextFormalization;
|
|
use OCP\TaskProcessing\TaskTypes\TextToTextSummary;
|
|
use OCP\TaskProcessing\TaskTypes\TextToTextTranslate;
|
|
use OCP\Translation\ITranslationManager;
|
|
use PHPUnit\Framework\MockObject\MockObject;
|
|
use Test\TestCase;
|
|
|
|
class CapabilitiesTest extends TestCase {
|
|
protected IConfig&MockObject $serverConfig;
|
|
protected Config&MockObject $talkConfig;
|
|
protected IAppConfig&MockObject $appConfig;
|
|
protected CommentsManager&MockObject $commentsManager;
|
|
protected IUserSession&MockObject $userSession;
|
|
protected IAppManager&MockObject $appManager;
|
|
protected ITranslationManager&MockObject $translationManager;
|
|
protected ITaskProcessingManager&MockObject $taskProcessingManager;
|
|
protected ICacheFactory&MockObject $cacheFactory;
|
|
protected ICache&MockObject $talkCache;
|
|
|
|
public function setUp(): void {
|
|
parent::setUp();
|
|
$this->serverConfig = $this->createMock(IConfig::class);
|
|
$this->talkConfig = $this->createMock(Config::class);
|
|
$this->appConfig = $this->createMock(IAppConfig::class);
|
|
$this->commentsManager = $this->createMock(CommentsManager::class);
|
|
$this->userSession = $this->createMock(IUserSession::class);
|
|
$this->appManager = $this->createMock(IAppManager::class);
|
|
$this->translationManager = $this->createMock(ITranslationManager::class);
|
|
$this->taskProcessingManager = $this->createMock(ITaskProcessingManager::class);
|
|
$this->cacheFactory = $this->createMock(ICacheFactory::class);
|
|
$this->talkCache = $this->createMock(ICache::class);
|
|
|
|
$this->cacheFactory->method('createLocal')
|
|
->with('talk::')
|
|
->willReturn($this->talkCache);
|
|
|
|
$this->commentsManager->expects($this->any())
|
|
->method('supportReactions')
|
|
->willReturn(true);
|
|
|
|
$this->appManager->expects($this->any())
|
|
->method('getAppVersion')
|
|
->with('spreed')
|
|
->willReturn('1.2.3');
|
|
}
|
|
|
|
protected function getCapabilities(): Capabilities {
|
|
return new Capabilities(
|
|
$this->serverConfig,
|
|
$this->talkConfig,
|
|
$this->appConfig,
|
|
$this->commentsManager,
|
|
$this->userSession,
|
|
$this->appManager,
|
|
$this->translationManager,
|
|
$this->taskProcessingManager,
|
|
$this->cacheFactory,
|
|
);
|
|
}
|
|
|
|
public function testGetCapabilitiesGuest(): void {
|
|
$capabilities = $this->getCapabilities();
|
|
|
|
$this->userSession->expects($this->once())
|
|
->method('getUser')
|
|
->willReturn(null);
|
|
|
|
$this->talkConfig->expects($this->never())
|
|
->method('isDisabledForUser');
|
|
|
|
$this->talkConfig->method('getConversationsListStyle')
|
|
->willReturn('two-lines');
|
|
|
|
$this->talkConfig->expects($this->once())
|
|
->method('isBreakoutRoomsEnabled')
|
|
->willReturn(false);
|
|
|
|
$this->serverConfig->expects($this->any())
|
|
->method('getAppValue')
|
|
->willReturnMap([
|
|
['spreed', 'has_reference_id', 'no', 'no'],
|
|
['spreed', 'max-gif-size', '3145728', '200000'],
|
|
['spreed', 'start_calls', (string)Room::START_CALL_EVERYONE, (string)Room::START_CALL_EVERYONE],
|
|
['spreed', 'session-ping-limit', '200', '200'],
|
|
['core', 'backgroundjobs_mode', 'ajax', 'cron'],
|
|
]);
|
|
|
|
$this->appConfig->method('getAppValueInt')
|
|
->willReturnMap([
|
|
['max_call_duration', 0, 0],
|
|
['retention_event_rooms', 28, 28],
|
|
['retention_phone_rooms', 7, 7],
|
|
['retention_instant_meetings', 1, 1],
|
|
]);
|
|
|
|
$this->assertInstanceOf(IPublicCapability::class, $capabilities);
|
|
$this->assertSame([
|
|
'spreed' => [
|
|
'features' => array_merge(
|
|
Capabilities::FEATURES, [
|
|
'message-expiration',
|
|
'reactions',
|
|
]
|
|
),
|
|
'features-local' => Capabilities::LOCAL_FEATURES,
|
|
'config' => [
|
|
'attachments' => [
|
|
'allowed' => false,
|
|
],
|
|
'call' => [
|
|
'enabled' => true,
|
|
'breakout-rooms' => false,
|
|
'recording' => false,
|
|
'recording-consent' => 0,
|
|
'supported-reactions' => ['❤️', '🎉', '👏', '👋', '👍', '👎', '🔥', '😂', '🤩', '🤔', '😲', '😥'],
|
|
'can-upload-background' => false,
|
|
'sip-enabled' => false,
|
|
'sip-dialout-enabled' => false,
|
|
'can-enable-sip' => false,
|
|
'start-without-media' => false,
|
|
'max-duration' => 0,
|
|
'blur-virtual-background' => false,
|
|
'end-to-end-encryption' => false,
|
|
'predefined-backgrounds' => [
|
|
'1_office.jpg',
|
|
'2_home.jpg',
|
|
'3_abstract.jpg',
|
|
'4_beach.jpg',
|
|
'5_park.jpg',
|
|
'6_theater.jpg',
|
|
'7_library.jpg',
|
|
'8_space_station.jpg',
|
|
],
|
|
'predefined-backgrounds-v2' => [
|
|
'/img/backgrounds/1_office.jpg',
|
|
'/img/backgrounds/2_home.jpg',
|
|
'/img/backgrounds/3_abstract.jpg',
|
|
'/img/backgrounds/4_beach.jpg',
|
|
'/img/backgrounds/5_park.jpg',
|
|
'/img/backgrounds/6_theater.jpg',
|
|
'/img/backgrounds/7_library.jpg',
|
|
'/img/backgrounds/8_space_station.jpg',
|
|
],
|
|
],
|
|
'chat' => [
|
|
'max-length' => 32000,
|
|
'read-privacy' => 0,
|
|
'has-translation-providers' => false,
|
|
'has-translation-task-providers' => false,
|
|
'typing-privacy' => 0,
|
|
'summary-threshold' => 100,
|
|
],
|
|
'conversations' => [
|
|
'can-create' => false,
|
|
'force-passwords' => false,
|
|
'list-style' => 'two-lines',
|
|
'description-length' => 2000,
|
|
'retention-event' => 28,
|
|
'retention-phone' => 7,
|
|
'retention-instant-meetings' => 1,
|
|
],
|
|
'federation' => [
|
|
'enabled' => false,
|
|
'incoming-enabled' => false,
|
|
'outgoing-enabled' => false,
|
|
'only-trusted-servers' => true,
|
|
],
|
|
'previews' => [
|
|
'max-gif-size' => 200000,
|
|
],
|
|
'signaling' => [
|
|
'session-ping-limit' => 200,
|
|
],
|
|
],
|
|
'config-local' => Capabilities::LOCAL_CONFIGS,
|
|
'version' => '1.2.3',
|
|
],
|
|
], $capabilities->getCapabilities());
|
|
}
|
|
|
|
public static function dataGetCapabilitiesUserAllowed(): array {
|
|
return [
|
|
[true, false, 'none', true, Participant::PRIVACY_PRIVATE],
|
|
[false, true, '1 MB', true, Participant::PRIVACY_PUBLIC],
|
|
[false, true, '0 B', false, Participant::PRIVACY_PUBLIC],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @dataProvider dataGetCapabilitiesUserAllowed
|
|
*/
|
|
public function testGetCapabilitiesUserAllowed(bool $isNotAllowed, bool $canCreate, string $quota, bool $canUpload, int $readPrivacy): void {
|
|
$capabilities = $this->getCapabilities();
|
|
|
|
$user = $this->createMock(IUser::class);
|
|
$user->expects($this->atLeastOnce())
|
|
->method('getUID')
|
|
->willReturn('uid');
|
|
$this->userSession->expects($this->once())
|
|
->method('getUser')
|
|
->willReturn($user);
|
|
|
|
$this->talkConfig->expects($this->once())
|
|
->method('isDisabledForUser')
|
|
->with($user)
|
|
->willReturn(false);
|
|
|
|
$this->talkConfig->expects($this->once())
|
|
->method('isBreakoutRoomsEnabled')
|
|
->willReturn(true);
|
|
|
|
$this->talkConfig->expects($this->once())
|
|
->method('getAttachmentFolder')
|
|
->with('uid')
|
|
->willReturn('/Talk');
|
|
|
|
$this->talkConfig->expects($this->once())
|
|
->method('isNotAllowedToCreateConversations')
|
|
->with($user)
|
|
->willReturn($isNotAllowed);
|
|
|
|
$this->talkConfig->expects($this->once())
|
|
->method('getUserReadPrivacy')
|
|
->with('uid')
|
|
->willReturn($readPrivacy);
|
|
|
|
$this->talkConfig->method('getConversationsListStyle')
|
|
->willReturn('two-lines');
|
|
|
|
$user->method('getQuota')
|
|
->willReturn($quota);
|
|
|
|
$this->taskProcessingManager->method('getAvailableTaskTypes')
|
|
->willReturn([TextToTextSummary::ID => true]);
|
|
|
|
$this->serverConfig->expects($this->any())
|
|
->method('getAppValue')
|
|
->willReturnMap([
|
|
['spreed', 'has_reference_id', 'no', 'yes'],
|
|
['spreed', 'max-gif-size', '3145728', '200000'],
|
|
['spreed', 'start_calls', (string)Room::START_CALL_EVERYONE, (string)Room::START_CALL_NOONE],
|
|
['spreed', 'session-ping-limit', '200', '50'],
|
|
['core', 'backgroundjobs_mode', 'ajax', 'cron'],
|
|
]);
|
|
|
|
$this->appConfig->expects($this->any())
|
|
->method('getAppValueBool')
|
|
->willReturnMap([
|
|
['backgrounds_default_for_users', true, true],
|
|
['backgrounds_upload_users', true, true],
|
|
]);
|
|
|
|
$this->appConfig->method('getAppValueInt')
|
|
->willReturnMap([
|
|
['max_call_duration', 0, 0],
|
|
['retention_event_rooms', 28, 28],
|
|
['retention_phone_rooms', 7, 7],
|
|
['retention_instant_meetings', 1, 1],
|
|
]);
|
|
|
|
$this->assertInstanceOf(IPublicCapability::class, $capabilities);
|
|
$data = $capabilities->getCapabilities();
|
|
$this->assertSame([
|
|
'spreed' => [
|
|
'features' => array_merge(
|
|
Capabilities::FEATURES, [
|
|
'message-expiration',
|
|
'reactions',
|
|
'chat-summary-api',
|
|
]
|
|
),
|
|
'features-local' => Capabilities::LOCAL_FEATURES,
|
|
'config' => [
|
|
'attachments' => [
|
|
'allowed' => true,
|
|
'folder' => '/Talk',
|
|
],
|
|
'call' => [
|
|
'enabled' => false,
|
|
'breakout-rooms' => true,
|
|
'recording' => false,
|
|
'recording-consent' => 0,
|
|
'supported-reactions' => ['❤️', '🎉', '👏', '👋', '👍', '👎', '🔥', '😂', '🤩', '🤔', '😲', '😥'],
|
|
'can-upload-background' => $canUpload,
|
|
'sip-enabled' => false,
|
|
'sip-dialout-enabled' => false,
|
|
'can-enable-sip' => false,
|
|
'start-without-media' => false,
|
|
'max-duration' => 0,
|
|
'blur-virtual-background' => false,
|
|
'end-to-end-encryption' => false,
|
|
'predefined-backgrounds' => [
|
|
'1_office.jpg',
|
|
'2_home.jpg',
|
|
'3_abstract.jpg',
|
|
'4_beach.jpg',
|
|
'5_park.jpg',
|
|
'6_theater.jpg',
|
|
'7_library.jpg',
|
|
'8_space_station.jpg',
|
|
],
|
|
'predefined-backgrounds-v2' => [
|
|
'/img/backgrounds/1_office.jpg',
|
|
'/img/backgrounds/2_home.jpg',
|
|
'/img/backgrounds/3_abstract.jpg',
|
|
'/img/backgrounds/4_beach.jpg',
|
|
'/img/backgrounds/5_park.jpg',
|
|
'/img/backgrounds/6_theater.jpg',
|
|
'/img/backgrounds/7_library.jpg',
|
|
'/img/backgrounds/8_space_station.jpg',
|
|
],
|
|
],
|
|
'chat' => [
|
|
'max-length' => 32000,
|
|
'read-privacy' => $readPrivacy,
|
|
'has-translation-providers' => false,
|
|
'has-translation-task-providers' => false,
|
|
'typing-privacy' => 0,
|
|
'summary-threshold' => 100,
|
|
],
|
|
'conversations' => [
|
|
'can-create' => $canCreate,
|
|
'force-passwords' => false,
|
|
'list-style' => 'two-lines',
|
|
'description-length' => 2000,
|
|
'retention-event' => 28,
|
|
'retention-phone' => 7,
|
|
'retention-instant-meetings' => 1,
|
|
],
|
|
'federation' => [
|
|
'enabled' => false,
|
|
'incoming-enabled' => false,
|
|
'outgoing-enabled' => false,
|
|
'only-trusted-servers' => true,
|
|
],
|
|
'previews' => [
|
|
'max-gif-size' => 200000,
|
|
],
|
|
'signaling' => [
|
|
'session-ping-limit' => 50,
|
|
],
|
|
],
|
|
'config-local' => Capabilities::LOCAL_CONFIGS,
|
|
'version' => '1.2.3',
|
|
],
|
|
], $data);
|
|
}
|
|
|
|
public function testCapabilitiesDocumentation(): void {
|
|
foreach (Capabilities::FEATURES as $feature) {
|
|
$suffix = '';
|
|
if (in_array($feature, Capabilities::LOCAL_FEATURES)) {
|
|
$suffix = ' (local)';
|
|
}
|
|
$this->assertCapabilityIsDocumented("`$feature`" . $suffix);
|
|
}
|
|
|
|
foreach (Capabilities::CONDITIONAL_FEATURES as $feature) {
|
|
$suffix = '';
|
|
if (in_array($feature, Capabilities::LOCAL_FEATURES)) {
|
|
$suffix = ' (local)';
|
|
}
|
|
$this->assertCapabilityIsDocumented("`$feature`" . $suffix);
|
|
}
|
|
|
|
$openapi = json_decode(file_get_contents(__DIR__ . '/../../openapi.json'), true, flags: JSON_THROW_ON_ERROR);
|
|
$configDefinition = $openapi['components']['schemas']['Capabilities']['properties']['config']['properties'] ?? null;
|
|
$this->assertIsArray($configDefinition, 'Failed to read Capabilities config from openapi.json');
|
|
|
|
$configFeatures = array_keys($configDefinition);
|
|
|
|
foreach ($configFeatures as $feature) {
|
|
foreach (array_keys($configDefinition[$feature]['properties']) as $config) {
|
|
$suffix = '';
|
|
if (isset($data['spreed']['config-local'][$feature]) && in_array($config, Capabilities::LOCAL_CONFIGS[$feature])) {
|
|
$suffix = ' (local)';
|
|
}
|
|
$this->assertCapabilityIsDocumented("`config => $feature => $config`" . $suffix);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected function assertCapabilityIsDocumented(string $capability): void {
|
|
$docs = file_get_contents(__DIR__ . '/../../docs/capabilities.md');
|
|
self::assertStringContainsString($capability, $docs, 'Asserting that capability ' . $capability . ' is documented');
|
|
}
|
|
|
|
public function testGetCapabilitiesUserDisallowed(): void {
|
|
$capabilities = $this->getCapabilities();
|
|
|
|
$user = $this->createMock(IUser::class);
|
|
$this->userSession->expects($this->once())
|
|
->method('getUser')
|
|
->willReturn($user);
|
|
|
|
$this->talkConfig->expects($this->once())
|
|
->method('isDisabledForUser')
|
|
->with($user)
|
|
->willReturn(true);
|
|
|
|
$this->assertInstanceOf(IPublicCapability::class, $capabilities);
|
|
$this->assertSame([], $capabilities->getCapabilities());
|
|
}
|
|
|
|
public function testCapabilitiesHelloV2Key(): void {
|
|
$capabilities = $this->getCapabilities();
|
|
|
|
$this->talkConfig->expects($this->once())
|
|
->method('getSignalingTokenPublicKey')
|
|
->willReturn('this-is-the-key');
|
|
|
|
$data = $capabilities->getCapabilities();
|
|
$this->assertEquals('this-is-the-key', $data['spreed']['config']['signaling']['hello-v2-token-key']);
|
|
}
|
|
|
|
public static function dataTestConfigRecording(): array {
|
|
return [
|
|
[true],
|
|
[false],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @dataProvider dataTestConfigRecording
|
|
*/
|
|
public function testConfigRecording(bool $enabled): void {
|
|
$capabilities = $this->getCapabilities();
|
|
|
|
$this->talkConfig->expects($this->once())
|
|
->method('isRecordingEnabled')
|
|
->willReturn($enabled);
|
|
|
|
$data = $capabilities->getCapabilities();
|
|
$this->assertEquals($data['spreed']['config']['call']['recording'], $enabled);
|
|
}
|
|
|
|
public function testCapabilitiesTranslations(): void {
|
|
$capabilities = $this->getCapabilities();
|
|
|
|
$this->translationManager->method('hasProviders')
|
|
->willReturn(true);
|
|
|
|
$data = json_decode(json_encode($capabilities->getCapabilities(), JSON_THROW_ON_ERROR), true);
|
|
$this->assertEquals(true, $data['spreed']['config']['chat']['has-translation-providers']);
|
|
}
|
|
|
|
public function testCapabilitiesTranslationsTaskProviders(): void {
|
|
$capabilities = $this->getCapabilities();
|
|
|
|
$this->taskProcessingManager->method('getAvailableTaskTypes')
|
|
->willReturn([TextToTextTranslate::ID => true]);
|
|
|
|
$data = json_decode(json_encode($capabilities->getCapabilities(), JSON_THROW_ON_ERROR), true);
|
|
$this->assertEquals(true, $data['spreed']['config']['chat']['has-translation-task-providers']);
|
|
}
|
|
|
|
public function testSummaryTaskProviders(): void {
|
|
$capabilities = $this->getCapabilities();
|
|
|
|
$this->taskProcessingManager->method('getAvailableTaskTypes')
|
|
->willReturn([TextToTextFormalization::ID => true]);
|
|
|
|
$data = json_decode(json_encode($capabilities->getCapabilities(), JSON_THROW_ON_ERROR), true);
|
|
$this->assertNotContains('chat-summary-api', $data['spreed']['features']);
|
|
}
|
|
}
|