diff options
author | Christoph Wurst <christoph@winzerhof-wurst.at> | 2019-09-17 16:33:27 +0200 |
---|---|---|
committer | npmbuildbot[bot] <npmbuildbot[bot]@users.noreply.github.com> | 2019-09-28 09:39:28 +0000 |
commit | de6940352a2f708376219a89ec84a8e6d25ca59e (patch) | |
tree | 459bacfc183b24d611be1877fbe22bbcd4efb1d6 /apps/settings/tests/Controller | |
parent | c8cd607681ac128228f57114ce14dd67ab05de04 (diff) | |
download | nextcloud-server-de6940352a2f708376219a89ec84a8e6d25ca59e.tar.gz nextcloud-server-de6940352a2f708376219a89ec84a8e6d25ca59e.zip |
Move settings to an app
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
Signed-off-by: npmbuildbot[bot] <npmbuildbot[bot]@users.noreply.github.com>
Diffstat (limited to 'apps/settings/tests/Controller')
8 files changed, 3228 insertions, 0 deletions
diff --git a/apps/settings/tests/Controller/AdminSettingsControllerTest.php b/apps/settings/tests/Controller/AdminSettingsControllerTest.php new file mode 100644 index 00000000000..f1f81c7c75b --- /dev/null +++ b/apps/settings/tests/Controller/AdminSettingsControllerTest.php @@ -0,0 +1,128 @@ +<?php +/** + * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> + * + * @author Lukas Reschke <lukas@statuscode.ch> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCA\Settings\Tests\Controller; + +use OCA\Settings\Personal\ServerDevNotice; +use OCA\Settings\Controller\AdminSettingsController; +use OCP\AppFramework\Http\TemplateResponse; +use OCP\Group\ISubAdmin; +use OCP\IGroupManager; +use OCP\INavigationManager; +use OCP\IRequest; +use OCP\IUser; +use OCP\IUserSession; +use OCP\Settings\IManager; +use PHPUnit\Framework\MockObject\MockObject; +use Test\TestCase; + +/** + * Class AdminSettingsControllerTest + * + * @group DB + * + * @package Tests\Settings\Controller + */ +class AdminSettingsControllerTest extends TestCase { + + /** @var AdminSettingsController */ + private $adminSettingsController; + /** @var IRequest|MockObject */ + private $request; + /** @var INavigationManager|MockObject */ + private $navigationManager; + /** @var IManager|MockObject */ + private $settingsManager; + /** @var IUserSession|MockObject */ + private $userSession; + /** @var IGroupManager|MockObject */ + private $groupManager; + /** @var ISubAdmin|MockObject */ + private $subAdmin; + /** @var string */ + private $adminUid = 'lololo'; + + public function setUp() { + parent::setUp(); + + $this->request = $this->createMock(IRequest::class); + $this->navigationManager = $this->createMock(INavigationManager::class); + $this->settingsManager = $this->createMock(IManager::class); + $this->userSession = $this->createMock(IUserSession::class); + $this->groupManager = $this->createMock(IGroupManager::class); + $this->subAdmin = $this->createMock(ISubAdmin::class); + + $this->adminSettingsController = new AdminSettingsController( + 'settings', + $this->request, + $this->navigationManager, + $this->settingsManager, + $this->userSession, + $this->groupManager, + $this->subAdmin + ); + + $user = \OC::$server->getUserManager()->createUser($this->adminUid, 'olo'); + \OC_User::setUserId($user->getUID()); + \OC::$server->getGroupManager()->createGroup('admin')->addUser($user); + } + + public function tearDown() { + \OC::$server->getUserManager()->get($this->adminUid)->delete(); + + parent::tearDown(); + } + + public function testIndex() { + $user = $this->createMock(IUser::class); + $this->userSession + ->method('getUser') + ->willReturn($user); + $user->method('getUID')->willReturn('user123'); + $this->groupManager + ->method('isAdmin') + ->with('user123') + ->willReturn(true); + $this->subAdmin + ->method('isSubAdmin') + ->with($user) + ->willReturn(false); + $this->settingsManager + ->expects($this->once()) + ->method('getAdminSections') + ->willReturn([]); + $this->settingsManager + ->expects($this->once()) + ->method('getPersonalSections') + ->willReturn([]); + $this->settingsManager + ->expects($this->once()) + ->method('getAdminSettings') + ->with('test') + ->willReturn([5 => new ServerDevNotice()]); + + $idx = $this->adminSettingsController->index('test'); + + $expected = new TemplateResponse('settings', 'settings/frame', ['forms' => ['personal' => [], 'admin' => []], 'content' => '']); + $this->assertEquals($expected, $idx); + } +} diff --git a/apps/settings/tests/Controller/AppSettingsControllerTest.php b/apps/settings/tests/Controller/AppSettingsControllerTest.php new file mode 100644 index 00000000000..449f158ec4a --- /dev/null +++ b/apps/settings/tests/Controller/AppSettingsControllerTest.php @@ -0,0 +1,247 @@ +<?php +/** + * @author Lukas Reschke <lukas@owncloud.com> + * + * @copyright Copyright (c) 2016, Lukas Reschke <lukas@statuscode.ch> + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCA\Settings\Tests\Controller; + +use OC\App\AppStore\Bundles\BundleFetcher; +use OC\App\AppStore\Fetcher\AppFetcher; +use OC\App\AppStore\Fetcher\CategoryFetcher; +use OC\Installer; +use OCA\Settings\Controller\AppSettingsController; +use OCP\AppFramework\Http\ContentSecurityPolicy; +use OCP\AppFramework\Http\JSONResponse; +use OCP\AppFramework\Http\TemplateResponse; +use OCP\ILogger; +use OCP\IURLGenerator; +use OCP\L10N\IFactory; +use PHPUnit\Framework\MockObject\MockObject; +use Test\TestCase; +use OCP\IRequest; +use OCP\IL10N; +use OCP\IConfig; +use OCP\INavigationManager; +use OCP\App\IAppManager; + +/** + * Class AppSettingsControllerTest + * + * @package Tests\Settings\Controller + * + * @group DB + */ +class AppSettingsControllerTest extends TestCase { + /** @var AppSettingsController */ + private $appSettingsController; + /** @var IRequest|MockObject */ + private $request; + /** @var IL10N|MockObject */ + private $l10n; + /** @var IConfig|MockObject */ + private $config; + /** @var INavigationManager|MockObject */ + private $navigationManager; + /** @var IAppManager|MockObject */ + private $appManager; + /** @var CategoryFetcher|MockObject */ + private $categoryFetcher; + /** @var AppFetcher|MockObject */ + private $appFetcher; + /** @var IFactory|MockObject */ + private $l10nFactory; + /** @var BundleFetcher|MockObject */ + private $bundleFetcher; + /** @var Installer|MockObject */ + private $installer; + /** @var IURLGenerator|MockObject */ + private $urlGenerator; + /** @var ILogger|MockObject */ + private $logger; + + public function setUp() { + parent::setUp(); + + $this->request = $this->createMock(IRequest::class); + $this->l10n = $this->createMock(IL10N::class); + $this->l10n->expects($this->any()) + ->method('t') + ->will($this->returnArgument(0)); + $this->config = $this->createMock(IConfig::class); + $this->navigationManager = $this->createMock(INavigationManager::class); + $this->appManager = $this->createMock(IAppManager::class); + $this->categoryFetcher = $this->createMock(CategoryFetcher::class); + $this->appFetcher = $this->createMock(AppFetcher::class); + $this->l10nFactory = $this->createMock(IFactory::class); + $this->bundleFetcher = $this->createMock(BundleFetcher::class); + $this->installer = $this->createMock(Installer::class); + $this->urlGenerator = $this->createMock(IURLGenerator::class); + $this->logger = $this->createMock(ILogger::class); + + $this->appSettingsController = new AppSettingsController( + 'settings', + $this->request, + $this->l10n, + $this->config, + $this->navigationManager, + $this->appManager, + $this->categoryFetcher, + $this->appFetcher, + $this->l10nFactory, + $this->bundleFetcher, + $this->installer, + $this->urlGenerator, + $this->logger + ); + } + + public function testListCategories() { + $this->installer->expects($this->any()) + ->method('isUpdateAvailable') + ->willReturn(false); + $expected = new JSONResponse([ + [ + 'id' => 'auth', + 'ident' => 'auth', + 'displayName' => 'Authentication & authorization', + ], + [ + 'id' => 'customization', + 'ident' => 'customization', + 'displayName' => 'Customization', + ], + [ + 'id' => 'files', + 'ident' => 'files', + 'displayName' => 'Files', + ], + [ + 'id' => 'integration', + 'ident' => 'integration', + 'displayName' => 'Integration', + ], + [ + 'id' => 'monitoring', + 'ident' => 'monitoring', + 'displayName' => 'Monitoring', + ], + [ + 'id' => 'multimedia', + 'ident' => 'multimedia', + 'displayName' => 'Multimedia', + ], + [ + 'id' => 'office', + 'ident' => 'office', + 'displayName' => 'Office & text', + ], + [ + 'id' => 'organization', + 'ident' => 'organization', + 'displayName' => 'Organization', + ], + [ + 'id' => 'social', + 'ident' => 'social', + 'displayName' => 'Social & communication', + ], + [ + 'id' => 'tools', + 'ident' => 'tools', + 'displayName' => 'Tools', + ], + ]); + + $this->categoryFetcher + ->expects($this->once()) + ->method('get') + ->willReturn(json_decode('[{"id":"auth","translations":{"cs":{"name":"Autentizace & autorizace","description":"Aplikace poskytující služby dodatečného ověření nebo přihlášení"},"hu":{"name":"Azonosítás és hitelesítés","description":"Apps that provide additional authentication or authorization services"},"de":{"name":"Authentifizierung & Authorisierung","description":"Apps die zusätzliche Autentifizierungs- oder Autorisierungsdienste bereitstellen"},"nl":{"name":"Authenticatie & authorisatie","description":"Apps die aanvullende authenticatie- en autorisatiediensten bieden"},"nb":{"name":"Pålogging og tilgangsstyring","description":"Apper for å tilby ekstra pålogging eller tilgangsstyring"},"it":{"name":"Autenticazione e autorizzazione","description":"Apps that provide additional authentication or authorization services"},"fr":{"name":"Authentification et autorisations","description":"Applications qui fournissent des services d\'authentification ou d\'autorisations additionnels."},"ru":{"name":"Аутентификация и авторизация","description":"Apps that provide additional authentication or authorization services"},"en":{"name":"Authentication & authorization","description":"Apps that provide additional authentication or authorization services"}}},{"id":"customization","translations":{"cs":{"name":"Přizpůsobení","description":"Motivy a aplikace měnící rozvržení a uživatelské rozhraní"},"it":{"name":"Personalizzazione","description":"Applicazioni di temi, modifiche della disposizione e UX"},"de":{"name":"Anpassung","description":"Apps zur Änderung von Themen, Layout und Benutzererfahrung"},"hu":{"name":"Személyre szabás","description":"Témák, elrendezések felhasználói felület módosító alkalmazások"},"nl":{"name":"Maatwerk","description":"Thema\'s, layout en UX aanpassingsapps"},"nb":{"name":"Tilpasning","description":"Apper for å endre Tema, utseende og brukeropplevelse"},"fr":{"name":"Personalisation","description":"Thèmes, apparence et applications modifiant l\'expérience utilisateur"},"ru":{"name":"Настройка","description":"Themes, layout and UX change apps"},"en":{"name":"Customization","description":"Themes, layout and UX change apps"}}},{"id":"files","translations":{"cs":{"name":"Soubory","description":"Aplikace rozšiřující správu souborů nebo aplikaci Soubory"},"it":{"name":"File","description":"Applicazioni di gestione dei file ed estensione dell\'applicazione FIle"},"de":{"name":"Dateien","description":"Dateimanagement sowie Erweiterungs-Apps für die Dateien-App"},"hu":{"name":"Fájlok","description":"Fájl kezelő és kiegészítő alkalmazások"},"nl":{"name":"Bestanden","description":"Bestandebeheer en uitbreidingen van bestand apps"},"nb":{"name":"Filer","description":"Apper for filhåndtering og filer"},"fr":{"name":"Fichiers","description":"Applications de gestion de fichiers et extensions à l\'application Fichiers"},"ru":{"name":"Файлы","description":"Расширение: файлы и управление файлами"},"en":{"name":"Files","description":"File management and Files app extension apps"}}},{"id":"integration","translations":{"it":{"name":"Integrazione","description":"Applicazioni che collegano Nextcloud con altri servizi e piattaforme"},"hu":{"name":"Integráció","description":"Apps that connect Nextcloud with other services and platforms"},"nl":{"name":"Integratie","description":"Apps die Nextcloud verbinden met andere services en platformen"},"nb":{"name":"Integrasjon","description":"Apper som kobler Nextcloud med andre tjenester og plattformer"},"de":{"name":"Integration","description":"Apps die Nextcloud mit anderen Diensten und Plattformen verbinden"},"cs":{"name":"Propojení","description":"Aplikace propojující NextCloud s dalšími službami a platformami"},"fr":{"name":"Intégration","description":"Applications qui connectent Nextcloud avec d\'autres services et plateformes"},"ru":{"name":"Интеграция","description":"Приложения, соединяющие Nextcloud с другими службами и платформами"},"en":{"name":"Integration","description":"Apps that connect Nextcloud with other services and platforms"}}},{"id":"monitoring","translations":{"nb":{"name":"Overvåking","description":"Apper for statistikk, systemdiagnose og aktivitet"},"it":{"name":"Monitoraggio","description":"Applicazioni di statistiche, diagnostica di sistema e attività"},"de":{"name":"Überwachung","description":"Datenstatistiken-, Systemdiagnose- und Aktivitäten-Apps"},"hu":{"name":"Megfigyelés","description":"Data statistics, system diagnostics and activity apps"},"nl":{"name":"Monitoren","description":"Gegevensstatistiek, systeem diagnose en activiteit apps"},"cs":{"name":"Kontrola","description":"Datové statistiky, diagnózy systému a aktivity aplikací"},"fr":{"name":"Surveillance","description":"Applications de statistiques sur les données, de diagnostics systèmes et d\'activité."},"ru":{"name":"Мониторинг","description":"Статистика данных, диагностика системы и активность приложений"},"en":{"name":"Monitoring","description":"Data statistics, system diagnostics and activity apps"}}},{"id":"multimedia","translations":{"nb":{"name":"Multimedia","description":"Apper for lyd, film og bilde"},"it":{"name":"Multimedia","description":"Applicazioni per audio, video e immagini"},"de":{"name":"Multimedia","description":"Audio-, Video- und Bilder-Apps"},"hu":{"name":"Multimédia","description":"Hang, videó és kép alkalmazások"},"nl":{"name":"Multimedia","description":"Audio, video en afbeelding apps"},"en":{"name":"Multimedia","description":"Audio, video and picture apps"},"cs":{"name":"Multimédia","description":"Aplikace audia, videa a obrázků"},"fr":{"name":"Multimédia","description":"Applications audio, vidéo et image"},"ru":{"name":"Мультимедиа","description":"Приложение аудио, видео и изображения"}}},{"id":"office","translations":{"nb":{"name":"Kontorstøtte og tekst","description":"Apper for Kontorstøtte og tekstbehandling"},"it":{"name":"Ufficio e testo","description":"Applicazione per ufficio ed elaborazione di testi"},"de":{"name":"Büro & Text","description":"Büro- und Textverarbeitungs-Apps"},"hu":{"name":"Iroda és szöveg","description":"Irodai és szöveg feldolgozó alkalmazások"},"nl":{"name":"Office & tekst","description":"Office en tekstverwerkingsapps"},"cs":{"name":"Kancelář a text","description":"Aplikace pro kancelář a zpracování textu"},"fr":{"name":"Bureautique & texte","description":"Applications de bureautique et de traitement de texte"},"en":{"name":"Office & text","description":"Office and text processing apps"}}},{"id":"organization","translations":{"nb":{"name":"Organisering","description":"Apper for tidsstyring, oppgaveliste og kalender"},"it":{"name":"Organizzazione","description":"Applicazioni di gestione del tempo, elenco delle cose da fare e calendario"},"hu":{"name":"Szervezet","description":"Időbeosztás, teendő lista és naptár alkalmazások"},"nl":{"name":"Organisatie","description":"Tijdmanagement, takenlijsten en agenda apps"},"cs":{"name":"Organizace","description":"Aplikace pro správu času, plánování a kalendáře"},"de":{"name":"Organisation","description":"Time management, Todo list and calendar apps"},"fr":{"name":"Organisation","description":"Applications de gestion du temps, de listes de tâches et d\'agendas"},"ru":{"name":"Организация","description":"Приложения по управлению временем, список задач и календарь"},"en":{"name":"Organization","description":"Time management, Todo list and calendar apps"}}},{"id":"social","translations":{"nb":{"name":"Sosialt og kommunikasjon","description":"Apper for meldinger, kontakthåndtering og sosiale medier"},"it":{"name":"Sociale e comunicazione","description":"Applicazioni di messaggistica, gestione dei contatti e reti sociali"},"de":{"name":"Kommunikation","description":"Nachrichten-, Kontaktverwaltungs- und Social-Media-Apps"},"hu":{"name":"Közösségi és kommunikáció","description":"Üzenetküldő, kapcsolat kezelő és közösségi média alkalmazások"},"nl":{"name":"Sociaal & communicatie","description":"Messaging, contactbeheer en social media apps"},"cs":{"name":"Sociální sítě a komunikace","description":"Aplikace pro zasílání zpráv, správu kontaktů a sociální sítě"},"fr":{"name":"Social & communication","description":"Applications de messagerie, de gestion de contacts et de réseaux sociaux"},"ru":{"name":"Социальное и связь","description":"Общение, управление контактами и социальное медиа-приложение"},"en":{"name":"Social & communication","description":"Messaging, contact management and social media apps"}}},{"id":"tools","translations":{"nb":{"name":"Verktøy","description":"Alt annet"},"it":{"name":"Strumenti","description":"Tutto il resto"},"hu":{"name":"Eszközök","description":"Minden más"},"nl":{"name":"Tools","description":"De rest"},"de":{"name":"Werkzeuge","description":"Alles Andere"},"en":{"name":"Tools","description":"Everything else"},"cs":{"name":"Nástroje","description":"Vše ostatní"},"fr":{"name":"Outils","description":"Tout le reste"},"ru":{"name":"Приложения","description":"Что-то еще"}}}]', true)); + + $this->assertEquals($expected, $this->appSettingsController->listCategories()); + } + + public function testViewApps() { + $this->bundleFetcher->expects($this->once())->method('getBundles')->willReturn([]); + $this->installer->expects($this->any()) + ->method('isUpdateAvailable') + ->willReturn(false); + $this->config + ->expects($this->once()) + ->method('getSystemValue') + ->with('appstoreenabled', true) + ->will($this->returnValue(true)); + $this->navigationManager + ->expects($this->once()) + ->method('setActiveEntry') + ->with('core_apps'); + + $policy = new ContentSecurityPolicy(); + $policy->addAllowedImageDomain('https://usercontent.apps.nextcloud.com'); + + $expected = new TemplateResponse('settings', + 'settings-vue', + [ + 'serverData' => [ + 'updateCount' => 0, + 'appstoreEnabled' => true, + 'bundles' => [], + 'developerDocumentation' => '' + ] + ], + 'user'); + $expected->setContentSecurityPolicy($policy); + + $this->assertEquals($expected, $this->appSettingsController->viewApps()); + } + + public function testViewAppsAppstoreNotEnabled() { + $this->installer->expects($this->any()) + ->method('isUpdateAvailable') + ->willReturn(false); + $this->bundleFetcher->expects($this->once())->method('getBundles')->willReturn([]); + $this->config + ->expects($this->once()) + ->method('getSystemValue') + ->with('appstoreenabled', true) + ->will($this->returnValue(false)); + $this->navigationManager + ->expects($this->once()) + ->method('setActiveEntry') + ->with('core_apps'); + + $policy = new ContentSecurityPolicy(); + $policy->addAllowedImageDomain('https://usercontent.apps.nextcloud.com'); + + $expected = new TemplateResponse('settings', + 'settings-vue', + [ + 'serverData' => [ + 'updateCount' => 0, + 'appstoreEnabled' => false, + 'bundles' => [], + 'developerDocumentation' => '' + ] + ], + 'user'); + $expected->setContentSecurityPolicy($policy); + + $this->assertEquals($expected, $this->appSettingsController->viewApps()); + } +} diff --git a/apps/settings/tests/Controller/AuthSettingsControllerTest.php b/apps/settings/tests/Controller/AuthSettingsControllerTest.php new file mode 100644 index 00000000000..88913b1f03f --- /dev/null +++ b/apps/settings/tests/Controller/AuthSettingsControllerTest.php @@ -0,0 +1,400 @@ +<?php +/** + * @author Christoph Wurst <christoph@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace Test\Settings\Controller; + +use OC\AppFramework\Http; +use OC\Authentication\Exceptions\InvalidTokenException; +use OC\Authentication\Token\DefaultToken; +use OC\Authentication\Token\IProvider; +use OC\Authentication\Token\IToken; +use OC\Authentication\Token\RemoteWipe; +use OCA\Settings\Controller\AuthSettingsController; +use OCP\Activity\IEvent; +use OCP\Activity\IManager; +use OCP\AppFramework\Http\JSONResponse; +use OCP\ILogger; +use OCP\IRequest; +use OCP\ISession; +use OCP\IUserSession; +use OCP\Security\ISecureRandom; +use OCP\Session\Exceptions\SessionNotAvailableException; +use PHPUnit\Framework\MockObject\MockObject; +use Test\TestCase; + +class AuthSettingsControllerTest extends TestCase { + + /** @var AuthSettingsController */ + private $controller; + /** @var IRequest|MockObject */ + private $request; + /** @var IProvider|MockObject */ + private $tokenProvider; + /** @var ISession|MockObject */ + private $session; + /**@var IUserSession|MockObject */ + private $userSession; + /** @var ISecureRandom|MockObject */ + private $secureRandom; + /** @var IManager|MockObject */ + private $activityManager; + /** @var RemoteWipe|MockObject */ + private $remoteWipe; + private $uid = 'jane'; + + protected function setUp() { + parent::setUp(); + + $this->request = $this->createMock(IRequest::class); + $this->tokenProvider = $this->createMock(IProvider::class); + $this->session = $this->createMock(ISession::class); + $this->userSession = $this->createMock(IUserSession::class); + $this->secureRandom = $this->createMock(ISecureRandom::class); + $this->activityManager = $this->createMock(IManager::class); + $this->remoteWipe = $this->createMock(RemoteWipe::class); + /** @var ILogger|MockObject $logger */ + $logger = $this->createMock(ILogger::class); + + $this->controller = new AuthSettingsController( + 'core', + $this->request, + $this->tokenProvider, + $this->session, + $this->secureRandom, + $this->uid, + $this->userSession, + $this->activityManager, + $this->remoteWipe, + $logger + ); + } + + public function testCreate() { + $name = 'Nexus 4'; + $sessionToken = $this->createMock(IToken::class); + $deviceToken = $this->createMock(IToken::class); + $password = '123456'; + + $this->session->expects($this->once()) + ->method('getId') + ->willReturn('sessionid'); + $this->tokenProvider->expects($this->once()) + ->method('getToken') + ->with('sessionid') + ->willReturn($sessionToken); + $this->tokenProvider->expects($this->once()) + ->method('getPassword') + ->with($sessionToken, 'sessionid') + ->willReturn($password); + $sessionToken->expects($this->once()) + ->method('getLoginName') + ->willReturn('User13'); + + $this->secureRandom->expects($this->exactly(5)) + ->method('generate') + ->with(5, ISecureRandom::CHAR_HUMAN_READABLE) + ->willReturn('XXXXX'); + $newToken = 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX'; + + $this->tokenProvider->expects($this->once()) + ->method('generateToken') + ->with($newToken, $this->uid, 'User13', $password, $name, IToken::PERMANENT_TOKEN) + ->willReturn($deviceToken); + + $deviceToken->expects($this->once()) + ->method('jsonSerialize') + ->willReturn(['dummy' => 'dummy', 'canDelete' => true]); + + $this->mockActivityManager(); + + $expected = [ + 'token' => $newToken, + 'deviceToken' => ['dummy' => 'dummy', 'canDelete' => true, 'canRename' => true], + 'loginName' => 'User13', + ]; + + $response = $this->controller->create($name); + $this->assertInstanceOf(JSONResponse::class, $response); + $this->assertEquals($expected, $response->getData()); + } + + public function testCreateSessionNotAvailable() { + $name = 'personal phone'; + + $this->session->expects($this->once()) + ->method('getId') + ->will($this->throwException(new SessionNotAvailableException())); + + $expected = new JSONResponse(); + $expected->setStatus(Http::STATUS_SERVICE_UNAVAILABLE); + + $this->assertEquals($expected, $this->controller->create($name)); + } + + public function testCreateInvalidToken() { + $name = 'Company IPhone'; + + $this->session->expects($this->once()) + ->method('getId') + ->willReturn('sessionid'); + $this->tokenProvider->expects($this->once()) + ->method('getToken') + ->with('sessionid') + ->will($this->throwException(new InvalidTokenException())); + + $expected = new JSONResponse(); + $expected->setStatus(Http::STATUS_SERVICE_UNAVAILABLE); + + $this->assertEquals($expected, $this->controller->create($name)); + } + + public function testDestroy() { + $tokenId = 124; + $token = $this->createMock(DefaultToken::class); + + $this->mockGetTokenById($tokenId, $token); + $this->mockActivityManager(); + + $token->expects($this->exactly(2)) + ->method('getId') + ->willReturn($tokenId); + + $token->expects($this->once()) + ->method('getUID') + ->willReturn('jane'); + + $this->tokenProvider->expects($this->once()) + ->method('invalidateTokenById') + ->with($this->uid, $tokenId); + + $this->assertEquals([], $this->controller->destroy($tokenId)); + } + + public function testDestroyWrongUser() { + $tokenId = 124; + $token = $this->createMock(DefaultToken::class); + + $this->mockGetTokenById($tokenId, $token); + + $token->expects($this->once()) + ->method('getUID') + ->willReturn('foobar'); + + $response = $this->controller->destroy($tokenId); + $this->assertSame([], $response->getData()); + $this->assertSame(\OCP\AppFramework\Http::STATUS_NOT_FOUND, $response->getStatus()); + } + + public function dataRenameToken(): array { + return [ + 'App password => Other token name' => ['App password', 'Other token name'], + 'Other token name => App password' => ['Other token name', 'App password'], + ]; + } + + /** + * @dataProvider dataRenameToken + * + * @param string $name + * @param string $newName + */ + public function testUpdateRename(string $name, string $newName): void { + $tokenId = 42; + $token = $this->createMock(DefaultToken::class); + + $this->mockGetTokenById($tokenId, $token); + $this->mockActivityManager(); + + $token->expects($this->once()) + ->method('getUID') + ->willReturn('jane'); + + $token->expects($this->once()) + ->method('getName') + ->willReturn($name); + + $token->expects($this->once()) + ->method('getScopeAsArray') + ->willReturn(['filesystem' => true]); + + $token->expects($this->once()) + ->method('setName') + ->with($this->equalTo($newName)); + + $this->tokenProvider->expects($this->once()) + ->method('updateToken') + ->with($this->equalTo($token)); + + $this->assertSame([], $this->controller->update($tokenId, ['filesystem' => true], $newName)); + } + + public function dataUpdateFilesystemScope(): array { + return [ + 'Grant filesystem access' => [false, true], + 'Revoke filesystem access' => [true, false], + ]; + } + + /** + * @dataProvider dataUpdateFilesystemScope + * + * @param bool $filesystem + * @param bool $newFilesystem + */ + public function testUpdateFilesystemScope(bool $filesystem, bool $newFilesystem): void { + $tokenId = 42; + $token = $this->createMock(DefaultToken::class); + + $this->mockGetTokenById($tokenId, $token); + $this->mockActivityManager(); + + $token->expects($this->once()) + ->method('getUID') + ->willReturn('jane'); + + $token->expects($this->once()) + ->method('getName') + ->willReturn('App password'); + + $token->expects($this->once()) + ->method('getScopeAsArray') + ->willReturn(['filesystem' => $filesystem]); + + $token->expects($this->once()) + ->method('setScope') + ->with($this->equalTo(['filesystem' => $newFilesystem])); + + $this->tokenProvider->expects($this->once()) + ->method('updateToken') + ->with($this->equalTo($token)); + + $this->assertSame([], $this->controller->update($tokenId, ['filesystem' => $newFilesystem], 'App password')); + } + + public function testUpdateNoChange(): void { + $tokenId = 42; + $token = $this->createMock(DefaultToken::class); + + $this->mockGetTokenById($tokenId, $token); + + $token->expects($this->once()) + ->method('getUID') + ->willReturn('jane'); + + $token->expects($this->once()) + ->method('getName') + ->willReturn('App password'); + + $token->expects($this->once()) + ->method('getScopeAsArray') + ->willReturn(['filesystem' => true]); + + $token->expects($this->never()) + ->method('setName'); + + $token->expects($this->never()) + ->method('setScope'); + + $this->tokenProvider->expects($this->once()) + ->method('updateToken') + ->with($this->equalTo($token)); + + $this->assertSame([], $this->controller->update($tokenId, ['filesystem' => true], 'App password')); + } + + public function testUpdateTokenWrongUser() { + $tokenId = 42; + $token = $this->createMock(DefaultToken::class); + + $this->mockGetTokenById($tokenId, $token); + + $token->expects($this->once()) + ->method('getUID') + ->willReturn('foobar'); + + $token->expects($this->never()) + ->method('setScope'); + $this->tokenProvider->expects($this->never()) + ->method('updateToken'); + + $response = $this->controller->update($tokenId, ['filesystem' => true], 'App password'); + $this->assertSame([], $response->getData()); + $this->assertSame(\OCP\AppFramework\Http::STATUS_NOT_FOUND, $response->getStatus()); + } + + public function testUpdateTokenNonExisting() { + $this->tokenProvider->expects($this->once()) + ->method('getTokenById') + ->with($this->equalTo(42)) + ->willThrowException(new InvalidTokenException('Token does not exist')); + + $this->tokenProvider->expects($this->never()) + ->method('updateToken'); + + $response = $this->controller->update(42, ['filesystem' => true], 'App password'); + $this->assertSame([], $response->getData()); + $this->assertSame(\OCP\AppFramework\Http::STATUS_NOT_FOUND, $response->getStatus()); + } + + private function mockActivityManager(): void { + $this->activityManager->expects($this->once()) + ->method('generateEvent') + ->willReturn($this->createMock(IEvent::class)); + $this->activityManager->expects($this->once()) + ->method('publish'); + } + + /** + * @param int $tokenId + * @param $token + */ + private function mockGetTokenById(int $tokenId, $token): void { + $this->tokenProvider->expects($this->once()) + ->method('getTokenById') + ->with($this->equalTo($tokenId)) + ->willReturn($token); + } + + public function testRemoteWipeNotSuccessful(): void { + $this->remoteWipe->expects($this->once()) + ->method('markTokenForWipe') + ->with(123) + ->willReturn(false); + + $response = $this->controller->wipe(123); + + $expected = new JSONResponse([], Http::STATUS_BAD_REQUEST); + $this->assertEquals($expected, $response); + } + + public function testRemoteWipeSuccessful(): void { + $this->remoteWipe->expects($this->once()) + ->method('markTokenForWipe') + ->with(123) + ->willReturn(true); + + $response = $this->controller->wipe(123); + + $expected = new JSONResponse([]); + $this->assertEquals($expected, $response); + } + +} diff --git a/apps/settings/tests/Controller/CertificateControllerTest.php b/apps/settings/tests/Controller/CertificateControllerTest.php new file mode 100644 index 00000000000..a36cc201779 --- /dev/null +++ b/apps/settings/tests/Controller/CertificateControllerTest.php @@ -0,0 +1,190 @@ +<?php +/** + * @author Lukas Reschke <lukas@owncloud.com> + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCA\Settings\Tests\Controller; + +use OCA\Settings\Controller\CertificateController; +use OCP\App\IAppManager; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\IRequest; +use OCP\IL10N; +use OCP\ICertificateManager; + +/** + * Class CertificateControllerTest + * + * @package Tests\Settings\Controller + */ +class CertificateControllerTest extends \Test\TestCase { + /** @var CertificateController */ + private $certificateController; + /** @var IRequest */ + private $request; + /** @var ICertificateManager */ + private $certificateManager; + /** @var IL10N */ + private $l10n; + /** @var IAppManager */ + private $appManager; + /** @var ICertificateManager */ + private $systemCertificateManager; + + public function setUp() { + parent::setUp(); + + $this->request = $this->getMockBuilder(IRequest::class)->getMock(); + $this->certificateManager = $this->getMockBuilder(ICertificateManager::class)->getMock(); + $this->systemCertificateManager = $this->getMockBuilder(ICertificateManager::class)->getMock(); + $this->l10n = $this->getMockBuilder(IL10N::class)->getMock(); + $this->appManager = $this->getMockBuilder(IAppManager::class)->getMock(); + + $this->certificateController = $this->getMockBuilder(CertificateController::class) + ->setConstructorArgs( + [ + 'settings', + $this->request, + $this->certificateManager, + $this->systemCertificateManager, + $this->l10n, + $this->appManager + ] + )->setMethods(['isCertificateImportAllowed'])->getMock(); + + $this->certificateController->expects($this->any()) + ->method('isCertificateImportAllowed')->willReturn(true); + } + + public function testAddPersonalRootCertificateWithEmptyFile() { + $this->request + ->expects($this->once()) + ->method('getUploadedFile') + ->with('rootcert_import') + ->will($this->returnValue(null)); + + $expected = new DataResponse(['message' => 'No file uploaded'], Http::STATUS_UNPROCESSABLE_ENTITY); + $this->assertEquals($expected, $this->certificateController->addPersonalRootCertificate()); + } + + public function testAddPersonalRootCertificateValidCertificate() { + $uploadedFile = [ + 'tmp_name' => __DIR__ . '/../../../../tests/data/certificates/goodCertificate.crt', + 'name' => 'goodCertificate.crt', + ]; + + $certificate = $this->getMockBuilder('\OCP\ICertificate')->getMock(); + $certificate + ->expects($this->once()) + ->method('getName') + ->will($this->returnValue('Name')); + $certificate + ->expects($this->once()) + ->method('getCommonName') + ->will($this->returnValue('CommonName')); + $certificate + ->expects($this->once()) + ->method('getOrganization') + ->will($this->returnValue('Organization')); + $certificate + ->expects($this->exactly(2)) + ->method('getIssueDate') + ->will($this->returnValue(new \DateTime('@1429099555'))); + $certificate + ->expects($this->exactly(2)) + ->method('getExpireDate') + ->will($this->returnValue(new \DateTime('@1529099555'))); + $certificate + ->expects($this->once()) + ->method('getIssuerName') + ->will($this->returnValue('Issuer')); + $certificate + ->expects($this->once()) + ->method('getIssuerOrganization') + ->will($this->returnValue('IssuerOrganization')); + + $this->request + ->expects($this->once()) + ->method('getUploadedFile') + ->with('rootcert_import') + ->will($this->returnValue($uploadedFile)); + $this->certificateManager + ->expects($this->once()) + ->method('addCertificate') + ->with(file_get_contents($uploadedFile['tmp_name'], 'goodCertificate.crt')) + ->will($this->returnValue($certificate)); + + $this->l10n + ->expects($this->at(0)) + ->method('l') + ->with('date', new \DateTime('@1429099555')) + ->will($this->returnValue('Valid From as String')); + $this->l10n + ->expects($this->at(1)) + ->method('l') + ->with('date', new \DateTime('@1529099555')) + ->will($this->returnValue('Valid Till as String')); + + + $expected = new DataResponse([ + 'name' => 'Name', + 'commonName' => 'CommonName', + 'organization' => 'Organization', + 'validFrom' => 1429099555, + 'validTill' => 1529099555, + 'validFromString' => 'Valid From as String', + 'validTillString' => 'Valid Till as String', + 'issuer' => 'Issuer', + 'issuerOrganization' => 'IssuerOrganization', + ]); + $this->assertEquals($expected, $this->certificateController->addPersonalRootCertificate()); + } + + public function testAddPersonalRootCertificateInvalidCertificate() { + $uploadedFile = [ + 'tmp_name' => __DIR__ . '/../../../../tests/data/certificates/badCertificate.crt', + 'name' => 'badCertificate.crt', + ]; + + $this->request + ->expects($this->once()) + ->method('getUploadedFile') + ->with('rootcert_import') + ->will($this->returnValue($uploadedFile)); + $this->certificateManager + ->expects($this->once()) + ->method('addCertificate') + ->with(file_get_contents($uploadedFile['tmp_name'], 'badCertificate.crt')) + ->will($this->throwException(new \Exception())); + + $expected = new DataResponse(['An error occurred.'], Http::STATUS_UNPROCESSABLE_ENTITY); + $this->assertEquals($expected, $this->certificateController->addPersonalRootCertificate()); + } + + public function testRemoveCertificate() { + $this->certificateManager + ->expects($this->once()) + ->method('removeCertificate') + ->with('CertificateToRemove'); + + $this->assertEquals(new DataResponse(), $this->certificateController->removePersonalRootCertificate('CertificateToRemove')); + } + +} diff --git a/apps/settings/tests/Controller/CheckSetupControllerTest.php b/apps/settings/tests/Controller/CheckSetupControllerTest.php new file mode 100644 index 00000000000..23e282b6eb4 --- /dev/null +++ b/apps/settings/tests/Controller/CheckSetupControllerTest.php @@ -0,0 +1,1449 @@ +<?php +/** + * @author Lukas Reschke <lukas@owncloud.com> + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCA\Settings\Tests\Controller; + +use OC; +use OC\DB\Connection; +use OC\MemoryInfo; +use OC\Security\SecureRandom; +use OCA\Settings\Controller\CheckSetupController; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataDisplayResponse; +use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\Http\RedirectResponse; +use OCP\Http\Client\IClientService; +use OCP\IConfig; +use OCP\IDateTimeFormatter; +use OCP\IL10N; +use OCP\ILogger; +use OCP\IRequest; +use OCP\IURLGenerator; +use OCP\Lock\ILockingProvider; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Http\Message\ResponseInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Test\TestCase; +use OC\IntegrityCheck\Checker; + +/** + * Class CheckSetupControllerTest + * + * @backupStaticAttributes + * @package Tests\Settings\Controller + */ +class CheckSetupControllerTest extends TestCase { + /** @var CheckSetupController | \PHPUnit_Framework_MockObject_MockObject */ + private $checkSetupController; + /** @var IRequest | \PHPUnit_Framework_MockObject_MockObject */ + private $request; + /** @var IConfig | \PHPUnit_Framework_MockObject_MockObject */ + private $config; + /** @var IClientService | \PHPUnit_Framework_MockObject_MockObject*/ + private $clientService; + /** @var IURLGenerator | \PHPUnit_Framework_MockObject_MockObject */ + private $urlGenerator; + /** @var IL10N | \PHPUnit_Framework_MockObject_MockObject */ + private $l10n; + /** @var ILogger */ + private $logger; + /** @var Checker|\PHPUnit_Framework_MockObject_MockObject */ + private $checker; + /** @var EventDispatcherInterface|\PHPUnit_Framework_MockObject_MockObject */ + private $dispatcher; + /** @var Connection|\PHPUnit_Framework_MockObject_MockObject */ + private $db; + /** @var ILockingProvider|\PHPUnit_Framework_MockObject_MockObject */ + private $lockingProvider; + /** @var IDateTimeFormatter|\PHPUnit_Framework_MockObject_MockObject */ + private $dateTimeFormatter; + /** @var MemoryInfo|MockObject */ + private $memoryInfo; + /** @var SecureRandom|\PHPUnit_Framework_MockObject_MockObject */ + private $secureRandom; + + /** + * Holds a list of directories created during tests. + * + * @var array + */ + private $dirsToRemove = []; + + public function setUp() { + parent::setUp(); + + $this->request = $this->getMockBuilder(IRequest::class) + ->disableOriginalConstructor()->getMock(); + $this->config = $this->getMockBuilder(IConfig::class) + ->disableOriginalConstructor()->getMock(); + $this->clientService = $this->getMockBuilder(IClientService::class) + ->disableOriginalConstructor()->getMock(); + $this->urlGenerator = $this->getMockBuilder(IURLGenerator::class) + ->disableOriginalConstructor()->getMock(); + $this->l10n = $this->getMockBuilder(IL10N::class) + ->disableOriginalConstructor()->getMock(); + $this->l10n->expects($this->any()) + ->method('t') + ->will($this->returnCallback(function($message, array $replace) { + return vsprintf($message, $replace); + })); + $this->dispatcher = $this->getMockBuilder(EventDispatcherInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->checker = $this->getMockBuilder('\OC\IntegrityCheck\Checker') + ->disableOriginalConstructor()->getMock(); + $this->logger = $this->getMockBuilder(ILogger::class)->getMock(); + $this->db = $this->getMockBuilder(Connection::class) + ->disableOriginalConstructor()->getMock(); + $this->lockingProvider = $this->getMockBuilder(ILockingProvider::class)->getMock(); + $this->dateTimeFormatter = $this->getMockBuilder(IDateTimeFormatter::class)->getMock(); + $this->memoryInfo = $this->getMockBuilder(MemoryInfo::class) + ->setMethods(['isMemoryLimitSufficient',]) + ->getMock(); + $this->secureRandom = $this->getMockBuilder(SecureRandom::class)->getMock(); + $this->checkSetupController = $this->getMockBuilder(CheckSetupController::class) + ->setConstructorArgs([ + 'settings', + $this->request, + $this->config, + $this->clientService, + $this->urlGenerator, + $this->l10n, + $this->checker, + $this->logger, + $this->dispatcher, + $this->db, + $this->lockingProvider, + $this->dateTimeFormatter, + $this->memoryInfo, + $this->secureRandom, + ]) + ->setMethods([ + 'isReadOnlyConfig', + 'hasValidTransactionIsolationLevel', + 'hasFileinfoInstalled', + 'hasWorkingFileLocking', + 'getLastCronInfo', + 'getSuggestedOverwriteCliURL', + 'getCurlVersion', + 'isPhpOutdated', + 'isOpcacheProperlySetup', + 'hasFreeTypeSupport', + 'hasMissingIndexes', + 'isSqliteUsed', + 'isPHPMailerUsed', + 'hasOpcacheLoaded', + 'getAppDirsWithDifferentOwner', + 'hasRecommendedPHPModules', + 'hasBigIntConversionPendingColumns', + 'isMysqlUsedWithoutUTF8MB4', + 'isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed', + ])->getMock(); + } + + /** + * Removes directories created during tests. + * + * @after + * @return void + */ + public function removeTestDirectories() { + foreach ($this->dirsToRemove as $dirToRemove) { + rmdir($dirToRemove); + } + $this->dirsToRemove = []; + } + + public function testIsInternetConnectionWorkingDisabledViaConfig() { + $this->config->expects($this->once()) + ->method('getSystemValue') + ->with('has_internet_connection', true) + ->will($this->returnValue(false)); + + $this->assertFalse( + self::invokePrivate( + $this->checkSetupController, + 'hasInternetConnectivityProblems' + ) + ); + } + + public function testIsInternetConnectionWorkingCorrectly() { + $this->config->expects($this->at(0)) + ->method('getSystemValue') + ->with('has_internet_connection', true) + ->will($this->returnValue(true)); + + $this->config->expects($this->at(1)) + ->method('getSystemValue') + ->with('connectivity_check_domains', ['www.nextcloud.com', 'www.startpage.com', 'www.eff.org', 'www.edri.org']) + ->will($this->returnValue(['www.nextcloud.com', 'www.startpage.com', 'www.eff.org', 'www.edri.org'])); + + $client = $this->getMockBuilder('\OCP\Http\Client\IClient') + ->disableOriginalConstructor()->getMock(); + $client->expects($this->any()) + ->method('get'); + + $this->clientService->expects($this->once()) + ->method('newClient') + ->will($this->returnValue($client)); + + + $this->assertFalse( + self::invokePrivate( + $this->checkSetupController, + 'hasInternetConnectivityProblems' + ) + ); + } + + public function testIsInternetConnectionFail() { + $this->config->expects($this->at(0)) + ->method('getSystemValue') + ->with('has_internet_connection', true) + ->will($this->returnValue(true)); + + $this->config->expects($this->at(1)) + ->method('getSystemValue') + ->with('connectivity_check_domains', ['www.nextcloud.com', 'www.startpage.com', 'www.eff.org', 'www.edri.org']) + ->will($this->returnValue(['www.nextcloud.com', 'www.startpage.com', 'www.eff.org', 'www.edri.org'])); + + $client = $this->getMockBuilder('\OCP\Http\Client\IClient') + ->disableOriginalConstructor()->getMock(); + $client->expects($this->any()) + ->method('get') + ->will($this->throwException(new \Exception())); + + $this->clientService->expects($this->exactly(4)) + ->method('newClient') + ->will($this->returnValue($client)); + + $this->assertTrue( + self::invokePrivate( + $this->checkSetupController, + 'hasInternetConnectivityProblems' + ) + ); + } + + + public function testIsMemcacheConfiguredFalse() { + $this->config->expects($this->once()) + ->method('getSystemValue') + ->with('memcache.local', null) + ->will($this->returnValue(null)); + + $this->assertFalse( + self::invokePrivate( + $this->checkSetupController, + 'isMemcacheConfigured' + ) + ); + } + + public function testIsMemcacheConfiguredTrue() { + $this->config->expects($this->once()) + ->method('getSystemValue') + ->with('memcache.local', null) + ->will($this->returnValue('SomeProvider')); + + $this->assertTrue( + self::invokePrivate( + $this->checkSetupController, + 'isMemcacheConfigured' + ) + ); + } + + public function testIsPhpSupportedFalse() { + $this->checkSetupController + ->expects($this->once()) + ->method('isPhpOutdated') + ->willReturn(true); + + $this->assertEquals( + ['eol' => true, 'version' => PHP_VERSION], + self::invokePrivate($this->checkSetupController, 'isPhpSupported') + ); + } + + public function testIsPhpSupportedTrue() { + $this->checkSetupController + ->expects($this->exactly(2)) + ->method('isPhpOutdated') + ->willReturn(false); + + $this->assertEquals( + ['eol' => false, 'version' => PHP_VERSION], + self::invokePrivate($this->checkSetupController, 'isPhpSupported') + ); + + + $this->assertEquals( + ['eol' => false, 'version' => PHP_VERSION], + self::invokePrivate($this->checkSetupController, 'isPhpSupported') + ); + } + + /** + * @dataProvider dataForwardedForHeadersWorking + * + * @param array $trustedProxies + * @param string $remoteAddrNotForwarded + * @param string $remoteAddr + * @param bool $result + */ + public function testForwardedForHeadersWorking(array $trustedProxies, string $remoteAddrNotForwarded, string $remoteAddr, bool $result) { + $this->config->expects($this->once()) + ->method('getSystemValue') + ->with('trusted_proxies', []) + ->willReturn($trustedProxies); + $this->request->expects($this->atLeastOnce()) + ->method('getHeader') + ->willReturnMap([ + ['REMOTE_ADDR', $remoteAddrNotForwarded], + ['X-Forwarded-Host', ''] + ]); + $this->request->expects($this->any()) + ->method('getRemoteAddress') + ->willReturn($remoteAddr); + + $this->assertEquals( + $result, + self::invokePrivate($this->checkSetupController, 'forwardedForHeadersWorking') + ); + } + + public function dataForwardedForHeadersWorking() { + return [ + // description => trusted proxies, getHeader('REMOTE_ADDR'), getRemoteAddr, expected result + 'no trusted proxies' => [[], '2.2.2.2', '2.2.2.2', true], + 'trusted proxy, remote addr not trusted proxy' => [['1.1.1.1'], '2.2.2.2', '2.2.2.2', true], + 'trusted proxy, remote addr is trusted proxy, x-forwarded-for working' => [['1.1.1.1'], '1.1.1.1', '2.2.2.2', true], + 'trusted proxy, remote addr is trusted proxy, x-forwarded-for not set' => [['1.1.1.1'], '1.1.1.1', '1.1.1.1', false], + ]; + } + + public function testForwardedHostPresentButTrustedProxiesEmpty() { + $this->config->expects($this->once()) + ->method('getSystemValue') + ->with('trusted_proxies', []) + ->willReturn([]); + $this->request->expects($this->atLeastOnce()) + ->method('getHeader') + ->willReturnMap([ + ['REMOTE_ADDR', '1.1.1.1'], + ['X-Forwarded-Host', 'nextcloud.test'] + ]); + $this->request->expects($this->any()) + ->method('getRemoteAddress') + ->willReturn('1.1.1.1'); + + $this->assertEquals( + false, + self::invokePrivate($this->checkSetupController, 'forwardedForHeadersWorking') + ); + } + + public function testCheck() { + $this->config->expects($this->at(0)) + ->method('getAppValue') + ->with('core', 'cronErrors') + ->willReturn(''); + $this->config->expects($this->at(2)) + ->method('getSystemValue') + ->with('connectivity_check_domains', ['www.nextcloud.com', 'www.startpage.com', 'www.eff.org', 'www.edri.org']) + ->will($this->returnValue(['www.nextcloud.com', 'www.startpage.com', 'www.eff.org', 'www.edri.org'])); + $this->config->expects($this->at(3)) + ->method('getSystemValue') + ->with('memcache.local', null) + ->will($this->returnValue('SomeProvider')); + $this->config->expects($this->at(4)) + ->method('getSystemValue') + ->with('has_internet_connection', true) + ->will($this->returnValue(true)); + $this->config->expects($this->at(5)) + ->method('getSystemValue') + ->with('appstoreenabled', true) + ->will($this->returnValue(false)); + + $this->request->expects($this->atLeastOnce()) + ->method('getHeader') + ->willReturnMap([ + ['REMOTE_ADDR', '4.3.2.1'], + ['X-Forwarded-Host', ''] + ]); + + $client = $this->getMockBuilder('\OCP\Http\Client\IClient') + ->disableOriginalConstructor()->getMock(); + $client->expects($this->at(0)) + ->method('get') + ->with('http://www.nextcloud.com/', []) + ->will($this->throwException(new \Exception())); + $client->expects($this->at(1)) + ->method('get') + ->with('http://www.startpage.com/', []) + ->will($this->throwException(new \Exception())); + $client->expects($this->at(2)) + ->method('get') + ->with('http://www.eff.org/', []) + ->will($this->throwException(new \Exception())); + $client->expects($this->at(3)) + ->method('get') + ->with('http://www.edri.org/', []) + ->will($this->throwException(new \Exception())); + $this->clientService->expects($this->exactly(4)) + ->method('newClient') + ->will($this->returnValue($client)); + $this->urlGenerator->expects($this->at(0)) + ->method('linkToDocs') + ->with('admin-performance') + ->willReturn('http://docs.example.org/server/go.php?to=admin-performance'); + $this->urlGenerator->expects($this->at(1)) + ->method('linkToDocs') + ->with('admin-security') + ->willReturn('https://docs.example.org/server/8.1/admin_manual/configuration_server/hardening.html'); + $this->checkSetupController + ->expects($this->once()) + ->method('isPhpOutdated') + ->willReturn(true); + $this->checkSetupController + ->expects($this->once()) + ->method('isOpcacheProperlySetup') + ->willReturn(false); + $this->urlGenerator->expects($this->at(2)) + ->method('linkToDocs') + ->with('admin-reverse-proxy') + ->willReturn('reverse-proxy-doc-link'); + $this->urlGenerator->expects($this->at(3)) + ->method('linkToDocs') + ->with('admin-code-integrity') + ->willReturn('http://docs.example.org/server/go.php?to=admin-code-integrity'); + $this->urlGenerator->expects($this->at(4)) + ->method('linkToDocs') + ->with('admin-php-opcache') + ->willReturn('http://docs.example.org/server/go.php?to=admin-php-opcache'); + $this->urlGenerator->expects($this->at(5)) + ->method('linkToDocs') + ->with('admin-db-conversion') + ->willReturn('http://docs.example.org/server/go.php?to=admin-db-conversion'); + $this->urlGenerator->expects($this->at(6)) + ->method('getAbsoluteURL') + ->with('index.php/settings/admin') + ->willReturn('https://server/index.php/settings/admin'); + $this->checkSetupController + ->method('hasFreeTypeSupport') + ->willReturn(false); + $this->checkSetupController + ->method('hasMissingIndexes') + ->willReturn([]); + $this->checkSetupController + ->method('isSqliteUsed') + ->willReturn(false); + $this->checkSetupController + ->expects($this->once()) + ->method('isReadOnlyConfig') + ->willReturn(false); + $this->checkSetupController + ->expects($this->once()) + ->method('hasValidTransactionIsolationLevel') + ->willReturn(true); + $this->checkSetupController + ->expects($this->once()) + ->method('hasFileinfoInstalled') + ->willReturn(true); + $this->checkSetupController + ->expects($this->once()) + ->method('hasOpcacheLoaded') + ->willReturn(true); + $this->checkSetupController + ->expects($this->once()) + ->method('hasWorkingFileLocking') + ->willReturn(true); + $this->checkSetupController + ->expects($this->once()) + ->method('getSuggestedOverwriteCliURL') + ->willReturn(''); + $this->checkSetupController + ->expects($this->once()) + ->method('getLastCronInfo') + ->willReturn([ + 'diffInSeconds' => 123, + 'relativeTime' => '2 hours ago', + 'backgroundJobsUrl' => 'https://example.org', + ]); + $this->checkSetupController + ->expects($this->once()) + ->method('isPHPMailerUsed') + ->willReturn(false); + $this->checker + ->expects($this->once()) + ->method('hasPassedCheck') + ->willReturn(true); + $this->memoryInfo + ->method('isMemoryLimitSufficient') + ->willReturn(true); + + $this->checkSetupController + ->expects($this->once()) + ->method('getAppDirsWithDifferentOwner') + ->willReturn([]); + + $this->checkSetupController + ->expects($this->once()) + ->method('hasRecommendedPHPModules') + ->willReturn([]); + + $this->checkSetupController + ->expects($this->once()) + ->method('hasBigIntConversionPendingColumns') + ->willReturn([]); + + $this->checkSetupController + ->expects($this->once()) + ->method('isMysqlUsedWithoutUTF8MB4') + ->willReturn(false); + + $this->checkSetupController + ->expects($this->once()) + ->method('isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed') + ->willReturn(true); + + $expected = new DataResponse( + [ + 'isGetenvServerWorking' => true, + 'isReadOnlyConfig' => false, + 'hasValidTransactionIsolationLevel' => true, + 'hasFileinfoInstalled' => true, + 'hasWorkingFileLocking' => true, + 'suggestedOverwriteCliURL' => '', + 'cronInfo' => [ + 'diffInSeconds' => 123, + 'relativeTime' => '2 hours ago', + 'backgroundJobsUrl' => 'https://example.org', + ], + 'cronErrors' => [], + 'serverHasInternetConnectionProblems' => true, + 'isMemcacheConfigured' => true, + 'memcacheDocs' => 'http://docs.example.org/server/go.php?to=admin-performance', + 'isRandomnessSecure' => self::invokePrivate($this->checkSetupController, 'isRandomnessSecure'), + 'securityDocs' => 'https://docs.example.org/server/8.1/admin_manual/configuration_server/hardening.html', + 'isUsedTlsLibOutdated' => '', + 'phpSupported' => [ + 'eol' => true, + 'version' => PHP_VERSION + ], + 'forwardedForHeadersWorking' => true, + 'reverseProxyDocs' => 'reverse-proxy-doc-link', + 'isCorrectMemcachedPHPModuleInstalled' => true, + 'hasPassedCodeIntegrityCheck' => true, + 'codeIntegrityCheckerDocumentation' => 'http://docs.example.org/server/go.php?to=admin-code-integrity', + 'isOpcacheProperlySetup' => false, + 'hasOpcacheLoaded' => true, + 'phpOpcacheDocumentation' => 'http://docs.example.org/server/go.php?to=admin-php-opcache', + 'isSettimelimitAvailable' => true, + 'hasFreeTypeSupport' => false, + 'isSqliteUsed' => false, + 'databaseConversionDocumentation' => 'http://docs.example.org/server/go.php?to=admin-db-conversion', + 'missingIndexes' => [], + 'isPHPMailerUsed' => false, + 'mailSettingsDocumentation' => 'https://server/index.php/settings/admin', + 'isMemoryLimitSufficient' => true, + 'appDirsWithDifferentOwner' => [], + 'recommendedPHPModules' => [], + 'pendingBigIntConversionColumns' => [], + 'isMysqlUsedWithoutUTF8MB4' => false, + 'isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed' => true, + ] + ); + $this->assertEquals($expected, $this->checkSetupController->check()); + } + + public function testIsPHPMailerUsed() { + $checkSetupController = $this->getMockBuilder(CheckSetupController::class) + ->setConstructorArgs([ + 'settings', + $this->request, + $this->config, + $this->clientService, + $this->urlGenerator, + $this->l10n, + $this->checker, + $this->logger, + $this->dispatcher, + $this->db, + $this->lockingProvider, + $this->dateTimeFormatter, + $this->memoryInfo, + $this->secureRandom, + ]) + ->setMethods(null)->getMock(); + + $this->config->expects($this->at(0)) + ->method('getSystemValue') + ->with('mail_smtpmode', 'smtp') + ->will($this->returnValue('php')); + $this->config->expects($this->at(1)) + ->method('getSystemValue') + ->with('mail_smtpmode', 'smtp') + ->will($this->returnValue('not-php')); + + $this->assertTrue($this->invokePrivate($checkSetupController, 'isPHPMailerUsed')); + $this->assertFalse($this->invokePrivate($checkSetupController, 'isPHPMailerUsed')); + } + + public function testGetCurlVersion() { + $checkSetupController = $this->getMockBuilder(CheckSetupController::class) + ->setConstructorArgs([ + 'settings', + $this->request, + $this->config, + $this->clientService, + $this->urlGenerator, + $this->l10n, + $this->checker, + $this->logger, + $this->dispatcher, + $this->db, + $this->lockingProvider, + $this->dateTimeFormatter, + $this->memoryInfo, + $this->secureRandom, + ]) + ->setMethods(null)->getMock(); + + $this->assertArrayHasKey('ssl_version', $this->invokePrivate($checkSetupController, 'getCurlVersion')); + } + + public function testIsUsedTlsLibOutdatedWithAnotherLibrary() { + $this->config->expects($this->any()) + ->method('getSystemValue') + ->will($this->returnValue(true)); + $this->checkSetupController + ->expects($this->once()) + ->method('getCurlVersion') + ->will($this->returnValue(['ssl_version' => 'SSLlib'])); + $this->assertSame('', $this->invokePrivate($this->checkSetupController, 'isUsedTlsLibOutdated')); + } + + public function testIsUsedTlsLibOutdatedWithMisbehavingCurl() { + $this->config->expects($this->any()) + ->method('getSystemValue') + ->will($this->returnValue(true)); + $this->checkSetupController + ->expects($this->once()) + ->method('getCurlVersion') + ->will($this->returnValue([])); + $this->assertSame('', $this->invokePrivate($this->checkSetupController, 'isUsedTlsLibOutdated')); + } + + public function testIsUsedTlsLibOutdatedWithOlderOpenSsl() { + $this->config->expects($this->any()) + ->method('getSystemValue') + ->will($this->returnValue(true)); + $this->checkSetupController + ->expects($this->once()) + ->method('getCurlVersion') + ->will($this->returnValue(['ssl_version' => 'OpenSSL/1.0.1c'])); + $this->assertSame('cURL is using an outdated OpenSSL version (OpenSSL/1.0.1c). Please update your operating system or features such as installing and updating apps via the app store or Federated Cloud Sharing will not work reliably.', $this->invokePrivate($this->checkSetupController, 'isUsedTlsLibOutdated')); + } + + public function testIsUsedTlsLibOutdatedWithOlderOpenSslAndWithoutAppstore() { + $this->config + ->expects($this->at(0)) + ->method('getSystemValue') + ->with('has_internet_connection', true) + ->will($this->returnValue(true)); + $this->checkSetupController + ->expects($this->once()) + ->method('getCurlVersion') + ->will($this->returnValue(['ssl_version' => 'OpenSSL/1.0.1c'])); + $this->assertSame('cURL is using an outdated OpenSSL version (OpenSSL/1.0.1c). Please update your operating system or features such as Federated Cloud Sharing will not work reliably.', $this->invokePrivate($this->checkSetupController, 'isUsedTlsLibOutdated')); + } + + public function testIsUsedTlsLibOutdatedWithOlderOpenSsl1() { + $this->config->expects($this->any()) + ->method('getSystemValue') + ->will($this->returnValue(true)); + $this->checkSetupController + ->expects($this->once()) + ->method('getCurlVersion') + ->will($this->returnValue(['ssl_version' => 'OpenSSL/1.0.2a'])); + $this->assertSame('cURL is using an outdated OpenSSL version (OpenSSL/1.0.2a). Please update your operating system or features such as installing and updating apps via the app store or Federated Cloud Sharing will not work reliably.', $this->invokePrivate($this->checkSetupController, 'isUsedTlsLibOutdated')); + } + + public function testIsUsedTlsLibOutdatedWithMatchingOpenSslVersion() { + $this->config->expects($this->any()) + ->method('getSystemValue') + ->will($this->returnValue(true)); + $this->checkSetupController + ->expects($this->once()) + ->method('getCurlVersion') + ->will($this->returnValue(['ssl_version' => 'OpenSSL/1.0.1d'])); + $this->assertSame('', $this->invokePrivate($this->checkSetupController, 'isUsedTlsLibOutdated')); + } + + public function testIsUsedTlsLibOutdatedWithMatchingOpenSslVersion1() { + $this->config->expects($this->any()) + ->method('getSystemValue') + ->will($this->returnValue(true)); + $this->checkSetupController + ->expects($this->once()) + ->method('getCurlVersion') + ->will($this->returnValue(['ssl_version' => 'OpenSSL/1.0.2b'])); + $this->assertSame('', $this->invokePrivate($this->checkSetupController, 'isUsedTlsLibOutdated')); + } + + /** + * Setups a temp directory and some subdirectories. + * Then calls the 'getAppDirsWithDifferentOwner' method. + * The result is expected to be empty since + * there are no directories with different owners than the current user. + * + * @return void + */ + public function testAppDirectoryOwnersOk() { + $tempDir = tempnam(sys_get_temp_dir(), 'apps') . 'dir'; + mkdir($tempDir); + mkdir($tempDir . DIRECTORY_SEPARATOR . 'app1'); + mkdir($tempDir . DIRECTORY_SEPARATOR . 'app2'); + $this->dirsToRemove[] = $tempDir . DIRECTORY_SEPARATOR . 'app1'; + $this->dirsToRemove[] = $tempDir . DIRECTORY_SEPARATOR . 'app2'; + $this->dirsToRemove[] = $tempDir; + OC::$APPSROOTS = [ + [ + 'path' => $tempDir, + 'url' => '/apps', + 'writable' => true, + ], + ]; + $this->assertSame( + [], + $this->invokePrivate($this->checkSetupController, 'getAppDirsWithDifferentOwner') + ); + } + + /** + * Calls the check for a none existing app root that is marked as not writable. + * It's expected that no error happens since the check shouldn't apply. + * + * @return void + */ + public function testAppDirectoryOwnersNotWritable() { + $tempDir = tempnam(sys_get_temp_dir(), 'apps') . 'dir'; + OC::$APPSROOTS = [ + [ + 'path' => $tempDir, + 'url' => '/apps', + 'writable' => false, + ], + ]; + $this->assertSame( + [], + $this->invokePrivate($this->checkSetupController, 'getAppDirsWithDifferentOwner') + ); + } + + public function testIsBuggyNss400() { + $this->config->expects($this->any()) + ->method('getSystemValue') + ->will($this->returnValue(true)); + $this->checkSetupController + ->expects($this->once()) + ->method('getCurlVersion') + ->will($this->returnValue(['ssl_version' => 'NSS/1.0.2b'])); + $client = $this->getMockBuilder('\OCP\Http\Client\IClient') + ->disableOriginalConstructor()->getMock(); + $exception = $this->getMockBuilder('\GuzzleHttp\Exception\ClientException') + ->disableOriginalConstructor()->getMock(); + $response = $this->getMockBuilder(ResponseInterface::class) + ->disableOriginalConstructor()->getMock(); + $response->expects($this->once()) + ->method('getStatusCode') + ->will($this->returnValue(400)); + $exception->expects($this->once()) + ->method('getResponse') + ->will($this->returnValue($response)); + + $client->expects($this->at(0)) + ->method('get') + ->with('https://nextcloud.com/', []) + ->will($this->throwException($exception)); + + $this->clientService->expects($this->once()) + ->method('newClient') + ->will($this->returnValue($client)); + + $this->assertSame('cURL is using an outdated NSS version (NSS/1.0.2b). Please update your operating system or features such as installing and updating apps via the app store or Federated Cloud Sharing will not work reliably.', $this->invokePrivate($this->checkSetupController, 'isUsedTlsLibOutdated')); + } + + + public function testIsBuggyNss200() { + $this->config->expects($this->any()) + ->method('getSystemValue') + ->will($this->returnValue(true)); + $this->checkSetupController + ->expects($this->once()) + ->method('getCurlVersion') + ->will($this->returnValue(['ssl_version' => 'NSS/1.0.2b'])); + $client = $this->getMockBuilder('\OCP\Http\Client\IClient') + ->disableOriginalConstructor()->getMock(); + $exception = $this->getMockBuilder('\GuzzleHttp\Exception\ClientException') + ->disableOriginalConstructor()->getMock(); + $response = $this->getMockBuilder(ResponseInterface::class) + ->disableOriginalConstructor()->getMock(); + $response->expects($this->once()) + ->method('getStatusCode') + ->will($this->returnValue(200)); + $exception->expects($this->once()) + ->method('getResponse') + ->will($this->returnValue($response)); + + $client->expects($this->at(0)) + ->method('get') + ->with('https://nextcloud.com/', []) + ->will($this->throwException($exception)); + + $this->clientService->expects($this->once()) + ->method('newClient') + ->will($this->returnValue($client)); + + $this->assertSame('', $this->invokePrivate($this->checkSetupController, 'isUsedTlsLibOutdated')); + } + + public function testIsUsedTlsLibOutdatedWithInternetDisabled() { + $this->config + ->expects($this->at(0)) + ->method('getSystemValue') + ->with('has_internet_connection', true) + ->will($this->returnValue(false)); + $this->assertSame('', $this->invokePrivate($this->checkSetupController, 'isUsedTlsLibOutdated')); + } + + public function testIsUsedTlsLibOutdatedWithAppstoreDisabledAndServerToServerSharingEnabled() { + $this->config + ->expects($this->at(0)) + ->method('getSystemValue') + ->with('has_internet_connection', true) + ->will($this->returnValue(true)); + $this->config + ->expects($this->at(1)) + ->method('getSystemValue') + ->with('appstoreenabled', true) + ->will($this->returnValue(false)); + $this->config + ->expects($this->at(2)) + ->method('getAppValue') + ->with('files_sharing', 'outgoing_server2server_share_enabled', 'yes') + ->will($this->returnValue('no')); + $this->config + ->expects($this->at(3)) + ->method('getAppValue') + ->with('files_sharing', 'incoming_server2server_share_enabled', 'yes') + ->will($this->returnValue('yes')); + + $this->checkSetupController + ->expects($this->once()) + ->method('getCurlVersion') + ->will($this->returnValue([])); + $this->assertSame('', $this->invokePrivate($this->checkSetupController, 'isUsedTlsLibOutdated')); + } + + public function testIsUsedTlsLibOutdatedWithAppstoreDisabledAndServerToServerSharingDisabled() { + $this->config + ->expects($this->at(0)) + ->method('getSystemValue') + ->with('has_internet_connection', true) + ->will($this->returnValue(true)); + $this->config + ->expects($this->at(1)) + ->method('getSystemValue') + ->with('appstoreenabled', true) + ->will($this->returnValue(false)); + $this->config + ->expects($this->at(2)) + ->method('getAppValue') + ->with('files_sharing', 'outgoing_server2server_share_enabled', 'yes') + ->will($this->returnValue('no')); + $this->config + ->expects($this->at(3)) + ->method('getAppValue') + ->with('files_sharing', 'incoming_server2server_share_enabled', 'yes') + ->will($this->returnValue('no')); + + $this->checkSetupController + ->expects($this->never()) + ->method('getCurlVersion') + ->will($this->returnValue([])); + $this->assertSame('', $this->invokePrivate($this->checkSetupController, 'isUsedTlsLibOutdated')); + } + + public function testRescanFailedIntegrityCheck() { + $this->checker + ->expects($this->once()) + ->method('runInstanceVerification'); + $this->urlGenerator + ->expects($this->once()) + ->method('linkToRoute') + ->with('settings.AdminSettings.index') + ->will($this->returnValue('/admin')); + + $expected = new RedirectResponse('/admin'); + $this->assertEquals($expected, $this->checkSetupController->rescanFailedIntegrityCheck()); + } + + public function testGetFailedIntegrityCheckDisabled() { + $this->checker + ->expects($this->once()) + ->method('isCodeCheckEnforced') + ->willReturn(false); + + $expected = new DataDisplayResponse('Integrity checker has been disabled. Integrity cannot be verified.'); + $this->assertEquals($expected, $this->checkSetupController->getFailedIntegrityCheckFiles()); + } + + + public function testGetFailedIntegrityCheckFilesWithNoErrorsFound() { + $this->checker + ->expects($this->once()) + ->method('isCodeCheckEnforced') + ->willReturn(true); + $this->checker + ->expects($this->once()) + ->method('getResults') + ->will($this->returnValue([])); + + $expected = new DataDisplayResponse( + 'No errors have been found.', + Http::STATUS_OK, + [ + 'Content-Type' => 'text/plain', + ] + ); + $this->assertEquals($expected, $this->checkSetupController->getFailedIntegrityCheckFiles()); + } + + public function testGetFailedIntegrityCheckFilesWithSomeErrorsFound() { + $this->checker + ->expects($this->once()) + ->method('isCodeCheckEnforced') + ->willReturn(true); + $this->checker + ->expects($this->once()) + ->method('getResults') + ->will($this->returnValue(array ( 'core' => array ( 'EXTRA_FILE' => array('/testfile' => array()), 'INVALID_HASH' => array ( '/.idea/workspace.xml' => array ( 'expected' => 'f1c5e2630d784bc9cb02d5a28f55d6f24d06dae2a0fee685f3c2521b050955d9d452769f61454c9ddfa9c308146ade10546cfa829794448eaffbc9a04a29d216', 'current' => 'ce08bf30bcbb879a18b49239a9bec6b8702f52452f88a9d32142cad8d2494d5735e6bfa0d8642b2762c62ca5be49f9bf4ec231d4a230559d4f3e2c471d3ea094', ), '/lib/private/integritycheck/checker.php' => array ( 'expected' => 'c5a03bacae8dedf8b239997901ba1fffd2fe51271d13a00cc4b34b09cca5176397a89fc27381cbb1f72855fa18b69b6f87d7d5685c3b45aee373b09be54742ea', 'current' => '88a3a92c11db91dec1ac3be0e1c87f862c95ba6ffaaaa3f2c3b8f682187c66f07af3a3b557a868342ef4a271218fe1c1e300c478e6c156c5955ed53c40d06585', ), '/settings/controller/checksetupcontroller.php' => array ( 'expected' => '3e1de26ce93c7bfe0ede7c19cb6c93cadc010340225b375607a7178812e9de163179b0dc33809f451e01f491d93f6f5aaca7929685d21594cccf8bda732327c4', 'current' => '09563164f9904a837f9ca0b5f626db56c838e5098e0ccc1d8b935f68fa03a25c5ec6f6b2d9e44a868e8b85764dafd1605522b4af8db0ae269d73432e9a01e63a', ), ), ), 'bookmarks' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'dav' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'encryption' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'external' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'federation' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'files' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'files_antivirus' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'files_drop' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'files_external' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'files_pdfviewer' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'files_sharing' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'files_trashbin' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'files_versions' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'files_videoviewer' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'firstrunwizard' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'gitsmart' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'logreader' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature could not get verified.', ), ), 'password_policy' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'provisioning_api' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'sketch' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'threatblock' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'two_factor_auth' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'user_ldap' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), 'user_shibboleth' => array ( 'EXCEPTION' => array ( 'class' => 'OC\\IntegrityCheck\\Exceptions\\InvalidSignatureException', 'message' => 'Signature data not found.', ), ), ))); + + $expected = new DataDisplayResponse( + 'Technical information +===================== +The following list covers which files have failed the integrity check. Please read +the previous linked documentation to learn more about the errors and how to fix +them. + +Results +======= +- core + - EXTRA_FILE + - /testfile + - INVALID_HASH + - /.idea/workspace.xml + - /lib/private/integritycheck/checker.php + - /settings/controller/checksetupcontroller.php +- bookmarks + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- dav + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- encryption + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- external + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- federation + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- files + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- files_antivirus + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- files_drop + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- files_external + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- files_pdfviewer + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- files_sharing + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- files_trashbin + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- files_versions + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- files_videoviewer + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- firstrunwizard + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- gitsmart + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- logreader + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature could not get verified. +- password_policy + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- provisioning_api + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- sketch + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- threatblock + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- two_factor_auth + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- user_ldap + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. +- user_shibboleth + - EXCEPTION + - OC\IntegrityCheck\Exceptions\InvalidSignatureException + - Signature data not found. + +Raw output +========== +Array +( + [core] => Array + ( + [EXTRA_FILE] => Array + ( + [/testfile] => Array + ( + ) + + ) + + [INVALID_HASH] => Array + ( + [/.idea/workspace.xml] => Array + ( + [expected] => f1c5e2630d784bc9cb02d5a28f55d6f24d06dae2a0fee685f3c2521b050955d9d452769f61454c9ddfa9c308146ade10546cfa829794448eaffbc9a04a29d216 + [current] => ce08bf30bcbb879a18b49239a9bec6b8702f52452f88a9d32142cad8d2494d5735e6bfa0d8642b2762c62ca5be49f9bf4ec231d4a230559d4f3e2c471d3ea094 + ) + + [/lib/private/integritycheck/checker.php] => Array + ( + [expected] => c5a03bacae8dedf8b239997901ba1fffd2fe51271d13a00cc4b34b09cca5176397a89fc27381cbb1f72855fa18b69b6f87d7d5685c3b45aee373b09be54742ea + [current] => 88a3a92c11db91dec1ac3be0e1c87f862c95ba6ffaaaa3f2c3b8f682187c66f07af3a3b557a868342ef4a271218fe1c1e300c478e6c156c5955ed53c40d06585 + ) + + [/settings/controller/checksetupcontroller.php] => Array + ( + [expected] => 3e1de26ce93c7bfe0ede7c19cb6c93cadc010340225b375607a7178812e9de163179b0dc33809f451e01f491d93f6f5aaca7929685d21594cccf8bda732327c4 + [current] => 09563164f9904a837f9ca0b5f626db56c838e5098e0ccc1d8b935f68fa03a25c5ec6f6b2d9e44a868e8b85764dafd1605522b4af8db0ae269d73432e9a01e63a + ) + + ) + + ) + + [bookmarks] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [dav] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [encryption] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [external] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [federation] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [files] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [files_antivirus] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [files_drop] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [files_external] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [files_pdfviewer] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [files_sharing] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [files_trashbin] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [files_versions] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [files_videoviewer] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [firstrunwizard] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [gitsmart] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [logreader] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature could not get verified. + ) + + ) + + [password_policy] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [provisioning_api] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [sketch] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [threatblock] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [two_factor_auth] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [user_ldap] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + + [user_shibboleth] => Array + ( + [EXCEPTION] => Array + ( + [class] => OC\IntegrityCheck\Exceptions\InvalidSignatureException + [message] => Signature data not found. + ) + + ) + +) +', + Http::STATUS_OK, + [ + 'Content-Type' => 'text/plain', + ] + ); + $this->assertEquals($expected, $this->checkSetupController->getFailedIntegrityCheckFiles()); + } + + public function dataForIsMysqlUsedWithoutUTF8MB4() { + return [ + ['sqlite', false, false], + ['sqlite', true, false], + ['postgres', false, false], + ['postgres', true, false], + ['oci', false, false], + ['oci', true, false], + ['mysql', false, true], + ['mysql', true, false], + ]; + } + + /** + * @dataProvider dataForIsMysqlUsedWithoutUTF8MB4 + */ + public function testIsMysqlUsedWithoutUTF8MB4(string $db, bool $useUTF8MB4, bool $expected) { + $this->config->method('getSystemValue') + ->will($this->returnCallback(function($key, $default) use ($db, $useUTF8MB4) { + if ($key === 'dbtype') { + return $db; + } + if ($key === 'mysql.utf8mb4') { + return $useUTF8MB4; + } + return $default; + })); + + $checkSetupController = new CheckSetupController( + 'settings', + $this->request, + $this->config, + $this->clientService, + $this->urlGenerator, + $this->l10n, + $this->checker, + $this->logger, + $this->dispatcher, + $this->db, + $this->lockingProvider, + $this->dateTimeFormatter, + $this->memoryInfo, + $this->secureRandom + ); + + $this->assertSame($expected, $this->invokePrivate($checkSetupController, 'isMysqlUsedWithoutUTF8MB4')); + } + + public function dataForIsEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed() { + return [ + ['singlebucket', 'OC\\Files\\ObjectStore\\Swift', true], + ['multibucket', 'OC\\Files\\ObjectStore\\Swift', true], + ['singlebucket', 'OC\\Files\\ObjectStore\\Custom', true], + ['multibucket', 'OC\Files\\ObjectStore\\Custom', true], + ['singlebucket', 'OC\Files\ObjectStore\Swift', true], + ['multibucket', 'OC\Files\ObjectStore\Swift', true], + ['singlebucket', 'OC\Files\ObjectStore\Custom', true], + ['multibucket', 'OC\Files\ObjectStore\Custom', true], + ]; + } + + /** + * @dataProvider dataForIsEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed + */ + public function testIsEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed(string $mode, string $className, bool $expected) { + $this->config->method('getSystemValue') + ->will($this->returnCallback(function($key, $default) use ($mode, $className) { + if ($key === 'objectstore' && $mode === 'singlebucket') { + return ['class' => $className]; + } + if ($key === 'objectstore_multibucket' && $mode === 'multibucket') { + return ['class' => $className]; + } + return $default; + })); + + $checkSetupController = new CheckSetupController( + 'settings', + $this->request, + $this->config, + $this->clientService, + $this->urlGenerator, + $this->l10n, + $this->checker, + $this->logger, + $this->dispatcher, + $this->db, + $this->lockingProvider, + $this->dateTimeFormatter, + $this->memoryInfo, + $this->secureRandom + ); + + $this->assertSame($expected, $this->invokePrivate($checkSetupController, 'isEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed')); + } +} diff --git a/apps/settings/tests/Controller/MailSettingsControllerTest.php b/apps/settings/tests/Controller/MailSettingsControllerTest.php new file mode 100644 index 00000000000..7b12ca03e6c --- /dev/null +++ b/apps/settings/tests/Controller/MailSettingsControllerTest.php @@ -0,0 +1,178 @@ +<?php +/** + * @copyright 2014 Lukas Reschke lukas@nextcloud.com + * @copyright Copyright (c) 2017 Joas Schilling <coding@schilljs.com> + * + * @author Lukas Reschke <lukas@statuscode.ch> + * @author Joas Schilling <coding@schilljs.com> + * + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\Settings\Tests\Controller; + +use OC\Mail\Message; +use OCA\Settings\Controller\MailSettingsController; +use OCP\AppFramework\Http; +use OCP\IConfig; +use OCP\IL10N; +use OCP\IRequest; +use OCP\IUserSession; +use OCP\Mail\IEMailTemplate; +use OCP\Mail\IMailer; +use OC\User\User; + +/** + * @package Tests\Settings\Controller + */ +class MailSettingsControllerTest extends \Test\TestCase { + + /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ + private $config; + /** @var IUserSession|\PHPUnit_Framework_MockObject_MockObject */ + private $userSession; + /** @var IMailer|\PHPUnit_Framework_MockObject_MockObject */ + private $mailer; + /** @var IL10N|\PHPUnit_Framework_MockObject_MockObject */ + private $l; + + /** @var MailSettingsController */ + private $mailController; + + protected function setUp() { + parent::setUp(); + + $this->l = $this->createMock(IL10N::class); + $this->config = $this->createMock(IConfig::class); + $this->userSession = $this->createMock(IUserSession::class); + $this->mailer = $this->createMock(IMailer::class); + /** @var IRequest|\PHPUnit_Framework_MockObject_MockObject $request */ + $request = $this->createMock(IRequest::class); + $this->mailController = new MailSettingsController( + 'settings', + $request, + $this->l, + $this->config, + $this->userSession, + $this->mailer, + 'no-reply@nextcloud.com' + ); + } + + public function testSetMailSettings() { + $this->config->expects($this->exactly(2)) + ->method('setSystemValues') + ->withConsecutive( + [[ + 'mail_domain' => 'nextcloud.com', + 'mail_from_address' => 'demo@nextcloud.com', + 'mail_smtpmode' => 'smtp', + 'mail_smtpsecure' => 'ssl', + 'mail_smtphost' => 'mx.nextcloud.org', + 'mail_smtpauthtype' => 'NTLM', + 'mail_smtpauth' => 1, + 'mail_smtpport' => '25', + 'mail_sendmailmode' => null, + ]], + [[ + 'mail_domain' => 'nextcloud.com', + 'mail_from_address' => 'demo@nextcloud.com', + 'mail_smtpmode' => 'smtp', + 'mail_smtpsecure' => 'ssl', + 'mail_smtphost' => 'mx.nextcloud.org', + 'mail_smtpauthtype' => 'NTLM', + 'mail_smtpauth' => null, + 'mail_smtpport' => '25', + 'mail_smtpname' => null, + 'mail_smtppassword' => null, + 'mail_sendmailmode' => null, + ]] + ); + + // With authentication + $response = $this->mailController->setMailSettings( + 'nextcloud.com', + 'demo@nextcloud.com', + 'smtp', + 'ssl', + 'mx.nextcloud.org', + 'NTLM', + 1, + '25', + null + ); + $this->assertSame(Http::STATUS_OK, $response->getStatus()); + + // Without authentication (testing the deletion of the stored password) + $response = $this->mailController->setMailSettings( + 'nextcloud.com', + 'demo@nextcloud.com', + 'smtp', + 'ssl', + 'mx.nextcloud.org', + 'NTLM', + 0, + '25', + null + ); + $this->assertSame(Http::STATUS_OK, $response->getStatus()); + + } + + public function testStoreCredentials() { + $this->config + ->expects($this->once()) + ->method('setSystemValues') + ->with([ + 'mail_smtpname' => 'UsernameToStore', + 'mail_smtppassword' => 'PasswordToStore', + ]); + + $response = $this->mailController->storeCredentials('UsernameToStore', 'PasswordToStore'); + $this->assertSame(Http::STATUS_OK, $response->getStatus()); + } + + public function testSendTestMail() { + $user = $this->createMock(User::class); + $user->expects($this->any()) + ->method('getUID') + ->will($this->returnValue('Werner')); + $user->expects($this->any()) + ->method('getDisplayName') + ->will($this->returnValue('Werner Brösel')); + + $this->l->expects($this->any()) + ->method('t') + ->willReturnCallback(function($text, $parameters = []) { + return vsprintf($text, $parameters); + }); + $this->userSession + ->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($user)); + + // Ensure that it fails when no mail address has been specified + $response = $this->mailController->sendTestMail(); + $this->assertSame(Http::STATUS_BAD_REQUEST, $response->getStatus()); + $this->assertSame('You need to set your user email before being able to send test emails.', $response->getData()); + + // If no exception is thrown it should work + $this->config + ->expects($this->any()) + ->method('getUserValue') + ->will($this->returnValue('mail@example.invalid')); + $this->mailer->expects($this->once()) + ->method('createMessage') + ->willReturn($this->createMock(Message::class)); + $emailTemplate = $this->createMock(IEMailTemplate::class); + $this->mailer + ->expects($this->once()) + ->method('createEMailTemplate') + ->willReturn($emailTemplate); + $response = $this->mailController->sendTestMail(); + $this->assertSame(Http::STATUS_OK, $response->getStatus(), $response->getData()); + } + +} diff --git a/apps/settings/tests/Controller/TwoFactorSettingsControllerTest.php b/apps/settings/tests/Controller/TwoFactorSettingsControllerTest.php new file mode 100644 index 00000000000..58b82bc0930 --- /dev/null +++ b/apps/settings/tests/Controller/TwoFactorSettingsControllerTest.php @@ -0,0 +1,84 @@ +<?php +/** + * @copyright 2018 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2018 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCA\Settings\Tests\Controller; + +use OC\Authentication\TwoFactorAuth\EnforcementState; +use OC\Authentication\TwoFactorAuth\MandatoryTwoFactor; +use OCA\Settings\Controller\TwoFactorSettingsController; +use OCP\AppFramework\Http\JSONResponse; +use OCP\IRequest; +use PHPUnit\Framework\MockObject\MockObject; +use Test\TestCase; + +class TwoFactorSettingsControllerTest extends TestCase { + + /** @var IRequest|MockObject */ + private $request; + + /** @var MandatoryTwoFactor|MockObject */ + private $mandatoryTwoFactor; + + /** @var TwoFactorSettingsController */ + private $controller; + + protected function setUp() { + parent::setUp(); + + $this->request = $this->createMock(IRequest::class); + $this->mandatoryTwoFactor = $this->createMock(MandatoryTwoFactor::class); + + $this->controller = new TwoFactorSettingsController( + 'settings', + $this->request, + $this->mandatoryTwoFactor + ); + } + + public function testIndex() { + $state = new EnforcementState(true); + $this->mandatoryTwoFactor->expects($this->once()) + ->method('getState') + ->willReturn($state); + $expected = new JSONResponse($state); + + $resp = $this->controller->index(); + + $this->assertEquals($expected, $resp); + } + + public function testUpdate() { + $state = new EnforcementState(true); + $this->mandatoryTwoFactor->expects($this->once()) + ->method('setState') + ->with($this->equalTo(new EnforcementState(true))); + $this->mandatoryTwoFactor->expects($this->once()) + ->method('getState') + ->willReturn($state); + $expected = new JSONResponse($state); + + $resp = $this->controller->update(true); + + $this->assertEquals($expected, $resp); + } + +} diff --git a/apps/settings/tests/Controller/UsersControllerTest.php b/apps/settings/tests/Controller/UsersControllerTest.php new file mode 100644 index 00000000000..5ca45297c58 --- /dev/null +++ b/apps/settings/tests/Controller/UsersControllerTest.php @@ -0,0 +1,552 @@ +<?php +/** + * @author Lukas Reschke + * @copyright 2014-2015 Lukas Reschke lukas@owncloud.com + * + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\Settings\Tests\Controller; + +use OC\Accounts\AccountManager; +use OC\Encryption\Exceptions\ModuleDoesNotExistsException; +use OC\Group\Manager; +use OCA\Settings\Controller\UsersController; +use OCP\App\IAppManager; +use OCP\AppFramework\Http; +use OCP\BackgroundJob\IJobList; +use OCP\Encryption\IEncryptionModule; +use OCP\Encryption\IManager; +use OCP\IAvatarManager; +use OCP\IConfig; +use OCP\IGroupManager; +use OCP\IL10N; +use OCP\ILogger; +use OCP\IRequest; +use OCP\IUser; +use OCP\IUserManager; +use OCP\IUserSession; +use OCP\L10N\IFactory; +use OCP\Mail\IMailer; +use OCP\Security\ISecureRandom; + +/** + * @group DB + * + * @package Tests\Settings\Controller + */ +class UsersControllerTest extends \Test\TestCase { + + /** @var IGroupManager|\PHPUnit_Framework_MockObject_MockObject */ + private $groupManager; + /** @var IUserManager|\PHPUnit_Framework_MockObject_MockObject */ + private $userManager; + /** @var IUserSession|\PHPUnit_Framework_MockObject_MockObject */ + private $userSession; + /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ + private $config; + /** @var ILogger|\PHPUnit_Framework_MockObject_MockObject */ + private $logger; + /** @var IMailer|\PHPUnit_Framework_MockObject_MockObject */ + private $mailer; + /** @var IFactory|\PHPUnit_Framework_MockObject_MockObject */ + private $l10nFactory; + /** @var IAppManager|\PHPUnit_Framework_MockObject_MockObject */ + private $appManager; + /** @var IAvatarManager|\PHPUnit_Framework_MockObject_MockObject */ + private $avatarManager; + /** @var IL10N|\PHPUnit_Framework_MockObject_MockObject */ + private $l; + /** @var AccountManager | \PHPUnit_Framework_MockObject_MockObject */ + private $accountManager; + /** @var ISecureRandom | \PHPUnit_Framework_MockObject_MockObject */ + private $secureRandom; + /** @var \OCA\Settings\Mailer\NewUserMailHelper|\PHPUnit_Framework_MockObject_MockObject */ + private $newUserMailHelper; + /** @var IJobList | \PHPUnit_Framework_MockObject_MockObject */ + private $jobList; + /** @var \OC\Security\IdentityProof\Manager |\PHPUnit_Framework_MockObject_MockObject */ + private $securityManager; + /** @var IManager | \PHPUnit_Framework_MockObject_MockObject */ + private $encryptionManager; + /** @var IEncryptionModule | \PHPUnit_Framework_MockObject_MockObject */ + private $encryptionModule; + + protected function setUp() { + parent::setUp(); + + $this->userManager = $this->createMock(IUserManager::class); + $this->groupManager = $this->createMock(Manager::class); + $this->userSession = $this->createMock(IUserSession::class); + $this->config = $this->createMock(IConfig::class); + $this->l = $this->createMock(IL10N::class); + $this->mailer = $this->createMock(IMailer::class); + $this->l10nFactory = $this->createMock(IFactory::class); + $this->appManager = $this->createMock(IAppManager::class); + $this->accountManager = $this->createMock(AccountManager::class); + $this->securityManager = $this->getMockBuilder(\OC\Security\IdentityProof\Manager::class)->disableOriginalConstructor()->getMock(); + $this->jobList = $this->createMock(IJobList::class); + $this->encryptionManager = $this->createMock(IManager::class); + + $this->l->method('t') + ->will($this->returnCallback(function ($text, $parameters = []) { + return vsprintf($text, $parameters); + })); + + $this->encryptionModule = $this->createMock(IEncryptionModule::class); + $this->encryptionManager->expects($this->any())->method('getEncryptionModules') + ->willReturn(['encryptionModule' => ['callback' => function() { return $this->encryptionModule;}]]); + + } + + /** + * @param bool $isAdmin + * @return UsersController | \PHPUnit_Framework_MockObject_MockObject + */ + protected function getController($isAdmin = false, $mockedMethods = []) { + if (empty($mockedMethods)) { + return new UsersController( + 'settings', + $this->createMock(IRequest::class), + $this->userManager, + $this->groupManager, + $this->userSession, + $this->config, + $isAdmin, + $this->l, + $this->mailer, + $this->l10nFactory, + $this->appManager, + $this->accountManager, + $this->securityManager, + $this->jobList, + $this->encryptionManager + ); + } else { + return $this->getMockBuilder(UsersController::class) + ->setConstructorArgs( + [ + 'settings', + $this->createMock(IRequest::class), + $this->userManager, + $this->groupManager, + $this->userSession, + $this->config, + $isAdmin, + $this->l, + $this->mailer, + $this->l10nFactory, + $this->appManager, + $this->accountManager, + $this->securityManager, + $this->jobList, + $this->encryptionManager + ] + )->setMethods($mockedMethods)->getMock(); + } + } + + /** + * @dataProvider dataTestSetUserSettings + * + * @param string $email + * @param bool $validEmail + * @param $expectedStatus + */ + public function testSetUserSettings($email, $validEmail, $expectedStatus) { + $controller = $this->getController(false, ['saveUserSettings']); + $user = $this->createMock(IUser::class); + + $this->userSession->method('getUser')->willReturn($user); + + if (!empty($email) && $validEmail) { + $this->mailer->expects($this->once())->method('validateMailAddress') + ->willReturn($validEmail); + } + + $saveData = (!empty($email) && $validEmail) || empty($email); + + if ($saveData) { + $this->accountManager->expects($this->once()) + ->method('getUser') + ->with($user) + ->willReturn([ + AccountManager::PROPERTY_DISPLAYNAME => + [ + 'value' => 'Display name', + 'scope' => AccountManager::VISIBILITY_CONTACTS_ONLY, + 'verified' => AccountManager::NOT_VERIFIED, + ], + AccountManager::PROPERTY_ADDRESS => + [ + 'value' => '', + 'scope' => AccountManager::VISIBILITY_PRIVATE, + 'verified' => AccountManager::NOT_VERIFIED, + ], + AccountManager::PROPERTY_WEBSITE => + [ + 'value' => '', + 'scope' => AccountManager::VISIBILITY_PRIVATE, + 'verified' => AccountManager::NOT_VERIFIED, + ], + AccountManager::PROPERTY_EMAIL => + [ + 'value' => '', + 'scope' => AccountManager::VISIBILITY_CONTACTS_ONLY, + 'verified' => AccountManager::NOT_VERIFIED, + ], + AccountManager::PROPERTY_AVATAR => + [ + 'scope' => AccountManager::VISIBILITY_CONTACTS_ONLY + ], + AccountManager::PROPERTY_PHONE => + [ + 'value' => '', + 'scope' => AccountManager::VISIBILITY_PRIVATE, + 'verified' => AccountManager::NOT_VERIFIED, + ], + AccountManager::PROPERTY_TWITTER => + [ + 'value' => '', + 'scope' => AccountManager::VISIBILITY_PRIVATE, + 'verified' => AccountManager::NOT_VERIFIED, + ], + ]); + + $controller->expects($this->once())->method('saveUserSettings'); + } else { + $controller->expects($this->never())->method('saveUserSettings'); + } + + $result = $controller->setUserSettings( + AccountManager::VISIBILITY_CONTACTS_ONLY, + 'displayName', + AccountManager::VISIBILITY_CONTACTS_ONLY, + '47658468', + AccountManager::VISIBILITY_CONTACTS_ONLY, + $email, + AccountManager::VISIBILITY_CONTACTS_ONLY, + 'nextcloud.com', + AccountManager::VISIBILITY_CONTACTS_ONLY, + 'street and city', + AccountManager::VISIBILITY_CONTACTS_ONLY, + '@nextclouders', + AccountManager::VISIBILITY_CONTACTS_ONLY + ); + + $this->assertSame($expectedStatus, $result->getStatus()); + } + + public function dataTestSetUserSettings() { + return [ + ['', true, Http::STATUS_OK], + ['', false, Http::STATUS_OK], + ['example.com', false, Http::STATUS_UNPROCESSABLE_ENTITY], + ['john@example.com', true, Http::STATUS_OK], + ]; + } + + /** + * @dataProvider dataTestSaveUserSettings + * + * @param array $data + * @param string $oldEmailAddress + * @param string $oldDisplayName + */ + public function testSaveUserSettings($data, + $oldEmailAddress, + $oldDisplayName + ) { + $controller = $this->getController(); + $user = $this->createMock(IUser::class); + + $user->method('getDisplayName')->willReturn($oldDisplayName); + $user->method('getEMailAddress')->willReturn($oldEmailAddress); + $user->method('canChangeDisplayName')->willReturn(true); + + if ($data[AccountManager::PROPERTY_EMAIL]['value'] === $oldEmailAddress || + ($oldEmailAddress === null && $data[AccountManager::PROPERTY_EMAIL]['value'] === '')) { + $user->expects($this->never())->method('setEMailAddress'); + } else { + $user->expects($this->once())->method('setEMailAddress') + ->with($data[AccountManager::PROPERTY_EMAIL]['value']) + ->willReturn(true); + } + + if ($data[AccountManager::PROPERTY_DISPLAYNAME]['value'] === $oldDisplayName || + ($oldDisplayName === null && $data[AccountManager::PROPERTY_DISPLAYNAME]['value'] === '')) { + $user->expects($this->never())->method('setDisplayName'); + } else { + $user->expects($this->once())->method('setDisplayName') + ->with($data[AccountManager::PROPERTY_DISPLAYNAME]['value']) + ->willReturn(true); + } + + $this->accountManager->expects($this->once())->method('updateUser') + ->with($user, $data); + + $this->invokePrivate($controller, 'saveUserSettings', [$user, $data]); + } + + public function dataTestSaveUserSettings() { + return [ + [ + [ + AccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'], + ], + 'john@example.com', + 'john doe' + ], + [ + [ + AccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'], + ], + 'johnNew@example.com', + 'john New doe' + ], + [ + [ + AccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'], + ], + 'johnNew@example.com', + 'john doe' + ], + [ + [ + AccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'], + ], + 'john@example.com', + 'john New doe' + ], + [ + [ + AccountManager::PROPERTY_EMAIL => ['value' => ''], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'], + ], + null, + 'john New doe' + ], + [ + [ + AccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'], + ], + 'john@example.com', + null + ], + + ]; + } + + /** + * @dataProvider dataTestSaveUserSettingsException + * + * @param array $data + * @param string $oldEmailAddress + * @param string $oldDisplayName + * @param bool $setDisplayNameResult + * @param bool $canChangeEmail + * + * @expectedException \OC\ForbiddenException + */ + public function testSaveUserSettingsException($data, + $oldEmailAddress, + $oldDisplayName, + $setDisplayNameResult, + $canChangeEmail + ) { + $controller = $this->getController(); + $user = $this->createMock(IUser::class); + + $user->method('getDisplayName')->willReturn($oldDisplayName); + $user->method('getEMailAddress')->willReturn($oldEmailAddress); + + if ($data[AccountManager::PROPERTY_EMAIL]['value'] !== $oldEmailAddress) { + $user->method('canChangeDisplayName') + ->willReturn($canChangeEmail); + } + + if ($data[AccountManager::PROPERTY_DISPLAYNAME]['value'] !== $oldDisplayName) { + $user->method('setDisplayName') + ->with($data[AccountManager::PROPERTY_DISPLAYNAME]['value']) + ->willReturn($setDisplayNameResult); + } + + $this->invokePrivate($controller, 'saveUserSettings', [$user, $data]); + } + + + public function dataTestSaveUserSettingsException() { + return [ + [ + [ + AccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'], + ], + 'johnNew@example.com', + 'john New doe', + true, + false + ], + [ + [ + AccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'], + ], + 'johnNew@example.com', + 'john New doe', + false, + true + ], + [ + [ + AccountManager::PROPERTY_EMAIL => ['value' => 'john@example.com'], + AccountManager::PROPERTY_DISPLAYNAME => ['value' => 'john doe'], + ], + 'johnNew@example.com', + 'john New doe', + false, + false + ], + + ]; + } + + /** + * @param string $account + * @param string $type + * @param array $dataBefore + * @param array $expectedData + * + * @dataProvider dataTestGetVerificationCode + */ + public function testGetVerificationCode($account, $type, $dataBefore, $expectedData, $onlyVerificationCode) { + + $message = 'Use my Federated Cloud ID to share with me: user@nextcloud.com'; + $signature = 'theSignature'; + + $code = $message . ' ' . $signature; + if($type === AccountManager::PROPERTY_TWITTER) { + $code = $message . ' ' . md5($signature); + } + + $controller = $this->getController(false, ['signMessage', 'getCurrentTime']); + + $user = $this->createMock(IUser::class); + $this->userSession->expects($this->once())->method('getUser')->willReturn($user); + $this->accountManager->expects($this->once())->method('getUser')->with($user)->willReturn($dataBefore); + $user->expects($this->any())->method('getCloudId')->willReturn('user@nextcloud.com'); + $user->expects($this->any())->method('getUID')->willReturn('uid'); + $controller->expects($this->once())->method('signMessage')->with($user, $message)->willReturn($signature); + $controller->expects($this->any())->method('getCurrentTime')->willReturn(1234567); + + if ($onlyVerificationCode === false) { + $this->accountManager->expects($this->once())->method('updateUser')->with($user, $expectedData); + $this->jobList->expects($this->once())->method('add') + ->with('OCA\Settings\BackgroundJobs\VerifyUserData', + [ + 'verificationCode' => $code, + 'data' => $dataBefore[$type]['value'], + 'type' => $type, + 'uid' => 'uid', + 'try' => 0, + 'lastRun' => 1234567 + ]); + } + + $result = $controller->getVerificationCode($account, $onlyVerificationCode); + + $data = $result->getData(); + $this->assertSame(Http::STATUS_OK, $result->getStatus()); + $this->assertSame($code, $data['code']); + } + + public function dataTestGetVerificationCode() { + + $accountDataBefore = [ + AccountManager::PROPERTY_WEBSITE => ['value' => 'https://nextcloud.com', 'verified' => AccountManager::NOT_VERIFIED], + AccountManager::PROPERTY_TWITTER => ['value' => '@nextclouders', 'verified' => AccountManager::NOT_VERIFIED, 'signature' => 'theSignature'], + ]; + + $accountDataAfterWebsite = [ + AccountManager::PROPERTY_WEBSITE => ['value' => 'https://nextcloud.com', 'verified' => AccountManager::VERIFICATION_IN_PROGRESS, 'signature' => 'theSignature'], + AccountManager::PROPERTY_TWITTER => ['value' => '@nextclouders', 'verified' => AccountManager::NOT_VERIFIED, 'signature' => 'theSignature'], + ]; + + $accountDataAfterTwitter = [ + AccountManager::PROPERTY_WEBSITE => ['value' => 'https://nextcloud.com', 'verified' => AccountManager::NOT_VERIFIED], + AccountManager::PROPERTY_TWITTER => ['value' => '@nextclouders', 'verified' => AccountManager::VERIFICATION_IN_PROGRESS, 'signature' => 'theSignature'], + ]; + + return [ + ['verify-twitter', AccountManager::PROPERTY_TWITTER, $accountDataBefore, $accountDataAfterTwitter, false], + ['verify-website', AccountManager::PROPERTY_WEBSITE, $accountDataBefore, $accountDataAfterWebsite, false], + ['verify-twitter', AccountManager::PROPERTY_TWITTER, $accountDataBefore, $accountDataAfterTwitter, true], + ['verify-website', AccountManager::PROPERTY_WEBSITE, $accountDataBefore, $accountDataAfterWebsite, true], + ]; + } + + /** + * test get verification code in case no valid user was given + */ + public function testGetVerificationCodeInvalidUser() { + + $controller = $this->getController(); + $this->userSession->expects($this->once())->method('getUser')->willReturn(null); + $result = $controller->getVerificationCode('account', false); + + $this->assertSame(Http::STATUS_BAD_REQUEST, $result->getStatus()); + } + + /** + * @dataProvider dataTestCanAdminChangeUserPasswords + * + * @param bool $encryptionEnabled + * @param bool $encryptionModuleLoaded + * @param bool $masterKeyEnabled + * @param bool $expected + */ + public function testCanAdminChangeUserPasswords($encryptionEnabled, + $encryptionModuleLoaded, + $masterKeyEnabled, + $expected) { + $controller = $this->getController(); + + $this->encryptionManager->expects($this->any()) + ->method('isEnabled') + ->willReturn($encryptionEnabled); + $this->encryptionManager->expects($this->any()) + ->method('getEncryptionModule') + ->willReturnCallback(function() use ($encryptionModuleLoaded) { + if ($encryptionModuleLoaded) return $this->encryptionModule; + else throw new ModuleDoesNotExistsException(); + }); + $this->encryptionModule->expects($this->any()) + ->method('needDetailedAccessList') + ->willReturn(!$masterKeyEnabled); + + $result = $this->invokePrivate($controller, 'canAdminChangeUserPasswords', []); + $this->assertSame($expected, $result); + } + + public function dataTestCanAdminChangeUserPasswords() { + return [ + // encryptionEnabled, encryptionModuleLoaded, masterKeyEnabled, expectedResult + [true, true, true, true], + [false, true, true, true], + [true, false, true, false], + [false, false, true, true], + [true, true, false, false], + [false, true, false, false], + [true, false, false, false], + [false, false, false, true], + ]; + } + +} |