aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files_versions/tests
diff options
context:
space:
mode:
Diffstat (limited to 'apps/files_versions/tests')
-rw-r--r--apps/files_versions/tests/BackgroundJob/ExpireVersionsTest.php55
-rw-r--r--apps/files_versions/tests/Command/CleanupTest.php162
-rw-r--r--apps/files_versions/tests/Command/ExpireTest.php28
-rw-r--r--apps/files_versions/tests/Controller/PreviewControllerTest.php155
-rw-r--r--apps/files_versions/tests/ExpirationTest.php114
-rw-r--r--apps/files_versions/tests/StorageTest.php101
-rw-r--r--apps/files_versions/tests/VersioningTest.php998
-rw-r--r--apps/files_versions/tests/Versions/VersionManagerTest.php140
-rw-r--r--apps/files_versions/tests/command/cleanuptest.php170
-rw-r--r--apps/files_versions/tests/command/expiretest.php43
-rw-r--r--apps/files_versions/tests/expirationtest.php206
-rw-r--r--apps/files_versions/tests/js/versioncollectionSpec.js161
-rw-r--r--apps/files_versions/tests/js/versionmodelSpec.js96
-rw-r--r--apps/files_versions/tests/js/versionstabviewSpec.js208
-rw-r--r--apps/files_versions/tests/versions.php848
15 files changed, 1753 insertions, 1732 deletions
diff --git a/apps/files_versions/tests/BackgroundJob/ExpireVersionsTest.php b/apps/files_versions/tests/BackgroundJob/ExpireVersionsTest.php
new file mode 100644
index 00000000000..21e88e86f90
--- /dev/null
+++ b/apps/files_versions/tests/BackgroundJob/ExpireVersionsTest.php
@@ -0,0 +1,55 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\Files_Versions\Tests\BackgroundJob;
+
+use OCA\Files_Versions\BackgroundJob\ExpireVersions;
+use OCA\Files_Versions\Expiration;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\BackgroundJob\IJobList;
+use OCP\IConfig;
+use OCP\IUserManager;
+use PHPUnit\Framework\MockObject\MockObject;
+use Test\TestCase;
+
+class ExpireVersionsTest extends TestCase {
+ private IConfig&MockObject $config;
+ private IUserManager&MockObject $userManager;
+ private Expiration&MockObject $expiration;
+ private IJobList&MockObject $jobList;
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $this->config = $this->createMock(IConfig::class);
+ $this->userManager = $this->createMock(IUserManager::class);
+ $this->expiration = $this->createMock(Expiration::class);
+ $this->jobList = $this->createMock(IJobList::class);
+
+ $this->jobList->expects($this->once())
+ ->method('setLastRun');
+ $this->jobList->expects($this->once())
+ ->method('setExecutionTime');
+ }
+
+ public function testBackgroundJobDeactivated(): void {
+ $this->config->method('getAppValue')
+ ->with('files_versions', 'background_job_expire_versions', 'yes')
+ ->willReturn('no');
+ $this->expiration->expects($this->never())
+ ->method('getMaxAgeAsTimestamp');
+
+ $timeFactory = $this->createMock(ITimeFactory::class);
+ $timeFactory->method('getTime')
+ ->with()
+ ->willReturn(999999999);
+
+ $job = new ExpireVersions($this->config, $this->userManager, $this->expiration, $timeFactory);
+ $job->start($this->jobList);
+ }
+}
diff --git a/apps/files_versions/tests/Command/CleanupTest.php b/apps/files_versions/tests/Command/CleanupTest.php
new file mode 100644
index 00000000000..dd6665f5aef
--- /dev/null
+++ b/apps/files_versions/tests/Command/CleanupTest.php
@@ -0,0 +1,162 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+namespace OCA\Files_Versions\Tests\Command;
+
+use OC\User\Manager;
+use OCA\Files_Versions\Command\CleanUp;
+use OCA\Files_Versions\Db\VersionsMapper;
+use OCP\Files\Cache\ICache;
+use OCP\Files\Folder;
+use OCP\Files\IRootFolder;
+use OCP\Files\Storage\IStorage;
+use OCP\UserInterface;
+use PHPUnit\Framework\MockObject\MockObject;
+use Test\TestCase;
+
+/**
+ * Class CleanupTest
+ *
+ * @group DB
+ *
+ * @package OCA\Files_Versions\Tests\Command
+ */
+class CleanupTest extends TestCase {
+ protected Manager&MockObject $userManager;
+ protected IRootFolder&MockObject $rootFolder;
+ protected VersionsMapper&MockObject $versionMapper;
+ protected CleanUp $cleanup;
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $this->rootFolder = $this->createMock(IRootFolder::class);
+ $this->userManager = $this->createMock(Manager::class);
+ $this->versionMapper = $this->createMock(VersionsMapper::class);
+
+ $this->cleanup = new CleanUp($this->rootFolder, $this->userManager, $this->versionMapper);
+ }
+
+ /**
+ * @param boolean $nodeExists
+ */
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataTestDeleteVersions')]
+ public function testDeleteVersions(bool $nodeExists): void {
+ $this->rootFolder->expects($this->once())
+ ->method('nodeExists')
+ ->with('/testUser/files_versions')
+ ->willReturn($nodeExists);
+
+ $userFolder = $this->createMock(Folder::class);
+ $userHomeStorage = $this->createMock(IStorage::class);
+ $userHomeStorageCache = $this->createMock(ICache::class);
+ $this->rootFolder->expects($this->once())
+ ->method('getUserFolder')
+ ->willReturn($userFolder);
+ $userFolder->expects($this->once())
+ ->method('getStorage')
+ ->willReturn($userHomeStorage);
+ $userHomeStorage->expects($this->once())
+ ->method('getCache')
+ ->willReturn($userHomeStorageCache);
+ $userHomeStorageCache->expects($this->once())
+ ->method('getNumericStorageId')
+ ->willReturn(1);
+
+ if ($nodeExists) {
+ $this->rootFolder->expects($this->once())
+ ->method('get')
+ ->with('/testUser/files_versions')
+ ->willReturn($this->rootFolder);
+ $this->rootFolder->expects($this->once())
+ ->method('delete');
+ } else {
+ $this->rootFolder->expects($this->never())
+ ->method('get');
+ $this->rootFolder->expects($this->never())
+ ->method('delete');
+ }
+
+ $this->invokePrivate($this->cleanup, 'deleteVersions', ['testUser']);
+ }
+
+ public static function dataTestDeleteVersions(): array {
+ return [
+ [true],
+ [false]
+ ];
+ }
+
+
+ /**
+ * test delete versions from users given as parameter
+ */
+ public function testExecuteDeleteListOfUsers(): void {
+ $userIds = ['user1', 'user2', 'user3'];
+
+ $instance = $this->getMockBuilder(CleanUp::class)
+ ->onlyMethods(['deleteVersions'])
+ ->setConstructorArgs([$this->rootFolder, $this->userManager, $this->versionMapper])
+ ->getMock();
+ $instance->expects($this->exactly(count($userIds)))
+ ->method('deleteVersions')
+ ->willReturnCallback(function ($user) use ($userIds): void {
+ $this->assertTrue(in_array($user, $userIds));
+ });
+
+ $this->userManager->expects($this->exactly(count($userIds)))
+ ->method('userExists')->willReturn(true);
+
+ $inputInterface = $this->createMock(\Symfony\Component\Console\Input\InputInterface::class);
+ $inputInterface->expects($this->once())->method('getArgument')
+ ->with('user_id')
+ ->willReturn($userIds);
+
+ $outputInterface = $this->createMock(\Symfony\Component\Console\Output\OutputInterface::class);
+
+ $this->invokePrivate($instance, 'execute', [$inputInterface, $outputInterface]);
+ }
+
+ /**
+ * test delete versions of all users
+ */
+ public function testExecuteAllUsers(): void {
+ $userIds = [];
+ $backendUsers = ['user1', 'user2'];
+
+ $instance = $this->getMockBuilder(CleanUp::class)
+ ->onlyMethods(['deleteVersions'])
+ ->setConstructorArgs([$this->rootFolder, $this->userManager, $this->versionMapper])
+ ->getMock();
+
+ $backend = $this->getMockBuilder(UserInterface::class)
+ ->disableOriginalConstructor()->getMock();
+ $backend->expects($this->once())->method('getUsers')
+ ->with('', 500, 0)
+ ->willReturn($backendUsers);
+
+ $instance->expects($this->exactly(count($backendUsers)))
+ ->method('deleteVersions')
+ ->willReturnCallback(function ($user) use ($backendUsers): void {
+ $this->assertTrue(in_array($user, $backendUsers));
+ });
+
+ $inputInterface = $this->createMock(\Symfony\Component\Console\Input\InputInterface::class);
+ $inputInterface->expects($this->once())->method('getArgument')
+ ->with('user_id')
+ ->willReturn($userIds);
+
+ $outputInterface = $this->createMock(\Symfony\Component\Console\Output\OutputInterface::class);
+
+ $this->userManager->expects($this->once())
+ ->method('getBackends')
+ ->willReturn([$backend]);
+
+ $this->invokePrivate($instance, 'execute', [$inputInterface, $outputInterface]);
+ }
+}
diff --git a/apps/files_versions/tests/Command/ExpireTest.php b/apps/files_versions/tests/Command/ExpireTest.php
new file mode 100644
index 00000000000..b74457a7fd6
--- /dev/null
+++ b/apps/files_versions/tests/Command/ExpireTest.php
@@ -0,0 +1,28 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+namespace OCA\Files_Versions\Tests\Command;
+
+use OCA\Files_Versions\Command\Expire;
+use Test\TestCase;
+
+/**
+ * Class ExpireTest
+ *
+ * @group DB
+ *
+ * @package OCA\Files_Versions\Tests\Command
+ */
+class ExpireTest extends TestCase {
+ public function testExpireNonExistingUser(): void {
+ $command = new Expire($this->getUniqueID('test'), '');
+ $command->handle();
+
+ $this->addToAssertionCount(1);
+ }
+}
diff --git a/apps/files_versions/tests/Controller/PreviewControllerTest.php b/apps/files_versions/tests/Controller/PreviewControllerTest.php
new file mode 100644
index 00000000000..542ea2b6b34
--- /dev/null
+++ b/apps/files_versions/tests/Controller/PreviewControllerTest.php
@@ -0,0 +1,155 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\Files_Versions\Tests\Controller;
+
+use OCA\Files_Versions\Controller\PreviewController;
+use OCA\Files_Versions\Versions\IVersionManager;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\Files\File;
+use OCP\Files\Folder;
+use OCP\Files\IRootFolder;
+use OCP\Files\NotFoundException;
+use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\IPreview;
+use OCP\IRequest;
+use OCP\IUser;
+use OCP\IUserSession;
+use OCP\Preview\IMimeIconProvider;
+use PHPUnit\Framework\MockObject\MockObject;
+use Test\TestCase;
+
+class PreviewControllerTest extends TestCase {
+ private IRootFolder&MockObject $rootFolder;
+ private string $userId;
+ private IPreview&MockObject $previewManager;
+ private IUserSession&MockObject $userSession;
+ private IVersionManager&MockObject $versionManager;
+
+ private IMimeIconProvider&MockObject $mimeIconProvider;
+ private PreviewController $controller;
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $this->rootFolder = $this->createMock(IRootFolder::class);
+ $this->userId = 'user';
+ $user = $this->createMock(IUser::class);
+ $user->expects($this->any())
+ ->method('getUID')
+ ->willReturn($this->userId);
+ $this->previewManager = $this->createMock(IPreview::class);
+ $this->userSession = $this->createMock(IUserSession::class);
+ $this->userSession->expects($this->any())
+ ->method('getUser')
+ ->willReturn($user);
+ $this->versionManager = $this->createMock(IVersionManager::class);
+ $this->mimeIconProvider = $this->createMock(IMimeIconProvider::class);
+
+ $this->controller = new PreviewController(
+ 'files_versions',
+ $this->createMock(IRequest::class),
+ $this->rootFolder,
+ $this->userSession,
+ $this->versionManager,
+ $this->previewManager,
+ $this->mimeIconProvider,
+ );
+ }
+
+ public function testInvalidFile(): void {
+ $res = $this->controller->getPreview('');
+ $expected = new DataResponse([], Http::STATUS_BAD_REQUEST);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testInvalidWidth(): void {
+ $res = $this->controller->getPreview('file', 0);
+ $expected = new DataResponse([], Http::STATUS_BAD_REQUEST);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testInvalidHeight(): void {
+ $res = $this->controller->getPreview('file', 10, 0);
+ $expected = new DataResponse([], Http::STATUS_BAD_REQUEST);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testInvalidVersion(): void {
+ $res = $this->controller->getPreview('file', 10, 0);
+ $expected = new DataResponse([], Http::STATUS_BAD_REQUEST);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testValidPreview(): void {
+ $userFolder = $this->createMock(Folder::class);
+ $userRoot = $this->createMock(Folder::class);
+
+ $this->rootFolder->method('getUserFolder')
+ ->with($this->userId)
+ ->willReturn($userFolder);
+ $userFolder->method('getParent')
+ ->willReturn($userRoot);
+
+ $sourceFile = $this->createMock(File::class);
+ $userFolder->method('get')
+ ->with('file')
+ ->willReturn($sourceFile);
+
+ $file = $this->createMock(File::class);
+ $file->method('getMimetype')
+ ->willReturn('myMime');
+
+ $this->versionManager->method('getVersionFile')
+ ->willReturn($file);
+
+ $preview = $this->createMock(ISimpleFile::class);
+ $preview->method('getName')->willReturn('name');
+ $preview->method('getMTime')->willReturn(42);
+ $this->previewManager->method('getPreview')
+ ->with($this->equalTo($file), 10, 10, true, IPreview::MODE_FILL, 'myMime')
+ ->willReturn($preview);
+ $preview->method('getMimeType')
+ ->willReturn('previewMime');
+
+ $res = $this->controller->getPreview('file', 10, 10, '42');
+
+ $this->assertEquals('previewMime', $res->getHeaders()['Content-Type']);
+ $this->assertEquals(Http::STATUS_OK, $res->getStatus());
+ $this->assertEquals($preview, $this->invokePrivate($res, 'file'));
+ }
+
+ public function testVersionNotFound(): void {
+ $userFolder = $this->createMock(Folder::class);
+ $userRoot = $this->createMock(Folder::class);
+
+ $this->rootFolder->method('getUserFolder')
+ ->with($this->userId)
+ ->willReturn($userFolder);
+ $userFolder->method('getParent')
+ ->willReturn($userRoot);
+
+ $sourceFile = $this->createMock(File::class);
+ $userFolder->method('get')
+ ->with('file')
+ ->willReturn($sourceFile);
+
+ $this->versionManager->method('getVersionFile')
+ ->willThrowException(new NotFoundException());
+
+ $res = $this->controller->getPreview('file', 10, 10, '42');
+ $expected = new DataResponse([], Http::STATUS_NOT_FOUND);
+
+ $this->assertEquals($expected, $res);
+ }
+}
diff --git a/apps/files_versions/tests/ExpirationTest.php b/apps/files_versions/tests/ExpirationTest.php
new file mode 100644
index 00000000000..8cf412c3fe0
--- /dev/null
+++ b/apps/files_versions/tests/ExpirationTest.php
@@ -0,0 +1,114 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+namespace OCA\Files_Versions\Tests;
+
+use OCA\Files_Versions\Expiration;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\IConfig;
+use PHPUnit\Framework\MockObject\MockObject;
+use Psr\Log\LoggerInterface;
+
+class ExpirationTest extends \Test\TestCase {
+ public const SECONDS_PER_DAY = 86400; //60*60*24
+
+ public static function expirationData(): array {
+ $today = 100 * self::SECONDS_PER_DAY;
+ $back10Days = (100 - 10) * self::SECONDS_PER_DAY;
+ $back20Days = (100 - 20) * self::SECONDS_PER_DAY;
+ $back30Days = (100 - 30) * self::SECONDS_PER_DAY;
+ $back35Days = (100 - 35) * self::SECONDS_PER_DAY;
+
+ // it should never happen, but who knows :/
+ $ahead100Days = (100 + 100) * self::SECONDS_PER_DAY;
+
+ return [
+ // Expiration is disabled - always should return false
+ [ 'disabled', $today, $back10Days, false, false],
+ [ 'disabled', $today, $back10Days, true, false],
+ [ 'disabled', $today, $ahead100Days, true, false],
+
+ // Default: expire in 30 days or earlier when quota requirements are met
+ [ 'auto', $today, $back10Days, false, false],
+ [ 'auto', $today, $back35Days, false, false],
+ [ 'auto', $today, $back10Days, true, true],
+ [ 'auto', $today, $back35Days, true, true],
+ [ 'auto', $today, $ahead100Days, true, true],
+
+ // The same with 'auto'
+ [ 'auto, auto', $today, $back10Days, false, false],
+ [ 'auto, auto', $today, $back35Days, false, false],
+ [ 'auto, auto', $today, $back10Days, true, true],
+ [ 'auto, auto', $today, $back35Days, true, true],
+
+ // Keep for 15 days but expire anytime if space needed
+ [ '15, auto', $today, $back10Days, false, false],
+ [ '15, auto', $today, $back20Days, false, false],
+ [ '15, auto', $today, $back10Days, true, true],
+ [ '15, auto', $today, $back20Days, true, true],
+ [ '15, auto', $today, $ahead100Days, true, true],
+
+ // Expire anytime if space needed, Expire all older than max
+ [ 'auto, 15', $today, $back10Days, false, false],
+ [ 'auto, 15', $today, $back20Days, false, true],
+ [ 'auto, 15', $today, $back10Days, true, true],
+ [ 'auto, 15', $today, $back20Days, true, true],
+ [ 'auto, 15', $today, $ahead100Days, true, true],
+
+ // Expire all older than max OR older than min if space needed
+ [ '15, 25', $today, $back10Days, false, false],
+ [ '15, 25', $today, $back20Days, false, false],
+ [ '15, 25', $today, $back30Days, false, true],
+ [ '15, 25', $today, $back10Days, false, false],
+ [ '15, 25', $today, $back20Days, true, true],
+ [ '15, 25', $today, $back30Days, true, true],
+ [ '15, 25', $today, $ahead100Days, true, false],
+
+ // Expire all older than max OR older than min if space needed
+ // Max<Min case
+ [ '25, 15', $today, $back10Days, false, false],
+ [ '25, 15', $today, $back20Days, false, false],
+ [ '25, 15', $today, $back30Days, false, true],
+ [ '25, 15', $today, $back10Days, false, false],
+ [ '25, 15', $today, $back20Days, true, false],
+ [ '25, 15', $today, $back30Days, true, true],
+ [ '25, 15', $today, $ahead100Days, true, false],
+ ];
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('expirationData')]
+ public function testExpiration(string $retentionObligation, int $timeNow, int $timestamp, bool $quotaExceeded, bool $expectedResult): void {
+ $mockedConfig = $this->getMockedConfig($retentionObligation);
+ $mockedTimeFactory = $this->getMockedTimeFactory($timeNow);
+ $mockedLogger = $this->createMock(LoggerInterface::class);
+
+ $expiration = new Expiration($mockedConfig, $mockedTimeFactory, $mockedLogger);
+ $actualResult = $expiration->isExpired($timestamp, $quotaExceeded);
+
+ $this->assertEquals($expectedResult, $actualResult);
+ }
+
+
+ private function getMockedTimeFactory(int $time): ITimeFactory&MockObject {
+ $mockedTimeFactory = $this->createMock(ITimeFactory::class);
+ $mockedTimeFactory->expects($this->any())
+ ->method('getTime')
+ ->willReturn($time);
+
+ return $mockedTimeFactory;
+ }
+
+ private function getMockedConfig(string $returnValue): IConfig&MockObject {
+ $mockedConfig = $this->createMock(IConfig::class);
+ $mockedConfig->expects($this->any())
+ ->method('getSystemValue')
+ ->willReturn($returnValue);
+
+ return $mockedConfig;
+ }
+}
diff --git a/apps/files_versions/tests/StorageTest.php b/apps/files_versions/tests/StorageTest.php
new file mode 100644
index 00000000000..443cff3ee06
--- /dev/null
+++ b/apps/files_versions/tests/StorageTest.php
@@ -0,0 +1,101 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\files_versions\tests;
+
+use OCA\Files_Versions\Expiration;
+use OCA\Files_Versions\Storage;
+use OCP\Files\IRootFolder;
+use OCP\Files\NotFoundException;
+use OCP\Server;
+use Test\TestCase;
+use Test\Traits\UserTrait;
+
+/**
+ * @group DB
+ */
+class StorageTest extends TestCase {
+ use UserTrait;
+
+ private $versionsRoot;
+ private $userFolder;
+ private int $expireTimestamp = 10;
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $expiration = $this->createMock(Expiration::class);
+ $expiration->method('getMaxAgeAsTimestamp')
+ ->willReturnCallback(function () {
+ return $this->expireTimestamp;
+ });
+ $this->overwriteService(Expiration::class, $expiration);
+
+ \OC::$server->boot();
+
+ $this->createUser('version_test', '');
+ $this->loginAsUser('version_test');
+ /** @var IRootFolder $root */
+ $root = Server::get(IRootFolder::class);
+ $this->userFolder = $root->getUserFolder('version_test');
+ }
+
+
+ protected function createPastFile(string $path, int $mtime): void {
+ try {
+ $file = $this->userFolder->get($path);
+ $file->putContent((string)$mtime);
+ } catch (NotFoundException $e) {
+ $file = $this->userFolder->newFile($path, (string)$mtime);
+ }
+ $file->touch($mtime);
+ }
+
+ public function testExpireMaxAge(): void {
+ $this->userFolder->newFolder('folder1');
+ $this->userFolder->newFolder('folder1/sub1');
+ $this->userFolder->newFolder('folder2');
+
+ $this->createPastFile('file1', 100);
+ $this->createPastFile('file1', 500);
+ $this->createPastFile('file1', 900);
+
+ $this->createPastFile('folder1/file2', 100);
+ $this->createPastFile('folder1/file2', 200);
+ $this->createPastFile('folder1/file2', 300);
+
+ $this->createPastFile('folder1/sub1/file3', 400);
+ $this->createPastFile('folder1/sub1/file3', 500);
+ $this->createPastFile('folder1/sub1/file3', 600);
+
+ $this->createPastFile('folder2/file4', 100);
+ $this->createPastFile('folder2/file4', 600);
+ $this->createPastFile('folder2/file4', 800);
+
+ $this->assertCount(2, Storage::getVersions('version_test', 'file1'));
+ $this->assertCount(2, Storage::getVersions('version_test', 'folder1/file2'));
+ $this->assertCount(2, Storage::getVersions('version_test', 'folder1/sub1/file3'));
+ $this->assertCount(2, Storage::getVersions('version_test', 'folder2/file4'));
+
+ $this->expireTimestamp = 150;
+ Storage::expireOlderThanMaxForUser('version_test');
+
+ $this->assertCount(1, Storage::getVersions('version_test', 'file1'));
+ $this->assertCount(1, Storage::getVersions('version_test', 'folder1/file2'));
+ $this->assertCount(2, Storage::getVersions('version_test', 'folder1/sub1/file3'));
+ $this->assertCount(1, Storage::getVersions('version_test', 'folder2/file4'));
+
+ $this->expireTimestamp = 550;
+ Storage::expireOlderThanMaxForUser('version_test');
+
+ $this->assertCount(0, Storage::getVersions('version_test', 'file1'));
+ $this->assertCount(0, Storage::getVersions('version_test', 'folder1/file2'));
+ $this->assertCount(0, Storage::getVersions('version_test', 'folder1/sub1/file3'));
+ $this->assertCount(1, Storage::getVersions('version_test', 'folder2/file4'));
+ }
+}
diff --git a/apps/files_versions/tests/VersioningTest.php b/apps/files_versions/tests/VersioningTest.php
new file mode 100644
index 00000000000..c9f7d27d7ab
--- /dev/null
+++ b/apps/files_versions/tests/VersioningTest.php
@@ -0,0 +1,998 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+namespace OCA\Files_Versions\Tests;
+
+use OC\AllConfig;
+use OC\Files\Cache\Watcher;
+use OC\Files\Filesystem;
+use OC\Files\Storage\Temporary;
+use OC\Files\View;
+use OC\SystemConfig;
+use OC\User\NoUserException;
+use OCA\Files_Sharing\AppInfo\Application;
+use OCA\Files_Versions\Db\VersionEntity;
+use OCA\Files_Versions\Db\VersionsMapper;
+use OCA\Files_Versions\Events\VersionRestoredEvent;
+use OCA\Files_Versions\Storage;
+use OCA\Files_Versions\Versions\IVersionManager;
+use OCP\Constants;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\Files\IMimeTypeLoader;
+use OCP\IConfig;
+use OCP\IUser;
+use OCP\IUserManager;
+use OCP\Server;
+use OCP\Share\IShare;
+use OCP\Util;
+
+/**
+ * Class Test_Files_versions
+ * this class provide basic files versions test
+ *
+ * @group DB
+ */
+class VersioningTest extends \Test\TestCase {
+ public const TEST_VERSIONS_USER = 'test-versions-user';
+ public const TEST_VERSIONS_USER2 = 'test-versions-user2';
+ public const USERS_VERSIONS_ROOT = '/test-versions-user/files_versions';
+
+ /**
+ * @var View
+ */
+ private $rootView;
+ /**
+ * @var VersionsMapper
+ */
+ private $versionsMapper;
+ /**
+ * @var IMimeTypeLoader
+ */
+ private $mimeTypeLoader;
+ private $user1;
+ private $user2;
+
+ public static function setUpBeforeClass(): void {
+ parent::setUpBeforeClass();
+
+ $application = new Application();
+
+ // create test user
+ self::loginHelper(self::TEST_VERSIONS_USER2, true);
+ self::loginHelper(self::TEST_VERSIONS_USER, true);
+ }
+
+ public static function tearDownAfterClass(): void {
+ // cleanup test user
+ $user = Server::get(IUserManager::class)->get(self::TEST_VERSIONS_USER);
+ if ($user !== null) {
+ $user->delete();
+ }
+ $user = Server::get(IUserManager::class)->get(self::TEST_VERSIONS_USER2);
+ if ($user !== null) {
+ $user->delete();
+ }
+
+ parent::tearDownAfterClass();
+ }
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $config = Server::get(IConfig::class);
+ $mockConfig = $this->getMockBuilder(AllConfig::class)
+ ->onlyMethods(['getSystemValue'])
+ ->setConstructorArgs([Server::get(SystemConfig::class)])
+ ->getMock();
+ $mockConfig->expects($this->any())
+ ->method('getSystemValue')
+ ->willReturnCallback(function ($key, $default) use ($config) {
+ if ($key === 'filesystem_check_changes') {
+ return Watcher::CHECK_ONCE;
+ } else {
+ return $config->getSystemValue($key, $default);
+ }
+ });
+ $this->overwriteService(AllConfig::class, $mockConfig);
+
+ // clear hooks
+ \OC_Hook::clear();
+ \OC::registerShareHooks(Server::get(SystemConfig::class));
+ \OC::$server->boot();
+
+ self::loginHelper(self::TEST_VERSIONS_USER);
+ $this->rootView = new View();
+ if (!$this->rootView->file_exists(self::USERS_VERSIONS_ROOT)) {
+ $this->rootView->mkdir(self::USERS_VERSIONS_ROOT);
+ }
+
+ $this->versionsMapper = Server::get(VersionsMapper::class);
+ $this->mimeTypeLoader = Server::get(IMimeTypeLoader::class);
+
+ $this->user1 = $this->createMock(IUser::class);
+ $this->user1->method('getUID')
+ ->willReturn(self::TEST_VERSIONS_USER);
+ $this->user2 = $this->createMock(IUser::class);
+ $this->user2->method('getUID')
+ ->willReturn(self::TEST_VERSIONS_USER2);
+ }
+
+ protected function tearDown(): void {
+ $this->restoreService(AllConfig::class);
+
+ if ($this->rootView) {
+ $this->rootView->deleteAll(self::TEST_VERSIONS_USER . '/files/');
+ $this->rootView->deleteAll(self::TEST_VERSIONS_USER2 . '/files/');
+ $this->rootView->deleteAll(self::TEST_VERSIONS_USER . '/files_versions/');
+ $this->rootView->deleteAll(self::TEST_VERSIONS_USER2 . '/files_versions/');
+ }
+
+ \OC_Hook::clear();
+
+ parent::tearDown();
+ }
+
+ /**
+ * @medium
+ * test expire logic
+ */
+ #[\PHPUnit\Framework\Attributes\DataProvider('versionsProvider')]
+ public function testGetExpireList($versions, $sizeOfAllDeletedFiles): void {
+
+ // last interval end at 2592000
+ $startTime = 5000000;
+
+ $testClass = new VersionStorageToTest();
+ [$deleted, $size] = $testClass->callProtectedGetExpireList($startTime, $versions);
+
+ // we should have deleted 16 files each of the size 1
+ $this->assertEquals($sizeOfAllDeletedFiles, $size);
+
+ // the deleted array should only contain versions which should be deleted
+ foreach ($deleted as $key => $path) {
+ unset($versions[$key]);
+ $this->assertEquals('delete', substr($path, 0, strlen('delete')));
+ }
+
+ // the versions array should only contain versions which should be kept
+ foreach ($versions as $version) {
+ $this->assertEquals('keep', $version['path']);
+ }
+ }
+
+ public static function versionsProvider(): array {
+ return [
+ // first set of versions uniformly distributed versions
+ [
+ [
+ // first slice (10sec) keep one version every 2 seconds
+ ['version' => 4999999, 'path' => 'keep', 'size' => 1],
+ ['version' => 4999998, 'path' => 'delete', 'size' => 1],
+ ['version' => 4999997, 'path' => 'keep', 'size' => 1],
+ ['version' => 4999995, 'path' => 'keep', 'size' => 1],
+ ['version' => 4999994, 'path' => 'delete', 'size' => 1],
+ //next slice (60sec) starts at 4999990 keep one version every 10 secons
+ ['version' => 4999988, 'path' => 'keep', 'size' => 1],
+ ['version' => 4999978, 'path' => 'keep', 'size' => 1],
+ ['version' => 4999975, 'path' => 'delete', 'size' => 1],
+ ['version' => 4999972, 'path' => 'delete', 'size' => 1],
+ ['version' => 4999967, 'path' => 'keep', 'size' => 1],
+ ['version' => 4999958, 'path' => 'delete', 'size' => 1],
+ ['version' => 4999957, 'path' => 'keep', 'size' => 1],
+ //next slice (3600sec) start at 4999940 keep one version every 60 seconds
+ ['version' => 4999900, 'path' => 'keep', 'size' => 1],
+ ['version' => 4999841, 'path' => 'delete', 'size' => 1],
+ ['version' => 4999840, 'path' => 'keep', 'size' => 1],
+ ['version' => 4999780, 'path' => 'keep', 'size' => 1],
+ ['version' => 4996401, 'path' => 'keep', 'size' => 1],
+ // next slice (86400sec) start at 4996400 keep one version every 3600 seconds
+ ['version' => 4996350, 'path' => 'delete', 'size' => 1],
+ ['version' => 4992800, 'path' => 'keep', 'size' => 1],
+ ['version' => 4989800, 'path' => 'delete', 'size' => 1],
+ ['version' => 4989700, 'path' => 'delete', 'size' => 1],
+ ['version' => 4989200, 'path' => 'keep', 'size' => 1],
+ // next slice (2592000sec) start at 4913600 keep one version every 86400 seconds
+ ['version' => 4913600, 'path' => 'keep', 'size' => 1],
+ ['version' => 4852800, 'path' => 'delete', 'size' => 1],
+ ['version' => 4827201, 'path' => 'delete', 'size' => 1],
+ ['version' => 4827200, 'path' => 'keep', 'size' => 1],
+ ['version' => 4777201, 'path' => 'delete', 'size' => 1],
+ ['version' => 4777501, 'path' => 'delete', 'size' => 1],
+ ['version' => 4740000, 'path' => 'keep', 'size' => 1],
+ // final slice starts at 2408000 keep one version every 604800 secons
+ ['version' => 2408000, 'path' => 'keep', 'size' => 1],
+ ['version' => 1803201, 'path' => 'delete', 'size' => 1],
+ ['version' => 1803200, 'path' => 'keep', 'size' => 1],
+ ['version' => 1800199, 'path' => 'delete', 'size' => 1],
+ ['version' => 1800100, 'path' => 'delete', 'size' => 1],
+ ['version' => 1198300, 'path' => 'keep', 'size' => 1],
+ ],
+ 16 // size of all deleted files (every file has the size 1)
+ ],
+ // second set of versions, here we have only really old versions
+ [
+ [
+ // first slice (10sec) keep one version every 2 seconds
+ // next slice (60sec) starts at 4999990 keep one version every 10 secons
+ // next slice (3600sec) start at 4999940 keep one version every 60 seconds
+ // next slice (86400sec) start at 4996400 keep one version every 3600 seconds
+ ['version' => 4996400, 'path' => 'keep', 'size' => 1],
+ ['version' => 4996350, 'path' => 'delete', 'size' => 1],
+ ['version' => 4996350, 'path' => 'delete', 'size' => 1],
+ ['version' => 4992800, 'path' => 'keep', 'size' => 1],
+ ['version' => 4989800, 'path' => 'delete', 'size' => 1],
+ ['version' => 4989700, 'path' => 'delete', 'size' => 1],
+ ['version' => 4989200, 'path' => 'keep', 'size' => 1],
+ // next slice (2592000sec) start at 4913600 keep one version every 86400 seconds
+ ['version' => 4913600, 'path' => 'keep', 'size' => 1],
+ ['version' => 4852800, 'path' => 'delete', 'size' => 1],
+ ['version' => 4827201, 'path' => 'delete', 'size' => 1],
+ ['version' => 4827200, 'path' => 'keep', 'size' => 1],
+ ['version' => 4777201, 'path' => 'delete', 'size' => 1],
+ ['version' => 4777501, 'path' => 'delete', 'size' => 1],
+ ['version' => 4740000, 'path' => 'keep', 'size' => 1],
+ // final slice starts at 2408000 keep one version every 604800 secons
+ ['version' => 2408000, 'path' => 'keep', 'size' => 1],
+ ['version' => 1803201, 'path' => 'delete', 'size' => 1],
+ ['version' => 1803200, 'path' => 'keep', 'size' => 1],
+ ['version' => 1800199, 'path' => 'delete', 'size' => 1],
+ ['version' => 1800100, 'path' => 'delete', 'size' => 1],
+ ['version' => 1198300, 'path' => 'keep', 'size' => 1],
+ ],
+ 11 // size of all deleted files (every file has the size 1)
+ ],
+ // third set of versions, with some gaps between
+ [
+ [
+ // first slice (10sec) keep one version every 2 seconds
+ ['version' => 4999999, 'path' => 'keep', 'size' => 1],
+ ['version' => 4999998, 'path' => 'delete', 'size' => 1],
+ ['version' => 4999997, 'path' => 'keep', 'size' => 1],
+ ['version' => 4999995, 'path' => 'keep', 'size' => 1],
+ ['version' => 4999994, 'path' => 'delete', 'size' => 1],
+ //next slice (60sec) starts at 4999990 keep one version every 10 secons
+ ['version' => 4999988, 'path' => 'keep', 'size' => 1],
+ ['version' => 4999978, 'path' => 'keep', 'size' => 1],
+ //next slice (3600sec) start at 4999940 keep one version every 60 seconds
+ // next slice (86400sec) start at 4996400 keep one version every 3600 seconds
+ ['version' => 4989200, 'path' => 'keep', 'size' => 1],
+ // next slice (2592000sec) start at 4913600 keep one version every 86400 seconds
+ ['version' => 4913600, 'path' => 'keep', 'size' => 1],
+ ['version' => 4852800, 'path' => 'delete', 'size' => 1],
+ ['version' => 4827201, 'path' => 'delete', 'size' => 1],
+ ['version' => 4827200, 'path' => 'keep', 'size' => 1],
+ ['version' => 4777201, 'path' => 'delete', 'size' => 1],
+ ['version' => 4777501, 'path' => 'delete', 'size' => 1],
+ ['version' => 4740000, 'path' => 'keep', 'size' => 1],
+ // final slice starts at 2408000 keep one version every 604800 secons
+ ['version' => 2408000, 'path' => 'keep', 'size' => 1],
+ ['version' => 1803201, 'path' => 'delete', 'size' => 1],
+ ['version' => 1803200, 'path' => 'keep', 'size' => 1],
+ ['version' => 1800199, 'path' => 'delete', 'size' => 1],
+ ['version' => 1800100, 'path' => 'delete', 'size' => 1],
+ ['version' => 1198300, 'path' => 'keep', 'size' => 1],
+ ],
+ 9 // size of all deleted files (every file has the size 1)
+ ],
+ // fourth set of versions: empty (see issue #19066)
+ [
+ [],
+ 0
+ ]
+
+ ];
+ }
+
+ public function testRename(): void {
+ Filesystem::file_put_contents('test.txt', 'test file');
+
+ $t1 = time();
+ // second version is two weeks older, this way we make sure that no
+ // version will be expired
+ $t2 = $t1 - 60 * 60 * 24 * 14;
+
+ // create some versions
+ $v1 = self::USERS_VERSIONS_ROOT . '/test.txt.v' . $t1;
+ $v2 = self::USERS_VERSIONS_ROOT . '/test.txt.v' . $t2;
+ $v1Renamed = self::USERS_VERSIONS_ROOT . '/test2.txt.v' . $t1;
+ $v2Renamed = self::USERS_VERSIONS_ROOT . '/test2.txt.v' . $t2;
+
+ $this->rootView->file_put_contents($v1, 'version1');
+ $this->rootView->file_put_contents($v2, 'version2');
+
+ // execute rename hook of versions app
+ Filesystem::rename('test.txt', 'test2.txt');
+
+ $this->runCommands();
+
+ $this->assertFalse($this->rootView->file_exists($v1), 'version 1 of old file does not exist');
+ $this->assertFalse($this->rootView->file_exists($v2), 'version 2 of old file does not exist');
+
+ $this->assertTrue($this->rootView->file_exists($v1Renamed), 'version 1 of renamed file exists');
+ $this->assertTrue($this->rootView->file_exists($v2Renamed), 'version 2 of renamed file exists');
+ }
+
+ public function testRenameInSharedFolder(): void {
+ Filesystem::mkdir('folder1');
+ Filesystem::mkdir('folder1/folder2');
+ Filesystem::file_put_contents('folder1/test.txt', 'test file');
+
+ $t1 = time();
+ // second version is two weeks older, this way we make sure that no
+ // version will be expired
+ $t2 = $t1 - 60 * 60 * 24 * 14;
+
+ $this->rootView->mkdir(self::USERS_VERSIONS_ROOT . '/folder1');
+ // create some versions
+ $v1 = self::USERS_VERSIONS_ROOT . '/folder1/test.txt.v' . $t1;
+ $v2 = self::USERS_VERSIONS_ROOT . '/folder1/test.txt.v' . $t2;
+ $v1Renamed = self::USERS_VERSIONS_ROOT . '/folder1/folder2/test.txt.v' . $t1;
+ $v2Renamed = self::USERS_VERSIONS_ROOT . '/folder1/folder2/test.txt.v' . $t2;
+
+ $this->rootView->file_put_contents($v1, 'version1');
+ $this->rootView->file_put_contents($v2, 'version2');
+
+ $node = \OC::$server->getUserFolder(self::TEST_VERSIONS_USER)->get('folder1');
+ $share = Server::get(\OCP\Share\IManager::class)->newShare();
+ $share->setNode($node)
+ ->setShareType(IShare::TYPE_USER)
+ ->setSharedBy(self::TEST_VERSIONS_USER)
+ ->setSharedWith(self::TEST_VERSIONS_USER2)
+ ->setPermissions(Constants::PERMISSION_ALL);
+ $share = Server::get(\OCP\Share\IManager::class)->createShare($share);
+ Server::get(\OCP\Share\IManager::class)->acceptShare($share, self::TEST_VERSIONS_USER2);
+
+ self::loginHelper(self::TEST_VERSIONS_USER2);
+
+ $this->assertTrue(Filesystem::file_exists('folder1/test.txt'));
+
+ // execute rename hook of versions app
+ Filesystem::rename('/folder1/test.txt', '/folder1/folder2/test.txt');
+
+ $this->runCommands();
+
+ self::loginHelper(self::TEST_VERSIONS_USER);
+
+ $this->assertFalse($this->rootView->file_exists($v1), 'version 1 of old file does not exist');
+ $this->assertFalse($this->rootView->file_exists($v2), 'version 2 of old file does not exist');
+
+ $this->assertTrue($this->rootView->file_exists($v1Renamed), 'version 1 of renamed file exists');
+ $this->assertTrue($this->rootView->file_exists($v2Renamed), 'version 2 of renamed file exists');
+
+ Server::get(\OCP\Share\IManager::class)->deleteShare($share);
+ }
+
+ public function testMoveFolder(): void {
+ Filesystem::mkdir('folder1');
+ Filesystem::mkdir('folder2');
+ Filesystem::file_put_contents('folder1/test.txt', 'test file');
+
+ $t1 = time();
+ // second version is two weeks older, this way we make sure that no
+ // version will be expired
+ $t2 = $t1 - 60 * 60 * 24 * 14;
+
+ // create some versions
+ $this->rootView->mkdir(self::USERS_VERSIONS_ROOT . '/folder1');
+ $v1 = self::USERS_VERSIONS_ROOT . '/folder1/test.txt.v' . $t1;
+ $v2 = self::USERS_VERSIONS_ROOT . '/folder1/test.txt.v' . $t2;
+ $v1Renamed = self::USERS_VERSIONS_ROOT . '/folder2/folder1/test.txt.v' . $t1;
+ $v2Renamed = self::USERS_VERSIONS_ROOT . '/folder2/folder1/test.txt.v' . $t2;
+
+ $this->rootView->file_put_contents($v1, 'version1');
+ $this->rootView->file_put_contents($v2, 'version2');
+
+ // execute rename hook of versions app
+ Filesystem::rename('folder1', 'folder2/folder1');
+
+ $this->runCommands();
+
+ $this->assertFalse($this->rootView->file_exists($v1));
+ $this->assertFalse($this->rootView->file_exists($v2));
+
+ $this->assertTrue($this->rootView->file_exists($v1Renamed));
+ $this->assertTrue($this->rootView->file_exists($v2Renamed));
+ }
+
+
+ public function testMoveFileIntoSharedFolderAsRecipient(): void {
+ Filesystem::mkdir('folder1');
+ $fileInfo = Filesystem::getFileInfo('folder1');
+
+ $node = \OC::$server->getUserFolder(self::TEST_VERSIONS_USER)->get('folder1');
+ $share = Server::get(\OCP\Share\IManager::class)->newShare();
+ $share->setNode($node)
+ ->setShareType(IShare::TYPE_USER)
+ ->setSharedBy(self::TEST_VERSIONS_USER)
+ ->setSharedWith(self::TEST_VERSIONS_USER2)
+ ->setPermissions(Constants::PERMISSION_ALL);
+ $share = Server::get(\OCP\Share\IManager::class)->createShare($share);
+ Server::get(\OCP\Share\IManager::class)->acceptShare($share, self::TEST_VERSIONS_USER2);
+
+ self::loginHelper(self::TEST_VERSIONS_USER2);
+ $versionsFolder2 = '/' . self::TEST_VERSIONS_USER2 . '/files_versions';
+ Filesystem::file_put_contents('test.txt', 'test file');
+
+ $t1 = time();
+ // second version is two weeks older, this way we make sure that no
+ // version will be expired
+ $t2 = $t1 - 60 * 60 * 24 * 14;
+
+ $this->rootView->mkdir($versionsFolder2);
+ // create some versions
+ $v1 = $versionsFolder2 . '/test.txt.v' . $t1;
+ $v2 = $versionsFolder2 . '/test.txt.v' . $t2;
+
+ $this->rootView->file_put_contents($v1, 'version1');
+ $this->rootView->file_put_contents($v2, 'version2');
+
+ // move file into the shared folder as recipient
+ $success = Filesystem::rename('/test.txt', '/folder1/test.txt');
+
+ $this->assertTrue($success);
+ $this->assertFalse($this->rootView->file_exists($v1));
+ $this->assertFalse($this->rootView->file_exists($v2));
+
+ self::loginHelper(self::TEST_VERSIONS_USER);
+
+ $versionsFolder1 = '/' . self::TEST_VERSIONS_USER . '/files_versions';
+
+ $v1Renamed = $versionsFolder1 . '/folder1/test.txt.v' . $t1;
+ $v2Renamed = $versionsFolder1 . '/folder1/test.txt.v' . $t2;
+
+ $this->assertTrue($this->rootView->file_exists($v1Renamed));
+ $this->assertTrue($this->rootView->file_exists($v2Renamed));
+
+ Server::get(\OCP\Share\IManager::class)->deleteShare($share);
+ }
+
+ public function testMoveFolderIntoSharedFolderAsRecipient(): void {
+ Filesystem::mkdir('folder1');
+
+ $node = \OC::$server->getUserFolder(self::TEST_VERSIONS_USER)->get('folder1');
+ $share = Server::get(\OCP\Share\IManager::class)->newShare();
+ $share->setNode($node)
+ ->setShareType(IShare::TYPE_USER)
+ ->setSharedBy(self::TEST_VERSIONS_USER)
+ ->setSharedWith(self::TEST_VERSIONS_USER2)
+ ->setPermissions(Constants::PERMISSION_ALL);
+ $share = Server::get(\OCP\Share\IManager::class)->createShare($share);
+ Server::get(\OCP\Share\IManager::class)->acceptShare($share, self::TEST_VERSIONS_USER2);
+
+ self::loginHelper(self::TEST_VERSIONS_USER2);
+ $versionsFolder2 = '/' . self::TEST_VERSIONS_USER2 . '/files_versions';
+ Filesystem::mkdir('folder2');
+ Filesystem::file_put_contents('folder2/test.txt', 'test file');
+
+ $t1 = time();
+ // second version is two weeks older, this way we make sure that no
+ // version will be expired
+ $t2 = $t1 - 60 * 60 * 24 * 14;
+
+ $this->rootView->mkdir($versionsFolder2);
+ $this->rootView->mkdir($versionsFolder2 . '/folder2');
+ // create some versions
+ $v1 = $versionsFolder2 . '/folder2/test.txt.v' . $t1;
+ $v2 = $versionsFolder2 . '/folder2/test.txt.v' . $t2;
+
+ $this->rootView->file_put_contents($v1, 'version1');
+ $this->rootView->file_put_contents($v2, 'version2');
+
+ // move file into the shared folder as recipient
+ Filesystem::rename('/folder2', '/folder1/folder2');
+
+ $this->assertFalse($this->rootView->file_exists($v1));
+ $this->assertFalse($this->rootView->file_exists($v2));
+
+ self::loginHelper(self::TEST_VERSIONS_USER);
+
+ $versionsFolder1 = '/' . self::TEST_VERSIONS_USER . '/files_versions';
+
+ $v1Renamed = $versionsFolder1 . '/folder1/folder2/test.txt.v' . $t1;
+ $v2Renamed = $versionsFolder1 . '/folder1/folder2/test.txt.v' . $t2;
+
+ $this->assertTrue($this->rootView->file_exists($v1Renamed));
+ $this->assertTrue($this->rootView->file_exists($v2Renamed));
+
+ Server::get(\OCP\Share\IManager::class)->deleteShare($share);
+ }
+
+ public function testRenameSharedFile(): void {
+ Filesystem::file_put_contents('test.txt', 'test file');
+
+ $t1 = time();
+ // second version is two weeks older, this way we make sure that no
+ // version will be expired
+ $t2 = $t1 - 60 * 60 * 24 * 14;
+
+ $this->rootView->mkdir(self::USERS_VERSIONS_ROOT);
+ // create some versions
+ $v1 = self::USERS_VERSIONS_ROOT . '/test.txt.v' . $t1;
+ $v2 = self::USERS_VERSIONS_ROOT . '/test.txt.v' . $t2;
+ // the renamed versions should not exist! Because we only moved the mount point!
+ $v1Renamed = self::USERS_VERSIONS_ROOT . '/test2.txt.v' . $t1;
+ $v2Renamed = self::USERS_VERSIONS_ROOT . '/test2.txt.v' . $t2;
+
+ $this->rootView->file_put_contents($v1, 'version1');
+ $this->rootView->file_put_contents($v2, 'version2');
+
+ $node = \OC::$server->getUserFolder(self::TEST_VERSIONS_USER)->get('test.txt');
+ $share = Server::get(\OCP\Share\IManager::class)->newShare();
+ $share->setNode($node)
+ ->setShareType(IShare::TYPE_USER)
+ ->setSharedBy(self::TEST_VERSIONS_USER)
+ ->setSharedWith(self::TEST_VERSIONS_USER2)
+ ->setPermissions(Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE | Constants::PERMISSION_SHARE);
+ $share = Server::get(\OCP\Share\IManager::class)->createShare($share);
+ Server::get(\OCP\Share\IManager::class)->acceptShare($share, self::TEST_VERSIONS_USER2);
+
+ self::loginHelper(self::TEST_VERSIONS_USER2);
+
+ $this->assertTrue(Filesystem::file_exists('test.txt'));
+
+ // execute rename hook of versions app
+ Filesystem::rename('test.txt', 'test2.txt');
+
+ self::loginHelper(self::TEST_VERSIONS_USER);
+
+ $this->runCommands();
+
+ $this->assertTrue($this->rootView->file_exists($v1));
+ $this->assertTrue($this->rootView->file_exists($v2));
+
+ $this->assertFalse($this->rootView->file_exists($v1Renamed));
+ $this->assertFalse($this->rootView->file_exists($v2Renamed));
+
+ Server::get(\OCP\Share\IManager::class)->deleteShare($share);
+ }
+
+ public function testCopy(): void {
+ Filesystem::file_put_contents('test.txt', 'test file');
+
+ $t1 = time();
+ // second version is two weeks older, this way we make sure that no
+ // version will be expired
+ $t2 = $t1 - 60 * 60 * 24 * 14;
+
+ // create some versions
+ $v1 = self::USERS_VERSIONS_ROOT . '/test.txt.v' . $t1;
+ $v2 = self::USERS_VERSIONS_ROOT . '/test.txt.v' . $t2;
+ $v1Copied = self::USERS_VERSIONS_ROOT . '/test2.txt.v' . $t1;
+ $v2Copied = self::USERS_VERSIONS_ROOT . '/test2.txt.v' . $t2;
+
+ $this->rootView->file_put_contents($v1, 'version1');
+ $this->rootView->file_put_contents($v2, 'version2');
+
+ // execute copy hook of versions app
+ Filesystem::copy('test.txt', 'test2.txt');
+
+ $this->runCommands();
+
+ $this->assertTrue($this->rootView->file_exists($v1), 'version 1 of original file exists');
+ $this->assertTrue($this->rootView->file_exists($v2), 'version 2 of original file exists');
+
+ $this->assertTrue($this->rootView->file_exists($v1Copied), 'version 1 of copied file exists');
+ $this->assertTrue($this->rootView->file_exists($v2Copied), 'version 2 of copied file exists');
+ }
+
+ /**
+ * test if we find all versions and if the versions array contain
+ * the correct 'path' and 'name'
+ */
+ public function testGetVersions(): void {
+ $t1 = time();
+ // second version is two weeks older, this way we make sure that no
+ // version will be expired
+ $t2 = $t1 - 60 * 60 * 24 * 14;
+
+ // create some versions
+ $v1 = self::USERS_VERSIONS_ROOT . '/subfolder/test.txt.v' . $t1;
+ $v2 = self::USERS_VERSIONS_ROOT . '/subfolder/test.txt.v' . $t2;
+
+ $this->rootView->mkdir(self::USERS_VERSIONS_ROOT . '/subfolder/');
+
+ $this->rootView->file_put_contents($v1, 'version1');
+ $this->rootView->file_put_contents($v2, 'version2');
+
+ // execute copy hook of versions app
+ $versions = Storage::getVersions(self::TEST_VERSIONS_USER, '/subfolder/test.txt');
+
+ $this->assertCount(2, $versions);
+
+ foreach ($versions as $version) {
+ $this->assertSame('/subfolder/test.txt', $version['path']);
+ $this->assertSame('test.txt', $version['name']);
+ }
+
+ //cleanup
+ $this->rootView->deleteAll(self::USERS_VERSIONS_ROOT . '/subfolder');
+ }
+
+ /**
+ * test if we find all versions and if the versions array contain
+ * the correct 'path' and 'name'
+ */
+ public function testGetVersionsEmptyFile(): void {
+ // execute copy hook of versions app
+ $versions = Storage::getVersions(self::TEST_VERSIONS_USER, '');
+ $this->assertCount(0, $versions);
+
+ $versions = Storage::getVersions(self::TEST_VERSIONS_USER, null);
+ $this->assertCount(0, $versions);
+ }
+
+ public function testExpireNonexistingFile(): void {
+ $this->logout();
+ // needed to have a FS setup (the background job does this)
+ \OC_Util::setupFS(self::TEST_VERSIONS_USER);
+
+ $this->assertFalse(Storage::expire('/void/unexist.txt', self::TEST_VERSIONS_USER));
+ }
+
+
+ public function testExpireNonexistingUser(): void {
+ $this->expectException(NoUserException::class);
+
+ $this->logout();
+ // needed to have a FS setup (the background job does this)
+ \OC_Util::setupFS(self::TEST_VERSIONS_USER);
+ Filesystem::file_put_contents('test.txt', 'test file');
+
+ $this->assertFalse(Storage::expire('test.txt', 'unexist'));
+ }
+
+ public function testRestoreSameStorage(): void {
+ Filesystem::mkdir('sub');
+ $this->doTestRestore();
+ }
+
+ public function testRestoreCrossStorage(): void {
+ $storage2 = new Temporary([]);
+ Filesystem::mount($storage2, [], self::TEST_VERSIONS_USER . '/files/sub');
+
+ $this->doTestRestore();
+ }
+
+ public function testRestoreNoPermission(): void {
+ $this->loginAsUser(self::TEST_VERSIONS_USER);
+
+ $userHome = \OC::$server->getUserFolder(self::TEST_VERSIONS_USER);
+ $node = $userHome->newFolder('folder');
+ $file = $node->newFile('test.txt');
+
+ $share = Server::get(\OCP\Share\IManager::class)->newShare();
+ $share->setNode($node)
+ ->setShareType(IShare::TYPE_USER)
+ ->setSharedBy(self::TEST_VERSIONS_USER)
+ ->setSharedWith(self::TEST_VERSIONS_USER2)
+ ->setPermissions(Constants::PERMISSION_READ);
+ $share = Server::get(\OCP\Share\IManager::class)->createShare($share);
+ Server::get(\OCP\Share\IManager::class)->acceptShare($share, self::TEST_VERSIONS_USER2);
+
+ $versions = $this->createAndCheckVersions(
+ Filesystem::getView(),
+ 'folder/test.txt'
+ );
+
+ $file->putContent('test file');
+
+ $this->loginAsUser(self::TEST_VERSIONS_USER2);
+
+ $firstVersion = current($versions);
+
+ $this->assertFalse(Storage::rollback('folder/test.txt', (int)$firstVersion['version'], $this->user2), 'Revert did not happen');
+
+ $this->loginAsUser(self::TEST_VERSIONS_USER);
+
+ Server::get(\OCP\Share\IManager::class)->deleteShare($share);
+ $this->assertEquals('test file', $file->getContent(), 'File content has not changed');
+ }
+
+ public function testRestoreMovedShare(): void {
+ $this->markTestSkipped('Unreliable test');
+ $this->loginAsUser(self::TEST_VERSIONS_USER);
+
+ $userHome = \OC::$server->getUserFolder(self::TEST_VERSIONS_USER);
+ $node = $userHome->newFolder('folder');
+ $file = $node->newFile('test.txt');
+
+ $userHome2 = \OC::$server->getUserFolder(self::TEST_VERSIONS_USER2);
+ $userHome2->newFolder('subfolder');
+
+ $share = Server::get(\OCP\Share\IManager::class)->newShare();
+ $share->setNode($node)
+ ->setShareType(IShare::TYPE_USER)
+ ->setSharedBy(self::TEST_VERSIONS_USER)
+ ->setSharedWith(self::TEST_VERSIONS_USER2)
+ ->setPermissions(Constants::PERMISSION_ALL);
+ $share = Server::get(\OCP\Share\IManager::class)->createShare($share);
+ $shareManager = Server::get(\OCP\Share\IManager::class);
+ $shareManager->acceptShare($share, self::TEST_VERSIONS_USER2);
+
+ $share->setTarget('subfolder/folder');
+ $shareManager->moveShare($share, self::TEST_VERSIONS_USER2);
+
+ $versions = $this->createAndCheckVersions(
+ Filesystem::getView(),
+ 'folder/test.txt'
+ );
+
+ $file->putContent('test file');
+
+ $this->loginAsUser(self::TEST_VERSIONS_USER2);
+
+ $firstVersion = current($versions);
+
+ $this->assertTrue(Storage::rollback('folder/test.txt', $firstVersion['version'], $this->user1));
+
+ $this->loginAsUser(self::TEST_VERSIONS_USER);
+
+ Server::get(\OCP\Share\IManager::class)->deleteShare($share);
+ $this->assertEquals('version 2', $file->getContent(), 'File content has not changed');
+ }
+
+ /**
+ * @param string $hookName name of hook called
+ * @param string $params variable to receive parameters provided by hook
+ */
+ private function connectMockHooks($hookName, &$params) {
+ if ($hookName === null) {
+ return;
+ }
+
+ $eventHandler = $this->getMockBuilder(DummyHookListener::class)
+ ->onlyMethods(['callback'])
+ ->getMock();
+
+ $eventHandler->expects($this->any())
+ ->method('callback')
+ ->willReturnCallback(
+ function ($p) use (&$params): void {
+ $params = $p;
+ }
+ );
+
+ Util::connectHook(
+ '\OCP\Versions',
+ $hookName,
+ $eventHandler,
+ 'callback'
+ );
+ }
+
+ private function doTestRestore(): void {
+ $filePath = self::TEST_VERSIONS_USER . '/files/sub/test.txt';
+ $this->rootView->file_put_contents($filePath, 'test file');
+
+ $fileInfo = $this->rootView->getFileInfo($filePath);
+ $t0 = $this->rootView->filemtime($filePath);
+
+ // not exactly the same timestamp as the file
+ $t1 = time() - 60;
+ // second version is two weeks older
+ $t2 = $t1 - 60 * 60 * 24 * 14;
+
+ // create some versions
+ $v1 = self::USERS_VERSIONS_ROOT . '/sub/test.txt.v' . $t1;
+ $v2 = self::USERS_VERSIONS_ROOT . '/sub/test.txt.v' . $t2;
+
+ $this->rootView->mkdir(self::USERS_VERSIONS_ROOT . '/sub');
+
+ $this->rootView->file_put_contents($v1, 'version1');
+ $fileInfoV1 = $this->rootView->getFileInfo($v1);
+ $versionEntity = new VersionEntity();
+ $versionEntity->setFileId($fileInfo->getId());
+ $versionEntity->setTimestamp($t1);
+ $versionEntity->setSize($fileInfoV1->getSize());
+ $versionEntity->setMimetype($this->mimeTypeLoader->getId($fileInfoV1->getMimetype()));
+ $versionEntity->setMetadata([]);
+ $this->versionsMapper->insert($versionEntity);
+
+ $this->rootView->file_put_contents($v2, 'version2');
+ $fileInfoV2 = $this->rootView->getFileInfo($v2);
+ $versionEntity = new VersionEntity();
+ $versionEntity->setFileId($fileInfo->getId());
+ $versionEntity->setTimestamp($t2);
+ $versionEntity->setSize($fileInfoV2->getSize());
+ $versionEntity->setMimetype($this->mimeTypeLoader->getId($fileInfoV2->getMimetype()));
+ $versionEntity->setMetadata([]);
+ $this->versionsMapper->insert($versionEntity);
+
+ $oldVersions = Storage::getVersions(
+ self::TEST_VERSIONS_USER, '/sub/test.txt'
+ );
+
+ $this->assertCount(2, $oldVersions);
+
+ $this->assertEquals('test file', $this->rootView->file_get_contents($filePath));
+ $info1 = $this->rootView->getFileInfo($filePath);
+
+ $eventDispatcher = Server::get(IEventDispatcher::class);
+ $eventFired = false;
+ $eventDispatcher->addListener(VersionRestoredEvent::class, function ($event) use (&$eventFired, $t2): void {
+ $eventFired = true;
+ $this->assertEquals('/sub/test.txt', $event->getVersion()->getVersionPath());
+ $this->assertTrue($event->getVersion()->getRevisionId() > 0);
+ });
+
+ $versionManager = Server::get(IVersionManager::class);
+ $versions = $versionManager->getVersionsForFile($this->user1, $info1);
+ $version = array_filter($versions, function ($version) use ($t2) {
+ return $version->getRevisionId() === $t2;
+ });
+ $this->assertTrue($versionManager->rollback(current($version)));
+
+ $this->assertTrue($eventFired, 'VersionRestoredEvent was not fired');
+
+ $this->assertEquals('version2', $this->rootView->file_get_contents($filePath));
+ $info2 = $this->rootView->getFileInfo($filePath);
+
+ $this->assertNotEquals(
+ $info2['etag'],
+ $info1['etag'],
+ 'Etag must change after rolling back version'
+ );
+ $this->assertEquals(
+ $info2['fileid'],
+ $info1['fileid'],
+ 'File id must not change after rolling back version'
+ );
+ $this->assertEquals(
+ $info2['mtime'],
+ $t2,
+ 'Restored file has mtime from version'
+ );
+
+ $newVersions = Storage::getVersions(
+ self::TEST_VERSIONS_USER, '/sub/test.txt'
+ );
+
+ $this->assertTrue(
+ $this->rootView->file_exists(self::USERS_VERSIONS_ROOT . '/sub/test.txt.v' . $t0),
+ 'A version file was created for the file before restoration'
+ );
+ $this->assertTrue(
+ $this->rootView->file_exists($v1),
+ 'Untouched version file is still there'
+ );
+ $this->assertFalse(
+ $this->rootView->file_exists($v2),
+ 'Restored version file gone from files_version folder'
+ );
+
+ $this->assertCount(2, $newVersions, 'Additional version created');
+
+ $this->assertTrue(
+ isset($newVersions[$t0 . '#' . 'test.txt']),
+ 'A version was created for the file before restoration'
+ );
+ $this->assertTrue(
+ isset($newVersions[$t1 . '#' . 'test.txt']),
+ 'Untouched version is still there'
+ );
+ $this->assertFalse(
+ isset($newVersions[$t2 . '#' . 'test.txt']),
+ 'Restored version is not in the list any more'
+ );
+ }
+
+ /**
+ * Test whether versions are created when overwriting as owner
+ */
+ public function testStoreVersionAsOwner(): void {
+ $this->loginAsUser(self::TEST_VERSIONS_USER);
+
+ $this->createAndCheckVersions(
+ Filesystem::getView(),
+ 'test.txt'
+ );
+ }
+
+ /**
+ * Test whether versions are created when overwriting as share recipient
+ */
+ public function testStoreVersionAsRecipient(): void {
+ $this->loginAsUser(self::TEST_VERSIONS_USER);
+
+ Filesystem::mkdir('folder');
+ Filesystem::file_put_contents('folder/test.txt', 'test file');
+
+ $node = \OC::$server->getUserFolder(self::TEST_VERSIONS_USER)->get('folder');
+ $share = Server::get(\OCP\Share\IManager::class)->newShare();
+ $share->setNode($node)
+ ->setShareType(IShare::TYPE_USER)
+ ->setSharedBy(self::TEST_VERSIONS_USER)
+ ->setSharedWith(self::TEST_VERSIONS_USER2)
+ ->setPermissions(Constants::PERMISSION_ALL);
+ $share = Server::get(\OCP\Share\IManager::class)->createShare($share);
+ Server::get(\OCP\Share\IManager::class)->acceptShare($share, self::TEST_VERSIONS_USER2);
+
+ $this->loginAsUser(self::TEST_VERSIONS_USER2);
+
+ $this->createAndCheckVersions(
+ Filesystem::getView(),
+ 'folder/test.txt'
+ );
+
+ Server::get(\OCP\Share\IManager::class)->deleteShare($share);
+ }
+
+ /**
+ * Test whether versions are created when overwriting anonymously.
+ *
+ * When uploading through a public link or publicwebdav, no user
+ * is logged in. File modification must still be able to find
+ * the owner and create versions.
+ */
+ public function testStoreVersionAsAnonymous(): void {
+ $this->logout();
+
+ // note: public link upload does this,
+ // needed to make the hooks fire
+ \OC_Util::setupFS(self::TEST_VERSIONS_USER);
+
+ $userView = new View('/' . self::TEST_VERSIONS_USER . '/files');
+ $this->createAndCheckVersions(
+ $userView,
+ 'test.txt'
+ );
+ }
+
+ private function createAndCheckVersions(View $view, string $path): array {
+ $view->file_put_contents($path, 'test file');
+ $view->file_put_contents($path, 'version 1');
+ $view->file_put_contents($path, 'version 2');
+
+ $this->loginAsUser(self::TEST_VERSIONS_USER);
+
+ // need to scan for the versions
+ [$rootStorage,] = $this->rootView->resolvePath(self::TEST_VERSIONS_USER . '/files_versions');
+ $rootStorage->getScanner()->scan('files_versions');
+
+ $versions = Storage::getVersions(
+ self::TEST_VERSIONS_USER, '/' . $path
+ );
+
+ // note: we cannot predict how many versions are created due to
+ // test run timing
+ $this->assertGreaterThan(0, count($versions));
+
+ return $versions;
+ }
+
+ public static function loginHelper(string $user, bool $create = false) {
+ if ($create) {
+ $backend = new \Test\Util\User\Dummy();
+ $backend->createUser($user, $user);
+ Server::get(IUserManager::class)->registerBackend($backend);
+ }
+
+ \OC_Util::tearDownFS();
+ \OC_User::setUserId('');
+ Filesystem::tearDown();
+ \OC_User::setUserId($user);
+ \OC_Util::setupFS($user);
+ \OC::$server->getUserFolder($user);
+ }
+}
+
+class DummyHookListener {
+ public function callback() {
+ }
+}
+
+// extend the original class to make it possible to test protected methods
+class VersionStorageToTest extends Storage {
+
+ /**
+ * @param integer $time
+ */
+ public function callProtectedGetExpireList($time, $versions) {
+ return self::getExpireList($time, $versions);
+ }
+}
diff --git a/apps/files_versions/tests/Versions/VersionManagerTest.php b/apps/files_versions/tests/Versions/VersionManagerTest.php
new file mode 100644
index 00000000000..79caa65d5f1
--- /dev/null
+++ b/apps/files_versions/tests/Versions/VersionManagerTest.php
@@ -0,0 +1,140 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\Files_Versions\Tests\Versions;
+
+use OC\Files\Storage\Local;
+use OCA\Files_Versions\Events\VersionRestoredEvent;
+use OCA\Files_Versions\Versions\IVersion;
+use OCA\Files_Versions\Versions\IVersionBackend;
+use OCA\Files_Versions\Versions\VersionManager;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\Files\Storage\IStorage;
+use PHPUnit\Framework\MockObject\MockObject;
+use Test\TestCase;
+
+class VersionManagerTest extends TestCase {
+ private function getBackend(bool $shouldUse = true): IVersionBackend {
+ $backend = $this->createMock(IVersionBackend::class);
+ $backend->method('useBackendForStorage')
+ ->willReturn($shouldUse);
+ return $backend;
+ }
+
+ private function getStorage(string $class): IStorage&MockObject {
+ return $this->getMockBuilder($class)
+ ->disableOriginalConstructor()
+ ->onlyMethods(array_diff(get_class_methods($class), ['instanceOfStorage']))
+ ->getMock();
+ }
+
+ public function testGetBackendSingle(): void {
+ $dispatcher = $this->createMock(IEventDispatcher::class);
+ $manager = new VersionManager($dispatcher);
+ $backend = $this->getBackend();
+ $manager->registerBackend(IStorage::class, $backend);
+
+ $this->assertEquals($backend, $manager->getBackendForStorage($this->getStorage(Local::class)));
+ }
+
+ public function testGetBackendMoreSpecific(): void {
+ $dispatcher = $this->createMock(IEventDispatcher::class);
+ $manager = new VersionManager($dispatcher);
+ $backend1 = $this->getBackend();
+ $backend2 = $this->getBackend();
+ $manager->registerBackend(IStorage::class, $backend1);
+ $manager->registerBackend(Local::class, $backend2);
+
+ $this->assertEquals($backend2, $manager->getBackendForStorage($this->getStorage(Local::class)));
+ }
+
+ public function testGetBackendNoUse(): void {
+ $dispatcher = $this->createMock(IEventDispatcher::class);
+ $manager = new VersionManager($dispatcher);
+ $backend1 = $this->getBackend();
+ $backend2 = $this->getBackend(false);
+ $manager->registerBackend(IStorage::class, $backend1);
+ $manager->registerBackend(Local::class, $backend2);
+
+ $this->assertEquals($backend1, $manager->getBackendForStorage($this->getStorage(Local::class)));
+ }
+
+ public function testGetBackendMultiple(): void {
+ $dispatcher = $this->createMock(IEventDispatcher::class);
+ $manager = new VersionManager($dispatcher);
+ $backend1 = $this->getBackend();
+ $backend2 = $this->getBackend(false);
+ $backend3 = $this->getBackend();
+ $manager->registerBackend(IStorage::class, $backend1);
+ $manager->registerBackend(Local::class, $backend2);
+ $manager->registerBackend(Local::class, $backend3);
+
+ $this->assertEquals($backend3, $manager->getBackendForStorage($this->getStorage(Local::class)));
+ }
+
+ public function testRollbackSuccess(): void {
+ $versionMock = $this->createMock(IVersion::class);
+ $backendMock = $this->createMock(IVersionBackend::class);
+
+ $backendMock->expects($this->once())
+ ->method('rollback')
+ ->with($versionMock)
+ ->willReturn(true);
+
+ $versionMock->method('getBackend')->willReturn($backendMock);
+
+ $dispatcherMock = $this->createMock(IEventDispatcher::class);
+ $dispatcherMock->expects($this->once())
+ ->method('dispatchTyped')
+ ->with($this->isInstanceOf(VersionRestoredEvent::class));
+
+ $manager = new VersionManager($dispatcherMock);
+
+ $this->assertTrue($manager->rollback($versionMock));
+ }
+
+ public function testRollbackNull(): void {
+ $versionMock = $this->createMock(IVersion::class);
+ $backendMock = $this->createMock(IVersionBackend::class);
+
+ $backendMock->expects($this->once())
+ ->method('rollback')
+ ->with($versionMock)
+ ->willReturn(null);
+
+ $versionMock->method('getBackend')->willReturn($backendMock);
+
+ $dispatcherMock = $this->createMock(IEventDispatcher::class);
+ $dispatcherMock->expects($this->once())
+ ->method('dispatchTyped')
+ ->with($this->isInstanceOf(VersionRestoredEvent::class));
+
+ $manager = new VersionManager($dispatcherMock);
+
+ $this->assertNull($manager->rollback($versionMock));
+ }
+
+ public function testRollbackFailure(): void {
+ $versionMock = $this->createMock(IVersion::class);
+ $backendMock = $this->createMock(IVersionBackend::class);
+
+ $backendMock->expects($this->once())
+ ->method('rollback')
+ ->with($versionMock)
+ ->willReturn(false);
+
+ $versionMock->method('getBackend')->willReturn($backendMock);
+
+ $dispatcherMock = $this->createMock(IEventDispatcher::class);
+ $dispatcherMock->expects($this->never())->method('dispatchTyped');
+
+ $manager = new VersionManager($dispatcherMock);
+
+ $this->assertFalse($manager->rollback($versionMock));
+ }
+}
diff --git a/apps/files_versions/tests/command/cleanuptest.php b/apps/files_versions/tests/command/cleanuptest.php
deleted file mode 100644
index af217b18893..00000000000
--- a/apps/files_versions/tests/command/cleanuptest.php
+++ /dev/null
@@ -1,170 +0,0 @@
-<?php
-/**
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-
-namespace OCA\Files_Versions\Tests\Command;
-
-
-use OCA\Files_Versions\Command\CleanUp;
-use Test\TestCase;
-use OC\User\Manager;
-use OCP\Files\IRootFolder;
-
-/**
- * Class CleanupTest
- *
- * @group DB
- *
- * @package OCA\Files_Versions\Tests\Command
- */
-class CleanupTest extends TestCase {
-
- /** @var CleanUp */
- protected $cleanup;
-
- /** @var \PHPUnit_Framework_MockObject_MockObject | Manager */
- protected $userManager;
-
- /** @var \PHPUnit_Framework_MockObject_MockObject | IRootFolder */
- protected $rootFolder;
-
- public function setUp() {
- parent::setUp();
-
- $this->rootFolder = $this->getMockBuilder('OCP\Files\IRootFolder')
- ->disableOriginalConstructor()->getMock();
- $this->userManager = $this->getMockBuilder('OC\User\Manager')
- ->disableOriginalConstructor()->getMock();
-
-
- $this->cleanup = new CleanUp($this->rootFolder, $this->userManager);
- }
-
- /**
- * @dataProvider dataTestDeleteVersions
- * @param boolean $nodeExists
- */
- public function testDeleteVersions($nodeExists) {
-
- $this->rootFolder->expects($this->once())
- ->method('nodeExists')
- ->with('/testUser/files_versions')
- ->willReturn($nodeExists);
-
-
- if($nodeExists) {
- $this->rootFolder->expects($this->once())
- ->method('get')
- ->with('/testUser/files_versions')
- ->willReturn($this->rootFolder);
- $this->rootFolder->expects($this->once())
- ->method('delete');
- } else {
- $this->rootFolder->expects($this->never())
- ->method('get');
- $this->rootFolder->expects($this->never())
- ->method('delete');
- }
-
- $this->invokePrivate($this->cleanup, 'deleteVersions', ['testUser']);
- }
-
- public function dataTestDeleteVersions() {
- return array(
- array(true),
- array(false)
- );
- }
-
-
- /**
- * test delete versions from users given as parameter
- */
- public function testExecuteDeleteListOfUsers() {
- $userIds = ['user1', 'user2', 'user3'];
-
- $instance = $this->getMockBuilder('OCA\Files_Versions\Command\CleanUp')
- ->setMethods(['deleteVersions'])
- ->setConstructorArgs([$this->rootFolder, $this->userManager])
- ->getMock();
- $instance->expects($this->exactly(count($userIds)))
- ->method('deleteVersions')
- ->willReturnCallback(function ($user) use ($userIds) {
- $this->assertTrue(in_array($user, $userIds));
- });
-
- $this->userManager->expects($this->exactly(count($userIds)))
- ->method('userExists')->willReturn(true);
-
- $inputInterface = $this->getMockBuilder('\Symfony\Component\Console\Input\InputInterface')
- ->disableOriginalConstructor()->getMock();
- $inputInterface->expects($this->once())->method('getArgument')
- ->with('user_id')
- ->willReturn($userIds);
-
- $outputInterface = $this->getMockBuilder('\Symfony\Component\Console\Output\OutputInterface')
- ->disableOriginalConstructor()->getMock();
-
- $this->invokePrivate($instance, 'execute', [$inputInterface, $outputInterface]);
- }
-
- /**
- * test delete versions of all users
- */
- public function testExecuteAllUsers() {
- $userIds = [];
- $backendUsers = ['user1', 'user2'];
-
- $instance = $this->getMockBuilder('OCA\Files_Versions\Command\CleanUp')
- ->setMethods(['deleteVersions'])
- ->setConstructorArgs([$this->rootFolder, $this->userManager])
- ->getMock();
-
- $backend = $this->getMockBuilder('OC_User_Interface')
- ->disableOriginalConstructor()->getMock();
- $backend->expects($this->once())->method('getUsers')
- ->with('', 500, 0)
- ->willReturn($backendUsers);
-
- $instance->expects($this->exactly(count($backendUsers)))
- ->method('deleteVersions')
- ->willReturnCallback(function ($user) use ($backendUsers) {
- $this->assertTrue(in_array($user, $backendUsers));
- });
-
- $inputInterface = $this->getMockBuilder('\Symfony\Component\Console\Input\InputInterface')
- ->disableOriginalConstructor()->getMock();
- $inputInterface->expects($this->once())->method('getArgument')
- ->with('user_id')
- ->willReturn($userIds);
-
- $outputInterface = $this->getMockBuilder('\Symfony\Component\Console\Output\OutputInterface')
- ->disableOriginalConstructor()->getMock();
-
- $this->userManager->expects($this->once())
- ->method('getBackends')
- ->willReturn([$backend]);
-
- $this->invokePrivate($instance, 'execute', [$inputInterface, $outputInterface]);
- }
-
-}
diff --git a/apps/files_versions/tests/command/expiretest.php b/apps/files_versions/tests/command/expiretest.php
deleted file mode 100644
index f89ece82515..00000000000
--- a/apps/files_versions/tests/command/expiretest.php
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php
-/**
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OCA\Files_Versions\Tests\Command;
-
-use OCA\Files_Versions\Command\Expire;
-use Test\TestCase;
-
-/**
- * Class ExpireTest
- *
- * @group DB
- *
- * @package OCA\Files_Versions\Tests\Command
- */
-class ExpireTest extends TestCase {
- public function testExpireNonExistingUser() {
- $command = new Expire($this->getUniqueID('test'), '');
- $command->handle();
-
- $this->assertTrue(true);
- }
-}
diff --git a/apps/files_versions/tests/expirationtest.php b/apps/files_versions/tests/expirationtest.php
deleted file mode 100644
index 2dfff19f230..00000000000
--- a/apps/files_versions/tests/expirationtest.php
+++ /dev/null
@@ -1,206 +0,0 @@
-<?php
-/**
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Victor Dubiniuk <dubiniuk@owncloud.com>
- *
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OCA\Files_Versions\Tests;
-
-use \OCA\Files_Versions\Expiration;
-
-class Expiration_Test extends \Test\TestCase {
- const SECONDS_PER_DAY = 86400; //60*60*24
-
- public function expirationData(){
- $today = 100*self::SECONDS_PER_DAY;
- $back10Days = (100-10)*self::SECONDS_PER_DAY;
- $back20Days = (100-20)*self::SECONDS_PER_DAY;
- $back30Days = (100-30)*self::SECONDS_PER_DAY;
- $back35Days = (100-35)*self::SECONDS_PER_DAY;
-
- // it should never happen, but who knows :/
- $ahead100Days = (100+100)*self::SECONDS_PER_DAY;
-
- return [
- // Expiration is disabled - always should return false
- [ 'disabled', $today, $back10Days, false, false],
- [ 'disabled', $today, $back10Days, true, false],
- [ 'disabled', $today, $ahead100Days, true, false],
-
- // Default: expire in 30 days or earlier when quota requirements are met
- [ 'auto', $today, $back10Days, false, false],
- [ 'auto', $today, $back35Days, false, false],
- [ 'auto', $today, $back10Days, true, true],
- [ 'auto', $today, $back35Days, true, true],
- [ 'auto', $today, $ahead100Days, true, true],
-
- // The same with 'auto'
- [ 'auto, auto', $today, $back10Days, false, false],
- [ 'auto, auto', $today, $back35Days, false, false],
- [ 'auto, auto', $today, $back10Days, true, true],
- [ 'auto, auto', $today, $back35Days, true, true],
-
- // Keep for 15 days but expire anytime if space needed
- [ '15, auto', $today, $back10Days, false, false],
- [ '15, auto', $today, $back20Days, false, false],
- [ '15, auto', $today, $back10Days, true, true],
- [ '15, auto', $today, $back20Days, true, true],
- [ '15, auto', $today, $ahead100Days, true, true],
-
- // Expire anytime if space needed, Expire all older than max
- [ 'auto, 15', $today, $back10Days, false, false],
- [ 'auto, 15', $today, $back20Days, false, true],
- [ 'auto, 15', $today, $back10Days, true, true],
- [ 'auto, 15', $today, $back20Days, true, true],
- [ 'auto, 15', $today, $ahead100Days, true, true],
-
- // Expire all older than max OR older than min if space needed
- [ '15, 25', $today, $back10Days, false, false],
- [ '15, 25', $today, $back20Days, false, false],
- [ '15, 25', $today, $back30Days, false, true],
- [ '15, 25', $today, $back10Days, false, false],
- [ '15, 25', $today, $back20Days, true, true],
- [ '15, 25', $today, $back30Days, true, true],
- [ '15, 25', $today, $ahead100Days, true, false],
-
- // Expire all older than max OR older than min if space needed
- // Max<Min case
- [ '25, 15', $today, $back10Days, false, false],
- [ '25, 15', $today, $back20Days, false, false],
- [ '25, 15', $today, $back30Days, false, true],
- [ '25, 15', $today, $back10Days, false, false],
- [ '25, 15', $today, $back20Days, true, false],
- [ '25, 15', $today, $back30Days, true, true],
- [ '25, 15', $today, $ahead100Days, true, false],
- ];
- }
-
- /**
- * @dataProvider expirationData
- *
- * @param string $retentionObligation
- * @param int $timeNow
- * @param int $timestamp
- * @param bool $quotaExceeded
- * @param string $expectedResult
- */
- public function testExpiration($retentionObligation, $timeNow, $timestamp, $quotaExceeded, $expectedResult){
- $mockedConfig = $this->getMockedConfig($retentionObligation);
- $mockedTimeFactory = $this->getMockedTimeFactory($timeNow);
-
- $expiration = new Expiration($mockedConfig, $mockedTimeFactory);
- $actualResult = $expiration->isExpired($timestamp, $quotaExceeded);
-
- $this->assertEquals($expectedResult, $actualResult);
- }
-
-
- public function configData(){
- return [
- [ 'disabled', null, null, null],
- [ 'auto', Expiration::NO_OBLIGATION, Expiration::NO_OBLIGATION, true ],
- [ 'auto,auto', Expiration::NO_OBLIGATION, Expiration::NO_OBLIGATION, true ],
- [ 'auto, auto', Expiration::NO_OBLIGATION, Expiration::NO_OBLIGATION, true ],
- [ 'auto, 3', Expiration::NO_OBLIGATION, 3, true ],
- [ '5, auto', 5, Expiration::NO_OBLIGATION, true ],
- [ '3, 5', 3, 5, false ],
- [ '10, 3', 10, 10, false ],
- [ 'g,a,r,b,a,g,e', Expiration::NO_OBLIGATION, Expiration::NO_OBLIGATION, true ],
- [ '-3,8', Expiration::NO_OBLIGATION, Expiration::NO_OBLIGATION, true ]
- ];
- }
-
-
- /**
- * @dataProvider configData
- *
- * @param string $configValue
- * @param int $expectedMinAge
- * @param int $expectedMaxAge
- * @param bool $expectedCanPurgeToSaveSpace
- */
- public function testParseRetentionObligation($configValue, $expectedMinAge, $expectedMaxAge, $expectedCanPurgeToSaveSpace){
- $mockedConfig = $this->getMockedConfig($configValue);
- $mockedTimeFactory = $this->getMockedTimeFactory(
- time()
- );
-
- $expiration = new Expiration($mockedConfig, $mockedTimeFactory);
- $this->assertAttributeEquals($expectedMinAge, 'minAge', $expiration);
- $this->assertAttributeEquals($expectedMaxAge, 'maxAge', $expiration);
- $this->assertAttributeEquals($expectedCanPurgeToSaveSpace, 'canPurgeToSaveSpace', $expiration);
- }
-
- /**
- *
- * @param int $time
- * @return \OCP\AppFramework\Utility\ITimeFactory
- */
- private function getMockedTimeFactory($time){
- $mockedTimeFactory = $this->getMockBuilder('\OCP\AppFramework\Utility\ITimeFactory')
- ->disableOriginalConstructor()
- ->setMethods(['getTime'])
- ->getMock()
- ;
- $mockedTimeFactory->expects($this->any())->method('getTime')->will(
- $this->returnValue($time)
- );
-
- return $mockedTimeFactory;
- }
-
- /**
- *
- * @param string $returnValue
- * @return \OCP\IConfig
- */
- private function getMockedConfig($returnValue){
- $mockedConfig = $this->getMockBuilder('\OCP\IConfig')
- ->disableOriginalConstructor()
- ->setMethods(
- [
- 'setSystemValues',
- 'setSystemValue',
- 'getSystemValue',
- 'getFilteredSystemValue',
- 'deleteSystemValue',
- 'getAppKeys',
- 'setAppValue',
- 'getAppValue',
- 'deleteAppValue',
- 'deleteAppValues',
- 'setUserValue',
- 'getUserValue',
- 'getUserValueForUsers',
- 'getUserKeys',
- 'deleteUserValue',
- 'deleteAllUserValues',
- 'deleteAppFromAllUsers',
- 'getUsersForUserValue'
- ]
- )
- ->getMock()
- ;
- $mockedConfig->expects($this->any())->method('getSystemValue')->will(
- $this->returnValue($returnValue)
- );
-
- return $mockedConfig;
- }
-}
diff --git a/apps/files_versions/tests/js/versioncollectionSpec.js b/apps/files_versions/tests/js/versioncollectionSpec.js
deleted file mode 100644
index 87065fa1d36..00000000000
--- a/apps/files_versions/tests/js/versioncollectionSpec.js
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (c) 2015
- *
- * This file is licensed under the Affero General Public License version 3
- * or later.
- *
- * See the COPYING-README file.
- *
- */
-describe('OCA.Versions.VersionCollection', function() {
- var VersionCollection = OCA.Versions.VersionCollection;
- var collection, fileInfoModel;
-
- beforeEach(function() {
- fileInfoModel = new OCA.Files.FileInfoModel({
- path: '/subdir',
- name: 'some file.txt'
- });
- collection = new VersionCollection();
- collection.setFileInfo(fileInfoModel);
- });
- it('fetches the next page', function() {
- collection.fetchNext();
-
- expect(fakeServer.requests.length).toEqual(1);
- expect(fakeServer.requests[0].url).toEqual(
- OC.generateUrl('apps/files_versions/ajax/getVersions.php') +
- '?source=%2Fsubdir%2Fsome%20file.txt&start=0'
- );
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({
- status: 'success',
- data: {
- endReached: false,
- versions: [{
- version: 10000000,
- size: 123,
- name: 'some file.txt',
- fullPath: '/subdir/some file.txt'
- },{
- version: 15000000,
- size: 150,
- name: 'some file.txt',
- path: '/subdir/some file.txt'
- }]
- }
- })
- );
-
- expect(collection.length).toEqual(2);
- expect(collection.hasMoreResults()).toEqual(true);
-
- collection.fetchNext();
-
- expect(fakeServer.requests.length).toEqual(2);
- expect(fakeServer.requests[1].url).toEqual(
- OC.generateUrl('apps/files_versions/ajax/getVersions.php') +
- '?source=%2Fsubdir%2Fsome%20file.txt&start=2'
- );
- fakeServer.requests[1].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({
- status: 'success',
- data: {
- endReached: true,
- versions: [{
- version: 18000000,
- size: 123,
- name: 'some file.txt',
- path: '/subdir/some file.txt'
- }]
- }
- })
- );
-
- expect(collection.length).toEqual(3);
- expect(collection.hasMoreResults()).toEqual(false);
-
- collection.fetchNext();
-
- // no further requests
- expect(fakeServer.requests.length).toEqual(2);
- });
- it('properly parses the results', function() {
- collection.fetchNext();
-
- expect(fakeServer.requests.length).toEqual(1);
- expect(fakeServer.requests[0].url).toEqual(
- OC.generateUrl('apps/files_versions/ajax/getVersions.php') +
- '?source=%2Fsubdir%2Fsome%20file.txt&start=0'
- );
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({
- status: 'success',
- data: {
- endReached: false,
- versions: [{
- version: 10000000,
- size: 123,
- name: 'some file.txt',
- path: '/subdir/some file.txt'
- },{
- version: 15000000,
- size: 150,
- name: 'some file.txt',
- path: '/subdir/some file.txt'
- }]
- }
- })
- );
-
- expect(collection.length).toEqual(2);
-
- var model = collection.at(0);
- expect(model.get('id')).toEqual(10000000);
- expect(model.get('timestamp')).toEqual(10000000);
- expect(model.get('name')).toEqual('some file.txt');
- expect(model.get('fullPath')).toEqual('/subdir/some file.txt');
- expect(model.get('size')).toEqual(123);
-
- model = collection.at(1);
- expect(model.get('id')).toEqual(15000000);
- expect(model.get('timestamp')).toEqual(15000000);
- expect(model.get('name')).toEqual('some file.txt');
- expect(model.get('fullPath')).toEqual('/subdir/some file.txt');
- expect(model.get('size')).toEqual(150);
- });
- it('resets page counted when setting a new file info model', function() {
- collection.fetchNext();
-
- expect(fakeServer.requests.length).toEqual(1);
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({
- status: 'success',
- data: {
- endReached: true,
- versions: [{
- version: 18000000,
- size: 123,
- name: 'some file.txt',
- path: '/subdir/some file.txt'
- }]
- }
- })
- );
-
- expect(collection.hasMoreResults()).toEqual(false);
-
- collection.setFileInfo(fileInfoModel);
-
- expect(collection.hasMoreResults()).toEqual(true);
- });
-});
-
diff --git a/apps/files_versions/tests/js/versionmodelSpec.js b/apps/files_versions/tests/js/versionmodelSpec.js
deleted file mode 100644
index 0f1c06581d5..00000000000
--- a/apps/files_versions/tests/js/versionmodelSpec.js
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (c) 2015
- *
- * This file is licensed under the Affero General Public License version 3
- * or later.
- *
- * See the COPYING-README file.
- *
- */
-describe('OCA.Versions.VersionModel', function() {
- var VersionModel = OCA.Versions.VersionModel;
- var model;
-
- beforeEach(function() {
- model = new VersionModel({
- id: 10000000,
- timestamp: 10000000,
- fullPath: '/subdir/some file.txt',
- name: 'some file.txt',
- size: 150
- });
- });
-
- it('returns the full path', function() {
- expect(model.getFullPath()).toEqual('/subdir/some file.txt');
- });
- it('returns the preview url', function() {
- expect(model.getPreviewUrl())
- .toEqual(OC.generateUrl('/apps/files_versions/preview') +
- '?file=%2Fsubdir%2Fsome%20file.txt&version=10000000'
- );
- });
- it('returns the download url', function() {
- expect(model.getDownloadUrl())
- .toEqual(OC.generateUrl('/apps/files_versions/download.php') +
- '?file=%2Fsubdir%2Fsome%20file.txt&revision=10000000'
- );
- });
- describe('reverting', function() {
- var revertEventStub;
- var successStub;
- var errorStub;
-
- beforeEach(function() {
- revertEventStub = sinon.stub();
- errorStub = sinon.stub();
- successStub = sinon.stub();
-
- model.on('revert', revertEventStub);
- model.on('error', errorStub);
- });
- it('tells the server to revert when calling the revert method', function() {
- model.revert({
- success: successStub
- });
-
- expect(fakeServer.requests.length).toEqual(1);
- expect(fakeServer.requests[0].url)
- .toEqual(
- OC.generateUrl('/apps/files_versions/ajax/rollbackVersion.php') +
- '?file=%2Fsubdir%2Fsome+file.txt&revision=10000000'
- );
-
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({
- status: 'success',
- })
- );
-
- expect(revertEventStub.calledOnce).toEqual(true);
- expect(successStub.calledOnce).toEqual(true);
- expect(errorStub.notCalled).toEqual(true);
- });
- it('triggers error event when server returns a failure', function() {
- model.revert({
- success: successStub
- });
-
- expect(fakeServer.requests.length).toEqual(1);
- fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
- JSON.stringify({
- status: 'error',
- })
- );
-
- expect(revertEventStub.notCalled).toEqual(true);
- expect(successStub.notCalled).toEqual(true);
- expect(errorStub.calledOnce).toEqual(true);
- });
- });
-});
-
diff --git a/apps/files_versions/tests/js/versionstabviewSpec.js b/apps/files_versions/tests/js/versionstabviewSpec.js
deleted file mode 100644
index 306dd66be2a..00000000000
--- a/apps/files_versions/tests/js/versionstabviewSpec.js
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (c) 2015
- *
- * This file is licensed under the Affero General Public License version 3
- * or later.
- *
- * See the COPYING-README file.
- *
- */
-describe('OCA.Versions.VersionsTabView', function() {
- var VersionCollection = OCA.Versions.VersionCollection;
- var VersionModel = OCA.Versions.VersionModel;
- var VersionsTabView = OCA.Versions.VersionsTabView;
-
- var fetchStub, fileInfoModel, tabView, testVersions, clock;
-
- beforeEach(function() {
- clock = sinon.useFakeTimers(Date.UTC(2015, 6, 17, 1, 2, 0, 3));
- var time1 = Date.UTC(2015, 6, 17, 1, 2, 0, 3) / 1000;
- var time2 = Date.UTC(2015, 6, 15, 1, 2, 0, 3) / 1000;
-
- var version1 = new VersionModel({
- id: time1,
- timestamp: time1,
- name: 'some file.txt',
- size: 140,
- fullPath: '/subdir/some file.txt'
- });
- var version2 = new VersionModel({
- id: time2,
- timestamp: time2,
- name: 'some file.txt',
- size: 150,
- fullPath: '/subdir/some file.txt'
- });
-
- testVersions = [version1, version2];
-
- fetchStub = sinon.stub(VersionCollection.prototype, 'fetch');
- fileInfoModel = new OCA.Files.FileInfoModel({
- id: 123,
- name: 'test.txt'
- });
- tabView = new VersionsTabView();
- tabView.render();
- });
-
- afterEach(function() {
- fetchStub.restore();
- tabView.remove();
- clock.restore();
- });
-
- describe('rendering', function() {
- it('reloads matching versions when setting file info model', function() {
- tabView.setFileInfo(fileInfoModel);
- expect(fetchStub.calledOnce).toEqual(true);
- });
-
- it('renders loading icon while fetching versions', function() {
- tabView.setFileInfo(fileInfoModel);
- tabView.collection.trigger('request');
-
- expect(tabView.$el.find('.loading').length).toEqual(1);
- expect(tabView.$el.find('.versions li').length).toEqual(0);
- });
-
- it('renders versions', function() {
-
- tabView.setFileInfo(fileInfoModel);
- tabView.collection.set(testVersions);
-
- var version1 = testVersions[0];
- var version2 = testVersions[1];
- var $versions = tabView.$el.find('.versions>li');
- expect($versions.length).toEqual(2);
- var $item = $versions.eq(0);
- expect($item.find('.downloadVersion').attr('href')).toEqual(version1.getDownloadUrl());
- expect($item.find('.versiondate').text()).toEqual('seconds ago');
- expect($item.find('.revertVersion').length).toEqual(1);
- expect($item.find('.preview').attr('src')).toEqual(version1.getPreviewUrl());
-
- $item = $versions.eq(1);
- expect($item.find('.downloadVersion').attr('href')).toEqual(version2.getDownloadUrl());
- expect($item.find('.versiondate').text()).toEqual('2 days ago');
- expect($item.find('.revertVersion').length).toEqual(1);
- expect($item.find('.preview').attr('src')).toEqual(version2.getPreviewUrl());
- });
- });
-
- describe('More versions', function() {
- var hasMoreResultsStub;
-
- beforeEach(function() {
- tabView.collection.set(testVersions);
- hasMoreResultsStub = sinon.stub(VersionCollection.prototype, 'hasMoreResults');
- });
- afterEach(function() {
- hasMoreResultsStub.restore();
- });
-
- it('shows "More versions" button when more versions are available', function() {
- hasMoreResultsStub.returns(true);
- tabView.collection.trigger('sync');
-
- expect(tabView.$el.find('.showMoreVersions').hasClass('hidden')).toEqual(false);
- });
- it('does not show "More versions" button when more versions are available', function() {
- hasMoreResultsStub.returns(false);
- tabView.collection.trigger('sync');
-
- expect(tabView.$el.find('.showMoreVersions').hasClass('hidden')).toEqual(true);
- });
- it('fetches and appends the next page when clicking the "More" button', function() {
- hasMoreResultsStub.returns(true);
-
- expect(fetchStub.notCalled).toEqual(true);
-
- tabView.$el.find('.showMoreVersions').click();
-
- expect(fetchStub.calledOnce).toEqual(true);
- });
- it('appends version to the list when added to collection', function() {
- var time3 = Date.UTC(2015, 6, 10, 1, 0, 0, 0) / 1000;
-
- var version3 = new VersionModel({
- id: time3,
- timestamp: time3,
- name: 'some file.txt',
- size: 54,
- fullPath: '/subdir/some file.txt'
- });
-
- tabView.collection.add(version3);
-
- expect(tabView.$el.find('.versions>li').length).toEqual(3);
-
- var $item = tabView.$el.find('.versions>li').eq(2);
- expect($item.find('.downloadVersion').attr('href')).toEqual(version3.getDownloadUrl());
- expect($item.find('.versiondate').text()).toEqual('7 days ago');
- expect($item.find('.revertVersion').length).toEqual(1);
- expect($item.find('.preview').attr('src')).toEqual(version3.getPreviewUrl());
- });
- });
-
- describe('Reverting', function() {
- var revertStub;
-
- beforeEach(function() {
- revertStub = sinon.stub(VersionModel.prototype, 'revert');
- tabView.setFileInfo(fileInfoModel);
- tabView.collection.set(testVersions);
- });
-
- afterEach(function() {
- revertStub.restore();
- });
-
- it('tells the model to revert when clicking "Revert"', function() {
- tabView.$el.find('.revertVersion').eq(1).click();
-
- expect(revertStub.calledOnce).toEqual(true);
- });
- it('triggers busy state during revert', function() {
- var busyStub = sinon.stub();
- fileInfoModel.on('busy', busyStub);
-
- tabView.$el.find('.revertVersion').eq(1).click();
-
- expect(busyStub.calledOnce).toEqual(true);
- expect(busyStub.calledWith(fileInfoModel, true)).toEqual(true);
-
- busyStub.reset();
- revertStub.getCall(0).args[0].success();
-
- expect(busyStub.calledOnce).toEqual(true);
- expect(busyStub.calledWith(fileInfoModel, false)).toEqual(true);
- });
- it('updates the file info model with the information from the reverted revision', function() {
- var changeStub = sinon.stub();
- fileInfoModel.on('change', changeStub);
-
- tabView.$el.find('.revertVersion').eq(1).click();
-
- expect(changeStub.notCalled).toEqual(true);
-
- revertStub.getCall(0).args[0].success();
-
- expect(changeStub.calledOnce).toEqual(true);
- var changes = changeStub.getCall(0).args[0].changed;
- expect(changes.size).toEqual(150);
- expect(changes.mtime).toEqual(testVersions[1].get('timestamp') * 1000);
- expect(changes.etag).toBeDefined();
- });
- it('shows notification on revert error', function() {
- var notificationStub = sinon.stub(OC.Notification, 'showTemporary');
-
- tabView.$el.find('.revertVersion').eq(1).click();
-
- revertStub.getCall(0).args[0].error();
-
- expect(notificationStub.calledOnce).toEqual(true);
-
- notificationStub.restore();
- });
- });
-});
-
diff --git a/apps/files_versions/tests/versions.php b/apps/files_versions/tests/versions.php
deleted file mode 100644
index f6658e092bd..00000000000
--- a/apps/files_versions/tests/versions.php
+++ /dev/null
@@ -1,848 +0,0 @@
-<?php
-/**
- * @author Arthur Schiwon <blizzz@owncloud.com>
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Georg Ehrke <georg@owncloud.com>
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Roeland Jago Douma <rullzer@owncloud.com>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-require_once __DIR__ . '/../appinfo/app.php';
-
-use OC\Files\Storage\Temporary;
-
-/**
- * Class Test_Files_versions
- * this class provide basic files versions test
- *
- * @group DB
- */
-class Test_Files_Versioning extends \Test\TestCase {
-
- const TEST_VERSIONS_USER = 'test-versions-user';
- const TEST_VERSIONS_USER2 = 'test-versions-user2';
- const USERS_VERSIONS_ROOT = '/test-versions-user/files_versions';
-
- /**
- * @var \OC\Files\View
- */
- private $rootView;
-
- public static function setUpBeforeClass() {
- parent::setUpBeforeClass();
-
- $application = new \OCA\Files_Sharing\AppInfo\Application();
- $application->registerMountProviders();
-
- // create test user
- self::loginHelper(self::TEST_VERSIONS_USER2, true);
- self::loginHelper(self::TEST_VERSIONS_USER, true);
- }
-
- public static function tearDownAfterClass() {
- // cleanup test user
- $user = \OC::$server->getUserManager()->get(self::TEST_VERSIONS_USER);
- if ($user !== null) { $user->delete(); }
- $user = \OC::$server->getUserManager()->get(self::TEST_VERSIONS_USER2);
- if ($user !== null) { $user->delete(); }
-
- parent::tearDownAfterClass();
- }
-
- protected function setUp() {
- parent::setUp();
-
- $config = \OC::$server->getConfig();
- $mockConfig = $this->getMock('\OCP\IConfig');
- $mockConfig->expects($this->any())
- ->method('getSystemValue')
- ->will($this->returnCallback(function ($key, $default) use ($config) {
- if ($key === 'filesystem_check_changes') {
- return \OC\Files\Cache\Watcher::CHECK_ONCE;
- } else {
- return $config->getSystemValue($key, $default);
- }
- }));
- $this->overwriteService('AllConfig', $mockConfig);
-
- // clear hooks
- \OC_Hook::clear();
- \OC::registerShareHooks();
- \OCA\Files_Versions\Hooks::connectHooks();
-
- self::loginHelper(self::TEST_VERSIONS_USER);
- $this->rootView = new \OC\Files\View();
- if (!$this->rootView->file_exists(self::USERS_VERSIONS_ROOT)) {
- $this->rootView->mkdir(self::USERS_VERSIONS_ROOT);
- }
- }
-
- protected function tearDown() {
- $this->restoreService('AllConfig');
-
- if ($this->rootView) {
- $this->rootView->deleteAll(self::TEST_VERSIONS_USER . '/files/');
- $this->rootView->deleteAll(self::TEST_VERSIONS_USER2 . '/files/');
- $this->rootView->deleteAll(self::TEST_VERSIONS_USER . '/files_versions/');
- $this->rootView->deleteAll(self::TEST_VERSIONS_USER2 . '/files_versions/');
- }
-
- \OC_Hook::clear();
-
- parent::tearDown();
- }
-
- /**
- * @medium
- * test expire logic
- * @dataProvider versionsProvider
- */
- public function testGetExpireList($versions, $sizeOfAllDeletedFiles) {
-
- // last interval end at 2592000
- $startTime = 5000000;
-
- $testClass = new VersionStorageToTest();
- list($deleted, $size) = $testClass->callProtectedGetExpireList($startTime, $versions);
-
- // we should have deleted 16 files each of the size 1
- $this->assertEquals($sizeOfAllDeletedFiles, $size);
-
- // the deleted array should only contain versions which should be deleted
- foreach($deleted as $key => $path) {
- unset($versions[$key]);
- $this->assertEquals("delete", substr($path, 0, strlen("delete")));
- }
-
- // the versions array should only contain versions which should be kept
- foreach ($versions as $version) {
- $this->assertEquals("keep", $version['path']);
- }
-
- }
-
- public function versionsProvider() {
- return array(
- // first set of versions uniformly distributed versions
- array(
- array(
- // first slice (10sec) keep one version every 2 seconds
- array("version" => 4999999, "path" => "keep", "size" => 1),
- array("version" => 4999998, "path" => "delete", "size" => 1),
- array("version" => 4999997, "path" => "keep", "size" => 1),
- array("version" => 4999995, "path" => "keep", "size" => 1),
- array("version" => 4999994, "path" => "delete", "size" => 1),
- //next slice (60sec) starts at 4999990 keep one version every 10 secons
- array("version" => 4999988, "path" => "keep", "size" => 1),
- array("version" => 4999978, "path" => "keep", "size" => 1),
- array("version" => 4999975, "path" => "delete", "size" => 1),
- array("version" => 4999972, "path" => "delete", "size" => 1),
- array("version" => 4999967, "path" => "keep", "size" => 1),
- array("version" => 4999958, "path" => "delete", "size" => 1),
- array("version" => 4999957, "path" => "keep", "size" => 1),
- //next slice (3600sec) start at 4999940 keep one version every 60 seconds
- array("version" => 4999900, "path" => "keep", "size" => 1),
- array("version" => 4999841, "path" => "delete", "size" => 1),
- array("version" => 4999840, "path" => "keep", "size" => 1),
- array("version" => 4999780, "path" => "keep", "size" => 1),
- array("version" => 4996401, "path" => "keep", "size" => 1),
- // next slice (86400sec) start at 4996400 keep one version every 3600 seconds
- array("version" => 4996350, "path" => "delete", "size" => 1),
- array("version" => 4992800, "path" => "keep", "size" => 1),
- array("version" => 4989800, "path" => "delete", "size" => 1),
- array("version" => 4989700, "path" => "delete", "size" => 1),
- array("version" => 4989200, "path" => "keep", "size" => 1),
- // next slice (2592000sec) start at 4913600 keep one version every 86400 seconds
- array("version" => 4913600, "path" => "keep", "size" => 1),
- array("version" => 4852800, "path" => "delete", "size" => 1),
- array("version" => 4827201, "path" => "delete", "size" => 1),
- array("version" => 4827200, "path" => "keep", "size" => 1),
- array("version" => 4777201, "path" => "delete", "size" => 1),
- array("version" => 4777501, "path" => "delete", "size" => 1),
- array("version" => 4740000, "path" => "keep", "size" => 1),
- // final slice starts at 2408000 keep one version every 604800 secons
- array("version" => 2408000, "path" => "keep", "size" => 1),
- array("version" => 1803201, "path" => "delete", "size" => 1),
- array("version" => 1803200, "path" => "keep", "size" => 1),
- array("version" => 1800199, "path" => "delete", "size" => 1),
- array("version" => 1800100, "path" => "delete", "size" => 1),
- array("version" => 1198300, "path" => "keep", "size" => 1),
- ),
- 16 // size of all deleted files (every file has the size 1)
- ),
- // second set of versions, here we have only really old versions
- array(
- array(
- // first slice (10sec) keep one version every 2 seconds
- // next slice (60sec) starts at 4999990 keep one version every 10 secons
- // next slice (3600sec) start at 4999940 keep one version every 60 seconds
- // next slice (86400sec) start at 4996400 keep one version every 3600 seconds
- array("version" => 4996400, "path" => "keep", "size" => 1),
- array("version" => 4996350, "path" => "delete", "size" => 1),
- array("version" => 4996350, "path" => "delete", "size" => 1),
- array("version" => 4992800, "path" => "keep", "size" => 1),
- array("version" => 4989800, "path" => "delete", "size" => 1),
- array("version" => 4989700, "path" => "delete", "size" => 1),
- array("version" => 4989200, "path" => "keep", "size" => 1),
- // next slice (2592000sec) start at 4913600 keep one version every 86400 seconds
- array("version" => 4913600, "path" => "keep", "size" => 1),
- array("version" => 4852800, "path" => "delete", "size" => 1),
- array("version" => 4827201, "path" => "delete", "size" => 1),
- array("version" => 4827200, "path" => "keep", "size" => 1),
- array("version" => 4777201, "path" => "delete", "size" => 1),
- array("version" => 4777501, "path" => "delete", "size" => 1),
- array("version" => 4740000, "path" => "keep", "size" => 1),
- // final slice starts at 2408000 keep one version every 604800 secons
- array("version" => 2408000, "path" => "keep", "size" => 1),
- array("version" => 1803201, "path" => "delete", "size" => 1),
- array("version" => 1803200, "path" => "keep", "size" => 1),
- array("version" => 1800199, "path" => "delete", "size" => 1),
- array("version" => 1800100, "path" => "delete", "size" => 1),
- array("version" => 1198300, "path" => "keep", "size" => 1),
- ),
- 11 // size of all deleted files (every file has the size 1)
- ),
- // third set of versions, with some gaps inbetween
- array(
- array(
- // first slice (10sec) keep one version every 2 seconds
- array("version" => 4999999, "path" => "keep", "size" => 1),
- array("version" => 4999998, "path" => "delete", "size" => 1),
- array("version" => 4999997, "path" => "keep", "size" => 1),
- array("version" => 4999995, "path" => "keep", "size" => 1),
- array("version" => 4999994, "path" => "delete", "size" => 1),
- //next slice (60sec) starts at 4999990 keep one version every 10 secons
- array("version" => 4999988, "path" => "keep", "size" => 1),
- array("version" => 4999978, "path" => "keep", "size" => 1),
- //next slice (3600sec) start at 4999940 keep one version every 60 seconds
- // next slice (86400sec) start at 4996400 keep one version every 3600 seconds
- array("version" => 4989200, "path" => "keep", "size" => 1),
- // next slice (2592000sec) start at 4913600 keep one version every 86400 seconds
- array("version" => 4913600, "path" => "keep", "size" => 1),
- array("version" => 4852800, "path" => "delete", "size" => 1),
- array("version" => 4827201, "path" => "delete", "size" => 1),
- array("version" => 4827200, "path" => "keep", "size" => 1),
- array("version" => 4777201, "path" => "delete", "size" => 1),
- array("version" => 4777501, "path" => "delete", "size" => 1),
- array("version" => 4740000, "path" => "keep", "size" => 1),
- // final slice starts at 2408000 keep one version every 604800 secons
- array("version" => 2408000, "path" => "keep", "size" => 1),
- array("version" => 1803201, "path" => "delete", "size" => 1),
- array("version" => 1803200, "path" => "keep", "size" => 1),
- array("version" => 1800199, "path" => "delete", "size" => 1),
- array("version" => 1800100, "path" => "delete", "size" => 1),
- array("version" => 1198300, "path" => "keep", "size" => 1),
- ),
- 9 // size of all deleted files (every file has the size 1)
- ),
-
- );
- }
-
- public function testRename() {
-
- \OC\Files\Filesystem::file_put_contents("test.txt", "test file");
-
- $t1 = time();
- // second version is two weeks older, this way we make sure that no
- // version will be expired
- $t2 = $t1 - 60 * 60 * 24 * 14;
-
- // create some versions
- $v1 = self::USERS_VERSIONS_ROOT . '/test.txt.v' . $t1;
- $v2 = self::USERS_VERSIONS_ROOT . '/test.txt.v' . $t2;
- $v1Renamed = self::USERS_VERSIONS_ROOT . '/test2.txt.v' . $t1;
- $v2Renamed = self::USERS_VERSIONS_ROOT . '/test2.txt.v' . $t2;
-
- $this->rootView->file_put_contents($v1, 'version1');
- $this->rootView->file_put_contents($v2, 'version2');
-
- // execute rename hook of versions app
- \OC\Files\Filesystem::rename("test.txt", "test2.txt");
-
- $this->runCommands();
-
- $this->assertFalse($this->rootView->file_exists($v1));
- $this->assertFalse($this->rootView->file_exists($v2));
-
- $this->assertTrue($this->rootView->file_exists($v1Renamed));
- $this->assertTrue($this->rootView->file_exists($v2Renamed));
- }
-
- public function testRenameInSharedFolder() {
-
- \OC\Files\Filesystem::mkdir('folder1');
- \OC\Files\Filesystem::mkdir('folder1/folder2');
- \OC\Files\Filesystem::file_put_contents("folder1/test.txt", "test file");
-
- $fileInfo = \OC\Files\Filesystem::getFileInfo('folder1');
-
- $t1 = time();
- // second version is two weeks older, this way we make sure that no
- // version will be expired
- $t2 = $t1 - 60 * 60 * 24 * 14;
-
- $this->rootView->mkdir(self::USERS_VERSIONS_ROOT . '/folder1');
- // create some versions
- $v1 = self::USERS_VERSIONS_ROOT . '/folder1/test.txt.v' . $t1;
- $v2 = self::USERS_VERSIONS_ROOT . '/folder1/test.txt.v' . $t2;
- $v1Renamed = self::USERS_VERSIONS_ROOT . '/folder1/folder2/test.txt.v' . $t1;
- $v2Renamed = self::USERS_VERSIONS_ROOT . '/folder1/folder2/test.txt.v' . $t2;
-
- $this->rootView->file_put_contents($v1, 'version1');
- $this->rootView->file_put_contents($v2, 'version2');
-
- \OCP\Share::shareItem('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_VERSIONS_USER2, \OCP\Constants::PERMISSION_ALL);
-
- self::loginHelper(self::TEST_VERSIONS_USER2);
-
- $this->assertTrue(\OC\Files\Filesystem::file_exists('folder1/test.txt'));
-
- // execute rename hook of versions app
- \OC\Files\Filesystem::rename('/folder1/test.txt', '/folder1/folder2/test.txt');
-
- $this->runCommands();
-
- self::loginHelper(self::TEST_VERSIONS_USER);
-
- $this->assertFalse($this->rootView->file_exists($v1));
- $this->assertFalse($this->rootView->file_exists($v2));
-
- $this->assertTrue($this->rootView->file_exists($v1Renamed));
- $this->assertTrue($this->rootView->file_exists($v2Renamed));
- }
-
- public function testMoveFolder() {
-
- \OC\Files\Filesystem::mkdir('folder1');
- \OC\Files\Filesystem::mkdir('folder2');
- \OC\Files\Filesystem::file_put_contents('folder1/test.txt', 'test file');
-
- $t1 = time();
- // second version is two weeks older, this way we make sure that no
- // version will be expired
- $t2 = $t1 - 60 * 60 * 24 * 14;
-
- // create some versions
- $this->rootView->mkdir(self::USERS_VERSIONS_ROOT . '/folder1');
- $v1 = self::USERS_VERSIONS_ROOT . '/folder1/test.txt.v' . $t1;
- $v2 = self::USERS_VERSIONS_ROOT . '/folder1/test.txt.v' . $t2;
- $v1Renamed = self::USERS_VERSIONS_ROOT . '/folder2/folder1/test.txt.v' . $t1;
- $v2Renamed = self::USERS_VERSIONS_ROOT . '/folder2/folder1/test.txt.v' . $t2;
-
- $this->rootView->file_put_contents($v1, 'version1');
- $this->rootView->file_put_contents($v2, 'version2');
-
- // execute rename hook of versions app
- \OC\Files\Filesystem::rename('folder1', 'folder2/folder1');
-
- $this->runCommands();
-
- $this->assertFalse($this->rootView->file_exists($v1));
- $this->assertFalse($this->rootView->file_exists($v2));
-
- $this->assertTrue($this->rootView->file_exists($v1Renamed));
- $this->assertTrue($this->rootView->file_exists($v2Renamed));
- }
-
-
- public function testMoveFileIntoSharedFolderAsRecipient() {
-
- \OC\Files\Filesystem::mkdir('folder1');
- $fileInfo = \OC\Files\Filesystem::getFileInfo('folder1');
-
- \OCP\Share::shareItem(
- 'folder',
- $fileInfo['fileid'],
- \OCP\Share::SHARE_TYPE_USER,
- self::TEST_VERSIONS_USER2,
- \OCP\Constants::PERMISSION_ALL
- );
-
- self::loginHelper(self::TEST_VERSIONS_USER2);
- $versionsFolder2 = '/' . self::TEST_VERSIONS_USER2 . '/files_versions';
- \OC\Files\Filesystem::file_put_contents('test.txt', 'test file');
-
- $t1 = time();
- // second version is two weeks older, this way we make sure that no
- // version will be expired
- $t2 = $t1 - 60 * 60 * 24 * 14;
-
- $this->rootView->mkdir($versionsFolder2);
- // create some versions
- $v1 = $versionsFolder2 . '/test.txt.v' . $t1;
- $v2 = $versionsFolder2 . '/test.txt.v' . $t2;
-
- $this->rootView->file_put_contents($v1, 'version1');
- $this->rootView->file_put_contents($v2, 'version2');
-
- // move file into the shared folder as recipient
- \OC\Files\Filesystem::rename('/test.txt', '/folder1/test.txt');
-
- $this->assertFalse($this->rootView->file_exists($v1));
- $this->assertFalse($this->rootView->file_exists($v2));
-
- self::loginHelper(self::TEST_VERSIONS_USER);
-
- $versionsFolder1 = '/' . self::TEST_VERSIONS_USER . '/files_versions';
-
- $v1Renamed = $versionsFolder1 . '/folder1/test.txt.v' . $t1;
- $v2Renamed = $versionsFolder1 . '/folder1/test.txt.v' . $t2;
-
- $this->assertTrue($this->rootView->file_exists($v1Renamed));
- $this->assertTrue($this->rootView->file_exists($v2Renamed));
- }
-
- public function testMoveFolderIntoSharedFolderAsRecipient() {
-
- \OC\Files\Filesystem::mkdir('folder1');
- $fileInfo = \OC\Files\Filesystem::getFileInfo('folder1');
-
- \OCP\Share::shareItem(
- 'folder',
- $fileInfo['fileid'],
- \OCP\Share::SHARE_TYPE_USER,
- self::TEST_VERSIONS_USER2,
- \OCP\Constants::PERMISSION_ALL
- );
-
- self::loginHelper(self::TEST_VERSIONS_USER2);
- $versionsFolder2 = '/' . self::TEST_VERSIONS_USER2 . '/files_versions';
- \OC\Files\Filesystem::mkdir('folder2');
- \OC\Files\Filesystem::file_put_contents('folder2/test.txt', 'test file');
-
- $t1 = time();
- // second version is two weeks older, this way we make sure that no
- // version will be expired
- $t2 = $t1 - 60 * 60 * 24 * 14;
-
- $this->rootView->mkdir($versionsFolder2);
- $this->rootView->mkdir($versionsFolder2 . '/folder2');
- // create some versions
- $v1 = $versionsFolder2 . '/folder2/test.txt.v' . $t1;
- $v2 = $versionsFolder2 . '/folder2/test.txt.v' . $t2;
-
- $this->rootView->file_put_contents($v1, 'version1');
- $this->rootView->file_put_contents($v2, 'version2');
-
- // move file into the shared folder as recipient
- \OC\Files\Filesystem::rename('/folder2', '/folder1/folder2');
-
- $this->assertFalse($this->rootView->file_exists($v1));
- $this->assertFalse($this->rootView->file_exists($v2));
-
- self::loginHelper(self::TEST_VERSIONS_USER);
-
- $versionsFolder1 = '/' . self::TEST_VERSIONS_USER . '/files_versions';
-
- $v1Renamed = $versionsFolder1 . '/folder1/folder2/test.txt.v' . $t1;
- $v2Renamed = $versionsFolder1 . '/folder1/folder2/test.txt.v' . $t2;
-
- $this->assertTrue($this->rootView->file_exists($v1Renamed));
- $this->assertTrue($this->rootView->file_exists($v2Renamed));
- }
-
- public function testRenameSharedFile() {
-
- \OC\Files\Filesystem::file_put_contents("test.txt", "test file");
-
- $fileInfo = \OC\Files\Filesystem::getFileInfo('test.txt');
-
- $t1 = time();
- // second version is two weeks older, this way we make sure that no
- // version will be expired
- $t2 = $t1 - 60 * 60 * 24 * 14;
-
- $this->rootView->mkdir(self::USERS_VERSIONS_ROOT);
- // create some versions
- $v1 = self::USERS_VERSIONS_ROOT . '/test.txt.v' . $t1;
- $v2 = self::USERS_VERSIONS_ROOT . '/test.txt.v' . $t2;
- // the renamed versions should not exist! Because we only moved the mount point!
- $v1Renamed = self::USERS_VERSIONS_ROOT . '/test2.txt.v' . $t1;
- $v2Renamed = self::USERS_VERSIONS_ROOT . '/test2.txt.v' . $t2;
-
- $this->rootView->file_put_contents($v1, 'version1');
- $this->rootView->file_put_contents($v2, 'version2');
-
- \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_VERSIONS_USER2, \OCP\Constants::PERMISSION_ALL);
-
- self::loginHelper(self::TEST_VERSIONS_USER2);
-
- $this->assertTrue(\OC\Files\Filesystem::file_exists('test.txt'));
-
- // execute rename hook of versions app
- \OC\Files\Filesystem::rename('test.txt', 'test2.txt');
-
- self::loginHelper(self::TEST_VERSIONS_USER);
-
- $this->runCommands();
-
- $this->assertTrue($this->rootView->file_exists($v1));
- $this->assertTrue($this->rootView->file_exists($v2));
-
- $this->assertFalse($this->rootView->file_exists($v1Renamed));
- $this->assertFalse($this->rootView->file_exists($v2Renamed));
- }
-
- public function testCopy() {
-
- \OC\Files\Filesystem::file_put_contents("test.txt", "test file");
-
- $t1 = time();
- // second version is two weeks older, this way we make sure that no
- // version will be expired
- $t2 = $t1 - 60 * 60 * 24 * 14;
-
- // create some versions
- $v1 = self::USERS_VERSIONS_ROOT . '/test.txt.v' . $t1;
- $v2 = self::USERS_VERSIONS_ROOT . '/test.txt.v' . $t2;
- $v1Copied = self::USERS_VERSIONS_ROOT . '/test2.txt.v' . $t1;
- $v2Copied = self::USERS_VERSIONS_ROOT . '/test2.txt.v' . $t2;
-
- $this->rootView->file_put_contents($v1, 'version1');
- $this->rootView->file_put_contents($v2, 'version2');
-
- // execute copy hook of versions app
- \OC\Files\Filesystem::copy("test.txt", "test2.txt");
-
- $this->runCommands();
-
- $this->assertTrue($this->rootView->file_exists($v1));
- $this->assertTrue($this->rootView->file_exists($v2));
-
- $this->assertTrue($this->rootView->file_exists($v1Copied));
- $this->assertTrue($this->rootView->file_exists($v2Copied));
- }
-
- /**
- * test if we find all versions and if the versions array contain
- * the correct 'path' and 'name'
- */
- public function testGetVersions() {
-
- $t1 = time();
- // second version is two weeks older, this way we make sure that no
- // version will be expired
- $t2 = $t1 - 60 * 60 * 24 * 14;
-
- // create some versions
- $v1 = self::USERS_VERSIONS_ROOT . '/subfolder/test.txt.v' . $t1;
- $v2 = self::USERS_VERSIONS_ROOT . '/subfolder/test.txt.v' . $t2;
-
- $this->rootView->mkdir(self::USERS_VERSIONS_ROOT . '/subfolder/');
-
- $this->rootView->file_put_contents($v1, 'version1');
- $this->rootView->file_put_contents($v2, 'version2');
-
- // execute copy hook of versions app
- $versions = \OCA\Files_Versions\Storage::getVersions(self::TEST_VERSIONS_USER, '/subfolder/test.txt');
-
- $this->assertCount(2, $versions);
-
- foreach ($versions as $version) {
- $this->assertSame('/subfolder/test.txt', $version['path']);
- $this->assertSame('test.txt', $version['name']);
- }
-
- //cleanup
- $this->rootView->deleteAll(self::USERS_VERSIONS_ROOT . '/subfolder');
- }
-
- /**
- * test if we find all versions and if the versions array contain
- * the correct 'path' and 'name'
- */
- public function testGetVersionsEmptyFile() {
- // execute copy hook of versions app
- $versions = \OCA\Files_Versions\Storage::getVersions(self::TEST_VERSIONS_USER, '');
- $this->assertCount(0, $versions);
-
- $versions = \OCA\Files_Versions\Storage::getVersions(self::TEST_VERSIONS_USER, null);
- $this->assertCount(0, $versions);
- }
-
- public function testExpireNonexistingFile() {
- $this->logout();
- // needed to have a FS setup (the background job does this)
- \OC_Util::setupFS(self::TEST_VERSIONS_USER);
-
- $this->assertFalse(\OCA\Files_Versions\Storage::expire('/void/unexist.txt'));
- }
-
- public function testRestoreSameStorage() {
- \OC\Files\Filesystem::mkdir('sub');
- $this->doTestRestore();
- }
-
- public function testRestoreCrossStorage() {
- $storage2 = new Temporary(array());
- \OC\Files\Filesystem::mount($storage2, array(), self::TEST_VERSIONS_USER . '/files/sub');
-
- $this->doTestRestore();
- }
-
- /**
- * @param string $hookName name of hook called
- * @param string $params variable to recieve parameters provided by hook
- */
- private function connectMockHooks($hookName, &$params) {
- if ($hookName === null) {
- return;
- }
-
- $eventHandler = $this->getMockBuilder('\stdclass')
- ->setMethods(['callback'])
- ->getMock();
-
- $eventHandler->expects($this->any())
- ->method('callback')
- ->will($this->returnCallback(
- function($p) use (&$params) {
- $params = $p;
- }
- ));
-
- \OCP\Util::connectHook(
- '\OCP\Versions',
- $hookName,
- $eventHandler,
- 'callback'
- );
- }
-
- private function doTestRestore() {
- $filePath = self::TEST_VERSIONS_USER . '/files/sub/test.txt';
- $this->rootView->file_put_contents($filePath, 'test file');
-
- $t0 = $this->rootView->filemtime($filePath);
-
- // not exactly the same timestamp as the file
- $t1 = time() - 60;
- // second version is two weeks older
- $t2 = $t1 - 60 * 60 * 24 * 14;
-
- // create some versions
- $v1 = self::USERS_VERSIONS_ROOT . '/sub/test.txt.v' . $t1;
- $v2 = self::USERS_VERSIONS_ROOT . '/sub/test.txt.v' . $t2;
-
- $this->rootView->mkdir(self::USERS_VERSIONS_ROOT . '/sub');
- $this->rootView->file_put_contents($v1, 'version1');
- $this->rootView->file_put_contents($v2, 'version2');
-
- $oldVersions = \OCA\Files_Versions\Storage::getVersions(
- self::TEST_VERSIONS_USER, '/sub/test.txt'
- );
-
- $this->assertCount(2, $oldVersions);
-
- $this->assertEquals('test file', $this->rootView->file_get_contents($filePath));
- $info1 = $this->rootView->getFileInfo($filePath);
-
- $params = array();
- $this->connectMockHooks('rollback', $params);
-
- \OCA\Files_Versions\Storage::rollback('sub/test.txt', $t2);
- $expectedParams = array(
- 'path' => '/sub/test.txt',
- );
-
- $this->assertEquals($expectedParams['path'], $params['path']);
- $this->assertTrue(array_key_exists('revision', $params));
- $this->assertTrue($params['revision'] > 0);
-
- $this->assertEquals('version2', $this->rootView->file_get_contents($filePath));
- $info2 = $this->rootView->getFileInfo($filePath);
-
- $this->assertNotEquals(
- $info2['etag'],
- $info1['etag'],
- 'Etag must change after rolling back version'
- );
- $this->assertEquals(
- $info2['fileid'],
- $info1['fileid'],
- 'File id must not change after rolling back version'
- );
- $this->assertEquals(
- $info2['mtime'],
- $t2,
- 'Restored file has mtime from version'
- );
-
- $newVersions = \OCA\Files_Versions\Storage::getVersions(
- self::TEST_VERSIONS_USER, '/sub/test.txt'
- );
-
- $this->assertTrue(
- $this->rootView->file_exists(self::USERS_VERSIONS_ROOT . '/sub/test.txt.v' . $t0),
- 'A version file was created for the file before restoration'
- );
- $this->assertTrue(
- $this->rootView->file_exists($v1),
- 'Untouched version file is still there'
- );
- $this->assertFalse(
- $this->rootView->file_exists($v2),
- 'Restored version file gone from files_version folder'
- );
-
- $this->assertCount(2, $newVersions, 'Additional version created');
-
- $this->assertTrue(
- isset($newVersions[$t0 . '#' . 'test.txt']),
- 'A version was created for the file before restoration'
- );
- $this->assertTrue(
- isset($newVersions[$t1 . '#' . 'test.txt']),
- 'Untouched version is still there'
- );
- $this->assertFalse(
- isset($newVersions[$t2 . '#' . 'test.txt']),
- 'Restored version is not in the list any more'
- );
- }
-
- /**
- * Test whether versions are created when overwriting as owner
- */
- public function testStoreVersionAsOwner() {
- $this->loginAsUser(self::TEST_VERSIONS_USER);
-
- $this->createAndCheckVersions(
- \OC\Files\Filesystem::getView(),
- 'test.txt'
- );
- }
-
- /**
- * Test whether versions are created when overwriting as share recipient
- */
- public function testStoreVersionAsRecipient() {
- $this->loginAsUser(self::TEST_VERSIONS_USER);
-
- \OC\Files\Filesystem::mkdir('folder');
- \OC\Files\Filesystem::file_put_contents('folder/test.txt', 'test file');
- $fileInfo = \OC\Files\Filesystem::getFileInfo('folder');
-
- \OCP\Share::shareItem(
- 'folder',
- $fileInfo['fileid'],
- \OCP\Share::SHARE_TYPE_USER,
- self::TEST_VERSIONS_USER2,
- \OCP\Constants::PERMISSION_ALL
- );
-
- $this->loginAsUser(self::TEST_VERSIONS_USER2);
-
- $this->createAndCheckVersions(
- \OC\Files\Filesystem::getView(),
- 'folder/test.txt'
- );
- }
-
- /**
- * Test whether versions are created when overwriting anonymously.
- *
- * When uploading through a public link or publicwebdav, no user
- * is logged in. File modification must still be able to find
- * the owner and create versions.
- */
- public function testStoreVersionAsAnonymous() {
- $this->logout();
-
- // note: public link upload does this,
- // needed to make the hooks fire
- \OC_Util::setupFS(self::TEST_VERSIONS_USER);
-
- $userView = new \OC\Files\View('/' . self::TEST_VERSIONS_USER . '/files');
- $this->createAndCheckVersions(
- $userView,
- 'test.txt'
- );
- }
-
- /**
- * @param \OC\Files\View $view
- * @param string $path
- */
- private function createAndCheckVersions(\OC\Files\View $view, $path) {
- $view->file_put_contents($path, 'test file');
- $view->file_put_contents($path, 'version 1');
- $view->file_put_contents($path, 'version 2');
-
- $this->loginAsUser(self::TEST_VERSIONS_USER);
-
- // need to scan for the versions
- list($rootStorage,) = $this->rootView->resolvePath(self::TEST_VERSIONS_USER . '/files_versions');
- $rootStorage->getScanner()->scan('files_versions');
-
- $versions = \OCA\Files_Versions\Storage::getVersions(
- self::TEST_VERSIONS_USER, '/' . $path
- );
-
- // note: we cannot predict how many versions are created due to
- // test run timing
- $this->assertGreaterThan(0, count($versions));
- }
-
- /**
- * @param string $user
- * @param bool $create
- */
- public static function loginHelper($user, $create = false) {
-
- if ($create) {
- $backend = new \Test\Util\User\Dummy();
- $backend->createUser($user, $user);
- \OC::$server->getUserManager()->registerBackend($backend);
- }
-
- $storage = new \ReflectionClass('\OC\Files\Storage\Shared');
- $isInitialized = $storage->getProperty('initialized');
- $isInitialized->setAccessible(true);
- $isInitialized->setValue($storage, false);
- $isInitialized->setAccessible(false);
-
- \OC_Util::tearDownFS();
- \OC_User::setUserId('');
- \OC\Files\Filesystem::tearDown();
- \OC_User::setUserId($user);
- \OC_Util::setupFS($user);
- \OC::$server->getUserFolder($user);
- }
-
-}
-
-// extend the original class to make it possible to test protected methods
-class VersionStorageToTest extends \OCA\Files_Versions\Storage {
-
- /**
- * @param integer $time
- */
- public function callProtectedGetExpireList($time, $versions) {
- return self::getExpireList($time, $versions);
-
- }
-}