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.

376 lines
14 KiB

  1. <?php
  2. /**
  3. * @author Morris Jobke <hey@morrisjobke.de>
  4. * @author Robin Appelman <icewind@owncloud.com>
  5. * @author Vincent Petry <pvince81@owncloud.com>
  6. *
  7. * @copyright Copyright (c) 2015, ownCloud, Inc.
  8. * @license AGPL-3.0
  9. *
  10. * This code is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Affero General Public License, version 3,
  12. * as published by the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU Affero General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Affero General Public License, version 3,
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>
  21. *
  22. */
  23. namespace OCA\Files_trashbin\Tests\Storage;
  24. use OC\Files\Storage\Home;
  25. use OC\Files\Storage\Temporary;
  26. use OC\Files\Mount\MountPoint;
  27. use OC\Files\Filesystem;
  28. class Storage extends \Test\TestCase {
  29. /**
  30. * @var string
  31. */
  32. private $user;
  33. /**
  34. * @var \OC\Files\View
  35. */
  36. private $rootView;
  37. /**
  38. * @var \OC\Files\View
  39. */
  40. private $userView;
  41. protected function setUp() {
  42. parent::setUp();
  43. \OC_Hook::clear();
  44. \OCA\Files_Trashbin\Trashbin::registerHooks();
  45. $this->user = $this->getUniqueId('user');
  46. \OC::$server->getUserManager()->createUser($this->user, $this->user);
  47. // this will setup the FS
  48. $this->loginAsUser($this->user);
  49. \OCA\Files_Trashbin\Storage::setupStorage();
  50. $this->rootView = new \OC\Files\View('/');
  51. $this->userView = new \OC\Files\View('/' . $this->user . '/files/');
  52. $this->userView->file_put_contents('test.txt', 'foo');
  53. $this->userView->mkdir('folder');
  54. $this->userView->file_put_contents('folder/inside.txt', 'bar');
  55. }
  56. protected function tearDown() {
  57. \OC\Files\Filesystem::getLoader()->removeStorageWrapper('oc_trashbin');
  58. $this->logout();
  59. \OC_User::deleteUser($this->user);
  60. \OC_Hook::clear();
  61. parent::tearDown();
  62. }
  63. /**
  64. * Test that deleting a file puts it into the trashbin.
  65. */
  66. public function testSingleStorageDeleteFile() {
  67. $this->assertTrue($this->userView->file_exists('test.txt'));
  68. $this->userView->unlink('test.txt');
  69. list($storage,) = $this->userView->resolvePath('test.txt');
  70. $storage->getScanner()->scan(''); // make sure we check the storage
  71. $this->assertFalse($this->userView->getFileInfo('test.txt'));
  72. // check if file is in trashbin
  73. $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files/');
  74. $this->assertEquals(1, count($results));
  75. $name = $results[0]->getName();
  76. $this->assertEquals('test.txt', substr($name, 0, strrpos($name, '.')));
  77. }
  78. /**
  79. * Test that deleting a folder puts it into the trashbin.
  80. */
  81. public function testSingleStorageDeleteFolder() {
  82. $this->assertTrue($this->userView->file_exists('folder/inside.txt'));
  83. $this->userView->rmdir('folder');
  84. list($storage,) = $this->userView->resolvePath('folder/inside.txt');
  85. $storage->getScanner()->scan(''); // make sure we check the storage
  86. $this->assertFalse($this->userView->getFileInfo('folder'));
  87. // check if folder is in trashbin
  88. $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files/');
  89. $this->assertEquals(1, count($results));
  90. $name = $results[0]->getName();
  91. $this->assertEquals('folder', substr($name, 0, strrpos($name, '.')));
  92. $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files/' . $name . '/');
  93. $this->assertEquals(1, count($results));
  94. $name = $results[0]->getName();
  95. $this->assertEquals('inside.txt', $name);
  96. }
  97. /**
  98. * Test that deleting a file from another mounted storage properly
  99. * lands in the trashbin. This is a cross-storage situation because
  100. * the trashbin folder is in the root storage while the mounted one
  101. * isn't.
  102. */
  103. public function testCrossStorageDeleteFile() {
  104. $storage2 = new Temporary(array());
  105. \OC\Files\Filesystem::mount($storage2, array(), $this->user . '/files/substorage');
  106. $this->userView->file_put_contents('substorage/subfile.txt', 'foo');
  107. $storage2->getScanner()->scan('');
  108. $this->assertTrue($storage2->file_exists('subfile.txt'));
  109. $this->userView->unlink('substorage/subfile.txt');
  110. $storage2->getScanner()->scan('');
  111. $this->assertFalse($this->userView->getFileInfo('substorage/subfile.txt'));
  112. $this->assertFalse($storage2->file_exists('subfile.txt'));
  113. // check if file is in trashbin
  114. $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files');
  115. $this->assertEquals(1, count($results));
  116. $name = $results[0]->getName();
  117. $this->assertEquals('subfile.txt', substr($name, 0, strrpos($name, '.')));
  118. }
  119. /**
  120. * Test that deleting a folder from another mounted storage properly
  121. * lands in the trashbin. This is a cross-storage situation because
  122. * the trashbin folder is in the root storage while the mounted one
  123. * isn't.
  124. */
  125. public function testCrossStorageDeleteFolder() {
  126. $storage2 = new Temporary(array());
  127. \OC\Files\Filesystem::mount($storage2, array(), $this->user . '/files/substorage');
  128. $this->userView->mkdir('substorage/folder');
  129. $this->userView->file_put_contents('substorage/folder/subfile.txt', 'bar');
  130. $storage2->getScanner()->scan('');
  131. $this->assertTrue($storage2->file_exists('folder/subfile.txt'));
  132. $this->userView->rmdir('substorage/folder');
  133. $storage2->getScanner()->scan('');
  134. $this->assertFalse($this->userView->getFileInfo('substorage/folder'));
  135. $this->assertFalse($storage2->file_exists('folder/subfile.txt'));
  136. // check if folder is in trashbin
  137. $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files');
  138. $this->assertEquals(1, count($results));
  139. $name = $results[0]->getName();
  140. $this->assertEquals('folder', substr($name, 0, strrpos($name, '.')));
  141. $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files/' . $name . '/');
  142. $this->assertEquals(1, count($results));
  143. $name = $results[0]->getName();
  144. $this->assertEquals('subfile.txt', $name);
  145. }
  146. /**
  147. * Test that deleted versions properly land in the trashbin.
  148. */
  149. public function testDeleteVersionsOfFile() {
  150. \OCA\Files_Versions\Hooks::connectHooks();
  151. // trigger a version (multiple would not work because of the expire logic)
  152. $this->userView->file_put_contents('test.txt', 'v1');
  153. $results = $this->rootView->getDirectoryContent($this->user . '/files_versions/');
  154. $this->assertEquals(1, count($results));
  155. $this->userView->unlink('test.txt');
  156. // rescan trash storage
  157. list($rootStorage,) = $this->rootView->resolvePath($this->user . '/files_trashbin');
  158. $rootStorage->getScanner()->scan('');
  159. // check if versions are in trashbin
  160. $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/versions');
  161. $this->assertEquals(1, count($results));
  162. $name = $results[0]->getName();
  163. $this->assertEquals('test.txt.v', substr($name, 0, strlen('test.txt.v')));
  164. }
  165. /**
  166. * Test that deleted versions properly land in the trashbin.
  167. */
  168. public function testDeleteVersionsOfFolder() {
  169. \OCA\Files_Versions\Hooks::connectHooks();
  170. // trigger a version (multiple would not work because of the expire logic)
  171. $this->userView->file_put_contents('folder/inside.txt', 'v1');
  172. $results = $this->rootView->getDirectoryContent($this->user . '/files_versions/folder/');
  173. $this->assertEquals(1, count($results));
  174. $this->userView->rmdir('folder');
  175. // rescan trash storage
  176. list($rootStorage,) = $this->rootView->resolvePath($this->user . '/files_trashbin');
  177. $rootStorage->getScanner()->scan('');
  178. // check if versions are in trashbin
  179. $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/versions');
  180. $this->assertEquals(1, count($results));
  181. $name = $results[0]->getName();
  182. $this->assertEquals('folder.d', substr($name, 0, strlen('folder.d')));
  183. // check if versions are in trashbin
  184. $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/versions/' . $name . '/');
  185. $this->assertEquals(1, count($results));
  186. $name = $results[0]->getName();
  187. $this->assertEquals('inside.txt.v', substr($name, 0, strlen('inside.txt.v')));
  188. }
  189. /**
  190. * Test that versions are not auto-trashed when moving a file between
  191. * storages. This is because rename() between storages would call
  192. * unlink() which should NOT trigger the version deletion logic.
  193. */
  194. public function testKeepFileAndVersionsWhenMovingFileBetweenStorages() {
  195. \OCA\Files_Versions\Hooks::connectHooks();
  196. $storage2 = new Temporary(array());
  197. \OC\Files\Filesystem::mount($storage2, array(), $this->user . '/files/substorage');
  198. // trigger a version (multiple would not work because of the expire logic)
  199. $this->userView->file_put_contents('test.txt', 'v1');
  200. $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files');
  201. $this->assertEquals(0, count($results));
  202. $results = $this->rootView->getDirectoryContent($this->user . '/files_versions/');
  203. $this->assertEquals(1, count($results));
  204. // move to another storage
  205. $this->userView->rename('test.txt', 'substorage/test.txt');
  206. $this->assertTrue($this->userView->file_exists('substorage/test.txt'));
  207. // rescan trash storage
  208. list($rootStorage,) = $this->rootView->resolvePath($this->user . '/files_trashbin');
  209. $rootStorage->getScanner()->scan('');
  210. // versions were moved too
  211. $results = $this->rootView->getDirectoryContent($this->user . '/files_versions/substorage');
  212. $this->assertEquals(1, count($results));
  213. // check that nothing got trashed by the rename's unlink() call
  214. $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files');
  215. $this->assertEquals(0, count($results));
  216. // check that versions were moved and not trashed
  217. $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/versions/');
  218. $this->assertEquals(0, count($results));
  219. }
  220. /**
  221. * Test that versions are not auto-trashed when moving a file between
  222. * storages. This is because rename() between storages would call
  223. * unlink() which should NOT trigger the version deletion logic.
  224. */
  225. public function testKeepFileAndVersionsWhenMovingFolderBetweenStorages() {
  226. \OCA\Files_Versions\Hooks::connectHooks();
  227. $storage2 = new Temporary(array());
  228. \OC\Files\Filesystem::mount($storage2, array(), $this->user . '/files/substorage');
  229. // trigger a version (multiple would not work because of the expire logic)
  230. $this->userView->file_put_contents('folder/inside.txt', 'v1');
  231. $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files');
  232. $this->assertEquals(0, count($results));
  233. $results = $this->rootView->getDirectoryContent($this->user . '/files_versions/folder/');
  234. $this->assertEquals(1, count($results));
  235. // move to another storage
  236. $this->userView->rename('folder', 'substorage/folder');
  237. $this->assertTrue($this->userView->file_exists('substorage/folder/inside.txt'));
  238. // rescan trash storage
  239. list($rootStorage,) = $this->rootView->resolvePath($this->user . '/files_trashbin');
  240. $rootStorage->getScanner()->scan('');
  241. // versions were moved too
  242. $results = $this->rootView->getDirectoryContent($this->user . '/files_versions/substorage/folder/');
  243. $this->assertEquals(1, count($results));
  244. // check that nothing got trashed by the rename's unlink() call
  245. $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files');
  246. $this->assertEquals(0, count($results));
  247. // check that versions were moved and not trashed
  248. $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/versions/');
  249. $this->assertEquals(0, count($results));
  250. }
  251. /**
  252. * Delete should fail is the source file cant be deleted
  253. */
  254. public function testSingleStorageDeleteFileFail() {
  255. /**
  256. * @var \OC\Files\Storage\Temporary | \PHPUnit_Framework_MockObject_MockObject $storage
  257. */
  258. $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary')
  259. ->setConstructorArgs([[]])
  260. ->setMethods(['rename', 'unlink'])
  261. ->getMock();
  262. $storage->expects($this->any())
  263. ->method('unlink')
  264. ->will($this->returnValue(false));
  265. $cache = $storage->getCache();
  266. Filesystem::mount($storage, [], '/' . $this->user);
  267. $storage->mkdir('files');
  268. $this->userView->file_put_contents('test.txt', 'foo');
  269. $this->assertTrue($storage->file_exists('files/test.txt'));
  270. $this->assertFalse($this->userView->unlink('test.txt'));
  271. $this->assertTrue($storage->file_exists('files/test.txt'));
  272. $this->assertTrue($cache->inCache('files/test.txt'));
  273. // file should not be in the trashbin
  274. $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files/');
  275. $this->assertEquals(0, count($results));
  276. }
  277. /**
  278. * Delete should fail is the source folder cant be deleted
  279. */
  280. public function testSingleStorageDeleteFolderFail() {
  281. /**
  282. * @var \OC\Files\Storage\Temporary | \PHPUnit_Framework_MockObject_MockObject $storage
  283. */
  284. $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary')
  285. ->setConstructorArgs([[]])
  286. ->setMethods(['rename', 'unlink', 'rmdir'])
  287. ->getMock();
  288. $storage->expects($this->any())
  289. ->method('rmdir')
  290. ->will($this->returnValue(false));
  291. $cache = $storage->getCache();
  292. Filesystem::mount($storage, [], '/' . $this->user);
  293. $storage->mkdir('files');
  294. $this->userView->mkdir('folder');
  295. $this->userView->file_put_contents('folder/test.txt', 'foo');
  296. $this->assertTrue($storage->file_exists('files/folder/test.txt'));
  297. $this->assertFalse($this->userView->rmdir('files/folder'));
  298. $this->assertTrue($storage->file_exists('files/folder'));
  299. $this->assertTrue($storage->file_exists('files/folder/test.txt'));
  300. $this->assertTrue($cache->inCache('files/folder'));
  301. $this->assertTrue($cache->inCache('files/folder/test.txt'));
  302. // file should not be in the trashbin
  303. $results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files/');
  304. $this->assertEquals(0, count($results));
  305. }
  306. }