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.

CustomPropertiesBackendTest.php 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2017, Georg Ehrke <oc.list@georgehrke.com>
  4. *
  5. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  6. * @author Georg Ehrke <oc.list@georgehrke.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. *
  12. * @license GNU AGPL version 3 or any later version
  13. *
  14. * This program is free software: you can redistribute it and/or modify
  15. * it under the terms of the GNU Affero General Public License as
  16. * published by the Free Software Foundation, either version 3 of the
  17. * License, or (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU Affero General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU Affero General Public License
  25. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  26. *
  27. */
  28. namespace OCA\DAV\Tests\DAV;
  29. use OCA\DAV\DAV\CustomPropertiesBackend;
  30. use OCP\IDBConnection;
  31. use OCP\IUser;
  32. use Sabre\DAV\PropFind;
  33. use Sabre\DAV\PropPatch;
  34. use Sabre\DAV\Tree;
  35. use Test\TestCase;
  36. /**
  37. * @group DB
  38. */
  39. class CustomPropertiesBackendTest extends TestCase {
  40. /** @var Tree | \PHPUnit\Framework\MockObject\MockObject */
  41. private $tree;
  42. /** @var IDBConnection */
  43. private $dbConnection;
  44. /** @var IUser | \PHPUnit\Framework\MockObject\MockObject */
  45. private $user;
  46. /** @var CustomPropertiesBackend | \PHPUnit\Framework\MockObject\MockObject */
  47. private $backend;
  48. protected function setUp(): void {
  49. parent::setUp();
  50. $this->tree = $this->createMock(Tree::class);
  51. $this->user = $this->createMock(IUser::class);
  52. $this->user->method('getUID')
  53. ->with()
  54. ->willReturn('dummy_user_42');
  55. $this->dbConnection = \OC::$server->getDatabaseConnection();
  56. $this->backend = new CustomPropertiesBackend(
  57. $this->tree,
  58. $this->dbConnection,
  59. $this->user
  60. );
  61. }
  62. protected function tearDown(): void {
  63. $query = $this->dbConnection->getQueryBuilder();
  64. $query->delete('properties');
  65. $query->execute();
  66. parent::tearDown();
  67. }
  68. private function formatPath(string $path): string {
  69. if (strlen($path) > 250) {
  70. return sha1($path);
  71. } else {
  72. return $path;
  73. }
  74. }
  75. protected function insertProps(string $user, string $path, array $props) {
  76. foreach ($props as $name => $value) {
  77. $this->insertProp($user, $path, $name, $value);
  78. }
  79. }
  80. protected function insertProp(string $user, string $path, string $name, string $value) {
  81. $query = $this->dbConnection->getQueryBuilder();
  82. $query->insert('properties')
  83. ->values([
  84. 'userid' => $query->createNamedParameter($user),
  85. 'propertypath' => $query->createNamedParameter($this->formatPath($path)),
  86. 'propertyname' => $query->createNamedParameter($name),
  87. 'propertyvalue' => $query->createNamedParameter($value),
  88. ]);
  89. $query->execute();
  90. }
  91. protected function getProps(string $user, string $path) {
  92. $query = $this->dbConnection->getQueryBuilder();
  93. $query->select('propertyname', 'propertyvalue')
  94. ->from('properties')
  95. ->where($query->expr()->eq('userid', $query->createNamedParameter($user)))
  96. ->where($query->expr()->eq('propertypath', $query->createNamedParameter($this->formatPath($path))));
  97. $result = $query->execute();
  98. $data = [];
  99. while ($row = $result->fetch()) {
  100. $data[$row['propertyname']] = $row['propertyvalue'];
  101. }
  102. $result->closeCursor();
  103. return $data;
  104. }
  105. public function testPropFindNoDbCalls() {
  106. $db = $this->createMock(IDBConnection::class);
  107. $backend = new CustomPropertiesBackend(
  108. $this->tree,
  109. $db,
  110. $this->user
  111. );
  112. $propFind = $this->createMock(PropFind::class);
  113. $propFind->expects($this->at(0))
  114. ->method('get404Properties')
  115. ->with()
  116. ->willReturn([
  117. '{http://owncloud.org/ns}permissions',
  118. '{http://owncloud.org/ns}downloadURL',
  119. '{http://owncloud.org/ns}dDC',
  120. '{http://owncloud.org/ns}size',
  121. ]);
  122. $db->expects($this->never())
  123. ->method($this->anything());
  124. $backend->propFind('foo_bar_path_1337_0', $propFind);
  125. }
  126. public function testPropFindCalendarCall() {
  127. $propFind = $this->createMock(PropFind::class);
  128. $propFind->method('get404Properties')
  129. ->with()
  130. ->willReturn([
  131. '{DAV:}getcontentlength',
  132. '{DAV:}getcontenttype',
  133. '{DAV:}getetag',
  134. '{abc}def',
  135. ]);
  136. $propFind->method('getRequestedProperties')
  137. ->with()
  138. ->willReturn([
  139. '{DAV:}getcontentlength',
  140. '{DAV:}getcontenttype',
  141. '{DAV:}getetag',
  142. '{DAV:}displayname',
  143. '{urn:ietf:params:xml:ns:caldav}calendar-description',
  144. '{urn:ietf:params:xml:ns:caldav}calendar-timezone',
  145. '{abc}def',
  146. ]);
  147. $props = [
  148. '{abc}def' => 'a',
  149. '{DAV:}displayname' => 'b',
  150. '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'c',
  151. '{urn:ietf:params:xml:ns:caldav}calendar-timezone' => 'd',
  152. ];
  153. $this->insertProps('dummy_user_42', 'calendars/foo/bar_path_1337_0', $props);
  154. $setProps = [];
  155. $propFind->method('set')
  156. ->willReturnCallback(function ($name, $value, $status) use (&$setProps) {
  157. $setProps[$name] = $value;
  158. });
  159. $this->backend->propFind('calendars/foo/bar_path_1337_0', $propFind);
  160. $this->assertEquals($props, $setProps);
  161. }
  162. /**
  163. * @dataProvider propPatchProvider
  164. */
  165. public function testPropPatch(string $path, array $existing, array $props, array $result) {
  166. $this->insertProps($this->user->getUID(), $path, $existing);
  167. $propPatch = new PropPatch($props);
  168. $this->backend->propPatch($path, $propPatch);
  169. $propPatch->commit();
  170. $storedProps = $this->getProps($this->user->getUID(), $path);
  171. $this->assertEquals($result, $storedProps);
  172. }
  173. public function propPatchProvider() {
  174. $longPath = str_repeat('long_path', 100);
  175. return [
  176. ['foo_bar_path_1337', [], ['{DAV:}displayname' => 'anything'], ['{DAV:}displayname' => 'anything']],
  177. ['foo_bar_path_1337', ['{DAV:}displayname' => 'foo'], ['{DAV:}displayname' => 'anything'], ['{DAV:}displayname' => 'anything']],
  178. ['foo_bar_path_1337', ['{DAV:}displayname' => 'foo'], ['{DAV:}displayname' => null], []],
  179. [$longPath, [], ['{DAV:}displayname' => 'anything'], ['{DAV:}displayname' => 'anything']],
  180. ];
  181. }
  182. /**
  183. * @dataProvider deleteProvider
  184. */
  185. public function testDelete(string $path) {
  186. $this->insertProps('dummy_user_42', $path, ['foo' => 'bar']);
  187. $this->backend->delete($path);
  188. $this->assertEquals([], $this->getProps('dummy_user_42', $path));
  189. }
  190. public function deleteProvider() {
  191. return [
  192. ['foo_bar_path_1337'],
  193. [str_repeat('long_path', 100)]
  194. ];
  195. }
  196. /**
  197. * @dataProvider moveProvider
  198. */
  199. public function testMove(string $source, string $target) {
  200. $this->insertProps('dummy_user_42', $source, ['foo' => 'bar']);
  201. $this->backend->move($source, $target);
  202. $this->assertEquals([], $this->getProps('dummy_user_42', $source));
  203. $this->assertEquals(['foo' => 'bar'], $this->getProps('dummy_user_42', $target));
  204. }
  205. public function moveProvider() {
  206. return [
  207. ['foo_bar_path_1337', 'foo_bar_path_7333'],
  208. [str_repeat('long_path1', 100), str_repeat('long_path2', 100)]
  209. ];
  210. }
  211. }