cache.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  1. <?php
  2. /**
  3. * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
  4. * This file is licensed under the Affero General Public License version 3 or
  5. * later.
  6. * See the COPYING-README file.
  7. */
  8. namespace Test\Files\Cache;
  9. use PHPUnit_Framework_MockObject_MockObject;
  10. class LongId extends \OC\Files\Storage\Temporary {
  11. public function getId() {
  12. return 'long:' . str_repeat('foo', 50) . parent::getId();
  13. }
  14. }
  15. class Cache extends \Test\TestCase {
  16. /**
  17. * @var \OC\Files\Storage\Temporary $storage ;
  18. */
  19. protected $storage;
  20. /**
  21. * @var \OC\Files\Storage\Temporary $storage2 ;
  22. */
  23. protected $storage2;
  24. /**
  25. * @var \OC\Files\Cache\Cache $cache
  26. */
  27. protected $cache;
  28. /**
  29. * @var \OC\Files\Cache\Cache $cache2
  30. */
  31. protected $cache2;
  32. public function testGetNumericId() {
  33. $this->assertNotNull($this->cache->getNumericStorageId());
  34. }
  35. public function testSimple() {
  36. $file1 = 'foo';
  37. $file2 = 'foo/bar';
  38. $data1 = array('size' => 100, 'mtime' => 50, 'mimetype' => 'foo/folder');
  39. $data2 = array('size' => 1000, 'mtime' => 20, 'mimetype' => 'foo/file');
  40. $this->assertFalse($this->cache->inCache($file1));
  41. $this->assertEquals($this->cache->get($file1), null);
  42. $id1 = $this->cache->put($file1, $data1);
  43. $this->assertTrue($this->cache->inCache($file1));
  44. $cacheData1 = $this->cache->get($file1);
  45. foreach ($data1 as $key => $value) {
  46. $this->assertEquals($value, $cacheData1[$key]);
  47. }
  48. $this->assertEquals($cacheData1['mimepart'], 'foo');
  49. $this->assertEquals($cacheData1['fileid'], $id1);
  50. $this->assertEquals($id1, $this->cache->getId($file1));
  51. $this->assertFalse($this->cache->inCache($file2));
  52. $id2 = $this->cache->put($file2, $data2);
  53. $this->assertTrue($this->cache->inCache($file2));
  54. $cacheData2 = $this->cache->get($file2);
  55. foreach ($data2 as $key => $value) {
  56. $this->assertEquals($value, $cacheData2[$key]);
  57. }
  58. $this->assertEquals($cacheData1['fileid'], $cacheData2['parent']);
  59. $this->assertEquals($cacheData2['fileid'], $id2);
  60. $this->assertEquals($id2, $this->cache->getId($file2));
  61. $this->assertEquals($id1, $this->cache->getParentId($file2));
  62. $newSize = 1050;
  63. $newId2 = $this->cache->put($file2, array('size' => $newSize));
  64. $cacheData2 = $this->cache->get($file2);
  65. $this->assertEquals($newId2, $id2);
  66. $this->assertEquals($cacheData2['size'], $newSize);
  67. $this->assertEquals($cacheData1, $this->cache->get($file1));
  68. $this->cache->remove($file2);
  69. $this->assertFalse($this->cache->inCache($file2));
  70. $this->assertEquals($this->cache->get($file2), null);
  71. $this->assertTrue($this->cache->inCache($file1));
  72. $this->assertEquals($cacheData1, $this->cache->get($id1));
  73. }
  74. public function testPartial() {
  75. $file1 = 'foo';
  76. $this->cache->put($file1, array('size' => 10));
  77. $this->assertEquals(array('size' => 10), $this->cache->get($file1));
  78. $this->cache->put($file1, array('mtime' => 15));
  79. $this->assertEquals(array('size' => 10, 'mtime' => 15), $this->cache->get($file1));
  80. $this->cache->put($file1, array('size' => 12));
  81. $this->assertEquals(array('size' => 12, 'mtime' => 15), $this->cache->get($file1));
  82. }
  83. /**
  84. * @dataProvider folderDataProvider
  85. */
  86. public function testFolder($folder) {
  87. $file2 = $folder.'/bar';
  88. $file3 = $folder.'/foo';
  89. $data1 = array('size' => 100, 'mtime' => 50, 'mimetype' => 'httpd/unix-directory');
  90. $fileData = array();
  91. $fileData['bar'] = array('size' => 1000, 'mtime' => 20, 'mimetype' => 'foo/file');
  92. $fileData['foo'] = array('size' => 20, 'mtime' => 25, 'mimetype' => 'foo/file');
  93. $this->cache->put($folder, $data1);
  94. $this->cache->put($file2, $fileData['bar']);
  95. $this->cache->put($file3, $fileData['foo']);
  96. $content = $this->cache->getFolderContents($folder);
  97. $this->assertEquals(count($content), 2);
  98. foreach ($content as $cachedData) {
  99. $data = $fileData[$cachedData['name']];
  100. foreach ($data as $name => $value) {
  101. $this->assertEquals($value, $cachedData[$name]);
  102. }
  103. }
  104. $file4 = $folder.'/unkownSize';
  105. $fileData['unkownSize'] = array('size' => -1, 'mtime' => 25, 'mimetype' => 'foo/file');
  106. $this->cache->put($file4, $fileData['unkownSize']);
  107. $this->assertEquals(-1, $this->cache->calculateFolderSize($folder));
  108. $fileData['unkownSize'] = array('size' => 5, 'mtime' => 25, 'mimetype' => 'foo/file');
  109. $this->cache->put($file4, $fileData['unkownSize']);
  110. $this->assertEquals(1025, $this->cache->calculateFolderSize($folder));
  111. $this->cache->remove($file2);
  112. $this->cache->remove($file3);
  113. $this->cache->remove($file4);
  114. $this->assertEquals(0, $this->cache->calculateFolderSize($folder));
  115. $this->cache->remove($folder);
  116. $this->assertFalse($this->cache->inCache($folder.'/foo'));
  117. $this->assertFalse($this->cache->inCache($folder.'/bar'));
  118. }
  119. public function testRemoveRecursive() {
  120. $folderData = array('size' => 100, 'mtime' => 50, 'mimetype' => 'httpd/unix-directory');
  121. $fileData = array('size' => 1000, 'mtime' => 20, 'mimetype' => 'text/plain');
  122. $folders = ['folder', 'folder/subfolder', 'folder/sub2', 'folder/sub2/sub3'];
  123. $files = ['folder/foo.txt', 'folder/bar.txt', 'folder/subfolder/asd.txt', 'folder/sub2/qwerty.txt', 'folder/sub2/sub3/foo.txt'];
  124. foreach($folders as $folder){
  125. $this->cache->put($folder, $folderData);
  126. }
  127. foreach ($files as $file) {
  128. $this->cache->put($file, $fileData);
  129. }
  130. $this->cache->remove('folder');
  131. foreach ($files as $file) {
  132. $this->assertFalse($this->cache->inCache($file));
  133. }
  134. }
  135. public function folderDataProvider() {
  136. return array(
  137. array('folder'),
  138. // that was too easy, try something harder
  139. array('☺, WHITE SMILING FACE, UTF-8 hex E298BA'),
  140. // what about 4 byte utf-8
  141. array('😐, NEUTRAL_FACE, UTF-8 hex F09F9890'),
  142. // now the crazy stuff
  143. array(', UNASSIGNED PRIVATE USE, UTF-8 hex EF9890'),
  144. // and my favorite
  145. array('w͢͢͝h͡o͢͡ ̸͢k̵͟n̴͘ǫw̸̛s͘ ̀́w͘͢ḩ̵a҉̡͢t ̧̕h́o̵r͏̵rors̡ ̶͡͠lį̶e͟͟ ̶͝in͢ ͏t̕h̷̡͟e ͟͟d̛a͜r̕͡k̢̨ ͡h̴e͏a̷̢̡rt́͏ ̴̷͠ò̵̶f̸ u̧͘ní̛͜c͢͏o̷͏d̸͢e̡͝')
  146. );
  147. }
  148. public function testEncryptedFolder() {
  149. $file1 = 'folder';
  150. $file2 = 'folder/bar';
  151. $file3 = 'folder/foo';
  152. $data1 = array('size' => 100, 'mtime' => 50, 'mimetype' => 'httpd/unix-directory');
  153. $fileData = array();
  154. $fileData['bar'] = array('size' => 1000, 'encrypted' => 1, 'mtime' => 20, 'mimetype' => 'foo/file');
  155. $fileData['foo'] = array('size' => 20, 'encrypted' => 1, 'mtime' => 25, 'mimetype' => 'foo/file');
  156. $this->cache->put($file1, $data1);
  157. $this->cache->put($file2, $fileData['bar']);
  158. $this->cache->put($file3, $fileData['foo']);
  159. $content = $this->cache->getFolderContents($file1);
  160. $this->assertEquals(count($content), 2);
  161. foreach ($content as $cachedData) {
  162. $data = $fileData[$cachedData['name']];
  163. }
  164. $file4 = 'folder/unkownSize';
  165. $fileData['unkownSize'] = array('size' => -1, 'mtime' => 25, 'mimetype' => 'foo/file');
  166. $this->cache->put($file4, $fileData['unkownSize']);
  167. $this->assertEquals(-1, $this->cache->calculateFolderSize($file1));
  168. $fileData['unkownSize'] = array('size' => 5, 'mtime' => 25, 'mimetype' => 'foo/file');
  169. $this->cache->put($file4, $fileData['unkownSize']);
  170. $this->assertEquals(1025, $this->cache->calculateFolderSize($file1));
  171. // direct cache entry retrieval returns the original values
  172. $entry = $this->cache->get($file1);
  173. $this->assertEquals(1025, $entry['size']);
  174. $this->cache->remove($file2);
  175. $this->cache->remove($file3);
  176. $this->cache->remove($file4);
  177. $this->assertEquals(0, $this->cache->calculateFolderSize($file1));
  178. $this->cache->remove('folder');
  179. $this->assertFalse($this->cache->inCache('folder/foo'));
  180. $this->assertFalse($this->cache->inCache('folder/bar'));
  181. }
  182. public function testRootFolderSizeForNonHomeStorage() {
  183. $dir1 = 'knownsize';
  184. $dir2 = 'unknownsize';
  185. $fileData = array();
  186. $fileData[''] = array('size' => -1, 'mtime' => 20, 'mimetype' => 'httpd/unix-directory');
  187. $fileData[$dir1] = array('size' => 1000, 'mtime' => 20, 'mimetype' => 'httpd/unix-directory');
  188. $fileData[$dir2] = array('size' => -1, 'mtime' => 25, 'mimetype' => 'httpd/unix-directory');
  189. $this->cache->put('', $fileData['']);
  190. $this->cache->put($dir1, $fileData[$dir1]);
  191. $this->cache->put($dir2, $fileData[$dir2]);
  192. $this->assertTrue($this->cache->inCache($dir1));
  193. $this->assertTrue($this->cache->inCache($dir2));
  194. // check that root size ignored the unknown sizes
  195. $this->assertEquals(-1, $this->cache->calculateFolderSize(''));
  196. // clean up
  197. $this->cache->remove('');
  198. $this->cache->remove($dir1);
  199. $this->cache->remove($dir2);
  200. $this->assertFalse($this->cache->inCache($dir1));
  201. $this->assertFalse($this->cache->inCache($dir2));
  202. }
  203. function testStatus() {
  204. $this->assertEquals(\OC\Files\Cache\Cache::NOT_FOUND, $this->cache->getStatus('foo'));
  205. $this->cache->put('foo', array('size' => -1));
  206. $this->assertEquals(\OC\Files\Cache\Cache::PARTIAL, $this->cache->getStatus('foo'));
  207. $this->cache->put('foo', array('size' => -1, 'mtime' => 20, 'mimetype' => 'foo/file'));
  208. $this->assertEquals(\OC\Files\Cache\Cache::SHALLOW, $this->cache->getStatus('foo'));
  209. $this->cache->put('foo', array('size' => 10));
  210. $this->assertEquals(\OC\Files\Cache\Cache::COMPLETE, $this->cache->getStatus('foo'));
  211. }
  212. public function putWithAllKindOfQuotesData() {
  213. return [
  214. ['`backtick`'],
  215. ['´forward´'],
  216. ['\'single\''],
  217. ];
  218. }
  219. /**
  220. * @dataProvider putWithAllKindOfQuotesData
  221. * @param $fileName
  222. */
  223. public function testPutWithAllKindOfQuotes($fileName) {
  224. $this->assertEquals(\OC\Files\Cache\Cache::NOT_FOUND, $this->cache->get($fileName));
  225. $this->cache->put($fileName, array('size' => 20, 'mtime' => 25, 'mimetype' => 'foo/file', 'etag' => $fileName));
  226. $cacheEntry = $this->cache->get($fileName);
  227. $this->assertEquals($fileName, $cacheEntry['etag']);
  228. $this->assertEquals($fileName, $cacheEntry['path']);
  229. }
  230. function testSearch() {
  231. $file1 = 'folder';
  232. $file2 = 'folder/foobar';
  233. $file3 = 'folder/foo';
  234. $data1 = array('size' => 100, 'mtime' => 50, 'mimetype' => 'foo/folder');
  235. $fileData = array();
  236. $fileData['foobar'] = array('size' => 1000, 'mtime' => 20, 'mimetype' => 'foo/file');
  237. $fileData['foo'] = array('size' => 20, 'mtime' => 25, 'mimetype' => 'foo/file');
  238. $this->cache->put($file1, $data1);
  239. $this->cache->put($file2, $fileData['foobar']);
  240. $this->cache->put($file3, $fileData['foo']);
  241. $this->assertEquals(2, count($this->cache->search('%foo%')));
  242. $this->assertEquals(1, count($this->cache->search('foo')));
  243. $this->assertEquals(1, count($this->cache->search('%folder%')));
  244. $this->assertEquals(1, count($this->cache->search('folder%')));
  245. $this->assertEquals(3, count($this->cache->search('%')));
  246. // case insensitive search should match the same files
  247. $this->assertEquals(2, count($this->cache->search('%Foo%')));
  248. $this->assertEquals(1, count($this->cache->search('Foo')));
  249. $this->assertEquals(1, count($this->cache->search('%Folder%')));
  250. $this->assertEquals(1, count($this->cache->search('Folder%')));
  251. $this->assertEquals(3, count($this->cache->searchByMime('foo')));
  252. $this->assertEquals(2, count($this->cache->searchByMime('foo/file')));
  253. }
  254. function testSearchByTag() {
  255. $userId = $this->getUniqueId('user');
  256. \OC_User::createUser($userId, $userId);
  257. $this->loginAsUser($userId);
  258. $user = new \OC\User\User($userId, null);
  259. $file1 = 'folder';
  260. $file2 = 'folder/foobar';
  261. $file3 = 'folder/foo';
  262. $file4 = 'folder/foo2';
  263. $file5 = 'folder/foo3';
  264. $data1 = array('size' => 100, 'mtime' => 50, 'mimetype' => 'foo/folder');
  265. $fileData = array();
  266. $fileData['foobar'] = array('size' => 1000, 'mtime' => 20, 'mimetype' => 'foo/file');
  267. $fileData['foo'] = array('size' => 20, 'mtime' => 25, 'mimetype' => 'foo/file');
  268. $fileData['foo2'] = array('size' => 25, 'mtime' => 28, 'mimetype' => 'foo/file');
  269. $fileData['foo3'] = array('size' => 88, 'mtime' => 34, 'mimetype' => 'foo/file');
  270. $id1 = $this->cache->put($file1, $data1);
  271. $id2 = $this->cache->put($file2, $fileData['foobar']);
  272. $id3 = $this->cache->put($file3, $fileData['foo']);
  273. $id4 = $this->cache->put($file4, $fileData['foo2']);
  274. $id5 = $this->cache->put($file5, $fileData['foo3']);
  275. $tagManager = \OC::$server->getTagManager()->load('files', null, null, $userId);
  276. $this->assertTrue($tagManager->tagAs($id1, 'tag1'));
  277. $this->assertTrue($tagManager->tagAs($id1, 'tag2'));
  278. $this->assertTrue($tagManager->tagAs($id2, 'tag2'));
  279. $this->assertTrue($tagManager->tagAs($id3, 'tag1'));
  280. $this->assertTrue($tagManager->tagAs($id4, 'tag2'));
  281. // use tag name
  282. $results = $this->cache->searchByTag('tag1', $userId);
  283. $this->assertEquals(2, count($results));
  284. usort($results, function($value1, $value2) { return $value1['name'] >= $value2['name']; });
  285. $this->assertEquals('folder', $results[0]['name']);
  286. $this->assertEquals('foo', $results[1]['name']);
  287. // use tag id
  288. $tags = $tagManager->getTagsForUser($userId);
  289. $this->assertNotEmpty($tags);
  290. $tags = array_filter($tags, function($tag) { return $tag->getName() === 'tag2'; });
  291. $results = $this->cache->searchByTag(current($tags)->getId(), $userId);
  292. $this->assertEquals(3, count($results));
  293. usort($results, function($value1, $value2) { return $value1['name'] >= $value2['name']; });
  294. $this->assertEquals('folder', $results[0]['name']);
  295. $this->assertEquals('foo2', $results[1]['name']);
  296. $this->assertEquals('foobar', $results[2]['name']);
  297. $tagManager->delete('tag1');
  298. $tagManager->delete('tag2');
  299. $this->logout();
  300. \OC_User::deleteUser($userId);
  301. }
  302. function testMove() {
  303. $file1 = 'folder';
  304. $file2 = 'folder/bar';
  305. $file3 = 'folder/foo';
  306. $file4 = 'folder/foo/1';
  307. $file5 = 'folder/foo/2';
  308. $data = array('size' => 100, 'mtime' => 50, 'mimetype' => 'foo/bar');
  309. $folderData = array('size' => 100, 'mtime' => 50, 'mimetype' => 'httpd/unix-directory');
  310. $this->cache->put($file1, $folderData);
  311. $this->cache->put($file2, $folderData);
  312. $this->cache->put($file3, $folderData);
  313. $this->cache->put($file4, $data);
  314. $this->cache->put($file5, $data);
  315. /* simulate a second user with a different storage id but the same folder structure */
  316. $this->cache2->put($file1, $folderData);
  317. $this->cache2->put($file2, $folderData);
  318. $this->cache2->put($file3, $folderData);
  319. $this->cache2->put($file4, $data);
  320. $this->cache2->put($file5, $data);
  321. $this->cache->move('folder/foo', 'folder/foobar');
  322. $this->assertFalse($this->cache->inCache('folder/foo'));
  323. $this->assertFalse($this->cache->inCache('folder/foo/1'));
  324. $this->assertFalse($this->cache->inCache('folder/foo/2'));
  325. $this->assertTrue($this->cache->inCache('folder/bar'));
  326. $this->assertTrue($this->cache->inCache('folder/foobar'));
  327. $this->assertTrue($this->cache->inCache('folder/foobar/1'));
  328. $this->assertTrue($this->cache->inCache('folder/foobar/2'));
  329. /* the folder structure of the second user must not change! */
  330. $this->assertTrue($this->cache2->inCache('folder/bar'));
  331. $this->assertTrue($this->cache2->inCache('folder/foo'));
  332. $this->assertTrue($this->cache2->inCache('folder/foo/1'));
  333. $this->assertTrue($this->cache2->inCache('folder/foo/2'));
  334. $this->assertFalse($this->cache2->inCache('folder/foobar'));
  335. $this->assertFalse($this->cache2->inCache('folder/foobar/1'));
  336. $this->assertFalse($this->cache2->inCache('folder/foobar/2'));
  337. }
  338. function testGetIncomplete() {
  339. $file1 = 'folder1';
  340. $file2 = 'folder2';
  341. $file3 = 'folder3';
  342. $file4 = 'folder4';
  343. $data = array('size' => 10, 'mtime' => 50, 'mimetype' => 'foo/bar');
  344. $this->cache->put($file1, $data);
  345. $data['size'] = -1;
  346. $this->cache->put($file2, $data);
  347. $this->cache->put($file3, $data);
  348. $data['size'] = 12;
  349. $this->cache->put($file4, $data);
  350. $this->assertEquals($file3, $this->cache->getIncomplete());
  351. }
  352. function testNonExisting() {
  353. $this->assertFalse($this->cache->get('foo.txt'));
  354. $this->assertEquals(array(), $this->cache->getFolderContents('foo'));
  355. }
  356. function testGetById() {
  357. $storageId = $this->storage->getId();
  358. $data = array('size' => 1000, 'mtime' => 20, 'mimetype' => 'foo/file');
  359. $id = $this->cache->put('foo', $data);
  360. if (strlen($storageId) > 64) {
  361. $storageId = md5($storageId);
  362. }
  363. $this->assertEquals(array($storageId, 'foo'), \OC\Files\Cache\Cache::getById($id));
  364. }
  365. function testStorageMTime() {
  366. $data = array('size' => 1000, 'mtime' => 20, 'mimetype' => 'foo/file');
  367. $this->cache->put('foo', $data);
  368. $cachedData = $this->cache->get('foo');
  369. $this->assertEquals($data['mtime'], $cachedData['storage_mtime']); //if no storage_mtime is saved, mtime should be used
  370. $this->cache->put('foo', array('storage_mtime' => 30)); //when setting storage_mtime, mtime is also set
  371. $cachedData = $this->cache->get('foo');
  372. $this->assertEquals(30, $cachedData['storage_mtime']);
  373. $this->assertEquals(30, $cachedData['mtime']);
  374. $this->cache->put('foo', array('mtime' => 25)); //setting mtime does not change storage_mtime
  375. $cachedData = $this->cache->get('foo');
  376. $this->assertEquals(30, $cachedData['storage_mtime']);
  377. $this->assertEquals(25, $cachedData['mtime']);
  378. }
  379. function testLongId() {
  380. $storage = new LongId(array());
  381. $cache = $storage->getCache();
  382. $storageId = $storage->getId();
  383. $data = array('size' => 1000, 'mtime' => 20, 'mimetype' => 'foo/file');
  384. $id = $cache->put('foo', $data);
  385. $this->assertEquals(array(md5($storageId), 'foo'), \OC\Files\Cache\Cache::getById($id));
  386. }
  387. /**
  388. * this test show the bug resulting if we have no normalizer installed
  389. */
  390. public function testWithoutNormalizer() {
  391. // folder name "Schön" with U+00F6 (normalized)
  392. $folderWith00F6 = "\x53\x63\x68\xc3\xb6\x6e";
  393. // folder name "Schön" with U+0308 (un-normalized)
  394. $folderWith0308 = "\x53\x63\x68\x6f\xcc\x88\x6e";
  395. /**
  396. * @var \OC\Files\Cache\Cache | PHPUnit_Framework_MockObject_MockObject $cacheMock
  397. */
  398. $cacheMock = $this->getMock('\OC\Files\Cache\Cache', array('normalize'), array($this->storage), '', true);
  399. $cacheMock->expects($this->any())
  400. ->method('normalize')
  401. ->will($this->returnArgument(0));
  402. $data = array('size' => 100, 'mtime' => 50, 'mimetype' => 'httpd/unix-directory');
  403. // put root folder
  404. $this->assertFalse($cacheMock->get('folder'));
  405. $this->assertGreaterThan(0, $cacheMock->put('folder', $data));
  406. // put un-normalized folder
  407. $this->assertFalse($cacheMock->get('folder/' . $folderWith0308));
  408. $this->assertGreaterThan(0, $cacheMock->put('folder/' . $folderWith0308, $data));
  409. // get un-normalized folder by name
  410. $unNormalizedFolderName = $cacheMock->get('folder/' . $folderWith0308);
  411. // check if database layer normalized the folder name (this should not happen)
  412. $this->assertEquals($folderWith0308, $unNormalizedFolderName['name']);
  413. // put normalized folder
  414. $this->assertFalse($cacheMock->get('folder/' . $folderWith00F6));
  415. $this->assertGreaterThan(0, $cacheMock->put('folder/' . $folderWith00F6, $data));
  416. // this is our bug, we have two different hashes with the same name (Schön)
  417. $this->assertEquals(2, count($cacheMock->getFolderContents('folder')));
  418. }
  419. /**
  420. * this test shows that there is no bug if we use the normalizer
  421. */
  422. public function testWithNormalizer() {
  423. if (!class_exists('Patchwork\PHP\Shim\Normalizer')) {
  424. $this->markTestSkipped('The 3rdparty Normalizer extension is not available.');
  425. return;
  426. }
  427. // folder name "Schön" with U+00F6 (normalized)
  428. $folderWith00F6 = "\x53\x63\x68\xc3\xb6\x6e";
  429. // folder name "Schön" with U+0308 (un-normalized)
  430. $folderWith0308 = "\x53\x63\x68\x6f\xcc\x88\x6e";
  431. $data = array('size' => 100, 'mtime' => 50, 'mimetype' => 'httpd/unix-directory');
  432. // put root folder
  433. $this->assertFalse($this->cache->get('folder'));
  434. $this->assertGreaterThan(0, $this->cache->put('folder', $data));
  435. // put un-normalized folder
  436. $this->assertFalse($this->cache->get('folder/' . $folderWith0308));
  437. $this->assertGreaterThan(0, $this->cache->put('folder/' . $folderWith0308, $data));
  438. // get un-normalized folder by name
  439. $unNormalizedFolderName = $this->cache->get('folder/' . $folderWith0308);
  440. // check if folder name was normalized
  441. $this->assertEquals($folderWith00F6, $unNormalizedFolderName['name']);
  442. // put normalized folder
  443. $this->assertTrue(is_array($this->cache->get('folder/' . $folderWith00F6)));
  444. $this->assertGreaterThan(0, $this->cache->put('folder/' . $folderWith00F6, $data));
  445. // at this point we should have only one folder named "Schön"
  446. $this->assertEquals(1, count($this->cache->getFolderContents('folder')));
  447. }
  448. function bogusPathNamesProvider() {
  449. return array(
  450. array('/bogus.txt', 'bogus.txt'),
  451. array('//bogus.txt', 'bogus.txt'),
  452. array('bogus/', 'bogus'),
  453. array('bogus//', 'bogus'),
  454. );
  455. }
  456. /**
  457. * Test bogus paths with leading or doubled slashes
  458. *
  459. * @dataProvider bogusPathNamesProvider
  460. */
  461. public function testBogusPaths($bogusPath, $fixedBogusPath) {
  462. $data = array('size' => 100, 'mtime' => 50, 'mimetype' => 'httpd/unix-directory');
  463. // put root folder
  464. $this->assertFalse($this->cache->get(''));
  465. $parentId = $this->cache->put('', $data);
  466. $this->assertGreaterThan(0, $parentId);
  467. $this->assertGreaterThan(0, $this->cache->put($bogusPath, $data));
  468. $newData = $this->cache->get($fixedBogusPath);
  469. $this->assertNotFalse($newData);
  470. $this->assertEquals($fixedBogusPath, $newData['path']);
  471. // parent is the correct one, resolved properly (they used to not be)
  472. $this->assertEquals($parentId, $newData['parent']);
  473. $newDataFromBogus = $this->cache->get($bogusPath);
  474. // same entry
  475. $this->assertEquals($newData, $newDataFromBogus);
  476. }
  477. public function testNoReuseOfFileId() {
  478. $data1 = array('size' => 100, 'mtime' => 50, 'mimetype' => 'text/plain');
  479. $this->cache->put('somefile.txt', $data1);
  480. $info = $this->cache->get('somefile.txt');
  481. $fileId = $info['fileid'];
  482. $this->cache->remove('somefile.txt');
  483. $data2 = array('size' => 200, 'mtime' => 100, 'mimetype' => 'text/plain');
  484. $this->cache->put('anotherfile.txt', $data2);
  485. $info2 = $this->cache->get('anotherfile.txt');
  486. $fileId2 = $info2['fileid'];
  487. $this->assertNotEquals($fileId, $fileId2);
  488. }
  489. protected function tearDown() {
  490. if ($this->cache) {
  491. $this->cache->clear();
  492. }
  493. parent::tearDown();
  494. }
  495. protected function setUp() {
  496. parent::setUp();
  497. $this->storage = new \OC\Files\Storage\Temporary(array());
  498. $this->storage2 = new \OC\Files\Storage\Temporary(array());
  499. $this->cache = new \OC\Files\Cache\Cache($this->storage);
  500. $this->cache2 = new \OC\Files\Cache\Cache($this->storage2);
  501. }
  502. }