diff options
Diffstat (limited to 'tests')
35 files changed, 1438 insertions, 363 deletions
diff --git a/tests/Core/Controller/AvatarControllerTest.php b/tests/Core/Controller/AvatarControllerTest.php index 3369fa882c8..5fce8fc6359 100644 --- a/tests/Core/Controller/AvatarControllerTest.php +++ b/tests/Core/Controller/AvatarControllerTest.php @@ -53,7 +53,7 @@ use OCP\IUserManager; * @package OC\Core\Controller */ class AvatarControllerTest extends \Test\TestCase { - /** @var \OC\Core\Controller\AvatarController */ + /** @var AvatarController */ private $avatarController; /** @var IAvatar|\PHPUnit_Framework_MockObject_MockObject */ private $avatarMock; @@ -78,7 +78,7 @@ class AvatarControllerTest extends \Test\TestCase { private $request; /** @var TimeFactory|\PHPUnit_Framework_MockObject_MockObject */ private $timeFactory; - + protected function setUp() { parent::setUp(); diff --git a/tests/Core/Controller/ClientFlowLoginControllerTest.php b/tests/Core/Controller/ClientFlowLoginControllerTest.php index ba9caabd0b0..eddcc1bbdb9 100644 --- a/tests/Core/Controller/ClientFlowLoginControllerTest.php +++ b/tests/Core/Controller/ClientFlowLoginControllerTest.php @@ -30,7 +30,7 @@ use OCA\OAuth2\Db\AccessTokenMapper; use OCA\OAuth2\Db\Client; use OCA\OAuth2\Db\ClientMapper; use OCP\AppFramework\Http; -use OCP\AppFramework\Http\TemplateResponse; +use OCP\AppFramework\Http\StandaloneTemplateResponse; use OCP\Defaults; use OCP\IL10N; use OCP\IRequest; @@ -108,7 +108,7 @@ class ClientFlowLoginControllerTest extends TestCase { } public function testShowAuthPickerPageNoClientOrOauthRequest() { - $expected = new TemplateResponse( + $expected = new StandaloneTemplateResponse( 'core', 'error', [ @@ -166,7 +166,7 @@ class ClientFlowLoginControllerTest extends TestCase { ->method('getServerProtocol') ->willReturn('https'); - $expected = new TemplateResponse( + $expected = new StandaloneTemplateResponse( 'core', 'loginflow/authpicker', [ @@ -225,7 +225,7 @@ class ClientFlowLoginControllerTest extends TestCase { ->method('getServerProtocol') ->willReturn('https'); - $expected = new TemplateResponse( + $expected = new StandaloneTemplateResponse( 'core', 'loginflow/authpicker', [ @@ -253,11 +253,11 @@ class ClientFlowLoginControllerTest extends TestCase { ->method('remove') ->with('client.flow.state.token'); - $expected = new TemplateResponse( + $expected = new StandaloneTemplateResponse( 'core', '403', [ - 'file' => 'State token does not match', + 'message' => 'State token does not match', ], 'guest' ); diff --git a/tests/Core/Controller/GuestAvatarControllerTest.php b/tests/Core/Controller/GuestAvatarControllerTest.php new file mode 100644 index 00000000000..f720478e499 --- /dev/null +++ b/tests/Core/Controller/GuestAvatarControllerTest.php @@ -0,0 +1,89 @@ +<?php + +namespace Core\Controller; + +use OC\Core\Controller\GuestAvatarController; +use OCP\AppFramework\Http\FileDisplayResponse; +use OCP\Files\SimpleFS\ISimpleFile; +use OCP\IAvatar; +use OCP\IAvatarManager; +use OCP\ILogger; +use OCP\IRequest; + +/** + * This class provides tests for the guest avatar controller. + */ +class GuestAvatarControllerTest extends \Test\TestCase { + + /** + * @var GuestAvatarController + */ + private $guestAvatarController; + + /** + * @var IRequest|\PHPUnit_Framework_MockObject_MockObject + */ + private $request; + + /** + * @var IAvatarManager|\PHPUnit_Framework_MockObject_MockObject + */ + private $avatarManager; + + /** + * @var IAvatar|\PHPUnit_Framework_MockObject_MockObject + */ + private $avatar; + + /** + * @var \OCP\Files\File|\PHPUnit_Framework_MockObject_MockObject + */ + private $file; + + /** + * @var ILogger|\PHPUnit_Framework_MockObject_MockObject + */ + private $logger; + + /** + * Sets up the test environment. + */ + protected function setUp() { + parent::setUp(); + + $this->logger = $this->getMockBuilder(ILogger::class)->getMock(); + $this->request = $this->getMockBuilder(IRequest::class)->getMock(); + $this->avatar = $this->getMockBuilder(IAvatar::class)->getMock(); + $this->avatarManager = $this->getMockBuilder(IAvatarManager::class)->getMock(); + $this->file = $this->getMockBuilder(ISimpleFile::class)->getMock(); + $this->guestAvatarController = new GuestAvatarController( + 'core', + $this->request, + $this->avatarManager, + $this->logger + ); + } + + /** + * Tests getAvatar returns the guest avatar. + */ + public function testGetAvatar() { + $this->avatarManager->expects($this->once()) + ->method('getGuestAvatar') + ->with('Peter') + ->willReturn($this->avatar); + + $this->avatar->expects($this->once()) + ->method('getFile') + ->with(128) + ->willReturn($this->file); + + $this->file->method('getMimeType') + ->willReturn('image/svg+xml'); + + $response = $this->guestAvatarController->getAvatar('Peter', 128); + + $this->assertGreaterThanOrEqual(201, $response->getStatus()); + $this->assertInstanceOf(FileDisplayResponse::class, $response); + } +} diff --git a/tests/Core/Controller/LoginControllerTest.php b/tests/Core/Controller/LoginControllerTest.php index efe85d81e1c..bb21903b653 100644 --- a/tests/Core/Controller/LoginControllerTest.php +++ b/tests/Core/Controller/LoginControllerTest.php @@ -449,6 +449,10 @@ class LoginControllerTest extends TestCase { $this->config->expects($this->once()) ->method('setUserValue') ->with('uid', 'core', 'timezone', 'Europe/Berlin'); + $this->config + ->method('getSystemValue') + ->with('remember_login_cookie_lifetime') + ->willReturn(1234); $this->userSession->expects($this->never()) ->method('createRememberMeToken'); @@ -493,6 +497,10 @@ class LoginControllerTest extends TestCase { $this->config->expects($this->once()) ->method('deleteUserValue') ->with('uid', 'core', 'lostpassword'); + $this->config + ->method('getSystemValue') + ->with('remember_login_cookie_lifetime') + ->willReturn(1234); $this->userSession->expects($this->once()) ->method('createRememberMeToken') ->with($user); @@ -553,6 +561,10 @@ class LoginControllerTest extends TestCase { ->method('deleteUserValue'); $this->userSession->expects($this->never()) ->method('createRememberMeToken'); + $this->config + ->method('getSystemValue') + ->with('remember_login_cookie_lifetime') + ->willReturn(1234); $expected = new \OCP\AppFramework\Http\RedirectResponse($redirectUrl); $this->assertEquals($expected, $this->loginController->tryLogin('Jane', $password, $originalUrl)); @@ -590,6 +602,10 @@ class LoginControllerTest extends TestCase { $this->config->expects($this->once()) ->method('deleteUserValue') ->with('jane', 'core', 'lostpassword'); + $this->config + ->method('getSystemValue') + ->with('remember_login_cookie_lifetime') + ->willReturn(1234); $expected = new \OCP\AppFramework\Http\RedirectResponse(urldecode($redirectUrl)); $this->assertEquals($expected, $this->loginController->tryLogin('Jane', $password, $originalUrl)); @@ -642,6 +658,10 @@ class LoginControllerTest extends TestCase { $this->config->expects($this->once()) ->method('deleteUserValue') ->with('john', 'core', 'lostpassword'); + $this->config + ->method('getSystemValue') + ->with('remember_login_cookie_lifetime') + ->willReturn(1234); $this->userSession->expects($this->never()) ->method('createRememberMeToken'); @@ -694,6 +714,10 @@ class LoginControllerTest extends TestCase { $this->config->expects($this->once()) ->method('deleteUserValue') ->with('john', 'core', 'lostpassword'); + $this->config + ->method('getSystemValue') + ->with('remember_login_cookie_lifetime') + ->willReturn(1234); $this->userSession->expects($this->never()) ->method('createRememberMeToken'); diff --git a/tests/Core/Controller/LostControllerTest.php b/tests/Core/Controller/LostControllerTest.php index 91b52fc8efa..8635616a9d5 100644 --- a/tests/Core/Controller/LostControllerTest.php +++ b/tests/Core/Controller/LostControllerTest.php @@ -21,6 +21,7 @@ namespace Tests\Core\Controller; +use OC\Authentication\TwoFactorAuth\Manager; use OC\Core\Controller\LostController; use OC\Mail\Message; use OCP\AppFramework\Http\JSONResponse; @@ -31,6 +32,7 @@ use OCP\Encryption\IEncryptionModule; use OCP\Encryption\IManager; use OCP\IConfig; use OCP\IL10N; +use OCP\ILogger; use OCP\IRequest; use OCP\IURLGenerator; use OCP\IUser; @@ -74,6 +76,10 @@ class LostControllerTest extends \Test\TestCase { private $request; /** @var ICrypto|\PHPUnit_Framework_MockObject_MockObject */ private $crypto; + /** @var ILogger|\PHPUnit_Framework_MockObject_MockObject */ + private $logger; + /** @var Manager|\PHPUnit_Framework_MockObject_MockObject */ + private $twofactorManager; protected function setUp() { parent::setUp(); @@ -124,6 +130,8 @@ class LostControllerTest extends \Test\TestCase { ->method('isEnabled') ->willReturn(true); $this->crypto = $this->createMock(ICrypto::class); + $this->logger = $this->createMock(ILogger::class); + $this->twofactorManager = $this->createMock(Manager::class); $this->lostController = new LostController( 'Core', $this->request, @@ -137,7 +145,9 @@ class LostControllerTest extends \Test\TestCase { $this->encryptionManager, $this->mailer, $this->timeFactory, - $this->crypto + $this->crypto, + $this->logger, + $this->twofactorManager ); } @@ -265,6 +275,9 @@ class LostControllerTest extends \Test\TestCase { array(false, $nonExistingUser) ))); + $this->logger->expects($this->exactly(2)) + ->method('logException'); + $this->userManager ->method('getByEmail') ->willReturn([]); @@ -272,8 +285,7 @@ class LostControllerTest extends \Test\TestCase { // With a non existing user $response = $this->lostController->email($nonExistingUser); $expectedResponse = new JSONResponse([ - 'status' => 'error', - 'msg' => 'Couldn\'t send reset email. Please make sure your username is correct.' + 'status' => 'success', ]); $expectedResponse->throttle(); $this->assertEquals($expectedResponse, $response); @@ -286,8 +298,7 @@ class LostControllerTest extends \Test\TestCase { ->will($this->returnValue(null)); $response = $this->lostController->email($existingUser); $expectedResponse = new JSONResponse([ - 'status' => 'error', - 'msg' => 'Couldn\'t send reset email. Please make sure your username is correct.' + 'status' => 'success', ]); $expectedResponse->throttle(); $this->assertEquals($expectedResponse, $response); @@ -511,8 +522,11 @@ class LostControllerTest extends \Test\TestCase { $this->equalTo('test@example.comSECRET') )->willReturn('encryptedToken'); + $this->logger->expects($this->exactly(1)) + ->method('logException'); + $response = $this->lostController->email('ExistingUser'); - $expectedResponse = new JSONResponse(['status' => 'error', 'msg' => 'Couldn\'t send reset email. Please contact your administrator.']); + $expectedResponse = new JSONResponse(['status' => 'success']); $expectedResponse->throttle(); $this->assertEquals($expectedResponse, $response); } @@ -708,8 +722,11 @@ class LostControllerTest extends \Test\TestCase { ->with('ExistingUser') ->willReturn($user); + $this->logger->expects($this->exactly(1)) + ->method('logException'); + $response = $this->lostController->email('ExistingUser'); - $expectedResponse = new JSONResponse(['status' => 'error', 'msg' => 'Could not send reset email because there is no email address for this username. Please contact your administrator.']); + $expectedResponse = new JSONResponse(['status' => 'success']); $expectedResponse->throttle(); $this->assertEquals($expectedResponse, $response); } @@ -790,12 +807,14 @@ class LostControllerTest extends \Test\TestCase { ->method('getByEmail') ->willReturn([$user1, $user2]); + $this->logger->expects($this->exactly(1)) + ->method('logException'); + // request password reset for test@example.com $response = $this->lostController->email('test@example.com'); $expectedResponse = new JSONResponse([ - 'status' => 'error', - 'msg' => 'Couldn\'t send reset email. Please make sure your username is correct.' + 'status' => 'success' ]); $expectedResponse->throttle(); diff --git a/tests/Core/Controller/TwoFactorChallengeControllerTest.php b/tests/Core/Controller/TwoFactorChallengeControllerTest.php index 6a01c510ed2..a405914cc47 100644 --- a/tests/Core/Controller/TwoFactorChallengeControllerTest.php +++ b/tests/Core/Controller/TwoFactorChallengeControllerTest.php @@ -27,7 +27,7 @@ use OC\Authentication\TwoFactorAuth\ProviderSet; use OC\Core\Controller\TwoFactorChallengeController; use OC_Util; use OCP\AppFramework\Http\RedirectResponse; -use OCP\AppFramework\Http\TemplateResponse; +use OCP\AppFramework\Http\StandaloneTemplateResponse; use OCP\Authentication\TwoFactorAuth\IProvider; use OCP\Authentication\TwoFactorAuth\TwoFactorException; use OCP\IRequest; @@ -100,7 +100,7 @@ class TwoFactorChallengeControllerTest extends TestCase { ->with($user) ->will($this->returnValue($providerSet)); - $expected = new TemplateResponse('core', 'twofactorselectchallenge', [ + $expected = new StandaloneTemplateResponse('core', 'twofactorselectchallenge', [ 'providers' => [ $p1, ], @@ -151,7 +151,7 @@ class TwoFactorChallengeControllerTest extends TestCase { ->method('fetchPage') ->will($this->returnValue('<html/>')); - $expected = new TemplateResponse('core', 'twofactorshowchallenge', [ + $expected = new StandaloneTemplateResponse('core', 'twofactorshowchallenge', [ 'error' => true, 'provider' => $provider, 'backupProvider' => $backupProvider, diff --git a/tests/Settings/Controller/AppSettingsControllerTest.php b/tests/Settings/Controller/AppSettingsControllerTest.php index 14e537437ff..7ae815cc4fa 100644 --- a/tests/Settings/Controller/AppSettingsControllerTest.php +++ b/tests/Settings/Controller/AppSettingsControllerTest.php @@ -44,6 +44,8 @@ use OCP\App\IAppManager; * Class AppSettingsControllerTest * * @package Tests\Settings\Controller + * + * @group DB */ class AppSettingsControllerTest extends TestCase { /** @var AppSettingsController */ diff --git a/tests/Settings/Controller/AuthSettingsControllerTest.php b/tests/Settings/Controller/AuthSettingsControllerTest.php index 1c957299e39..d0ed40f25b7 100644 --- a/tests/Settings/Controller/AuthSettingsControllerTest.php +++ b/tests/Settings/Controller/AuthSettingsControllerTest.php @@ -1,5 +1,4 @@ <?php - /** * @author Christoph Wurst <christoph@owncloud.com> * @@ -28,11 +27,12 @@ use OC\Authentication\Token\DefaultToken; use OC\Authentication\Token\IProvider; use OC\Authentication\Token\IToken; use OC\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\IUser; -use OCP\IUserManager; use OCP\Security\ISecureRandom; use OCP\Session\Exceptions\SessionNotAvailableException; use Test\TestCase; @@ -41,26 +41,39 @@ class AuthSettingsControllerTest extends TestCase { /** @var AuthSettingsController */ private $controller; + /** @var IRequest|\PHPUnit_Framework_MockObject_MockObject */ private $request; /** @var IProvider|\PHPUnit_Framework_MockObject_MockObject */ private $tokenProvider; - private $userManager; + /** @var ISession|\PHPUnit_Framework_MockObject_MockObject */ private $session; + /** @var ISecureRandom|\PHPUnit_Framework_MockObject_MockObject */ private $secureRandom; - private $uid; + /** @var IManager|\PHPUnit_Framework_MockObject_MockObject */ + private $activityManager; + private $uid = 'jane'; protected function setUp() { parent::setUp(); $this->request = $this->createMock(IRequest::class); $this->tokenProvider = $this->createMock(IProvider::class); - $this->userManager = $this->createMock(IUserManager::class); $this->session = $this->createMock(ISession::class); $this->secureRandom = $this->createMock(ISecureRandom::class); - $this->uid = 'jane'; - $this->user = $this->createMock(IUser::class); - - $this->controller = new AuthSettingsController('core', $this->request, $this->tokenProvider, $this->userManager, $this->session, $this->secureRandom, $this->uid); + $this->activityManager = $this->createMock(IManager::class); + /** @var ILogger|\PHPUnit_Framework_MockObject_MockObject $logger */ + $logger = $this->createMock(ILogger::class); + + $this->controller = new AuthSettingsController( + 'core', + $this->request, + $this->tokenProvider, + $this->session, + $this->secureRandom, + $this->uid, + $this->activityManager, + $logger + ); } public function testIndex() { @@ -78,14 +91,14 @@ class AuthSettingsControllerTest extends TestCase { $this->tokenProvider->expects($this->once()) ->method('getTokenByUser') ->with($this->uid) - ->will($this->returnValue($tokens)); + ->willReturn($tokens); $this->session->expects($this->once()) ->method('getId') - ->will($this->returnValue('session123')); + ->willReturn('session123'); $this->tokenProvider->expects($this->once()) ->method('getToken') ->with('session123') - ->will($this->returnValue($sessionToken)); + ->willReturn($sessionToken); $this->assertEquals([ [ @@ -95,7 +108,8 @@ class AuthSettingsControllerTest extends TestCase { 'type' => 0, 'canDelete' => false, 'current' => true, - 'scope' => ['filesystem' => true] + 'scope' => ['filesystem' => true], + 'canRename' => false, ], [ 'id' => 200, @@ -103,7 +117,8 @@ class AuthSettingsControllerTest extends TestCase { 'lastActivity' => 0, 'type' => 0, 'canDelete' => true, - 'scope' => ['filesystem' => true] + 'scope' => ['filesystem' => true], + 'canRename' => true, ] ], $this->controller->index()); } @@ -116,39 +131,42 @@ class AuthSettingsControllerTest extends TestCase { $this->session->expects($this->once()) ->method('getId') - ->will($this->returnValue('sessionid')); + ->willReturn('sessionid'); $this->tokenProvider->expects($this->once()) ->method('getToken') ->with('sessionid') - ->will($this->returnValue($sessionToken)); + ->willReturn($sessionToken); $this->tokenProvider->expects($this->once()) ->method('getPassword') ->with($sessionToken, 'sessionid') - ->will($this->returnValue($password)); + ->willReturn($password); $sessionToken->expects($this->once()) ->method('getLoginName') - ->will($this->returnValue('User13')); + ->willReturn('User13'); $this->secureRandom->expects($this->exactly(5)) ->method('generate') ->with(5, ISecureRandom::CHAR_HUMAN_READABLE) - ->will($this->returnValue('XXXXX')); + ->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) - ->will($this->returnValue($deviceToken)); + ->willReturn($deviceToken); $deviceToken->expects($this->once()) ->method('jsonSerialize') - ->will($this->returnValue(['dummy' => 'dummy', 'canDelete' => true])); + ->willReturn(['dummy' => 'dummy', 'canDelete' => true]); + + $this->mockActivityManager(); $expected = [ 'token' => $newToken, - 'deviceToken' => ['dummy' => 'dummy', 'canDelete' => true], + 'deviceToken' => ['dummy' => 'dummy', 'canDelete' => true, 'canRename' => true], 'loginName' => 'User13', ]; + $response = $this->controller->create($name); $this->assertInstanceOf(JSONResponse::class, $response); $this->assertEquals($expected, $response->getData()); @@ -172,7 +190,7 @@ class AuthSettingsControllerTest extends TestCase { $this->session->expects($this->once()) ->method('getId') - ->will($this->returnValue('sessionid')); + ->willReturn('sessionid'); $this->tokenProvider->expects($this->once()) ->method('getToken') ->with('sessionid') @@ -185,23 +203,49 @@ class AuthSettingsControllerTest extends TestCase { } public function testDestroy() { - $id = 123; - $user = $this->createMock(IUser::class); + $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, $id); + ->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'); - $this->assertEquals([], $this->controller->destroy($id)); + $response = $this->controller->destroy($tokenId); + $this->assertSame([], $response->getData()); + $this->assertSame(\OCP\AppFramework\Http::STATUS_NOT_FOUND, $response->getStatus()); } + public function testUpdateToken() { + $tokenId = 42; $token = $this->createMock(DefaultToken::class); - $this->tokenProvider->expects($this->once()) - ->method('getTokenById') - ->with($this->equalTo(42)) - ->willReturn($token); + $this->mockGetTokenById($tokenId, $token); + $this->mockActivityManager(); $token->expects($this->once()) ->method('getUID') @@ -217,16 +261,14 @@ class AuthSettingsControllerTest extends TestCase { ->method('updateToken') ->with($this->equalTo($token)); - $this->assertSame([], $this->controller->update(42, ['filesystem' => true])); + $this->assertSame([], $this->controller->update($tokenId, ['filesystem' => true], 'App password')); } public function testUpdateTokenWrongUser() { + $tokenId = 42; $token = $this->createMock(DefaultToken::class); - $this->tokenProvider->expects($this->once()) - ->method('getTokenById') - ->with($this->equalTo(42)) - ->willReturn($token); + $this->mockGetTokenById($tokenId, $token); $token->expects($this->once()) ->method('getUID') @@ -237,7 +279,7 @@ class AuthSettingsControllerTest extends TestCase { $this->tokenProvider->expects($this->never()) ->method('updateToken'); - $response = $this->controller->update(42, ['filesystem' => true]); + $response = $this->controller->update($tokenId, ['filesystem' => true], 'App password'); $this->assertSame([], $response->getData()); $this->assertSame(\OCP\AppFramework\Http::STATUS_NOT_FOUND, $response->getStatus()); } @@ -251,9 +293,27 @@ class AuthSettingsControllerTest extends TestCase { $this->tokenProvider->expects($this->never()) ->method('updateToken'); - $response = $this->controller->update(42, ['filesystem' => true]); + $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); + } } diff --git a/tests/acceptance/config/behat.yml b/tests/acceptance/config/behat.yml index acb404aae26..182629701e8 100644 --- a/tests/acceptance/config/behat.yml +++ b/tests/acceptance/config/behat.yml @@ -15,6 +15,7 @@ default: - DialogContext - FeatureContext - FileListContext + - FilePickerContext - FilesAppContext - FilesAppSharingContext - LoginPageContext @@ -43,6 +44,7 @@ default: - DialogContext - FeatureContext - FileListContext + - FilePickerContext - FilesAppContext - FilesAppSharingContext - LoginPageContext diff --git a/tests/acceptance/features/app-files.feature b/tests/acceptance/features/app-files.feature index 7d216ffc1f4..50bb9d20022 100644 --- a/tests/acceptance/features/app-files.feature +++ b/tests/acceptance/features/app-files.feature @@ -140,6 +140,101 @@ Feature: app-files Then I see that the current section is "Deleted files" Then I see that the file list contains a file named "welcome.txt" + Scenario: move a file to another folder + Given I am logged in + And I create a new folder named "Destination" + When I start the move or copy operation for "welcome.txt" + And I select "Destination" in the file picker + And I move to the last selected folder in the file picker + Then I see that the file list does not contain a file named "welcome.txt" + And I enter in the folder named "Destination" + And I see that the file list contains a file named "welcome.txt" + + Scenario: move a selection to another folder + Given I am logged in + And I create a new folder named "Folder" + And I create a new folder named "Not selected folder" + And I create a new folder named "Destination" + When I select "welcome.txt" + And I select "Folder" + And I start the move or copy operation for the selected files + And I select "Destination" in the file picker + And I move to the last selected folder in the file picker + Then I see that the file list does not contain a file named "welcome.txt" + And I see that the file list does not contain a file named "Folder" + And I see that the file list contains a file named "Not selected folder" + And I enter in the folder named "Destination" + And I see that the file list contains a file named "welcome.txt" + And I see that the file list contains a file named "Folder" + And I see that the file list does not contain a file named "Not selected folder" + + Scenario: copy a file to another folder + Given I am logged in + And I create a new folder named "Destination" + When I start the move or copy operation for "welcome.txt" + And I select "Destination" in the file picker + And I copy to the last selected folder in the file picker + Then I enter in the folder named "Destination" + # The file will appear in the destination once the copy operation finishes + And I see that the file list contains a file named "welcome.txt" + # The Files app is open again to reload the file list in the root folder + And I open the Files app + And I see that the file list contains a file named "welcome.txt" + + Scenario: copy a selection to another folder + Given I am logged in + And I create a new folder named "Folder" + And I create a new folder named "Not selected folder" + And I create a new folder named "Destination" + When I select "welcome.txt" + And I select "Folder" + And I start the move or copy operation for the selected files + And I select "Destination" in the file picker + And I copy to the last selected folder in the file picker + Then I enter in the folder named "Destination" + # The files will appear in the destination once the copy operation finishes + And I see that the file list contains a file named "welcome.txt" + And I see that the file list contains a file named "Folder" + And I see that the file list does not contain a file named "Not selected folder" + # The Files app is open again to reload the file list in the root folder + And I open the Files app + And I see that the file list contains a file named "welcome.txt" + And I see that the file list contains a file named "Folder" + And I see that the file list contains a file named "Not selected folder" + + Scenario: copy a file in its same folder + Given I am logged in + When I start the move or copy operation for "welcome.txt" + # No folder was explicitly selected, so the last selected folder is the + # current folder. + And I copy to the last selected folder in the file picker + Then I see that the file list contains a file named "welcome.txt" + And I see that the file list contains a file named "welcome (copy).txt" + + Scenario: copy a file twice in its same folder + Given I am logged in + And I start the move or copy operation for "welcome.txt" + # No folder was explicitly selected, so the last selected folder is the + # current folder. + And I copy to the last selected folder in the file picker + When I start the move or copy operation for "welcome.txt" + And I copy to the last selected folder in the file picker + Then I see that the file list contains a file named "welcome.txt" + And I see that the file list contains a file named "welcome (copy).txt" + And I see that the file list contains a file named "welcome (copy 2).txt" + + Scenario: copy a copy of a file in its same folder + Given I am logged in + And I start the move or copy operation for "welcome.txt" + # No folder was explicitly selected, so the last selected folder is the + # current folder. + And I copy to the last selected folder in the file picker + When I start the move or copy operation for "welcome (copy).txt" + And I copy to the last selected folder in the file picker + Then I see that the file list contains a file named "welcome.txt" + And I see that the file list contains a file named "welcome (copy).txt" + And I see that the file list contains a file named "welcome (copy 2).txt" + Scenario: rename a file with the details view open Given I am logged in And I open the details view for "welcome.txt" diff --git a/tests/acceptance/features/bootstrap/FileListContext.php b/tests/acceptance/features/bootstrap/FileListContext.php index ee35de40c5e..cdf2e6acc6e 100644 --- a/tests/acceptance/features/bootstrap/FileListContext.php +++ b/tests/acceptance/features/bootstrap/FileListContext.php @@ -133,6 +133,48 @@ class FileListContext implements Context, ActorAwareInterface { /** * @return Locator */ + public static function fileListHeader($fileListAncestor) { + return Locator::forThe()->css("thead")-> + descendantOf($fileListAncestor)-> + describedAs("Header in file list"); + } + + /** + * @return Locator + */ + public static function selectedFilesActionsMenuButton($fileListAncestor) { + return Locator::forThe()->css(".actions-selected")-> + descendantOf(self::fileListHeader($fileListAncestor))-> + describedAs("Selected files actions menu button in file list"); + } + + /** + * @return Locator + */ + public static function selectedFilesActionsMenu() { + return Locator::forThe()->css(".filesSelectMenu")-> + describedAs("Selected files actions menu in file list"); + } + + /** + * @return Locator + */ + private static function selectedFilesActionsMenuItemFor($itemText) { + return Locator::forThe()->xpath("//a[normalize-space() = '$itemText']")-> + descendantOf(self::selectedFilesActionsMenu())-> + describedAs($itemText . " item in selected files actions menu in file list"); + } + + /** + * @return Locator + */ + public static function moveOrCopySelectedFilesMenuItem() { + return self::selectedFilesActionsMenuItemFor("Move or copy"); + } + + /** + * @return Locator + */ public static function rowForFile($fileListAncestor, $fileName) { return Locator::forThe()->xpath("//*[@id = 'fileList']//span[contains(concat(' ', normalize-space(@class), ' '), ' nametext ') and normalize-space() = '$fileName']/ancestor::tr")-> descendantOf($fileListAncestor)-> @@ -151,6 +193,26 @@ class FileListContext implements Context, ActorAwareInterface { /** * @return Locator */ + public static function selectionCheckboxForFile($fileListAncestor, $fileName) { + // Note that the element that the user interacts with is the label, not + // the checbox itself. + return Locator::forThe()->css(".selection label")-> + descendantOf(self::rowForFile($fileListAncestor, $fileName))-> + describedAs("Selection checkbox for file $fileName in file list"); + } + + /** + * @return Locator + */ + public static function selectionCheckboxInputForFile($fileListAncestor, $fileName) { + return Locator::forThe()->css(".selection input[type=checkbox]")-> + descendantOf(self::rowForFile($fileListAncestor, $fileName))-> + describedAs("Selection checkbox input for file $fileName in file list"); + } + + /** + * @return Locator + */ public static function favoriteMarkForFile($fileListAncestor, $fileName) { return Locator::forThe()->css(".favorite-mark")-> descendantOf(self::rowForFile($fileListAncestor, $fileName))-> @@ -268,6 +330,13 @@ class FileListContext implements Context, ActorAwareInterface { /** * @return Locator */ + public static function moveOrCopyMenuItem() { + return self::fileActionsMenuItemFor("Move or copy"); + } + + /** + * @return Locator + */ public static function viewFileInFolderMenuItem() { return self::fileActionsMenuItemFor("View in folder"); } @@ -297,6 +366,24 @@ class FileListContext implements Context, ActorAwareInterface { } /** + * @Given I select :fileName + */ + public function iSelect($fileName) { + $this->iSeeThatIsNotSelected($fileName); + + $this->actor->find(self::selectionCheckboxForFile($this->fileListAncestor, $fileName), 10)->click(); + } + + /** + * @Given I start the move or copy operation for the selected files + */ + public function iStartTheMoveOrCopyOperationForTheSelectedFiles() { + $this->actor->find(self::selectedFilesActionsMenuButton($this->fileListAncestor), 10)->click(); + + $this->actor->find(self::moveOrCopySelectedFilesMenuItem(), 2)->click(); + } + + /** * @Given I open the details view for :fileName */ public function iOpenTheDetailsViewFor($fileName) { @@ -326,6 +413,15 @@ class FileListContext implements Context, ActorAwareInterface { } /** + * @Given I start the move or copy operation for :fileName + */ + public function iStartTheMoveOrCopyOperationFor($fileName) { + $this->actor->find(self::fileActionsMenuButtonForFile($this->fileListAncestor, $fileName), 10)->click(); + + $this->actor->find(self::moveOrCopyMenuItem(), 2)->click(); + } + + /** * @Given I mark :fileName as favorite */ public function iMarkAsFavorite($fileName) { @@ -411,6 +507,18 @@ class FileListContext implements Context, ActorAwareInterface { } /** + * @Then I see that the file list does not contain a file named :fileName + */ + public function iSeeThatTheFileListDoesNotContainAFileNamed($fileName) { + if (!WaitFor::elementToBeEventuallyNotShown( + $this->actor, + self::rowForFile($this->fileListAncestor, $fileName), + $timeout = 10 * $this->actor->getFindTimeoutMultiplier())) { + PHPUnit_Framework_Assert::fail("The file list still contains a file named $fileName after $timeout seconds"); + } + } + + /** * @Then I see that :fileName1 precedes :fileName2 in the file list */ public function iSeeThatPrecedesInTheFileList($fileName1, $fileName2) { @@ -418,6 +526,13 @@ class FileListContext implements Context, ActorAwareInterface { } /** + * @Then I see that :fileName is not selected + */ + public function iSeeThatIsNotSelected($fileName) { + PHPUnit_Framework_Assert::assertFalse($this->actor->find(self::selectionCheckboxInputForFile($this->fileListAncestor, $fileName), 10)->isChecked()); + } + + /** * @Then I see that :fileName is marked as favorite */ public function iSeeThatIsMarkedAsFavorite($fileName) { diff --git a/tests/acceptance/features/bootstrap/FilePickerContext.php b/tests/acceptance/features/bootstrap/FilePickerContext.php new file mode 100644 index 00000000000..c62a505f705 --- /dev/null +++ b/tests/acceptance/features/bootstrap/FilePickerContext.php @@ -0,0 +1,125 @@ +<?php + +/** + * + * @copyright Copyright (c) 2018, Daniel Calviño Sánchez (danxuliu@gmail.com) + * + * @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/>. + * + */ + +use Behat\Behat\Context\Context; + +class FilePickerContext implements Context, ActorAwareInterface { + + use ActorAware; + + /** + * @return Locator + */ + public static function dialog() { + return Locator::forThe()->css(".oc-dialog")-> + describedAs("File picker dialog"); + } + + /** + * @return Locator + */ + public static function fileListContainer() { + return Locator::forThe()->css("#oc-dialog-filepicker-content")-> + descendantOf(self::dialog())-> + describedAs("File list container in the file picker dialog"); + } + + /** + * @return Locator + */ + public static function rowForFile($fileName) { + return Locator::forThe()->xpath("//*[@id = 'picker-filestable']//*[contains(concat(' ', normalize-space(@class), ' '), ' filename ') and normalize-space() = '$fileName']/ancestor::tr")-> + descendantOf(self::fileListContainer())-> + describedAs("Row for file $fileName in the file picker dialog"); + } + + /** + * @return Locator + */ + public static function buttonRow() { + return Locator::forThe()->css(".oc-dialog-buttonrow")-> + descendantOf(self::dialog())-> + describedAs("Button row in the file picker dialog"); + } + + /** + * @return Locator + */ + private static function buttonFor($buttonText) { + // "Copy" and "Move" buttons text is set to "Copy to XXX" and "Move to + // XXX" when a folder is selected. + return Locator::forThe()->xpath("//button[starts-with(normalize-space(), '$buttonText')]")-> + descendantOf(self::buttonRow())-> + describedAs($buttonText . " button in the file picker dialog"); + } + + /** + * @return Locator + */ + public static function copyButton() { + return self::buttonFor("Copy"); + } + + /** + * @return Locator + */ + public static function moveButton() { + return self::buttonFor("Move"); + } + + /** + * @return Locator + */ + public static function chooseButton() { + return self::buttonFor("Choose"); + } + + /** + * @When I select :fileName in the file picker + */ + public function iSelectInTheFilePicker($fileName) { + $this->actor->find(self::rowForFile($fileName), 10)->click(); + } + + /** + * @When I copy to the last selected folder in the file picker + */ + public function iCopyToTheLastSelectedFolderInTheFilePicker() { + $this->actor->find(self::copyButton(), 10)->click(); + } + + /** + * @When I move to the last selected folder in the file picker + */ + public function iMoveToTheLastSelectedFolderInTheFilePicker() { + $this->actor->find(self::moveButton(), 10)->click(); + } + + /** + * @When I choose the last selected file in the file picker + */ + public function iChooseTheLastSelectedFileInTheFilePicker() { + $this->actor->find(self::chooseButton(), 10)->click(); + } + +} diff --git a/tests/data/guest_avatar_einstein_32.png b/tests/data/guest_avatar_einstein_32.png Binary files differnew file mode 100644 index 00000000000..58562b7d711 --- /dev/null +++ b/tests/data/guest_avatar_einstein_32.png diff --git a/tests/data/guest_avatar_einstein_32.svg b/tests/data/guest_avatar_einstein_32.svg new file mode 100644 index 00000000000..d007f962f24 --- /dev/null +++ b/tests/data/guest_avatar_einstein_32.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> + <svg width="32" height="32" version="1.1" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg"> + <rect width="100%" height="100%" fill="#499aa2"></rect> + <text x="50%" y="350" style="font-weight:normal;font-size:279px;font-family:'Nunito';text-anchor:middle;fill:#fff">E</text> + </svg> diff --git a/tests/data/test.pdf b/tests/data/test.pdf Binary files differnew file mode 100644 index 00000000000..241e1e85d41 --- /dev/null +++ b/tests/data/test.pdf diff --git a/tests/lib/Activity/ManagerTest.php b/tests/lib/Activity/ManagerTest.php index b80d6fa01b6..ba6b87ca9aa 100644 --- a/tests/lib/Activity/ManagerTest.php +++ b/tests/lib/Activity/ManagerTest.php @@ -1,10 +1,23 @@ <?php /** - * Copyright (c) 2014 Thomas Müller <deepdiver@owncloud.com> - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. + * @copyright Copyright (c) 2014 Thomas Müller <deepdiver@owncloud.com> + * @copyright Copyright (c) 2019 Joas Schilling <coding@schilljs.com> + * + * @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/>. * */ @@ -46,27 +59,18 @@ class ManagerTest extends TestCase { $this->validator ); - $this->assertSame([], $this->invokePrivate($this->activityManager, 'getConsumers')); - $this->assertSame([], $this->invokePrivate($this->activityManager, 'getExtensions')); + $this->assertSame([], self::invokePrivate($this->activityManager, 'getConsumers')); $this->activityManager->registerConsumer(function() { return new NoOpConsumer(); }); - $this->activityManager->registerExtension(function() { - return new NoOpExtension(); - }); - $this->activityManager->registerExtension(function() { - return new SimpleExtension(); - }); - $this->assertNotEmpty($this->invokePrivate($this->activityManager, 'getConsumers')); - $this->assertNotEmpty($this->invokePrivate($this->activityManager, 'getConsumers')); - $this->assertNotEmpty($this->invokePrivate($this->activityManager, 'getExtensions')); - $this->assertNotEmpty($this->invokePrivate($this->activityManager, 'getExtensions')); + $this->assertNotEmpty(self::invokePrivate($this->activityManager, 'getConsumers')); + $this->assertNotEmpty(self::invokePrivate($this->activityManager, 'getConsumers')); } public function testGetConsumers() { - $consumers = $this->invokePrivate($this->activityManager, 'getConsumers'); + $consumers = self::invokePrivate($this->activityManager, 'getConsumers'); $this->assertNotEmpty($consumers); } @@ -79,111 +83,7 @@ class ManagerTest extends TestCase { return new \stdClass(); }); - $this->invokePrivate($this->activityManager, 'getConsumers'); - } - - public function testGetExtensions() { - $extensions = $this->invokePrivate($this->activityManager, 'getExtensions'); - - $this->assertNotEmpty($extensions); - } - - /** - * @expectedException \InvalidArgumentException - */ - public function testGetExtensionsInvalidExtension() { - $this->activityManager->registerExtension(function() { - return new \stdClass(); - }); - - $this->invokePrivate($this->activityManager, 'getExtensions'); - } - - public function testNotificationTypes() { - $result = $this->activityManager->getNotificationTypes('en'); - $this->assertTrue(is_array($result)); - $this->assertEquals(2, sizeof($result)); - } - - public function testDefaultTypes() { - $result = $this->activityManager->getDefaultTypes('stream'); - $this->assertTrue(is_array($result)); - $this->assertEquals(1, sizeof($result)); - - $result = $this->activityManager->getDefaultTypes('email'); - $this->assertTrue(is_array($result)); - $this->assertEquals(0, sizeof($result)); - } - - public function testTypeIcon() { - $result = $this->activityManager->getTypeIcon('NT1'); - $this->assertEquals('icon-nt-one', $result); - - $result = $this->activityManager->getTypeIcon('NT2'); - $this->assertEquals('', $result); - } - - public function testTranslate() { - $result = $this->activityManager->translate('APP0', '', array(), false, false, 'en'); - $this->assertEquals('Stupid translation', $result); - - $result = $this->activityManager->translate('APP1', '', array(), false, false, 'en'); - $this->assertFalse($result); - } - - public function testGetSpecialParameterList() { - $result = $this->activityManager->getSpecialParameterList('APP0', ''); - $this->assertEquals(array(0 => 'file', 1 => 'username'), $result); - - $result = $this->activityManager->getSpecialParameterList('APP1', ''); - $this->assertFalse($result); - } - - public function testGroupParameter() { - $result = $this->activityManager->getGroupParameter(array()); - $this->assertEquals(5, $result); - } - - public function testNavigation() { - $result = $this->activityManager->getNavigation(); - $this->assertEquals(4, sizeof($result['apps'])); - $this->assertEquals(2, sizeof($result['top'])); - } - - public function testIsFilterValid() { - $result = $this->activityManager->isFilterValid('fv01'); - $this->assertTrue($result); - - $result = $this->activityManager->isFilterValid('InvalidFilter'); - $this->assertFalse($result); - } - - public function testFilterNotificationTypes() { - $result = $this->activityManager->filterNotificationTypes(array('NT0', 'NT1', 'NT2', 'NT3'), 'fv01'); - $this->assertTrue(is_array($result)); - $this->assertEquals(3, sizeof($result)); - - $result = $this->activityManager->filterNotificationTypes(array('NT0', 'NT1', 'NT2', 'NT3'), 'InvalidFilter'); - $this->assertTrue(is_array($result)); - $this->assertEquals(4, sizeof($result)); - } - - public function testQueryForFilter() { - // Register twice, to test the created sql part - $this->activityManager->registerExtension(function() { - return new SimpleExtension(); - }); - - $result = $this->activityManager->getQueryForFilter('fv01'); - $this->assertEquals( - array( - ' and ((`app` = ? and `message` like ?) or (`app` = ? and `message` like ?))', - array('mail', 'ownCloud%', 'mail', 'ownCloud%') - ), $result - ); - - $result = $this->activityManager->getQueryForFilter('InvalidFilter'); - $this->assertEquals(array(null, null), $result); + self::invokePrivate($this->activityManager, 'getConsumers'); } public function getUserFromTokenThrowInvalidTokenData() { @@ -392,121 +292,6 @@ class ManagerTest extends TestCase { } } -class SimpleExtension implements \OCP\Activity\IExtension { - - public function getNotificationTypes($languageCode) { - return array('NT1', 'NT2'); - } - - public function getDefaultTypes($method) { - if ($method === 'stream') { - return array('DT0'); - } - - return array(); - } - - public function getTypeIcon($type) { - if ($type === 'NT1') { - return 'icon-nt-one'; - } - return ''; - } - - public function translate($app, $text, $params, $stripPath, $highlightParams, $languageCode) { - if ($app === 'APP0') { - return "Stupid translation"; - } - - return false; - } - - public function getSpecialParameterList($app, $text) { - if ($app === 'APP0') { - return array(0 => 'file', 1 => 'username'); - } - - return false; - } - - public function getGroupParameter($activity) { - return 5; - } - - public function getNavigation() { - return array( - 'apps' => array('nav1', 'nav2', 'nav3', 'nav4'), - 'top' => array('top1', 'top2') - ); - } - - public function isFilterValid($filterValue) { - if ($filterValue === 'fv01') { - return true; - } - - return false; - } - - public function filterNotificationTypes($types, $filter) { - if ($filter === 'fv01') { - unset($types[0]); - } - return $types; - } - - public function getQueryForFilter($filter) { - if ($filter === 'fv01') { - return array('`app` = ? and `message` like ?', array('mail', 'ownCloud%')); - } - - return false; - } -} - -class NoOpExtension implements \OCP\Activity\IExtension { - - public function getNotificationTypes($languageCode) { - return false; - } - - public function getDefaultTypes($method) { - return false; - } - - public function getTypeIcon($type) { - return false; - } - - public function translate($app, $text, $params, $stripPath, $highlightParams, $languageCode) { - return false; - } - - public function getSpecialParameterList($app, $text) { - return false; - } - - public function getGroupParameter($activity) { - return false; - } - - public function getNavigation() { - return false; - } - - public function isFilterValid($filterValue) { - return false; - } - - public function filterNotificationTypes($types, $filter) { - return false; - } - - public function getQueryForFilter($filter) { - return false; - } -} - class NoOpConsumer implements \OCP\Activity\IConsumer { public function receive(\OCP\Activity\IEvent $event) { diff --git a/tests/lib/App/AppManagerTest.php b/tests/lib/App/AppManagerTest.php index bea39d1bc16..67188fae633 100644 --- a/tests/lib/App/AppManagerTest.php +++ b/tests/lib/App/AppManagerTest.php @@ -149,7 +149,23 @@ class AppManagerTest extends TestCase { new Group('group2', array(), null) ); $this->expectClearCache(); - $this->manager->enableAppForGroups('test', $groups); + + /** @var AppManager|\PHPUnit_Framework_MockObject_MockObject $manager */ + $manager = $this->getMockBuilder(AppManager::class) + ->setConstructorArgs([ + $this->userSession, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->eventDispatcher + ]) + ->setMethods([ + 'getAppPath', + ]) + ->getMock(); + + $manager->expects($this->exactly(2)) + ->method('getAppPath') + ->with('test') + ->willReturn('apps/test'); + + $manager->enableAppForGroups('test', $groups); $this->assertEquals('["group1","group2"]', $this->appConfig->getValue('test', 'enabled', 'no')); } @@ -183,11 +199,17 @@ class AppManagerTest extends TestCase { $this->userSession, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->eventDispatcher ]) ->setMethods([ - 'getAppInfo' + 'getAppPath', + 'getAppInfo', ]) ->getMock(); $manager->expects($this->once()) + ->method('getAppPath') + ->with('test') + ->willReturn(null); + + $manager->expects($this->once()) ->method('getAppInfo') ->with('test') ->willReturn($appInfo); @@ -226,11 +248,17 @@ class AppManagerTest extends TestCase { $this->userSession, $this->appConfig, $this->groupManager, $this->cacheFactory, $this->eventDispatcher ]) ->setMethods([ - 'getAppInfo' + 'getAppPath', + 'getAppInfo', ]) ->getMock(); $manager->expects($this->once()) + ->method('getAppPath') + ->with('test') + ->willReturn(null); + + $manager->expects($this->once()) ->method('getAppInfo') ->with('test') ->willReturn([ diff --git a/tests/lib/AppFramework/Middleware/AdditionalScriptsMiddlewareTest.php b/tests/lib/AppFramework/Middleware/AdditionalScriptsMiddlewareTest.php new file mode 100644 index 00000000000..7f817e03c1e --- /dev/null +++ b/tests/lib/AppFramework/Middleware/AdditionalScriptsMiddlewareTest.php @@ -0,0 +1,135 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl> + * + * @author Roeland Jago Douma <roeland@famdouma.nl> + * + * @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 Test\AppFramework\Middleware; + +use OC\AppFramework\Middleware\AdditionalScriptsMiddleware; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\Response; +use OCP\AppFramework\Http\StandaloneTemplateResponse; +use OCP\AppFramework\Http\TemplateResponse; +use OCP\AppFramework\PublicShareController; +use OCP\IUserSession; +use PHPUnit\Framework\MockObject\MockObject; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; + +class AdditionalScriptsMiddlewareTest extends \Test\TestCase { + + /** @var EventDispatcherInterface|MockObject */ + private $dispatcher; + /** @var IUserSession|MockObject */ + private $userSession; + + /** @var Controller */ + private $controller; + + /** @var AdditionalScriptsMiddleware */ + private $middleWare; + + public function setUp() { + parent::setUp(); + + $this->dispatcher = $this->createMock(EventDispatcherInterface::class); + $this->userSession = $this->createMock(IUserSession::class); + $this->middleWare = new AdditionalScriptsMiddleware( + $this->dispatcher, + $this->userSession + ); + + $this->controller = $this->createMock(Controller::class); + } + + public function testNoTemplateResponse() { + $this->dispatcher->expects($this->never()) + ->method($this->anything()); + $this->userSession->expects($this->never()) + ->method($this->anything()); + + $this->middleWare->afterController($this->controller, 'myMethod', $this->createMock(Response::class)); + } + + public function testPublicShareController() { + $this->dispatcher->expects($this->never()) + ->method($this->anything()); + $this->userSession->expects($this->never()) + ->method($this->anything()); + + $this->middleWare->afterController($this->createMock(PublicShareController::class), 'myMethod', $this->createMock(Response::class)); + } + + public function testStandaloneTemplateResponse() { + $this->dispatcher->expects($this->once()) + ->method('dispatch') + ->willReturnCallback(function($eventName) { + if ($eventName === TemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPTS) { + return; + } + + $this->fail('Wrong event dispatched'); + }); + $this->userSession->expects($this->never()) + ->method($this->anything()); + + $this->middleWare->afterController($this->controller, 'myMethod', $this->createMock(StandaloneTemplateResponse::class)); + } + + public function testTemplateResponseNotLoggedIn() { + $this->dispatcher->expects($this->once()) + ->method('dispatch') + ->willReturnCallback(function($eventName) { + if ($eventName === TemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPTS) { + return; + } + + $this->fail('Wrong event dispatched'); + }); + $this->userSession->method('isLoggedIn') + ->willReturn(false); + + $this->middleWare->afterController($this->controller, 'myMethod', $this->createMock(TemplateResponse::class)); + } + + public function testTemplateResponseLoggedIn() { + $events = []; + + $this->dispatcher->expects($this->exactly(2)) + ->method('dispatch') + ->willReturnCallback(function($eventName) use (&$events) { + if ($eventName === TemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPTS || + $eventName === TemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPTS_LOGGEDIN) { + $events[] = $eventName; + return; + } + + $this->fail('Wrong event dispatched'); + }); + $this->userSession->method('isLoggedIn') + ->willReturn(true); + + $this->middleWare->afterController($this->controller, 'myMethod', $this->createMock(TemplateResponse::class)); + + $this->assertContains(TemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPTS, $events); + $this->assertContains(TemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPTS_LOGGEDIN, $events); + } +} diff --git a/tests/lib/AppFramework/Routing/RoutingTest.php b/tests/lib/AppFramework/Routing/RoutingTest.php index 76533fff014..fccece481ce 100644 --- a/tests/lib/AppFramework/Routing/RoutingTest.php +++ b/tests/lib/AppFramework/Routing/RoutingTest.php @@ -6,6 +6,9 @@ use OC\AppFramework\DependencyInjection\DIContainer; use OC\AppFramework\Routing\RouteActionHandler; use OC\AppFramework\Routing\RouteConfig; use OCP\ILogger; +use OCP\Route\IRouter; +use PHPUnit\Framework\MockObject\MockObject; +use OC\Route\Router; class RoutingTest extends \Test\TestCase { @@ -179,6 +182,27 @@ class RoutingTest extends \Test\TestCase $this->assertSimpleOCSRoute($routes, 'admin_folders.open_current', 'DELETE', '/apps/app1/folders/{folderId}/open', 'AdminFoldersController', 'openCurrent'); } + public function testOCSResource() + { + $routes = ['ocs-resources' => ['account' => ['url' => '/accounts']]]; + + $this->assertOCSResource($routes, 'account', '/apps/app1/accounts', 'AccountController', 'id'); + } + + public function testOCSResourceWithUnderScoreName() + { + $routes = ['ocs-resources' => ['admin_accounts' => ['url' => '/admin/accounts']]]; + + $this->assertOCSResource($routes, 'admin_accounts', '/apps/app1/admin/accounts', 'AdminAccountsController', 'id'); + } + + public function testOCSResourceWithRoot() + { + $routes = ['ocs-resources' => ['admin_accounts' => ['url' => '/admin/accounts', 'root' => '/core/endpoint']]]; + + $this->assertOCSResource($routes, 'admin_accounts', '/core/endpoint/admin/accounts', 'AdminAccountsController', 'id'); + } + public function testResource() { $routes = array('resources' => array('account' => array('url' => '/accounts'))); @@ -278,6 +302,67 @@ class RoutingTest extends \Test\TestCase } /** + * @param array $yaml + * @param string $resourceName + * @param string $url + * @param string $controllerName + * @param string $paramName + */ + private function assertOCSResource($yaml, $resourceName, $url, $controllerName, $paramName): void { + /** @var IRouter|MockObject $router */ + $router = $this->getMockBuilder(Router::class) + ->setMethods(['create']) + ->setConstructorArgs([$this->getMockBuilder(ILogger::class)->getMock()]) + ->getMock(); + + // route mocks + $container = new DIContainer('app1'); + $indexRoute = $this->mockRoute($container, 'GET', $controllerName, 'index'); + $showRoute = $this->mockRoute($container, 'GET', $controllerName, 'show'); + $createRoute = $this->mockRoute($container, 'POST', $controllerName, 'create'); + $updateRoute = $this->mockRoute($container, 'PUT', $controllerName, 'update'); + $destroyRoute = $this->mockRoute($container, 'DELETE', $controllerName, 'destroy'); + + $urlWithParam = $url . '/{' . $paramName . '}'; + + // we expect create to be called once: + $router + ->expects($this->at(0)) + ->method('create') + ->with($this->equalTo('ocs.app1.' . $resourceName . '.index'), $this->equalTo($url)) + ->willReturn($indexRoute); + + $router + ->expects($this->at(1)) + ->method('create') + ->with($this->equalTo('ocs.app1.' . $resourceName . '.show'), $this->equalTo($urlWithParam)) + ->willReturn($showRoute); + + $router + ->expects($this->at(2)) + ->method('create') + ->with($this->equalTo('ocs.app1.' . $resourceName . '.create'), $this->equalTo($url)) + ->willReturn($createRoute); + + $router + ->expects($this->at(3)) + ->method('create') + ->with($this->equalTo('ocs.app1.' . $resourceName . '.update'), $this->equalTo($urlWithParam)) + ->willReturn($updateRoute); + + $router + ->expects($this->at(4)) + ->method('create') + ->with($this->equalTo('ocs.app1.' . $resourceName . '.destroy'), $this->equalTo($urlWithParam)) + ->willReturn($destroyRoute); + + // load route configuration + $config = new RouteConfig($container, $router, $yaml); + + $config->register(); + } + + /** * @param string $resourceName * @param string $url * @param string $controllerName diff --git a/tests/lib/AvatarManagerTest.php b/tests/lib/Avatar/AvatarManagerTest.php index 9f2a4f4f337..7466f664eb5 100644 --- a/tests/lib/AvatarManagerTest.php +++ b/tests/lib/Avatar/AvatarManagerTest.php @@ -22,11 +22,10 @@ * */ -namespace Test; +namespace Test\Avatar; -use OC\Avatar; -use OC\AvatarManager; -use OC\Files\AppData\AppData; +use OC\Avatar\UserAvatar; +use OC\Avatar\AvatarManager; use OC\User\Manager; use OCP\Files\IAppData; use OCP\Files\SimpleFS\ISimpleFolder; @@ -34,7 +33,6 @@ use OCP\IConfig; use OCP\IL10N; use OCP\ILogger; use OCP\IUser; -use OCP\IUserManager; /** * Class AvatarManagerTest @@ -103,7 +101,7 @@ class AvatarManagerTest extends \Test\TestCase { ->with('valid-user') ->willReturn($folder); - $expected = new Avatar($folder, $this->l10n, $user, $this->logger, $this->config); + $expected = new UserAvatar($folder, $this->l10n, $user, $this->logger, $this->config); $this->assertEquals($expected, $this->avatarManager->getAvatar('valid-user')); } @@ -125,7 +123,7 @@ class AvatarManagerTest extends \Test\TestCase { ->with('valid-user') ->willReturn($folder); - $expected = new Avatar($folder, $this->l10n, $user, $this->logger, $this->config); + $expected = new UserAvatar($folder, $this->l10n, $user, $this->logger, $this->config); $this->assertEquals($expected, $this->avatarManager->getAvatar('vaLid-USER')); } } diff --git a/tests/lib/Avatar/GuestAvatarTest.php b/tests/lib/Avatar/GuestAvatarTest.php new file mode 100644 index 00000000000..0d13655133b --- /dev/null +++ b/tests/lib/Avatar/GuestAvatarTest.php @@ -0,0 +1,80 @@ +<?php +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2018, Michael Weimann <mail@michael-weimann.eu> + * + * @author Michael Weimann <mail@michael-weimann.eu> + * + * @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\Avatar; + +use OC\Avatar\GuestAvatar; +use OCP\Files\SimpleFS\InMemoryFile; +use OCP\ILogger; +use PHPUnit\Framework\MockObject\MockObject; +use Test\TestCase; + +/** + * This class provides test cases for the GuestAvatar class. + * + * @package Test\Avatar + */ +class GuestAvatarTest extends TestCase { + /** + * @var GuestAvatar + */ + private $guestAvatar; + + /** + * Setups a guest avatar instance for tests. + * + * @before + * @return void + */ + public function setupGuestAvatar() { + /* @var MockObject|ILogger $logger */ + $logger = $this->getMockBuilder(ILogger::class)->getMock(); + $this->guestAvatar = new GuestAvatar('einstein', $logger); + } + + /** + * Asserts that testGet() returns the expected avatar. + * + * For the test a static name "einstein" is used and + * the generated image is compared with an expected one. + * + * @return void + */ + public function testGet() { + $avatar = $this->guestAvatar->getFile(32); + self::assertInstanceOf(InMemoryFile::class, $avatar); + $expectedFile = file_get_contents( + __DIR__ . '/../../data/guest_avatar_einstein_32.png' + ); + self::assertEquals(trim($expectedFile), trim($avatar->getContent())); + } + + /** + * Asserts that "testIsCustomAvatar" returns false for guests. + * + * @return void + */ + public function testIsCustomAvatar() { + self::assertFalse($this->guestAvatar->isCustomAvatar()); + } +} diff --git a/tests/lib/AvatarTest.php b/tests/lib/Avatar/UserAvatarTest.php index c8c9d3b8317..049725c78c9 100644 --- a/tests/lib/AvatarTest.php +++ b/tests/lib/Avatar/UserAvatarTest.php @@ -6,7 +6,7 @@ * See the COPYING-README file. */ -namespace Test; +namespace Test\Avatar; use OC\Files\SimpleFS\SimpleFolder; use OC\User\User; @@ -18,11 +18,11 @@ use OCP\IConfig; use OCP\IL10N; use OCP\ILogger; -class AvatarTest extends \Test\TestCase { +class UserAvatarTest extends \Test\TestCase { /** @var Folder | \PHPUnit_Framework_MockObject_MockObject */ private $folder; - /** @var \OC\Avatar */ + /** @var \OC\Avatar\UserAvatar */ private $avatar; /** @var \OC\User\User | \PHPUnit_Framework_MockObject_MockObject $user */ @@ -41,7 +41,7 @@ class AvatarTest extends \Test\TestCase { $this->user = $this->createMock(User::class); $this->config = $this->createMock(IConfig::class); - $this->avatar = new \OC\Avatar( + $this->avatar = new \OC\Avatar\UserAvatar( $this->folder, $l, $this->user, diff --git a/tests/lib/Files/Node/FolderTest.php b/tests/lib/Files/Node/FolderTest.php index 2c87b645dd9..e1ee96c37ec 100644 --- a/tests/lib/Files/Node/FolderTest.php +++ b/tests/lib/Files/Node/FolderTest.php @@ -290,7 +290,8 @@ class FolderTest extends NodeTest { ->method('getUser') ->will($this->returnValue($this->user)); $storage = $this->createMock(Storage::class); - $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([''])->getMock(); + $storage->method('getId')->willReturn(''); + $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([$storage])->getMock(); $storage->expects($this->once()) ->method('getCache') @@ -340,8 +341,10 @@ class FolderTest extends NodeTest { $root->expects($this->any()) ->method('getUser') ->will($this->returnValue($this->user)); + /** @var \PHPUnit_Framework_MockObject_MockObject|Storage $storage */ $storage = $this->createMock(Storage::class); - $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([''])->getMock(); + $storage->method('getId')->willReturn(''); + $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([$storage])->getMock(); $mount = $this->createMock(IMountPoint::class); $mount->expects($this->once()) @@ -391,7 +394,8 @@ class FolderTest extends NodeTest { ->method('getUser') ->will($this->returnValue($this->user)); $storage = $this->createMock(Storage::class); - $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([''])->getMock(); + $storage->method('getId')->willReturn(''); + $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([$storage])->getMock(); $mount = $this->createMock(IMountPoint::class); $mount->expects($this->once()) @@ -441,7 +445,8 @@ class FolderTest extends NodeTest { ->method('getUser') ->will($this->returnValue($this->user)); $storage = $this->createMock(Storage::class); - $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([''])->getMock(); + $storage->method('getId')->willReturn(''); + $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([$storage])->getMock(); $mount = $this->createMock(IMountPoint::class); $mount->expects($this->once()) @@ -491,8 +496,9 @@ class FolderTest extends NodeTest { ->method('getUser') ->will($this->returnValue($this->user)); $storage = $this->createMock(Storage::class); - $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([''])->getMock(); - $subCache = $this->getMockBuilder(Cache::class)->setConstructorArgs([''])->getMock(); + $storage->method('getId')->willReturn(''); + $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([$storage])->getMock(); + $subCache = $this->getMockBuilder(Cache::class)->setConstructorArgs([$storage])->getMock(); $subStorage = $this->createMock(Storage::class); $subMount = $this->getMockBuilder(MountPoint::class)->setConstructorArgs([null, ''])->getMock(); @@ -572,7 +578,8 @@ class FolderTest extends NodeTest { ->getMock(); $storage = $this->createMock(\OC\Files\Storage\Storage::class); $mount = new MountPoint($storage, '/bar'); - $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([''])->getMock(); + $storage->method('getId')->willReturn(''); + $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([$storage])->getMock(); $fileInfo = new CacheEntry(['path' => 'foo/qwerty', 'mimetype' => 'text/plain'], null); @@ -625,7 +632,8 @@ class FolderTest extends NodeTest { ->getMock(); $storage = $this->createMock(\OC\Files\Storage\Storage::class); $mount = new MountPoint($storage, '/bar'); - $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([''])->getMock(); + $storage->method('getId')->willReturn(''); + $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([$storage])->getMock(); $fileInfo = new CacheEntry(['path' => '', 'mimetype' => 'text/plain'], null); @@ -673,7 +681,8 @@ class FolderTest extends NodeTest { ->getMock(); $storage = $this->createMock(\OC\Files\Storage\Storage::class); $mount = new MountPoint($storage, '/bar'); - $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([''])->getMock(); + $storage->method('getId')->willReturn(''); + $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([$storage])->getMock(); $fileInfo = new CacheEntry(['path' => 'foobar', 'mimetype' => 'text/plain'], null); @@ -726,7 +735,8 @@ class FolderTest extends NodeTest { $storage = $this->createMock(\OC\Files\Storage\Storage::class); $mount1 = new MountPoint($storage, '/bar'); $mount2 = new MountPoint($storage, '/bar/foo/asd'); - $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([''])->getMock(); + $storage->method('getId')->willReturn(''); + $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([$storage])->getMock(); $fileInfo = new CacheEntry(['path' => 'foo/qwerty', 'mimetype' => 'text/plain'], null); diff --git a/tests/lib/Files/ObjectStore/FailWriteObjectStore.php b/tests/lib/Files/ObjectStore/FailWriteObjectStore.php new file mode 100644 index 00000000000..4310d8ba27c --- /dev/null +++ b/tests/lib/Files/ObjectStore/FailWriteObjectStore.php @@ -0,0 +1,53 @@ +<?php declare(strict_types=1); +/** + * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl> + * + * @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 Test\Files\ObjectStore; + +use OCP\Files\ObjectStore\IObjectStore; + +class FailWriteObjectStore implements IObjectStore { + private $objectStore; + + public function __construct(IObjectStore $objectStore) { + $this->objectStore = $objectStore; + } + + public function getStorageId() { + return $this->objectStore->getStorageId(); + } + + public function readObject($urn) { + return $this->objectStore->readObject($urn); + } + + public function writeObject($urn, $stream) { + // emulate a failed write that didn't throw an error + return true; + } + + public function deleteObject($urn) { + $this->objectStore->deleteObject($urn); + } + + public function objectExists($urn) { + return $this->objectStore->objectExists($urn); + } +} diff --git a/tests/lib/Files/ObjectStore/ObjectStoreStorageOverwrite.php b/tests/lib/Files/ObjectStore/ObjectStoreStorageOverwrite.php new file mode 100644 index 00000000000..5e8faed3347 --- /dev/null +++ b/tests/lib/Files/ObjectStore/ObjectStoreStorageOverwrite.php @@ -0,0 +1,38 @@ +<?php declare(strict_types=1); +/** + * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl> + * + * @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 Test\Files\ObjectStore; + +use OC\Files\ObjectStore\ObjectStoreStorage; +use OCP\Files\ObjectStore\IObjectStore; + +/** + * Allow overwriting the object store instance for test purposes + */ +class ObjectStoreStorageOverwrite extends ObjectStoreStorage { + public function setObjectStore(IObjectStore $objectStore) { + $this->objectStore = $objectStore; + } + + public function getObjectStore(): IObjectStore { + return $this->objectStore; + } +} diff --git a/tests/lib/Files/ObjectStore/ObjectStoreStorageTest.php b/tests/lib/Files/ObjectStore/ObjectStoreStorageTest.php index c9d6c1bd922..3b3827f460a 100644 --- a/tests/lib/Files/ObjectStore/ObjectStoreStorageTest.php +++ b/tests/lib/Files/ObjectStore/ObjectStoreStorageTest.php @@ -30,6 +30,8 @@ use Test\Files\Storage\Storage; * @group DB */ class ObjectStoreStorageTest extends Storage { + /** @var ObjectStoreStorageOverwrite */ + protected $instance; /** * @var IObjectStore @@ -42,7 +44,7 @@ class ObjectStoreStorageTest extends Storage { $baseStorage = new Temporary(); $this->objectStorage = new StorageObjectStore($baseStorage); $config['objectstore'] = $this->objectStorage; - $this->instance = new ObjectStoreStorage($config); + $this->instance = new ObjectStoreStorageOverwrite($config); } protected function tearDown() { @@ -166,4 +168,17 @@ class ObjectStoreStorageTest extends Storage { $targetId = $this->instance->getCache()->getId('target'); $this->assertSame($sourceId, $targetId, 'fileid must be stable on move or shares will break'); } + + public function testWriteObjectSilentFailure() { + $objectStore = $this->instance->getObjectStore(); + $this->instance->setObjectStore(new FailWriteObjectStore($objectStore)); + + try { + $this->instance->file_put_contents('test.txt', 'foo'); + $this->fail('expected exception'); + } catch (\Exception $e) { + $this->assertStringStartsWith('Object not found after writing', $e->getMessage()); + } + $this->assertFalse($this->instance->file_exists('test.txt')); + } } diff --git a/tests/lib/Files/ObjectStore/ObjectStoreTest.php b/tests/lib/Files/ObjectStore/ObjectStoreTest.php index 2116306053e..1383c0149a2 100644 --- a/tests/lib/Files/ObjectStore/ObjectStoreTest.php +++ b/tests/lib/Files/ObjectStore/ObjectStoreTest.php @@ -94,4 +94,19 @@ abstract class ObjectStoreTest extends TestCase { $this->assertEquals(1, 1); } } + + public function testExists() { + $stream = $this->stringToStream('foobar'); + + $instance = $this->getInstance(); + $this->assertFalse($instance->objectExists('2')); + + $instance->writeObject('2', $stream); + + $this->assertTrue($instance->objectExists('2')); + + $instance->deleteObject('2'); + + $this->assertFalse($instance->objectExists('2')); + } } diff --git a/tests/lib/Files/ObjectStore/S3Test.php b/tests/lib/Files/ObjectStore/S3Test.php index a54ade8fd08..91b24d8b615 100644 --- a/tests/lib/Files/ObjectStore/S3Test.php +++ b/tests/lib/Files/ObjectStore/S3Test.php @@ -21,6 +21,7 @@ namespace Test\Files\ObjectStore; +use Icewind\Streams\Wrapper; use OC\Files\ObjectStore\S3; class MultiPartUploadS3 extends S3 { @@ -31,6 +32,30 @@ class MultiPartUploadS3 extends S3 { } } +class NonSeekableStream extends Wrapper { + public static function wrap($source) { + $context = stream_context_create(array( + 'nonseek' => array( + 'source' => $source + ) + )); + return Wrapper::wrapSource($source, $context, 'nonseek', self::class); + } + + public function dir_opendir($path, $options) { + return false; + } + + public function stream_open($path, $mode, $options, &$opened_path) { + $this->loadContext('nonseek'); + return true; + } + + public function stream_seek($offset, $whence = SEEK_SET) { + return false; + } +} + /** * @group PRIMARY-s3 */ @@ -44,15 +69,15 @@ class S3Test extends ObjectStoreTest { return new S3($config['arguments']); } - public function testMultiPartUploader() { + public function testUploadNonSeekable() { $config = \OC::$server->getConfig()->getSystemValue('objectstore'); if (!is_array($config) || $config['class'] !== 'OC\\Files\\ObjectStore\\S3') { $this->markTestSkipped('objectstore not configured for s3'); } - $s3 = new MultiPartUploadS3($config['arguments']); + $s3 = $this->getInstance(); - $s3->writeObject('multiparttest', fopen(__FILE__, 'r')); + $s3->writeObject('multiparttest', NonSeekableStream::wrap(fopen(__FILE__, 'r'))); $result = $s3->readObject('multiparttest'); diff --git a/tests/lib/Files/SimpleFS/InMemoryFileTest.php b/tests/lib/Files/SimpleFS/InMemoryFileTest.php new file mode 100644 index 00000000000..195a5d04a8f --- /dev/null +++ b/tests/lib/Files/SimpleFS/InMemoryFileTest.php @@ -0,0 +1,145 @@ +<?php +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2018, Michael Weimann <mail@michael-weimann.eu> + * + * @author Michael Weimann <mail@michael-weimann.eu> + * + * @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\File\SimpleFS; + +use OCP\Files\NotPermittedException; +use OCP\Files\SimpleFS\InMemoryFile; +use Test\TestCase; + +/** + * This class provide test casesf or the InMemoryFile. + * + * @package Test\File\SimpleFS + */ +class InMemoryFileTest extends TestCase { + /** + * Holds a pdf file with know attributes for tests. + * + * @var InMemoryFile + */ + private $testPdf; + + /** + * Sets the test file from "./resources/test.pdf". + * + * @before + * @return void + */ + public function setupTestPdf() { + $fileContents = file_get_contents( + __DIR__ . '/../../../data/test.pdf' + ); + $this->testPdf = new InMemoryFile('test.pdf', $fileContents); + } + + /** + * Asserts that putContent replaces the file contents. + * + * @return void + */ + public function testPutContent() { + $this->testPdf->putContent('test'); + self::assertEquals('test', $this->testPdf->getContent()); + } + + /** + * Asserts that delete() doesn't rise an exception. + * + * @return void + */ + public function testDelete() { + $this->testPdf->delete(); + // assert true, otherwise phpunit complains about not doing any assert + self::assertTrue(true); + } + + /** + * Asserts that getName returns the name passed on file creation. + * + * @return void + */ + public function testGetName() { + self::assertEquals('test.pdf', $this->testPdf->getName()); + } + + /** + * Asserts that the file size is the size of the test file. + * + * @return void + */ + public function testGetSize() { + self::assertEquals(7083, $this->testPdf->getSize()); + } + + /** + * Asserts the file contents are the same than the original file contents. + * + * @return void + */ + public function testGetContent() { + self::assertEquals( + file_get_contents(__DIR__ . '/../../../data/test.pdf'), + $this->testPdf->getContent() + ); + } + + /** + * Asserts the test file modification time is an integer. + * + * @return void + */ + public function testGetMTime() { + self::assertTrue(is_int($this->testPdf->getMTime())); + } + + /** + * Asserts the test file mime type is "application/json". + * + * @return void + */ + public function testGetMimeType() { + self::assertEquals('application/pdf', $this->testPdf->getMimeType()); + } + + + /** + * Asserts that read() raises an NotPermittedException. + * + * @return void + */ + public function testRead() { + self::expectException(NotPermittedException::class); + $this->testPdf->read(); + } + + /** + * Asserts that write() raises an NotPermittedException. + * + * @return void + */ + public function testWrite() { + self::expectException(NotPermittedException::class); + $this->testPdf->write(); + } +} diff --git a/tests/lib/Files/ViewTest.php b/tests/lib/Files/ViewTest.php index 97e3d42684f..7a32736adb3 100644 --- a/tests/lib/Files/ViewTest.php +++ b/tests/lib/Files/ViewTest.php @@ -1997,6 +1997,37 @@ class ViewTest extends \Test\TestCase { $this->assertNull($this->getFileLockType($view, $path), 'File got unlocked after exception'); } + public function testLockBasicOperationUnlocksAfterLockException() { + $view = new View('/' . $this->user . '/files/'); + + $storage = new Temporary([]); + + Filesystem::mount($storage, array(), $this->user . '/'); + + $storage->mkdir('files'); + $storage->mkdir('files/dir'); + $storage->file_put_contents('files/test.txt', 'blah'); + $storage->getScanner()->scan('files'); + + // get a shared lock + $handle = $view->fopen('test.txt', 'r'); + + $thrown = false; + try { + // try (and fail) to get a write lock + $view->unlink('test.txt'); + } catch (\Exception $e) { + $thrown = true; + $this->assertInstanceOf(LockedException::class, $e); + } + $this->assertTrue($thrown, 'Exception was rethrown'); + + // clean shared lock + fclose($handle); + + $this->assertNull($this->getFileLockType($view, 'test.txt'), 'File got unlocked'); + } + /** * Test locks for fopen with fclose at the end * diff --git a/tests/lib/InitialStateServiceTest.php b/tests/lib/InitialStateServiceTest.php new file mode 100644 index 00000000000..08bff615e3e --- /dev/null +++ b/tests/lib/InitialStateServiceTest.php @@ -0,0 +1,98 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2019 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 Test; + +use function json_encode; +use JsonSerializable; +use OC\InitialStateService; +use OCP\ILogger; +use stdClass; + +class InitialStateServiceTest extends TestCase { + + /** @var InitialStateService */ + private $service; + + protected function setUp() { + parent::setUp(); + + $this->service = new InitialStateService( + $this->createMock(ILogger::class) + ); + } + + public function staticData() { + return [ + ['string'], + [23], + [2.3], + [new class implements JsonSerializable { + public function jsonSerialize() { + return 3; + } + }], + ]; + } + + /** + * @dataProvider staticData + */ + public function testStaticData($value) { + $this->service->provideInitialState('test', 'key', $value); + $data = $this->service->getInitialStates(); + + $this->assertEquals( + ['test-key' => json_encode($value)], + $data + ); + } + + public function testStaticButInvalidData() { + $this->service->provideInitialState('test', 'key', new stdClass()); + $data = $this->service->getInitialStates(); + + $this->assertEquals( + [], + $data + ); + } + + /** + * @dataProvider staticData + */ + public function testLazyData($value) { + $this->service->provideLazyInitialState('test', 'key', function() use ($value) { + return $value; + }); + $data = $this->service->getInitialStates(); + + $this->assertEquals( + ['test-key' => json_encode($value)], + $data + ); + } + +} diff --git a/tests/lib/NavigationManagerTest.php b/tests/lib/NavigationManagerTest.php index 8bc1c372ac8..f552bd2eeed 100644 --- a/tests/lib/NavigationManagerTest.php +++ b/tests/lib/NavigationManagerTest.php @@ -221,15 +221,10 @@ class NavigationManagerTest extends TestCase { return '/apps/test/'; }); $this->urlGenerator - ->expects($this->once()) - ->method('linkToRouteAbsolute') - ->with( - 'core.login.logout', - [ - 'requesttoken' => \OCP\Util::callRegister() - ] - ) - ->willReturn('https://example.com/logout'); + ->expects($this->once()) + ->method('linkToRouteAbsolute') + ->with('core.login.logout') + ->willReturn('https://example.com/logout'); $user = $this->createMock(IUser::class); $user->expects($this->any())->method('getUID')->willReturn('user001'); $this->userSession->expects($this->any())->method('getUser')->willReturn($user); @@ -275,7 +270,7 @@ class NavigationManagerTest extends TestCase { 'logout' => [ 'id' => 'logout', 'order' => 99999, - 'href' => 'https://example.com/logout', + 'href' => 'https://example.com/logout?requesttoken='. urlencode(\OCP\Util::callRegister()), 'icon' => '/apps/core/img/actions/logout.svg', 'name' => 'Log out', 'active' => false, diff --git a/tests/lib/Repair/ClearGeneratedAvatarCacheTest.php b/tests/lib/Repair/ClearGeneratedAvatarCacheTest.php index ec107d300d6..dd98307993f 100644 --- a/tests/lib/Repair/ClearGeneratedAvatarCacheTest.php +++ b/tests/lib/Repair/ClearGeneratedAvatarCacheTest.php @@ -25,7 +25,7 @@ namespace Test\Repair; use OCP\IConfig; use OCP\Migration\IOutput; -use OC\AvatarManager; +use OC\Avatar\AvatarManager; use OC\Repair\ClearGeneratedAvatarCache; class ClearGeneratedAvatarCacheTest extends \Test\TestCase { diff --git a/tests/lib/ServerTest.php b/tests/lib/ServerTest.php index e76b2b96db7..604e11ec11e 100644 --- a/tests/lib/ServerTest.php +++ b/tests/lib/ServerTest.php @@ -57,7 +57,7 @@ class ServerTest extends \Test\TestCase { ['AppManager', '\OCP\App\IAppManager'], ['AsyncCommandBus', '\OC\Command\AsyncBus'], ['AsyncCommandBus', '\OCP\Command\IBus'], - ['AvatarManager', '\OC\AvatarManager'], + ['AvatarManager', '\OC\Avatar\AvatarManager'], ['AvatarManager', '\OCP\IAvatarManager'], ['CategoryFetcher', CategoryFetcher::class], diff --git a/tests/lib/SubAdminTest.php b/tests/lib/SubAdminTest.php index c1159132a50..4c0b030c44b 100644 --- a/tests/lib/SubAdminTest.php +++ b/tests/lib/SubAdminTest.php @@ -20,6 +20,9 @@ */ namespace Test; +/** + * @group DB + */ class SubAdminTest extends \Test\TestCase { /** @var \OCP\IUserManager */ @@ -97,7 +100,7 @@ class SubAdminTest extends \Test\TestCase { public function testCreateSubAdmin() { $subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn); - $this->assertTrue($subAdmin->createSubAdmin($this->users[0], $this->groups[0])); + $subAdmin->createSubAdmin($this->users[0], $this->groups[0]); // Look for subadmin in the database $qb = $this->dbConn->getQueryBuilder(); @@ -122,8 +125,8 @@ class SubAdminTest extends \Test\TestCase { public function testDeleteSubAdmin() { $subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn); - $this->assertTrue($subAdmin->createSubAdmin($this->users[0], $this->groups[0])); - $this->assertTrue($subAdmin->deleteSubAdmin($this->users[0], $this->groups[0])); + $subAdmin->createSubAdmin($this->users[0], $this->groups[0]); + $subAdmin->deleteSubAdmin($this->users[0], $this->groups[0]); // DB query should be empty $qb = $this->dbConn->getQueryBuilder(); @@ -138,8 +141,8 @@ class SubAdminTest extends \Test\TestCase { public function testGetSubAdminsGroups() { $subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn); - $this->assertTrue($subAdmin->createSubAdmin($this->users[0], $this->groups[0])); - $this->assertTrue($subAdmin->createSubAdmin($this->users[0], $this->groups[1])); + $subAdmin->createSubAdmin($this->users[0], $this->groups[0]); + $subAdmin->createSubAdmin($this->users[0], $this->groups[1]); $result = $subAdmin->getSubAdminsGroups($this->users[0]); @@ -148,14 +151,14 @@ class SubAdminTest extends \Test\TestCase { $this->assertNotContains($this->groups[2], $result); $this->assertNotContains(null, $result); - $this->assertTrue($subAdmin->deleteSubAdmin($this->users[0], $this->groups[0])); - $this->assertTrue($subAdmin->deleteSubAdmin($this->users[0], $this->groups[1])); + $subAdmin->deleteSubAdmin($this->users[0], $this->groups[0]); + $subAdmin->deleteSubAdmin($this->users[0], $this->groups[1]); } public function testGetGroupsSubAdmins() { $subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn); - $this->assertTrue($subAdmin->createSubAdmin($this->users[0], $this->groups[0])); - $this->assertTrue($subAdmin->createSubAdmin($this->users[1], $this->groups[0])); + $subAdmin->createSubAdmin($this->users[0], $this->groups[0]); + $subAdmin->createSubAdmin($this->users[1], $this->groups[0]); $result = $subAdmin->getGroupsSubAdmins($this->groups[0]); @@ -164,16 +167,16 @@ class SubAdminTest extends \Test\TestCase { $this->assertNotContains($this->users[2], $result); $this->assertNotContains(null, $result); - $this->assertTrue($subAdmin->deleteSubAdmin($this->users[0], $this->groups[0])); - $this->assertTrue($subAdmin->deleteSubAdmin($this->users[1], $this->groups[0])); + $subAdmin->deleteSubAdmin($this->users[0], $this->groups[0]); + $subAdmin->deleteSubAdmin($this->users[1], $this->groups[0]); } public function testGetAllSubAdmin() { $subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn); - $this->assertTrue($subAdmin->createSubAdmin($this->users[0], $this->groups[0])); - $this->assertTrue($subAdmin->createSubAdmin($this->users[1], $this->groups[1])); - $this->assertTrue($subAdmin->createSubAdmin($this->users[2], $this->groups[1])); + $subAdmin->createSubAdmin($this->users[0], $this->groups[0]); + $subAdmin->createSubAdmin($this->users[1], $this->groups[1]); + $subAdmin->createSubAdmin($this->users[2], $this->groups[1]); $result = $subAdmin->getAllSubAdmins(); @@ -185,23 +188,23 @@ class SubAdminTest extends \Test\TestCase { public function testIsSubAdminofGroup() { $subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn); - $this->assertTrue($subAdmin->createSubAdmin($this->users[0], $this->groups[0])); + $subAdmin->createSubAdmin($this->users[0], $this->groups[0]); $this->assertTrue($subAdmin->isSubAdminOfGroup($this->users[0], $this->groups[0])); $this->assertFalse($subAdmin->isSubAdminOfGroup($this->users[0], $this->groups[1])); $this->assertFalse($subAdmin->isSubAdminOfGroup($this->users[1], $this->groups[0])); - $this->assertTrue($subAdmin->deleteSubAdmin($this->users[0], $this->groups[0])); + $subAdmin->deleteSubAdmin($this->users[0], $this->groups[0]); } public function testIsSubAdmin() { $subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn); - $this->assertTrue($subAdmin->createSubAdmin($this->users[0], $this->groups[0])); + $subAdmin->createSubAdmin($this->users[0], $this->groups[0]); $this->assertTrue($subAdmin->isSubAdmin($this->users[0])); $this->assertFalse($subAdmin->isSubAdmin($this->users[1])); - $this->assertTrue($subAdmin->deleteSubAdmin($this->users[0], $this->groups[0])); + $subAdmin->deleteSubAdmin($this->users[0], $this->groups[0]); } public function testIsSubAdminAsAdmin() { @@ -216,15 +219,15 @@ class SubAdminTest extends \Test\TestCase { $this->groups[0]->addUser($this->users[1]); $this->groups[1]->addUser($this->users[1]); $this->groups[1]->addUser($this->users[2]); - $this->assertTrue($subAdmin->createSubAdmin($this->users[0], $this->groups[0])); - $this->assertTrue($subAdmin->createSubAdmin($this->users[2], $this->groups[2])); + $subAdmin->createSubAdmin($this->users[0], $this->groups[0]); + $subAdmin->createSubAdmin($this->users[2], $this->groups[2]); $this->assertTrue($subAdmin->isUserAccessible($this->users[0], $this->users[1])); $this->assertFalse($subAdmin->isUserAccessible($this->users[0], $this->users[2])); $this->assertFalse($subAdmin->isUserAccessible($this->users[2], $this->users[0])); - $this->assertTrue($subAdmin->deleteSubAdmin($this->users[0], $this->groups[0])); - $this->assertTrue($subAdmin->deleteSubAdmin($this->users[2], $this->groups[2])); + $subAdmin->deleteSubAdmin($this->users[0], $this->groups[0]); + $subAdmin->deleteSubAdmin($this->users[2], $this->groups[2]); } public function testIsUserAccessibleAsUser() { @@ -234,7 +237,7 @@ class SubAdminTest extends \Test\TestCase { public function testIsUserAccessibleAdmin() { $subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn); - $this->assertTrue($subAdmin->createSubAdmin($this->users[0], $this->groups[0])); + $subAdmin->createSubAdmin($this->users[0], $this->groups[0]); $this->groupManager->get('admin')->addUser($this->users[1]); $this->assertFalse($subAdmin->isUserAccessible($this->users[0], $this->users[1])); @@ -246,7 +249,7 @@ class SubAdminTest extends \Test\TestCase { $user = array_shift($this->users); foreach($this->groups as $group) { - $this->assertTrue($subAdmin->createSubAdmin($user, $group)); + $subAdmin->createSubAdmin($user, $group); } $user->delete(); @@ -258,7 +261,7 @@ class SubAdminTest extends \Test\TestCase { $group = array_shift($this->groups); foreach($this->users as $user) { - $this->assertTrue($subAdmin->createSubAdmin($user, $group)); + $subAdmin->createSubAdmin($user, $group); } $group->delete(); @@ -285,10 +288,10 @@ class SubAdminTest extends \Test\TestCase { $count++; }); - $this->assertTrue($subAdmin->createSubAdmin($u, $g)); + $subAdmin->createSubAdmin($u, $g); $this->assertEquals(1, $count); - $this->assertTrue($subAdmin->deleteSubAdmin($u, $g)); + $subAdmin->deleteSubAdmin($u, $g); $this->assertEquals(2, $count); } |