mirror of
https://github.com/nextcloud/server.git
synced 2026-10-22 10:16:56 +02:00
apps/viewer becomes a minimal, always enabled app again, the server side of the viewer. It keeps the user's viewer settings the way the Files app keeps its own: a config lexicon declaring them, a UserConfig service holding what the lexicon cannot say, an OCS endpoint to change one, and the settings handed to the viewer as initial state. They are the slideshow delay, and the volume of videos and audio and whether they start muted. Core keeps loading the viewer itself. It is no longer an abandoned app to clean up after, and continues the old app's versions at 9.0.0-dev.0, after 8.0.0 in 35. Assisted-by: ClaudeCode:claude-opus-5-5 Signed-off-by: John Molakvoæ <14975046+skjnldsv@users.noreply.github.com>
935 lines
26 KiB
PHP
935 lines
26 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
|
|
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
|
|
namespace Test\App;
|
|
|
|
use OC\App\AppManager;
|
|
use OC\App\DependencyAnalyzer;
|
|
use OC\App\Platform;
|
|
use OC\AppConfig;
|
|
use OC\Config\ConfigManager;
|
|
use OCP\App\AppPathNotFoundException;
|
|
use OCP\App\Events\AppDisableEvent;
|
|
use OCP\App\Events\AppEnableEvent;
|
|
use OCP\EventDispatcher\IEventDispatcher;
|
|
use OCP\ICache;
|
|
use OCP\ICacheFactory;
|
|
use OCP\IConfig;
|
|
use OCP\IGroup;
|
|
use OCP\IGroupManager;
|
|
use OCP\IURLGenerator;
|
|
use OCP\IUser;
|
|
use OCP\IUserSession;
|
|
use OCP\ServerVersion;
|
|
use PHPUnit\Framework\Attributes\DataProvider;
|
|
use PHPUnit\Framework\MockObject\MockObject;
|
|
use Psr\Log\LoggerInterface;
|
|
use Test\TestCase;
|
|
|
|
/**
|
|
* Class AppManagerTest
|
|
*
|
|
* @package Test\App
|
|
*/
|
|
class AppManagerTest extends TestCase {
|
|
protected function getAppConfig(): AppConfig&MockObject {
|
|
$appConfig = [];
|
|
$config = $this->createMock(AppConfig::class);
|
|
|
|
$config->expects($this->any())
|
|
->method('getValue')
|
|
->willReturnCallback(function ($app, $key, $default) use (&$appConfig) {
|
|
return (isset($appConfig[$app]) && isset($appConfig[$app][$key]))
|
|
? $appConfig[$app][$key]
|
|
: $default;
|
|
});
|
|
$config->expects($this->any())
|
|
->method('setValue')
|
|
->willReturnCallback(function ($app, $key, $value) use (&$appConfig): void {
|
|
if (!isset($appConfig[$app])) {
|
|
$appConfig[$app] = [];
|
|
}
|
|
$appConfig[$app][$key] = $value;
|
|
});
|
|
$config->expects($this->any())
|
|
->method('getValues')
|
|
->willReturnCallback(function ($app, $key) use (&$appConfig) {
|
|
if ($app) {
|
|
return $appConfig[$app];
|
|
} else {
|
|
$values = [];
|
|
foreach ($appConfig as $appid => $appData) {
|
|
if (isset($appData[$key])) {
|
|
$values[$appid] = $appData[$key];
|
|
}
|
|
}
|
|
return $values;
|
|
}
|
|
});
|
|
$config->expects($this->any())
|
|
->method('searchValues')
|
|
->willReturnCallback(function ($key, $lazy, $type) use (&$appConfig) {
|
|
$values = [];
|
|
foreach ($appConfig as $appid => $appData) {
|
|
if (isset($appData[$key])) {
|
|
$values[$appid] = $appData[$key];
|
|
}
|
|
}
|
|
return $values;
|
|
});
|
|
|
|
return $config;
|
|
}
|
|
|
|
protected IUserSession&MockObject $userSession;
|
|
private IConfig&MockObject $config;
|
|
protected IGroupManager&MockObject $groupManager;
|
|
protected AppConfig&MockObject $appConfig;
|
|
protected ICache&MockObject $cache;
|
|
protected ICacheFactory&MockObject $cacheFactory;
|
|
protected IEventDispatcher&MockObject $eventDispatcher;
|
|
protected LoggerInterface&MockObject $logger;
|
|
protected IURLGenerator&MockObject $urlGenerator;
|
|
protected ServerVersion&MockObject $serverVersion;
|
|
protected ConfigManager&MockObject $configManager;
|
|
|
|
protected DependencyAnalyzer $dependencyAnalyzer;
|
|
|
|
protected AppManager $manager;
|
|
|
|
#[\Override]
|
|
protected function setUp(): void {
|
|
parent::setUp();
|
|
|
|
$this->userSession = $this->createMock(IUserSession::class);
|
|
$this->groupManager = $this->createMock(IGroupManager::class);
|
|
$this->config = $this->createMock(IConfig::class);
|
|
$this->appConfig = $this->getAppConfig();
|
|
$this->cacheFactory = $this->createMock(ICacheFactory::class);
|
|
$this->cache = $this->createMock(ICache::class);
|
|
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
|
|
$this->logger = $this->createMock(LoggerInterface::class);
|
|
$this->urlGenerator = $this->createMock(IURLGenerator::class);
|
|
$this->serverVersion = $this->createMock(ServerVersion::class);
|
|
$this->configManager = $this->createMock(ConfigManager::class);
|
|
$this->dependencyAnalyzer = new DependencyAnalyzer($this->createMock(Platform::class));
|
|
|
|
$this->overwriteService(AppConfig::class, $this->appConfig);
|
|
$this->overwriteService(IURLGenerator::class, $this->urlGenerator);
|
|
|
|
$this->cacheFactory->expects($this->any())
|
|
->method('createDistributed')
|
|
->with('settings')
|
|
->willReturn($this->cache);
|
|
|
|
$this->config
|
|
->method('getSystemValueBool')
|
|
->with('installed', false)
|
|
->willReturn(true);
|
|
|
|
$this->manager = new AppManager(
|
|
$this->userSession,
|
|
$this->config,
|
|
$this->groupManager,
|
|
$this->cacheFactory,
|
|
$this->eventDispatcher,
|
|
$this->logger,
|
|
$this->serverVersion,
|
|
$this->configManager,
|
|
$this->dependencyAnalyzer,
|
|
);
|
|
}
|
|
|
|
#[DataProvider('dataGetAppIcon')]
|
|
public function testGetAppIcon($callback, ?bool $dark, ?string $expected): void {
|
|
$this->urlGenerator->expects($this->atLeastOnce())
|
|
->method('imagePath')
|
|
->willReturnCallback($callback);
|
|
|
|
if ($dark !== null) {
|
|
$this->assertEquals($expected, $this->manager->getAppIcon('test', $dark));
|
|
} else {
|
|
$this->assertEquals($expected, $this->manager->getAppIcon('test'));
|
|
}
|
|
}
|
|
|
|
public static function dataGetAppIcon(): array {
|
|
$nothing = function ($appId): void {
|
|
self::assertEquals('test', $appId);
|
|
throw new \RuntimeException();
|
|
};
|
|
|
|
$createCallback = function ($workingIcons) {
|
|
return function ($appId, $icon) use ($workingIcons) {
|
|
self::assertEquals('test', $appId);
|
|
if (in_array($icon, $workingIcons)) {
|
|
return '/path/' . $icon;
|
|
}
|
|
throw new \RuntimeException();
|
|
};
|
|
};
|
|
|
|
return [
|
|
'does not find anything' => [
|
|
$nothing,
|
|
false,
|
|
null,
|
|
],
|
|
'nothing if request dark but only bright available' => [
|
|
$createCallback(['app.svg']),
|
|
true,
|
|
null,
|
|
],
|
|
'nothing if request bright but only dark available' => [
|
|
$createCallback(['app-dark.svg']),
|
|
false,
|
|
null,
|
|
],
|
|
'bright and only app.svg' => [
|
|
$createCallback(['app.svg']),
|
|
false,
|
|
'/path/app.svg',
|
|
],
|
|
'dark and only app-dark.svg' => [
|
|
$createCallback(['app-dark.svg']),
|
|
true,
|
|
'/path/app-dark.svg',
|
|
],
|
|
'dark only appname -dark.svg' => [
|
|
$createCallback(['test-dark.svg']),
|
|
true,
|
|
'/path/test-dark.svg',
|
|
],
|
|
'bright and only appname.svg' => [
|
|
$createCallback(['test.svg']),
|
|
false,
|
|
'/path/test.svg',
|
|
],
|
|
'priotize custom over default' => [
|
|
$createCallback(['app.svg', 'test.svg']),
|
|
false,
|
|
'/path/test.svg',
|
|
],
|
|
'defaults to bright' => [
|
|
$createCallback(['test-dark.svg', 'test.svg']),
|
|
null,
|
|
'/path/test.svg',
|
|
],
|
|
'no dark icon on default' => [
|
|
$createCallback(['test-dark.svg', 'test.svg', 'app-dark.svg', 'app.svg']),
|
|
false,
|
|
'/path/test.svg',
|
|
],
|
|
'no bright icon on dark' => [
|
|
$createCallback(['test-dark.svg', 'test.svg', 'app-dark.svg', 'app.svg']),
|
|
true,
|
|
'/path/test-dark.svg',
|
|
],
|
|
];
|
|
}
|
|
|
|
public function testEnableApp(): void {
|
|
// making sure "files_trashbin" is disabled
|
|
if ($this->manager->isEnabledForUser('files_trashbin')) {
|
|
$this->manager->disableApp('files_trashbin');
|
|
}
|
|
$this->eventDispatcher->expects($this->once())->method('dispatchTyped')->with(new AppEnableEvent('files_trashbin'));
|
|
|
|
$this->manager->enableApp('files_trashbin');
|
|
$this->assertEquals('yes', $this->appConfig->getValue('files_trashbin', 'enabled', 'no'));
|
|
}
|
|
|
|
public function testDisableApp(): void {
|
|
$this->eventDispatcher->expects($this->once())->method('dispatchTyped')->with(new AppDisableEvent('files_trashbin'));
|
|
|
|
$this->manager->disableApp('files_trashbin');
|
|
$this->assertEquals('no', $this->appConfig->getValue('files_trashbin', 'enabled', 'no'));
|
|
}
|
|
|
|
public function testNotEnableIfNotInstalled(): void {
|
|
$this->expectException(AppPathNotFoundException::class);
|
|
$this->expectExceptionMessage('Could not find path for some_random_name_which_i_hope_is_not_an_app');
|
|
$this->appConfig->expects(self::never())
|
|
->method('setValue');
|
|
|
|
$this->manager->enableApp('some_random_name_which_i_hope_is_not_an_app');
|
|
}
|
|
|
|
public function testEnableAppForGroups(): void {
|
|
$group1 = $this->createMock(IGroup::class);
|
|
$group1->method('getGID')
|
|
->willReturn('group1');
|
|
$group2 = $this->createMock(IGroup::class);
|
|
$group2->method('getGID')
|
|
->willReturn('group2');
|
|
|
|
$groups = [$group1, $group2];
|
|
|
|
/** @var AppManager|MockObject $manager */
|
|
$manager = $this->getMockBuilder(AppManager::class)
|
|
->setConstructorArgs([
|
|
$this->userSession,
|
|
$this->config,
|
|
$this->groupManager,
|
|
$this->cacheFactory,
|
|
$this->eventDispatcher,
|
|
$this->logger,
|
|
$this->serverVersion,
|
|
$this->configManager,
|
|
$this->dependencyAnalyzer,
|
|
])
|
|
->onlyMethods([
|
|
'getAppPath',
|
|
])
|
|
->getMock();
|
|
|
|
$manager->expects($this->exactly(2))
|
|
->method('getAppPath')
|
|
->with('test')
|
|
->willReturn('apps/test');
|
|
|
|
$this->eventDispatcher->expects($this->once())
|
|
->method('dispatchTyped')
|
|
->with(new AppEnableEvent('test', ['group1', 'group2']));
|
|
|
|
$manager->enableAppForGroups('test', $groups);
|
|
$this->assertEquals('["group1","group2"]', $this->appConfig->getValue('test', 'enabled', 'no'));
|
|
}
|
|
|
|
public static function dataEnableAppForGroupsAllowedTypes(): array {
|
|
return [
|
|
[[]],
|
|
[[
|
|
'types' => [],
|
|
]],
|
|
[[
|
|
'types' => ['nickvergessen'],
|
|
]],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @param array $appInfo
|
|
*/
|
|
#[DataProvider('dataEnableAppForGroupsAllowedTypes')]
|
|
public function testEnableAppForGroupsAllowedTypes(array $appInfo): void {
|
|
$group1 = $this->createMock(IGroup::class);
|
|
$group1->method('getGID')
|
|
->willReturn('group1');
|
|
$group2 = $this->createMock(IGroup::class);
|
|
$group2->method('getGID')
|
|
->willReturn('group2');
|
|
|
|
$groups = [$group1, $group2];
|
|
|
|
/** @var AppManager|MockObject $manager */
|
|
$manager = $this->getMockBuilder(AppManager::class)
|
|
->setConstructorArgs([
|
|
$this->userSession,
|
|
$this->config,
|
|
$this->groupManager,
|
|
$this->cacheFactory,
|
|
$this->eventDispatcher,
|
|
$this->logger,
|
|
$this->serverVersion,
|
|
$this->configManager,
|
|
$this->dependencyAnalyzer,
|
|
])
|
|
->onlyMethods([
|
|
'getAppPath',
|
|
'getAppInfo',
|
|
])
|
|
->getMock();
|
|
|
|
$manager->expects($this->once())
|
|
->method('getAppPath')
|
|
->with('test')
|
|
->willReturn('');
|
|
|
|
$manager->expects($this->once())
|
|
->method('getAppInfo')
|
|
->with('test')
|
|
->willReturn($appInfo);
|
|
|
|
$this->eventDispatcher->expects($this->once())->method('dispatchTyped')->with(new AppEnableEvent('test', ['group1', 'group2']));
|
|
|
|
$manager->enableAppForGroups('test', $groups);
|
|
$this->assertEquals('["group1","group2"]', $this->appConfig->getValue('test', 'enabled', 'no'));
|
|
}
|
|
|
|
public static function dataEnableAppForGroupsForbiddenTypes(): array {
|
|
return [
|
|
['filesystem'],
|
|
['prelogin'],
|
|
['authentication'],
|
|
['logging'],
|
|
['prevent_group_restriction'],
|
|
];
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param string $type
|
|
*
|
|
*/
|
|
#[DataProvider('dataEnableAppForGroupsForbiddenTypes')]
|
|
public function testEnableAppForGroupsForbiddenTypes($type): void {
|
|
$this->expectException(\Exception::class);
|
|
$this->expectExceptionMessage('test can\'t be enabled for groups.');
|
|
|
|
$group1 = $this->createMock(IGroup::class);
|
|
$group1->method('getGID')
|
|
->willReturn('group1');
|
|
$group2 = $this->createMock(IGroup::class);
|
|
$group2->method('getGID')
|
|
->willReturn('group2');
|
|
|
|
$groups = [$group1, $group2];
|
|
|
|
/** @var AppManager|MockObject $manager */
|
|
$manager = $this->getMockBuilder(AppManager::class)
|
|
->setConstructorArgs([
|
|
$this->userSession,
|
|
$this->config,
|
|
$this->groupManager,
|
|
$this->cacheFactory,
|
|
$this->eventDispatcher,
|
|
$this->logger,
|
|
$this->serverVersion,
|
|
$this->configManager,
|
|
$this->dependencyAnalyzer,
|
|
])
|
|
->onlyMethods([
|
|
'getAppPath',
|
|
'getAppInfo',
|
|
])
|
|
->getMock();
|
|
|
|
$manager->expects($this->once())
|
|
->method('getAppPath')
|
|
->with('test')
|
|
->willReturn('');
|
|
|
|
$manager->expects($this->once())
|
|
->method('getAppInfo')
|
|
->with('test')
|
|
->willReturn([
|
|
'types' => [$type],
|
|
]);
|
|
|
|
$this->eventDispatcher->expects($this->never())->method('dispatchTyped')->with(new AppEnableEvent('test', ['group1', 'group2']));
|
|
|
|
$manager->enableAppForGroups('test', $groups);
|
|
}
|
|
|
|
public function testIsInstalledEnabled(): void {
|
|
$this->appConfig->setValue('test', 'enabled', 'yes');
|
|
$this->assertTrue($this->manager->isEnabledForAnyone('test'));
|
|
}
|
|
|
|
public function testIsInstalledDisabled(): void {
|
|
$this->appConfig->setValue('test', 'enabled', 'no');
|
|
$this->assertFalse($this->manager->isEnabledForAnyone('test'));
|
|
}
|
|
|
|
public function testIsInstalledEnabledForGroups(): void {
|
|
$this->appConfig->setValue('test', 'enabled', '["foo"]');
|
|
$this->assertTrue($this->manager->isEnabledForAnyone('test'));
|
|
}
|
|
|
|
private function newUser($uid) {
|
|
$user = $this->createMock(IUser::class);
|
|
$user->method('getUID')
|
|
->willReturn($uid);
|
|
|
|
return $user;
|
|
}
|
|
|
|
public function testIsEnabledForUserEnabled(): void {
|
|
$this->appConfig->setValue('test', 'enabled', 'yes');
|
|
$user = $this->newUser('user1');
|
|
$this->assertTrue($this->manager->isEnabledForUser('test', $user));
|
|
}
|
|
|
|
public function testIsEnabledForUserDisabled(): void {
|
|
$this->appConfig->setValue('test', 'enabled', 'no');
|
|
$user = $this->newUser('user1');
|
|
$this->assertFalse($this->manager->isEnabledForUser('test', $user));
|
|
}
|
|
|
|
public function testGetAppPath(): void {
|
|
$this->assertEquals(\OC::$SERVERROOT . '/apps/files', $this->manager->getAppPath('files'));
|
|
}
|
|
|
|
public function testGetAppPathSymlink(): void {
|
|
$fakeAppDirname = sha1(uniqid('test', true));
|
|
$fakeAppPath = sys_get_temp_dir() . '/' . $fakeAppDirname;
|
|
$fakeAppLink = \OC::$SERVERROOT . '/' . $fakeAppDirname;
|
|
|
|
mkdir($fakeAppPath);
|
|
if (symlink($fakeAppPath, $fakeAppLink) === false) {
|
|
$this->markTestSkipped('Failed to create symlink');
|
|
}
|
|
|
|
// Use the symlink as the app path
|
|
\OC::$APPSROOTS[] = [
|
|
'path' => $fakeAppLink,
|
|
'url' => \OC::$WEBROOT . '/' . $fakeAppDirname,
|
|
'writable' => false,
|
|
];
|
|
|
|
$fakeTestAppPath = $fakeAppPath . '/' . 'test_test_app';
|
|
mkdir($fakeTestAppPath);
|
|
|
|
$generatedAppPath = $this->manager->getAppPath('test_test_app');
|
|
|
|
rmdir($fakeTestAppPath);
|
|
unlink($fakeAppLink);
|
|
rmdir($fakeAppPath);
|
|
|
|
$this->assertEquals($fakeAppLink . '/test_test_app', $generatedAppPath);
|
|
}
|
|
|
|
public function testGetAppPathFail(): void {
|
|
$this->expectException(AppPathNotFoundException::class);
|
|
$this->manager->getAppPath('testnotexisting');
|
|
}
|
|
|
|
public function testIsEnabledForUserEnabledForGroup(): void {
|
|
$user = $this->newUser('user1');
|
|
$this->groupManager->expects($this->once())
|
|
->method('getUserGroupIds')
|
|
->with($user)
|
|
->willReturn(['foo', 'bar']);
|
|
|
|
$this->appConfig->setValue('test', 'enabled', '["foo"]');
|
|
$this->assertTrue($this->manager->isEnabledForUser('test', $user));
|
|
}
|
|
|
|
public function testIsEnabledForUserDisabledForGroup(): void {
|
|
$user = $this->newUser('user1');
|
|
$this->groupManager->expects($this->once())
|
|
->method('getUserGroupIds')
|
|
->with($user)
|
|
->willReturn(['bar']);
|
|
|
|
$this->appConfig->setValue('test', 'enabled', '["foo"]');
|
|
$this->assertFalse($this->manager->isEnabledForUser('test', $user));
|
|
}
|
|
|
|
public function testIsEnabledForUserLoggedOut(): void {
|
|
$this->appConfig->setValue('test', 'enabled', '["foo"]');
|
|
$this->assertFalse($this->manager->isEnabledForUser('test'));
|
|
}
|
|
|
|
public function testIsEnabledForUserLoggedIn(): void {
|
|
$user = $this->newUser('user1');
|
|
|
|
$this->userSession->expects($this->once())
|
|
->method('getUser')
|
|
->willReturn($user);
|
|
$this->groupManager->expects($this->once())
|
|
->method('getUserGroupIds')
|
|
->with($user)
|
|
->willReturn(['foo', 'bar']);
|
|
|
|
$this->appConfig->setValue('test', 'enabled', '["foo"]');
|
|
$this->assertTrue($this->manager->isEnabledForUser('test'));
|
|
}
|
|
|
|
public function testGetEnabledApps(): void {
|
|
$this->appConfig->setValue('test1', 'enabled', 'yes');
|
|
$this->appConfig->setValue('test2', 'enabled', 'no');
|
|
$this->appConfig->setValue('test3', 'enabled', '["foo"]');
|
|
$apps = [
|
|
'appstore',
|
|
'cloud_federation_api',
|
|
'dav',
|
|
'federatedfilesharing',
|
|
'files',
|
|
'lookup_server_connector',
|
|
'oauth2',
|
|
'profile',
|
|
'provisioning_api',
|
|
'settings',
|
|
'sharing',
|
|
'test1',
|
|
'test3',
|
|
'theming',
|
|
'twofactor_backupcodes',
|
|
'viewer',
|
|
'workflowengine',
|
|
];
|
|
$this->assertEquals($apps, $this->manager->getEnabledApps());
|
|
}
|
|
|
|
public function testGetAppsForUser(): void {
|
|
$user = $this->newUser('user1');
|
|
$this->groupManager->expects($this->any())
|
|
->method('getUserGroupIds')
|
|
->with($user)
|
|
->willReturn(['foo', 'bar']);
|
|
|
|
$this->appConfig->setValue('test1', 'enabled', 'yes');
|
|
$this->appConfig->setValue('test2', 'enabled', 'no');
|
|
$this->appConfig->setValue('test3', 'enabled', '["foo"]');
|
|
$this->appConfig->setValue('test4', 'enabled', '["asd"]');
|
|
$enabled = [
|
|
'appstore',
|
|
'cloud_federation_api',
|
|
'dav',
|
|
'federatedfilesharing',
|
|
'files',
|
|
'lookup_server_connector',
|
|
'oauth2',
|
|
'profile',
|
|
'provisioning_api',
|
|
'settings',
|
|
'sharing',
|
|
'test1',
|
|
'test3',
|
|
'theming',
|
|
'twofactor_backupcodes',
|
|
'viewer',
|
|
'workflowengine',
|
|
];
|
|
$this->assertEquals($enabled, $this->manager->getEnabledAppsForUser($user));
|
|
}
|
|
|
|
public function testGetAppsNeedingUpgrade(): void {
|
|
/** @var AppManager&MockObject $manager */
|
|
$manager = $this->getMockBuilder(AppManager::class)
|
|
->setConstructorArgs([
|
|
$this->userSession,
|
|
$this->config,
|
|
$this->groupManager,
|
|
$this->cacheFactory,
|
|
$this->eventDispatcher,
|
|
$this->logger,
|
|
$this->serverVersion,
|
|
$this->configManager,
|
|
$this->dependencyAnalyzer,
|
|
])
|
|
->onlyMethods(['getAppInfo'])
|
|
->getMock();
|
|
|
|
$appInfos = [
|
|
'appstore' => ['id' => 'appstore'],
|
|
'cloud_federation_api' => ['id' => 'cloud_federation_api'],
|
|
'dav' => ['id' => 'dav'],
|
|
'files' => ['id' => 'files'],
|
|
'federatedfilesharing' => ['id' => 'federatedfilesharing'],
|
|
'profile' => ['id' => 'profile'],
|
|
'provisioning_api' => ['id' => 'provisioning_api'],
|
|
'lookup_server_connector' => ['id' => 'lookup_server_connector'],
|
|
'test1' => ['id' => 'test1', 'version' => '1.0.1', 'requiremax' => '9.0.0'],
|
|
'test2' => ['id' => 'test2', 'version' => '1.0.0', 'requiremin' => '8.2.0'],
|
|
'test3' => ['id' => 'test3', 'version' => '1.2.4', 'requiremin' => '9.0.0'],
|
|
'test4' => ['id' => 'test4', 'version' => '3.0.0', 'requiremin' => '8.1.0'],
|
|
'testnoversion' => ['id' => 'testnoversion', 'requiremin' => '8.2.0'],
|
|
'settings' => ['id' => 'settings'],
|
|
'sharing' => ['id' => 'sharing'],
|
|
'theming' => ['id' => 'theming'],
|
|
'twofactor_backupcodes' => ['id' => 'twofactor_backupcodes'],
|
|
'viewer' => ['id' => 'viewer'],
|
|
'workflowengine' => ['id' => 'workflowengine'],
|
|
'oauth2' => ['id' => 'oauth2'],
|
|
];
|
|
|
|
$manager->expects($this->any())
|
|
->method('getAppInfo')
|
|
->willReturnCallback(
|
|
function ($appId) use ($appInfos) {
|
|
return $appInfos[$appId];
|
|
}
|
|
);
|
|
|
|
$this->appConfig->setValue('test1', 'enabled', 'yes');
|
|
$this->appConfig->setValue('test1', 'installed_version', '1.0.0');
|
|
$this->appConfig->setValue('test2', 'enabled', 'yes');
|
|
$this->appConfig->setValue('test2', 'installed_version', '1.0.0');
|
|
$this->appConfig->setValue('test3', 'enabled', 'yes');
|
|
$this->appConfig->setValue('test3', 'installed_version', '1.0.0');
|
|
$this->appConfig->setValue('test4', 'enabled', 'yes');
|
|
$this->appConfig->setValue('test4', 'installed_version', '2.4.0');
|
|
|
|
$apps = $manager->getAppsNeedingUpgrade('8.2.0');
|
|
|
|
$this->assertCount(2, $apps);
|
|
$this->assertEquals('test1', $apps[0]['id']);
|
|
$this->assertEquals('test4', $apps[1]['id']);
|
|
}
|
|
|
|
public function testGetIncompatibleApps(): void {
|
|
/** @var AppManager|MockObject $manager */
|
|
$manager = $this->getMockBuilder(AppManager::class)
|
|
->setConstructorArgs([
|
|
$this->userSession,
|
|
$this->config,
|
|
$this->groupManager,
|
|
$this->cacheFactory,
|
|
$this->eventDispatcher,
|
|
$this->logger,
|
|
$this->serverVersion,
|
|
$this->configManager,
|
|
$this->dependencyAnalyzer,
|
|
])
|
|
->onlyMethods(['getAppInfo'])
|
|
->getMock();
|
|
|
|
$appInfos = [
|
|
'appstore' => ['id' => 'appstore'],
|
|
'cloud_federation_api' => ['id' => 'cloud_federation_api'],
|
|
'dav' => ['id' => 'dav'],
|
|
'files' => ['id' => 'files'],
|
|
'federatedfilesharing' => ['id' => 'federatedfilesharing'],
|
|
'profile' => ['id' => 'profile'],
|
|
'provisioning_api' => ['id' => 'provisioning_api'],
|
|
'lookup_server_connector' => ['id' => 'lookup_server_connector'],
|
|
'test1' => ['id' => 'test1', 'version' => '1.0.1', 'requiremax' => '8.0.0'],
|
|
'test2' => ['id' => 'test2', 'version' => '1.0.0', 'requiremin' => '8.2.0'],
|
|
'test3' => ['id' => 'test3', 'version' => '1.2.4', 'requiremin' => '9.0.0'],
|
|
'settings' => ['id' => 'settings'],
|
|
'sharing' => ['id' => 'sharing'],
|
|
'testnoversion' => ['id' => 'testnoversion', 'requiremin' => '8.2.0'],
|
|
'theming' => ['id' => 'theming'],
|
|
'twofactor_backupcodes' => ['id' => 'twofactor_backupcodes'],
|
|
'workflowengine' => ['id' => 'workflowengine'],
|
|
'oauth2' => ['id' => 'oauth2'],
|
|
'viewer' => ['id' => 'viewer'],
|
|
];
|
|
|
|
$manager->expects($this->any())
|
|
->method('getAppInfo')
|
|
->willReturnCallback(
|
|
function ($appId) use ($appInfos) {
|
|
return $appInfos[$appId];
|
|
}
|
|
);
|
|
|
|
$this->appConfig->setValue('test1', 'enabled', 'yes');
|
|
$this->appConfig->setValue('test2', 'enabled', 'yes');
|
|
$this->appConfig->setValue('test3', 'enabled', 'yes');
|
|
|
|
$apps = $manager->getIncompatibleApps('8.2.0');
|
|
|
|
$this->assertCount(2, $apps);
|
|
$this->assertEquals('test1', $apps[0]['id']);
|
|
$this->assertEquals('test3', $apps[1]['id']);
|
|
}
|
|
|
|
public function testGetEnabledAppsForGroup(): void {
|
|
$group = $this->createMock(IGroup::class);
|
|
$group->expects($this->any())
|
|
->method('getGID')
|
|
->willReturn('foo');
|
|
|
|
$this->appConfig->setValue('test1', 'enabled', 'yes');
|
|
$this->appConfig->setValue('test2', 'enabled', 'no');
|
|
$this->appConfig->setValue('test3', 'enabled', '["foo"]');
|
|
$this->appConfig->setValue('test4', 'enabled', '["asd"]');
|
|
$enabled = [
|
|
'appstore',
|
|
'cloud_federation_api',
|
|
'dav',
|
|
'federatedfilesharing',
|
|
'files',
|
|
'lookup_server_connector',
|
|
'oauth2',
|
|
'profile',
|
|
'provisioning_api',
|
|
'settings',
|
|
'sharing',
|
|
'test1',
|
|
'test3',
|
|
'theming',
|
|
'twofactor_backupcodes',
|
|
'viewer',
|
|
'workflowengine',
|
|
];
|
|
$this->assertEquals($enabled, $this->manager->getEnabledAppsForGroup($group));
|
|
}
|
|
|
|
public function testGetAppRestriction(): void {
|
|
$this->appConfig->setValue('test1', 'enabled', 'yes');
|
|
$this->appConfig->setValue('test2', 'enabled', 'no');
|
|
$this->appConfig->setValue('test3', 'enabled', '["foo"]');
|
|
|
|
$this->assertEquals([], $this->manager->getAppRestriction('test1'));
|
|
$this->assertEquals([], $this->manager->getAppRestriction('test2'));
|
|
$this->assertEquals(['foo'], $this->manager->getAppRestriction('test3'));
|
|
}
|
|
|
|
public static function isBackendRequiredDataProvider(): array {
|
|
return [
|
|
// backend available
|
|
[
|
|
'caldav',
|
|
['app1' => ['caldav']],
|
|
true,
|
|
],
|
|
[
|
|
'caldav',
|
|
['app1' => [], 'app2' => ['foo'], 'app3' => ['caldav']],
|
|
true,
|
|
],
|
|
// backend not available
|
|
[
|
|
'caldav',
|
|
['app3' => [], 'app1' => ['foo'], 'app2' => ['bar', 'baz']],
|
|
false,
|
|
],
|
|
// no app available
|
|
[
|
|
'caldav',
|
|
[],
|
|
false,
|
|
],
|
|
];
|
|
}
|
|
|
|
#[DataProvider('isBackendRequiredDataProvider')]
|
|
public function testIsBackendRequired(
|
|
string $backend,
|
|
array $appBackends,
|
|
bool $expected,
|
|
): void {
|
|
$appInfoData = array_map(
|
|
static fn (array $backends) => ['dependencies' => ['backend' => $backends]],
|
|
$appBackends,
|
|
);
|
|
|
|
$reflection = new \ReflectionClass($this->manager);
|
|
$property = $reflection->getProperty('appInfos');
|
|
$property->setValue($this->manager, $appInfoData);
|
|
|
|
$this->assertEquals($expected, $this->manager->isBackendRequired($backend));
|
|
}
|
|
|
|
public function testGetAppVersion() {
|
|
$manager = $this->getMockBuilder(AppManager::class)
|
|
->setConstructorArgs([
|
|
$this->userSession,
|
|
$this->config,
|
|
$this->groupManager,
|
|
$this->cacheFactory,
|
|
$this->eventDispatcher,
|
|
$this->logger,
|
|
$this->serverVersion,
|
|
$this->configManager,
|
|
$this->dependencyAnalyzer,
|
|
])
|
|
->onlyMethods([
|
|
'getAppInfo',
|
|
])
|
|
->getMock();
|
|
|
|
$manager->expects(self::once())
|
|
->method('getAppInfo')
|
|
->with('myapp')
|
|
->willReturn(['version' => '99.99.99-rc.99']);
|
|
|
|
$this->serverVersion
|
|
->expects(self::never())
|
|
->method('getVersionString');
|
|
|
|
$this->assertEquals(
|
|
'99.99.99-rc.99',
|
|
$manager->getAppVersion('myapp'),
|
|
);
|
|
}
|
|
|
|
public function testGetAppVersionCore() {
|
|
$manager = $this->getMockBuilder(AppManager::class)
|
|
->setConstructorArgs([
|
|
$this->userSession,
|
|
$this->config,
|
|
$this->groupManager,
|
|
$this->cacheFactory,
|
|
$this->eventDispatcher,
|
|
$this->logger,
|
|
$this->serverVersion,
|
|
$this->configManager,
|
|
$this->dependencyAnalyzer,
|
|
])
|
|
->onlyMethods([
|
|
'getAppInfo',
|
|
])
|
|
->getMock();
|
|
|
|
$manager->expects(self::never())
|
|
->method('getAppInfo');
|
|
|
|
$this->serverVersion
|
|
->expects(self::once())
|
|
->method('getVersionString')
|
|
->willReturn('1.2.3-beta.4');
|
|
|
|
$this->assertEquals(
|
|
'1.2.3-beta.4',
|
|
$manager->getAppVersion('core'),
|
|
);
|
|
}
|
|
|
|
public function testGetAppVersionUnknown() {
|
|
$manager = $this->getMockBuilder(AppManager::class)
|
|
->setConstructorArgs([
|
|
$this->userSession,
|
|
$this->config,
|
|
$this->groupManager,
|
|
$this->cacheFactory,
|
|
$this->eventDispatcher,
|
|
$this->logger,
|
|
$this->serverVersion,
|
|
$this->configManager,
|
|
$this->dependencyAnalyzer,
|
|
])
|
|
->onlyMethods([
|
|
'getAppInfo',
|
|
])
|
|
->getMock();
|
|
|
|
$manager->expects(self::once())
|
|
->method('getAppInfo')
|
|
->with('unknown')
|
|
->willReturn(null);
|
|
|
|
$this->serverVersion
|
|
->expects(self::never())
|
|
->method('getVersionString');
|
|
|
|
$this->assertEquals(
|
|
'0',
|
|
$manager->getAppVersion('unknown'),
|
|
);
|
|
}
|
|
|
|
public static function dataCleanAppId(): array {
|
|
return [
|
|
['simple', 'simple'],
|
|
['UPPERCASEa', 'a'],
|
|
['MixEdCaSe', 'ixdae'],
|
|
['007startwithdigit', 'startwithdigit'],
|
|
['0-numb3rs-4ll0w3d-1n-m1ddle-0', 'numb3rs-4ll0w3d-1n-m1ddle-0'],
|
|
['hyphen-and_underscore_allowed', 'hyphen-and_underscore_allowed'],
|
|
['_but-not-at-the-end_', 'but-not-at-the-end'],
|
|
['-but-not-at-the-end-', 'but-not-at-the-end'],
|
|
['--_but-not-at-the-end___', 'but-not-at-the-end'],
|
|
[' also remove all spaces', 'alsoremoveallspaces'],
|
|
['a«"«»()@+-/*=%\{}…~|&œ—<>[]^±_−÷×≠‰A', 'a-_'],
|
|
];
|
|
}
|
|
|
|
#[DataProvider('dataCleanAppId')]
|
|
public function testCleanAppId(string $inputString, string $appid): void {
|
|
$this->assertEquals($appid, $this->manager->cleanAppId($inputString));
|
|
}
|
|
}
|