TrashbinTest.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Björn Schießle <bjoern@schiessle.org>
  6. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  7. * @author Joas Schilling <coding@schilljs.com>
  8. * @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
  9. * @author Morris Jobke <hey@morrisjobke.de>
  10. * @author Robin Appelman <robin@icewind.nl>
  11. * @author Roeland Jago Douma <roeland@famdouma.nl>
  12. * @author Thomas Müller <thomas.mueller@tmit.eu>
  13. * @author Tobia De Koninck <tobia@ledfan.be>
  14. * @author Vincent Petry <pvince81@owncloud.com>
  15. *
  16. * @license AGPL-3.0
  17. *
  18. * This code is free software: you can redistribute it and/or modify
  19. * it under the terms of the GNU Affero General Public License, version 3,
  20. * as published by the Free Software Foundation.
  21. *
  22. * This program is distributed in the hope that it will be useful,
  23. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25. * GNU Affero General Public License for more details.
  26. *
  27. * You should have received a copy of the GNU Affero General Public License, version 3,
  28. * along with this program. If not, see <http://www.gnu.org/licenses/>
  29. *
  30. */
  31. use OCA\Files_Sharing\AppInfo\Application;
  32. /**
  33. * Class Test_Encryption
  34. *
  35. * @group DB
  36. */
  37. class TrashbinTest extends \Test\TestCase {
  38. public const TEST_TRASHBIN_USER1 = "test-trashbin-user1";
  39. public const TEST_TRASHBIN_USER2 = "test-trashbin-user2";
  40. private $trashRoot1;
  41. private $trashRoot2;
  42. private static $rememberRetentionObligation;
  43. /**
  44. * @var bool
  45. */
  46. private static $trashBinStatus;
  47. /**
  48. * @var \OC\Files\View
  49. */
  50. private $rootView;
  51. public static function setUpBeforeClass(): void {
  52. parent::setUpBeforeClass();
  53. $appManager = \OC::$server->getAppManager();
  54. self::$trashBinStatus = $appManager->isEnabledForUser('files_trashbin');
  55. // reset backend
  56. \OC_User::clearBackends();
  57. \OC_User::useBackend('database');
  58. // clear share hooks
  59. \OC_Hook::clear('OCP\\Share');
  60. \OC::registerShareHooks();
  61. // init files sharing
  62. new Application();
  63. //disable encryption
  64. \OC::$server->getAppManager()->disableApp('encryption');
  65. $config = \OC::$server->getConfig();
  66. //configure trashbin
  67. self::$rememberRetentionObligation = $config->getSystemValue('trashbin_retention_obligation', \OCA\Files_Trashbin\Expiration::DEFAULT_RETENTION_OBLIGATION);
  68. /** @var \OCA\Files_Trashbin\Expiration $expiration */
  69. $expiration = \OC::$server->query(\OCA\Files_Trashbin\Expiration::class);
  70. $expiration->setRetentionObligation('auto, 2');
  71. // register hooks
  72. \OCA\Files_Trashbin\Trashbin::registerHooks();
  73. // create test user
  74. self::loginHelper(self::TEST_TRASHBIN_USER2, true);
  75. self::loginHelper(self::TEST_TRASHBIN_USER1, true);
  76. }
  77. public static function tearDownAfterClass(): void {
  78. // cleanup test user
  79. $user = \OC::$server->getUserManager()->get(self::TEST_TRASHBIN_USER1);
  80. if ($user !== null) {
  81. $user->delete();
  82. }
  83. /** @var \OCA\Files_Trashbin\Expiration $expiration */
  84. $expiration = \OC::$server->query(\OCA\Files_Trashbin\Expiration::class);
  85. $expiration->setRetentionObligation(self::$rememberRetentionObligation);
  86. \OC_Hook::clear();
  87. \OC\Files\Filesystem::getLoader()->removeStorageWrapper('oc_trashbin');
  88. if (self::$trashBinStatus) {
  89. \OC::$server->getAppManager()->enableApp('files_trashbin');
  90. }
  91. parent::tearDownAfterClass();
  92. }
  93. protected function setUp(): void {
  94. parent::setUp();
  95. \OC::$server->getAppManager()->enableApp('files_trashbin');
  96. $config = \OC::$server->getConfig();
  97. $mockConfig = $this->createMock(\OCP\IConfig::class);
  98. $mockConfig->expects($this->any())
  99. ->method('getSystemValue')
  100. ->willReturnCallback(function ($key, $default) use ($config) {
  101. if ($key === 'filesystem_check_changes') {
  102. return \OC\Files\Cache\Watcher::CHECK_ONCE;
  103. } else {
  104. return $config->getSystemValue($key, $default);
  105. }
  106. });
  107. $this->overwriteService(\OC\AllConfig::class, $mockConfig);
  108. $this->trashRoot1 = '/' . self::TEST_TRASHBIN_USER1 . '/files_trashbin';
  109. $this->trashRoot2 = '/' . self::TEST_TRASHBIN_USER2 . '/files_trashbin';
  110. $this->rootView = new \OC\Files\View();
  111. self::loginHelper(self::TEST_TRASHBIN_USER1);
  112. }
  113. protected function tearDown(): void {
  114. $this->restoreService(\OC\AllConfig::class);
  115. // disable trashbin to be able to properly clean up
  116. \OC::$server->getAppManager()->disableApp('files_trashbin');
  117. $this->rootView->deleteAll('/' . self::TEST_TRASHBIN_USER1 . '/files');
  118. $this->rootView->deleteAll('/' . self::TEST_TRASHBIN_USER2 . '/files');
  119. $this->rootView->deleteAll($this->trashRoot1);
  120. $this->rootView->deleteAll($this->trashRoot2);
  121. // clear trash table
  122. $connection = \OC::$server->getDatabaseConnection();
  123. $connection->executeUpdate('DELETE FROM `*PREFIX*files_trash`');
  124. parent::tearDown();
  125. }
  126. /**
  127. * test expiration of files older then the max storage time defined for the trash
  128. */
  129. public function testExpireOldFiles() {
  130. /** @var \OCP\AppFramework\Utility\ITimeFactory $time */
  131. $time = \OC::$server->query(\OCP\AppFramework\Utility\ITimeFactory::class);
  132. $currentTime = $time->getTime();
  133. $expireAt = $currentTime - 2 * 24 * 60 * 60;
  134. $expiredDate = $currentTime - 3 * 24 * 60 * 60;
  135. // create some files
  136. \OC\Files\Filesystem::file_put_contents('file1.txt', 'file1');
  137. \OC\Files\Filesystem::file_put_contents('file2.txt', 'file2');
  138. \OC\Files\Filesystem::file_put_contents('file3.txt', 'file3');
  139. // delete them so that they end up in the trash bin
  140. \OC\Files\Filesystem::unlink('file1.txt');
  141. \OC\Files\Filesystem::unlink('file2.txt');
  142. \OC\Files\Filesystem::unlink('file3.txt');
  143. //make sure that files are in the trash bin
  144. $filesInTrash = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1, 'name');
  145. $this->assertSame(3, count($filesInTrash));
  146. // every second file will get a date in the past so that it will get expired
  147. $manipulatedList = $this->manipulateDeleteTime($filesInTrash, $this->trashRoot1, $expiredDate);
  148. $testClass = new TrashbinForTesting();
  149. list($sizeOfDeletedFiles, $count) = $testClass->dummyDeleteExpiredFiles($manipulatedList, $expireAt);
  150. $this->assertSame(10, $sizeOfDeletedFiles);
  151. $this->assertSame(2, $count);
  152. // only file2.txt should be left
  153. $remainingFiles = array_slice($manipulatedList, $count);
  154. $this->assertSame(1, count($remainingFiles));
  155. $remainingFile = reset($remainingFiles);
  156. // TODO: failing test
  157. #$this->assertSame('file2.txt', $remainingFile['name']);
  158. // check that file1.txt and file3.txt was really deleted
  159. $newTrashContent = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1);
  160. $this->assertSame(1, count($newTrashContent));
  161. $element = reset($newTrashContent);
  162. // TODO: failing test
  163. #$this->assertSame('file2.txt', $element['name']);
  164. }
  165. /**
  166. * test expiration of files older then the max storage time defined for the trash
  167. * in this test we delete a shared file and check if both trash bins, the one from
  168. * the owner of the file and the one from the user who deleted the file get expired
  169. * correctly
  170. */
  171. public function testExpireOldFilesShared() {
  172. $currentTime = time();
  173. $folder = "trashTest-" . $currentTime . '/';
  174. $expiredDate = $currentTime - 3 * 24 * 60 * 60;
  175. // create some files
  176. \OC\Files\Filesystem::mkdir($folder);
  177. \OC\Files\Filesystem::file_put_contents($folder . 'user1-1.txt', 'file1');
  178. \OC\Files\Filesystem::file_put_contents($folder . 'user1-2.txt', 'file2');
  179. \OC\Files\Filesystem::file_put_contents($folder . 'user1-3.txt', 'file3');
  180. \OC\Files\Filesystem::file_put_contents($folder . 'user1-4.txt', 'file4');
  181. //share user1-4.txt with user2
  182. $node = \OC::$server->getUserFolder(self::TEST_TRASHBIN_USER1)->get($folder);
  183. $share = \OC::$server->getShareManager()->newShare();
  184. $share->setShareType(\OCP\Share::SHARE_TYPE_USER)
  185. ->setNode($node)
  186. ->setSharedBy(self::TEST_TRASHBIN_USER1)
  187. ->setSharedWith(self::TEST_TRASHBIN_USER2)
  188. ->setPermissions(\OCP\Constants::PERMISSION_ALL);
  189. $share = \OC::$server->getShareManager()->createShare($share);
  190. \OC::$server->getShareManager()->acceptShare($share, self::TEST_TRASHBIN_USER2);
  191. // delete them so that they end up in the trash bin
  192. \OC\Files\Filesystem::unlink($folder . 'user1-1.txt');
  193. \OC\Files\Filesystem::unlink($folder . 'user1-2.txt');
  194. \OC\Files\Filesystem::unlink($folder . 'user1-3.txt');
  195. $filesInTrash = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1, 'name');
  196. $this->assertSame(3, count($filesInTrash));
  197. // every second file will get a date in the past so that it will get expired
  198. $this->manipulateDeleteTime($filesInTrash, $this->trashRoot1, $expiredDate);
  199. // login as user2
  200. self::loginHelper(self::TEST_TRASHBIN_USER2);
  201. $this->assertTrue(\OC\Files\Filesystem::file_exists($folder . "user1-4.txt"));
  202. // create some files
  203. \OC\Files\Filesystem::file_put_contents('user2-1.txt', 'file1');
  204. \OC\Files\Filesystem::file_put_contents('user2-2.txt', 'file2');
  205. // delete them so that they end up in the trash bin
  206. \OC\Files\Filesystem::unlink('user2-1.txt');
  207. \OC\Files\Filesystem::unlink('user2-2.txt');
  208. $filesInTrashUser2 = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER2, 'name');
  209. $this->assertSame(2, count($filesInTrashUser2));
  210. // every second file will get a date in the past so that it will get expired
  211. $this->manipulateDeleteTime($filesInTrashUser2, $this->trashRoot2, $expiredDate);
  212. \OC\Files\Filesystem::unlink($folder . 'user1-4.txt');
  213. $this->runCommands();
  214. $filesInTrashUser2AfterDelete = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER2);
  215. // user2-1.txt should have been expired
  216. $this->verifyArray($filesInTrashUser2AfterDelete, ['user2-2.txt', 'user1-4.txt']);
  217. self::loginHelper(self::TEST_TRASHBIN_USER1);
  218. // user1-1.txt and user1-3.txt should have been expired
  219. $filesInTrashUser1AfterDelete = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1);
  220. $this->verifyArray($filesInTrashUser1AfterDelete, ['user1-2.txt', 'user1-4.txt']);
  221. }
  222. /**
  223. * verify that the array contains the expected results
  224. *
  225. * @param OCP\Files\FileInfo[] $result
  226. * @param string[] $expected
  227. */
  228. private function verifyArray($result, $expected) {
  229. $this->assertSame(count($expected), count($result));
  230. foreach ($expected as $expectedFile) {
  231. $found = false;
  232. foreach ($result as $fileInTrash) {
  233. if ($expectedFile === $fileInTrash['name']) {
  234. $found = true;
  235. break;
  236. }
  237. }
  238. if (!$found) {
  239. // if we didn't found the expected file, something went wrong
  240. $this->assertTrue(false, "can't find expected file '" . $expectedFile . "' in trash bin");
  241. }
  242. }
  243. }
  244. /**
  245. * @param OCP\Files\FileInfo[] $files
  246. * @param string $trashRoot
  247. * @param integer $expireDate
  248. */
  249. private function manipulateDeleteTime($files, $trashRoot, $expireDate) {
  250. $counter = 0;
  251. foreach ($files as &$file) {
  252. // modify every second file
  253. $counter = ($counter + 1) % 2;
  254. if ($counter === 1) {
  255. $source = $trashRoot . '/files/' . $file['name'] . '.d' . $file['mtime'];
  256. $target = \OC\Files\Filesystem::normalizePath($trashRoot . '/files/' . $file['name'] . '.d' . $expireDate);
  257. $this->rootView->rename($source, $target);
  258. $file['mtime'] = $expireDate;
  259. }
  260. }
  261. return \OCA\Files\Helper::sortFiles($files, 'mtime');
  262. }
  263. /**
  264. * test expiration of old files in the trash bin until the max size
  265. * of the trash bin is met again
  266. */
  267. public function testExpireOldFilesUtilLimitsAreMet() {
  268. // create some files
  269. \OC\Files\Filesystem::file_put_contents('file1.txt', 'file1');
  270. \OC\Files\Filesystem::file_put_contents('file2.txt', 'file2');
  271. \OC\Files\Filesystem::file_put_contents('file3.txt', 'file3');
  272. // delete them so that they end up in the trash bin
  273. \OC\Files\Filesystem::unlink('file3.txt');
  274. sleep(1); // make sure that every file has a unique mtime
  275. \OC\Files\Filesystem::unlink('file2.txt');
  276. sleep(1); // make sure that every file has a unique mtime
  277. \OC\Files\Filesystem::unlink('file1.txt');
  278. //make sure that files are in the trash bin
  279. $filesInTrash = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1, 'mtime');
  280. $this->assertSame(3, count($filesInTrash));
  281. $testClass = new TrashbinForTesting();
  282. $sizeOfDeletedFiles = $testClass->dummyDeleteFiles($filesInTrash, -8);
  283. // the two oldest files (file3.txt and file2.txt) should be deleted
  284. $this->assertSame(10, $sizeOfDeletedFiles);
  285. $newTrashContent = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1);
  286. $this->assertSame(1, count($newTrashContent));
  287. $element = reset($newTrashContent);
  288. $this->assertSame('file1.txt', $element['name']);
  289. }
  290. /**
  291. * Test restoring a file
  292. */
  293. public function testRestoreFileInRoot() {
  294. $userFolder = \OC::$server->getUserFolder();
  295. $file = $userFolder->newFile('file1.txt');
  296. $file->putContent('foo');
  297. $this->assertTrue($userFolder->nodeExists('file1.txt'));
  298. $file->delete();
  299. $this->assertFalse($userFolder->nodeExists('file1.txt'));
  300. $filesInTrash = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1, 'mtime');
  301. $this->assertCount(1, $filesInTrash);
  302. /** @var \OCP\Files\FileInfo */
  303. $trashedFile = $filesInTrash[0];
  304. $this->assertTrue(
  305. OCA\Files_Trashbin\Trashbin::restore(
  306. 'file1.txt.d' . $trashedFile->getMtime(),
  307. $trashedFile->getName(),
  308. $trashedFile->getMtime()
  309. )
  310. );
  311. $file = $userFolder->get('file1.txt');
  312. $this->assertEquals('foo', $file->getContent());
  313. }
  314. /**
  315. * Test restoring a file in subfolder
  316. */
  317. public function testRestoreFileInSubfolder() {
  318. $userFolder = \OC::$server->getUserFolder();
  319. $folder = $userFolder->newFolder('folder');
  320. $file = $folder->newFile('file1.txt');
  321. $file->putContent('foo');
  322. $this->assertTrue($userFolder->nodeExists('folder/file1.txt'));
  323. $file->delete();
  324. $this->assertFalse($userFolder->nodeExists('folder/file1.txt'));
  325. $filesInTrash = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1, 'mtime');
  326. $this->assertCount(1, $filesInTrash);
  327. /** @var \OCP\Files\FileInfo */
  328. $trashedFile = $filesInTrash[0];
  329. $this->assertTrue(
  330. OCA\Files_Trashbin\Trashbin::restore(
  331. 'file1.txt.d' . $trashedFile->getMtime(),
  332. $trashedFile->getName(),
  333. $trashedFile->getMtime()
  334. )
  335. );
  336. $file = $userFolder->get('folder/file1.txt');
  337. $this->assertEquals('foo', $file->getContent());
  338. }
  339. /**
  340. * Test restoring a folder
  341. */
  342. public function testRestoreFolder() {
  343. $userFolder = \OC::$server->getUserFolder();
  344. $folder = $userFolder->newFolder('folder');
  345. $file = $folder->newFile('file1.txt');
  346. $file->putContent('foo');
  347. $this->assertTrue($userFolder->nodeExists('folder'));
  348. $folder->delete();
  349. $this->assertFalse($userFolder->nodeExists('folder'));
  350. $filesInTrash = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1, 'mtime');
  351. $this->assertCount(1, $filesInTrash);
  352. /** @var \OCP\Files\FileInfo */
  353. $trashedFolder = $filesInTrash[0];
  354. $this->assertTrue(
  355. OCA\Files_Trashbin\Trashbin::restore(
  356. 'folder.d' . $trashedFolder->getMtime(),
  357. $trashedFolder->getName(),
  358. $trashedFolder->getMtime()
  359. )
  360. );
  361. $file = $userFolder->get('folder/file1.txt');
  362. $this->assertEquals('foo', $file->getContent());
  363. }
  364. /**
  365. * Test restoring a file from inside a trashed folder
  366. */
  367. public function testRestoreFileFromTrashedSubfolder() {
  368. $userFolder = \OC::$server->getUserFolder();
  369. $folder = $userFolder->newFolder('folder');
  370. $file = $folder->newFile('file1.txt');
  371. $file->putContent('foo');
  372. $this->assertTrue($userFolder->nodeExists('folder'));
  373. $folder->delete();
  374. $this->assertFalse($userFolder->nodeExists('folder'));
  375. $filesInTrash = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1, 'mtime');
  376. $this->assertCount(1, $filesInTrash);
  377. /** @var \OCP\Files\FileInfo */
  378. $trashedFile = $filesInTrash[0];
  379. $this->assertTrue(
  380. OCA\Files_Trashbin\Trashbin::restore(
  381. 'folder.d' . $trashedFile->getMtime() . '/file1.txt',
  382. 'file1.txt',
  383. $trashedFile->getMtime()
  384. )
  385. );
  386. $file = $userFolder->get('file1.txt');
  387. $this->assertEquals('foo', $file->getContent());
  388. }
  389. /**
  390. * Test restoring a file whenever the source folder was removed.
  391. * The file should then land in the root.
  392. */
  393. public function testRestoreFileWithMissingSourceFolder() {
  394. $userFolder = \OC::$server->getUserFolder();
  395. $folder = $userFolder->newFolder('folder');
  396. $file = $folder->newFile('file1.txt');
  397. $file->putContent('foo');
  398. $this->assertTrue($userFolder->nodeExists('folder/file1.txt'));
  399. $file->delete();
  400. $this->assertFalse($userFolder->nodeExists('folder/file1.txt'));
  401. $filesInTrash = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1, 'mtime');
  402. $this->assertCount(1, $filesInTrash);
  403. /** @var \OCP\Files\FileInfo */
  404. $trashedFile = $filesInTrash[0];
  405. // delete source folder
  406. $folder->delete();
  407. $this->assertTrue(
  408. OCA\Files_Trashbin\Trashbin::restore(
  409. 'file1.txt.d' . $trashedFile->getMtime(),
  410. $trashedFile->getName(),
  411. $trashedFile->getMtime()
  412. )
  413. );
  414. $file = $userFolder->get('file1.txt');
  415. $this->assertEquals('foo', $file->getContent());
  416. }
  417. /**
  418. * Test restoring a file in the root folder whenever there is another file
  419. * with the same name in the root folder
  420. */
  421. public function testRestoreFileDoesNotOverwriteExistingInRoot() {
  422. $userFolder = \OC::$server->getUserFolder();
  423. $file = $userFolder->newFile('file1.txt');
  424. $file->putContent('foo');
  425. $this->assertTrue($userFolder->nodeExists('file1.txt'));
  426. $file->delete();
  427. $this->assertFalse($userFolder->nodeExists('file1.txt'));
  428. $filesInTrash = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1, 'mtime');
  429. $this->assertCount(1, $filesInTrash);
  430. /** @var \OCP\Files\FileInfo */
  431. $trashedFile = $filesInTrash[0];
  432. // create another file
  433. $file = $userFolder->newFile('file1.txt');
  434. $file->putContent('bar');
  435. $this->assertTrue(
  436. OCA\Files_Trashbin\Trashbin::restore(
  437. 'file1.txt.d' . $trashedFile->getMtime(),
  438. $trashedFile->getName(),
  439. $trashedFile->getMtime()
  440. )
  441. );
  442. $anotherFile = $userFolder->get('file1.txt');
  443. $this->assertEquals('bar', $anotherFile->getContent());
  444. $restoredFile = $userFolder->get('file1 (restored).txt');
  445. $this->assertEquals('foo', $restoredFile->getContent());
  446. }
  447. /**
  448. * Test restoring a file whenever there is another file
  449. * with the same name in the source folder
  450. */
  451. public function testRestoreFileDoesNotOverwriteExistingInSubfolder() {
  452. $userFolder = \OC::$server->getUserFolder();
  453. $folder = $userFolder->newFolder('folder');
  454. $file = $folder->newFile('file1.txt');
  455. $file->putContent('foo');
  456. $this->assertTrue($userFolder->nodeExists('folder/file1.txt'));
  457. $file->delete();
  458. $this->assertFalse($userFolder->nodeExists('folder/file1.txt'));
  459. $filesInTrash = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1, 'mtime');
  460. $this->assertCount(1, $filesInTrash);
  461. /** @var \OCP\Files\FileInfo */
  462. $trashedFile = $filesInTrash[0];
  463. // create another file
  464. $file = $folder->newFile('file1.txt');
  465. $file->putContent('bar');
  466. $this->assertTrue(
  467. OCA\Files_Trashbin\Trashbin::restore(
  468. 'file1.txt.d' . $trashedFile->getMtime(),
  469. $trashedFile->getName(),
  470. $trashedFile->getMtime()
  471. )
  472. );
  473. $anotherFile = $userFolder->get('folder/file1.txt');
  474. $this->assertEquals('bar', $anotherFile->getContent());
  475. $restoredFile = $userFolder->get('folder/file1 (restored).txt');
  476. $this->assertEquals('foo', $restoredFile->getContent());
  477. }
  478. /**
  479. * Test restoring a non-existing file from trashbin, returns false
  480. */
  481. public function testRestoreUnexistingFile() {
  482. $this->assertFalse(
  483. OCA\Files_Trashbin\Trashbin::restore(
  484. 'unexist.txt.d123456',
  485. 'unexist.txt',
  486. '123456'
  487. )
  488. );
  489. }
  490. /**
  491. * Test restoring a file into a read-only folder, will restore
  492. * the file to root instead
  493. */
  494. public function testRestoreFileIntoReadOnlySourceFolder() {
  495. $userFolder = \OC::$server->getUserFolder();
  496. $folder = $userFolder->newFolder('folder');
  497. $file = $folder->newFile('file1.txt');
  498. $file->putContent('foo');
  499. $this->assertTrue($userFolder->nodeExists('folder/file1.txt'));
  500. $file->delete();
  501. $this->assertFalse($userFolder->nodeExists('folder/file1.txt'));
  502. $filesInTrash = OCA\Files_Trashbin\Helper::getTrashFiles('/', self::TEST_TRASHBIN_USER1, 'mtime');
  503. $this->assertCount(1, $filesInTrash);
  504. /** @var \OCP\Files\FileInfo */
  505. $trashedFile = $filesInTrash[0];
  506. // delete source folder
  507. list($storage, $internalPath) = $this->rootView->resolvePath('/' . self::TEST_TRASHBIN_USER1 . '/files/folder');
  508. if ($storage instanceof \OC\Files\Storage\Local) {
  509. $folderAbsPath = $storage->getSourcePath($internalPath);
  510. // make folder read-only
  511. chmod($folderAbsPath, 0555);
  512. $this->assertTrue(
  513. OCA\Files_Trashbin\Trashbin::restore(
  514. 'file1.txt.d' . $trashedFile->getMtime(),
  515. $trashedFile->getName(),
  516. $trashedFile->getMtime()
  517. )
  518. );
  519. $file = $userFolder->get('file1.txt');
  520. $this->assertEquals('foo', $file->getContent());
  521. chmod($folderAbsPath, 0755);
  522. }
  523. }
  524. /**
  525. * @param string $user
  526. * @param bool $create
  527. */
  528. public static function loginHelper($user, $create = false) {
  529. if ($create) {
  530. try {
  531. \OC::$server->getUserManager()->createUser($user, $user);
  532. } catch (\Exception $e) { // catch username is already being used from previous aborted runs
  533. }
  534. }
  535. \OC_Util::tearDownFS();
  536. \OC_User::setUserId('');
  537. \OC\Files\Filesystem::tearDown();
  538. \OC_User::setUserId($user);
  539. \OC_Util::setupFS($user);
  540. \OC::$server->getUserFolder($user);
  541. }
  542. }
  543. // just a dummy class to make protected methods available for testing
  544. class TrashbinForTesting extends \OCA\Files_Trashbin\Trashbin {
  545. /**
  546. * @param OCP\Files\FileInfo[] $files
  547. * @param integer $limit
  548. */
  549. public function dummyDeleteExpiredFiles($files) {
  550. // dummy value for $retention_obligation because it is not needed here
  551. return parent::deleteExpiredFiles($files, TrashbinTest::TEST_TRASHBIN_USER1);
  552. }
  553. /**
  554. * @param OCP\Files\FileInfo[] $files
  555. * @param integer $availableSpace
  556. */
  557. public function dummyDeleteFiles($files, $availableSpace) {
  558. return parent::deleteFiles($files, TrashbinTest::TEST_TRASHBIN_USER1, $availableSpace);
  559. }
  560. }