TrashbinTest.php 21 KB

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