CleanUpTest.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-only
  6. */
  7. namespace OCA\Files_Trashbin\Tests\Command;
  8. use OC\User\Manager;
  9. use OCA\Files_Trashbin\Command\CleanUp;
  10. use OCP\Files\IRootFolder;
  11. use OCP\IDBConnection;
  12. use OCP\UserInterface;
  13. use Symfony\Component\Console\Exception\InvalidOptionException;
  14. use Symfony\Component\Console\Input\InputInterface;
  15. use Symfony\Component\Console\Output\NullOutput;
  16. use Symfony\Component\Console\Output\OutputInterface;
  17. use Test\TestCase;
  18. /**
  19. * Class CleanUpTest
  20. *
  21. * @group DB
  22. *
  23. * @package OCA\Files_Trashbin\Tests\Command
  24. */
  25. class CleanUpTest extends TestCase {
  26. /** @var CleanUp */
  27. protected $cleanup;
  28. /** @var \PHPUnit\Framework\MockObject\MockObject | Manager */
  29. protected $userManager;
  30. /** @var \PHPUnit\Framework\MockObject\MockObject | IRootFolder */
  31. protected $rootFolder;
  32. /** @var IDBConnection */
  33. protected $dbConnection;
  34. /** @var string */
  35. protected $trashTable = 'files_trash';
  36. /** @var string */
  37. protected $user0 = 'user0';
  38. protected function setUp(): void {
  39. parent::setUp();
  40. $this->rootFolder = $this->getMockBuilder('OCP\Files\IRootFolder')
  41. ->disableOriginalConstructor()->getMock();
  42. $this->userManager = $this->getMockBuilder('OC\User\Manager')
  43. ->disableOriginalConstructor()->getMock();
  44. $this->dbConnection = \OC::$server->getDatabaseConnection();
  45. $this->cleanup = new CleanUp($this->rootFolder, $this->userManager, $this->dbConnection);
  46. }
  47. /**
  48. * populate files_trash table with 10 dummy values
  49. */
  50. public function initTable() {
  51. $query = $this->dbConnection->getQueryBuilder();
  52. $query->delete($this->trashTable)->execute();
  53. for ($i = 0; $i < 10; $i++) {
  54. $query->insert($this->trashTable)
  55. ->values([
  56. 'id' => $query->expr()->literal('file' . $i),
  57. 'timestamp' => $query->expr()->literal($i),
  58. 'location' => $query->expr()->literal('.'),
  59. 'user' => $query->expr()->literal('user' . $i % 2)
  60. ])->execute();
  61. }
  62. $getAllQuery = $this->dbConnection->getQueryBuilder();
  63. $result = $getAllQuery->select('id')
  64. ->from($this->trashTable)
  65. ->execute()
  66. ->fetchAll();
  67. $this->assertSame(10, count($result));
  68. }
  69. /**
  70. * @dataProvider dataTestRemoveDeletedFiles
  71. * @param boolean $nodeExists
  72. */
  73. public function testRemoveDeletedFiles(bool $nodeExists): void {
  74. $this->initTable();
  75. $this->rootFolder
  76. ->method('nodeExists')
  77. ->with('/' . $this->user0 . '/files_trashbin')
  78. ->willReturnOnConsecutiveCalls($nodeExists, false);
  79. if ($nodeExists) {
  80. $this->rootFolder
  81. ->method('get')
  82. ->with('/' . $this->user0 . '/files_trashbin')
  83. ->willReturn($this->rootFolder);
  84. $this->rootFolder
  85. ->method('delete');
  86. } else {
  87. $this->rootFolder->expects($this->never())->method('get');
  88. $this->rootFolder->expects($this->never())->method('delete');
  89. }
  90. $this->invokePrivate($this->cleanup, 'removeDeletedFiles', [$this->user0, new NullOutput(), false]);
  91. if ($nodeExists) {
  92. // if the delete operation was executed only files from user1
  93. // should be left.
  94. $query = $this->dbConnection->getQueryBuilder();
  95. $query->select('user')
  96. ->from($this->trashTable);
  97. $qResult = $query->execute();
  98. $result = $qResult->fetchAll();
  99. $qResult->closeCursor();
  100. $this->assertSame(5, count($result));
  101. foreach ($result as $r) {
  102. $this->assertSame('user1', $r['user']);
  103. }
  104. } else {
  105. // if no delete operation was executed we should still have all 10
  106. // database entries
  107. $getAllQuery = $this->dbConnection->getQueryBuilder();
  108. $result = $getAllQuery->select('id')
  109. ->from($this->trashTable)
  110. ->execute()
  111. ->fetchAll();
  112. $this->assertSame(10, count($result));
  113. }
  114. }
  115. public function dataTestRemoveDeletedFiles() {
  116. return [
  117. [true],
  118. [false]
  119. ];
  120. }
  121. /**
  122. * test remove deleted files from users given as parameter
  123. */
  124. public function testExecuteDeleteListOfUsers(): void {
  125. $userIds = ['user1', 'user2', 'user3'];
  126. $instance = $this->getMockBuilder('OCA\Files_Trashbin\Command\CleanUp')
  127. ->setMethods(['removeDeletedFiles'])
  128. ->setConstructorArgs([$this->rootFolder, $this->userManager, $this->dbConnection])
  129. ->getMock();
  130. $instance->expects($this->exactly(count($userIds)))
  131. ->method('removeDeletedFiles')
  132. ->willReturnCallback(function ($user) use ($userIds): void {
  133. $this->assertTrue(in_array($user, $userIds));
  134. });
  135. $this->userManager->expects($this->exactly(count($userIds)))
  136. ->method('userExists')->willReturn(true);
  137. $inputInterface = $this->getMockBuilder('\Symfony\Component\Console\Input\InputInterface')
  138. ->disableOriginalConstructor()->getMock();
  139. $inputInterface->method('getArgument')
  140. ->with('user_id')
  141. ->willReturn($userIds);
  142. $inputInterface->method('getOption')
  143. ->willReturnMap([
  144. ['all-users', false],
  145. ['verbose', false],
  146. ]);
  147. $outputInterface = $this->getMockBuilder('\Symfony\Component\Console\Output\OutputInterface')
  148. ->disableOriginalConstructor()->getMock();
  149. $this->invokePrivate($instance, 'execute', [$inputInterface, $outputInterface]);
  150. }
  151. /**
  152. * test remove deleted files of all users
  153. */
  154. public function testExecuteAllUsers(): void {
  155. $userIds = [];
  156. $backendUsers = ['user1', 'user2'];
  157. $instance = $this->getMockBuilder('OCA\Files_Trashbin\Command\CleanUp')
  158. ->setMethods(['removeDeletedFiles'])
  159. ->setConstructorArgs([$this->rootFolder, $this->userManager, $this->dbConnection])
  160. ->getMock();
  161. $backend = $this->createMock(UserInterface::class);
  162. $backend->method('getUsers')
  163. ->with('', 500, 0)
  164. ->willReturn($backendUsers);
  165. $instance->expects($this->exactly(count($backendUsers)))
  166. ->method('removeDeletedFiles')
  167. ->willReturnCallback(function ($user) use ($backendUsers): void {
  168. $this->assertTrue(in_array($user, $backendUsers));
  169. });
  170. $inputInterface = $this->createMock(InputInterface::class);
  171. $inputInterface->method('getArgument')
  172. ->with('user_id')
  173. ->willReturn($userIds);
  174. $inputInterface->method('getOption')
  175. ->willReturnMap([
  176. ['all-users', true],
  177. ['verbose', false],
  178. ]);
  179. $outputInterface = $this->createMock(OutputInterface::class);
  180. $this->userManager
  181. ->method('getBackends')
  182. ->willReturn([$backend]);
  183. $this->invokePrivate($instance, 'execute', [$inputInterface, $outputInterface]);
  184. }
  185. public function testExecuteNoUsersAndNoAllUsers(): void {
  186. $inputInterface = $this->createMock(InputInterface::class);
  187. $inputInterface->method('getArgument')
  188. ->with('user_id')
  189. ->willReturn([]);
  190. $inputInterface->method('getOption')
  191. ->willReturnMap([
  192. ['all-users', false],
  193. ['verbose', false],
  194. ]);
  195. $outputInterface = $this->createMock(OutputInterface::class);
  196. $this->expectException(InvalidOptionException::class);
  197. $this->expectExceptionMessage('Either specify a user_id or --all-users');
  198. $this->invokePrivate($this->cleanup, 'execute', [$inputInterface, $outputInterface]);
  199. }
  200. public function testExecuteUsersAndAllUsers(): void {
  201. $inputInterface = $this->createMock(InputInterface::class);
  202. $inputInterface->method('getArgument')
  203. ->with('user_id')
  204. ->willReturn(['user1', 'user2']);
  205. $inputInterface->method('getOption')
  206. ->willReturnMap([
  207. ['all-users', true],
  208. ['verbose', false],
  209. ]);
  210. $outputInterface = $this->createMock(OutputInterface::class);
  211. $this->expectException(InvalidOptionException::class);
  212. $this->expectExceptionMessage('Either specify a user_id or --all-users');
  213. $this->invokePrivate($this->cleanup, 'execute', [$inputInterface, $outputInterface]);
  214. }
  215. }