You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TrashbinTest.php 23KB

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