clientSpec.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851
  1. /**
  2. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  3. * SPDX-FileCopyrightText: 2015 ownCloud Inc.
  4. * SPDX-License-Identifier: AGPL-3.0-or-later
  5. */
  6. /* global dav */
  7. describe('OC.Files.Client tests', function() {
  8. var Client = OC.Files.Client;
  9. var baseUrl;
  10. var client;
  11. var requestStub;
  12. var requestDeferred;
  13. beforeEach(function() {
  14. requestDeferred = new $.Deferred();
  15. requestStub = sinon.stub(dav.Client.prototype, 'request').returns(requestDeferred.promise());
  16. baseUrl = 'https://testhost/owncloud/remote.php/webdav/';
  17. client = new Client({
  18. host: 'testhost',
  19. root: '/owncloud/remote.php/webdav',
  20. useHTTPS: true
  21. });
  22. });
  23. afterEach(function() {
  24. client = null;
  25. requestStub.restore();
  26. });
  27. /**
  28. * Send an status response and check that the given
  29. * promise gets its success handler called with the error
  30. * status code
  31. *
  32. * @param {Promise} promise promise
  33. * @param {number} status status to test
  34. */
  35. function respondAndCheckStatus(promise, status) {
  36. var successHandler = sinon.stub();
  37. var failHandler = sinon.stub();
  38. promise.done(successHandler);
  39. promise.fail(failHandler);
  40. requestDeferred.resolve({
  41. status: status,
  42. body: ''
  43. });
  44. promise.then(function() {
  45. expect(successHandler.calledOnce).toEqual(true);
  46. expect(successHandler.getCall(0).args[0]).toEqual(status);
  47. expect(failHandler.notCalled).toEqual(true);
  48. });
  49. return promise;
  50. }
  51. /**
  52. * Send an error response and check that the given
  53. * promise gets its fail handler called with the error
  54. * status code
  55. *
  56. * @param {Promise} promise promise object
  57. * @param {number} status error status to test
  58. */
  59. function respondAndCheckError(promise, status) {
  60. var successHandler = sinon.stub();
  61. var failHandler = sinon.stub();
  62. promise.done(successHandler);
  63. promise.fail(failHandler);
  64. var errorXml =
  65. '<d:error xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">' +
  66. ' <s:exception>Sabre\\DAV\\Exception\\SomeException</s:exception>' +
  67. ' <s:message>Some error message</s:message>' +
  68. '</d:error>';
  69. var parser = new DOMParser();
  70. requestDeferred.resolve({
  71. status: status,
  72. body: errorXml,
  73. xhr: {
  74. responseXML: parser.parseFromString(errorXml, 'application/xml')
  75. }
  76. });
  77. promise.then(function() {
  78. expect(failHandler.calledOnce).toEqual(true);
  79. expect(failHandler.getCall(0).args[0]).toEqual(status);
  80. expect(failHandler.getCall(0).args[1].status).toEqual(status);
  81. expect(failHandler.getCall(0).args[1].message).toEqual('Some error message');
  82. expect(failHandler.getCall(0).args[1].exception).toEqual('Sabre\\DAV\\Exception\\SomeException');
  83. expect(successHandler.notCalled).toEqual(true);
  84. });
  85. return promise;
  86. }
  87. /**
  88. * Returns a list of request properties parsed from the given request body.
  89. *
  90. * @param {string} requestBody request XML
  91. *
  92. * @return {Array.<String>} array of request properties in the format
  93. * "{NS:}propname"
  94. */
  95. function getRequestedProperties(requestBody) {
  96. var doc = (new window.DOMParser()).parseFromString(
  97. requestBody,
  98. 'application/xml'
  99. );
  100. var propRoots = doc.getElementsByTagNameNS('DAV:', 'prop');
  101. var propsList = propRoots.item(0).childNodes;
  102. return _.map(propsList, function(propNode) {
  103. return '{' + propNode.namespaceURI + '}' + propNode.localName;
  104. });
  105. }
  106. function makePropBlock(props) {
  107. var s = '<d:prop>\n';
  108. _.each(props, function(value, key) {
  109. s += '<' + key + '>' + value + '</' + key + '>\n';
  110. });
  111. return s + '</d:prop>\n';
  112. }
  113. function makeResponseBlock(href, props, failedProps) {
  114. var s = '<d:response>\n';
  115. s += '<d:href>' + href + '</d:href>\n';
  116. s += '<d:propstat>\n';
  117. s += makePropBlock(props);
  118. s += '<d:status>HTTP/1.1 200 OK</d:status>';
  119. s += '</d:propstat>\n';
  120. if (failedProps) {
  121. s += '<d:propstat>\n';
  122. _.each(failedProps, function(prop) {
  123. s += '<' + prop + '/>\n';
  124. });
  125. s += '<d:status>HTTP/1.1 404 Not Found</d:status>\n';
  126. s += '</d:propstat>\n';
  127. }
  128. return s + '</d:response>\n';
  129. }
  130. describe('file listing', function() {
  131. // TODO: switch this to the already parsed structure
  132. var folderContentsXml = dav.Client.prototype.parseMultiStatus(
  133. '<?xml version="1.0" encoding="utf-8"?>' +
  134. '<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns">' +
  135. makeResponseBlock(
  136. '/owncloud/remote.php/webdav/path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/',
  137. {
  138. 'd:getlastmodified': 'Fri, 10 Jul 2015 10:00:05 GMT',
  139. 'd:getetag': '"56cfcabd79abb"',
  140. 'd:resourcetype': '<d:collection/>',
  141. 'oc:id': '00000011oc2d13a6a068',
  142. 'oc:fileid': '11',
  143. 'oc:permissions': 'GRDNVCK',
  144. 'oc:size': '120'
  145. },
  146. [
  147. 'd:getcontenttype',
  148. 'd:getcontentlength'
  149. ]
  150. ) +
  151. makeResponseBlock(
  152. '/owncloud/remote.php/webdav/path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/One.txt',
  153. {
  154. 'd:getlastmodified': 'Fri, 10 Jul 2015 13:38:05 GMT',
  155. 'd:getetag': '"559fcabd79a38"',
  156. 'd:getcontenttype': 'text/plain',
  157. 'd:getcontentlength': 250,
  158. 'd:resourcetype': '',
  159. 'oc:id': '00000051oc2d13a6a068',
  160. 'oc:fileid': '51',
  161. 'oc:permissions': 'RDNVW'
  162. },
  163. [
  164. 'oc:size',
  165. ]
  166. ) +
  167. makeResponseBlock(
  168. '/owncloud/remote.php/webdav/path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/sub',
  169. {
  170. 'd:getlastmodified': 'Fri, 10 Jul 2015 14:00:00 GMT',
  171. 'd:getetag': '"66cfcabd79abb"',
  172. 'd:resourcetype': '<d:collection/>',
  173. 'oc:id': '00000015oc2d13a6a068',
  174. 'oc:fileid': '15',
  175. 'oc:permissions': 'GRDNVCK',
  176. 'oc:size': '100'
  177. },
  178. [
  179. 'd:getcontenttype',
  180. 'd:getcontentlength'
  181. ]
  182. ) +
  183. '</d:multistatus>'
  184. );
  185. it('sends PROPFIND with explicit properties to get file list', function() {
  186. client.getFolderContents('path/to space/文件夹');
  187. expect(requestStub.calledOnce).toEqual(true);
  188. expect(requestStub.lastCall.args[0]).toEqual('PROPFIND');
  189. expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9');
  190. expect(requestStub.lastCall.args[2].Depth).toEqual('1');
  191. var props = getRequestedProperties(requestStub.lastCall.args[3]);
  192. expect(props).toContain('{DAV:}getlastmodified');
  193. expect(props).toContain('{DAV:}getcontentlength');
  194. expect(props).toContain('{DAV:}getcontenttype');
  195. expect(props).toContain('{DAV:}getetag');
  196. expect(props).toContain('{DAV:}resourcetype');
  197. expect(props).toContain('{http://owncloud.org/ns}fileid');
  198. expect(props).toContain('{http://owncloud.org/ns}size');
  199. expect(props).toContain('{http://owncloud.org/ns}permissions');
  200. expect(props).toContain('{http://nextcloud.org/ns}is-encrypted');
  201. });
  202. it('sends PROPFIND to base url when empty path given', function() {
  203. client.getFolderContents('');
  204. expect(requestStub.calledOnce).toEqual(true);
  205. expect(requestStub.lastCall.args[1]).toEqual(baseUrl);
  206. });
  207. it('sends PROPFIND to base url when root path given', function() {
  208. client.getFolderContents('/');
  209. expect(requestStub.calledOnce).toEqual(true);
  210. expect(requestStub.lastCall.args[1]).toEqual(baseUrl);
  211. });
  212. it('parses the result list into a FileInfo array', function() {
  213. var promise = client.getFolderContents('path/to space/文件夹');
  214. expect(requestStub.calledOnce).toEqual(true);
  215. requestDeferred.resolve({
  216. status: 207,
  217. body: folderContentsXml
  218. });
  219. promise.then(function(status, response) {
  220. expect(status).toEqual(207);
  221. expect(_.isArray(response)).toEqual(true);
  222. expect(response.length).toEqual(2);
  223. // file entry
  224. var info = response[0];
  225. expect(info instanceof OC.Files.FileInfo).toEqual(true);
  226. expect(info.id).toEqual(51);
  227. expect(info.path).toEqual('/path/to space/文件夹');
  228. expect(info.name).toEqual('One.txt');
  229. expect(info.permissions).toEqual(26);
  230. expect(info.size).toEqual(250);
  231. expect(info.mtime).toEqual(1436535485000);
  232. expect(info.mimetype).toEqual('text/plain');
  233. expect(info.etag).toEqual('559fcabd79a38');
  234. expect(info.isEncrypted).toEqual(false);
  235. // sub entry
  236. info = response[1];
  237. expect(info instanceof OC.Files.FileInfo).toEqual(true);
  238. expect(info.id).toEqual(15);
  239. expect(info.path).toEqual('/path/to space/文件夹');
  240. expect(info.name).toEqual('sub');
  241. expect(info.permissions).toEqual(31);
  242. expect(info.size).toEqual(100);
  243. expect(info.mtime).toEqual(1436536800000);
  244. expect(info.mimetype).toEqual('httpd/unix-directory');
  245. expect(info.etag).toEqual('66cfcabd79abb');
  246. expect(info.isEncrypted).toEqual(false);
  247. });
  248. });
  249. it('returns parent node in result if specified', function() {
  250. var promise = client.getFolderContents('path/to space/文件夹', {includeParent: true});
  251. expect(requestStub.calledOnce).toEqual(true);
  252. requestDeferred.resolve({
  253. status: 207,
  254. body: folderContentsXml
  255. });
  256. promise.then(function(status, response) {
  257. expect(status).toEqual(207);
  258. expect(_.isArray(response)).toEqual(true);
  259. expect(response.length).toEqual(3);
  260. // root entry
  261. var info = response[0];
  262. expect(info instanceof OC.Files.FileInfo).toEqual(true);
  263. expect(info.id).toEqual(11);
  264. expect(info.path).toEqual('/path/to space');
  265. expect(info.name).toEqual('文件夹');
  266. expect(info.permissions).toEqual(31);
  267. expect(info.size).toEqual(120);
  268. expect(info.mtime).toEqual(1436522405000);
  269. expect(info.mimetype).toEqual('httpd/unix-directory');
  270. expect(info.etag).toEqual('56cfcabd79abb');
  271. expect(info.isEncrypted).toEqual(false);
  272. // the two other entries follow
  273. expect(response[1].id).toEqual(51);
  274. expect(response[2].id).toEqual(15);
  275. });
  276. });
  277. it('rejects promise when an error occurred', function() {
  278. var promise = client.getFolderContents('path/to space/文件夹', {includeParent: true});
  279. respondAndCheckError(promise, 404);
  280. });
  281. it('throws exception if arguments are missing', function() {
  282. // TODO
  283. });
  284. });
  285. describe('file filtering', function() {
  286. // TODO: switch this to the already parsed structure
  287. var folderContentsXml = dav.Client.prototype.parseMultiStatus(
  288. '<?xml version="1.0" encoding="utf-8"?>' +
  289. '<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns">' +
  290. makeResponseBlock(
  291. '/owncloud/remote.php/webdav/path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/',
  292. {
  293. 'd:getlastmodified': 'Fri, 10 Jul 2015 10:00:05 GMT',
  294. 'd:getetag': '"56cfcabd79abb"',
  295. 'd:resourcetype': '<d:collection/>',
  296. 'oc:id': '00000011oc2d13a6a068',
  297. 'oc:fileid': '11',
  298. 'oc:permissions': 'RDNVCK',
  299. 'oc:size': '120'
  300. },
  301. [
  302. 'd:getcontenttype',
  303. 'd:getcontentlength'
  304. ]
  305. ) +
  306. makeResponseBlock(
  307. '/owncloud/remote.php/webdav/path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/One.txt',
  308. {
  309. 'd:getlastmodified': 'Fri, 10 Jul 2015 13:38:05 GMT',
  310. 'd:getetag': '"559fcabd79a38"',
  311. 'd:getcontenttype': 'text/plain',
  312. 'd:getcontentlength': 250,
  313. 'd:resourcetype': '',
  314. 'oc:id': '00000051oc2d13a6a068',
  315. 'oc:fileid': '51',
  316. 'oc:permissions': 'RDNVW'
  317. },
  318. [
  319. 'oc:size',
  320. ]
  321. ) +
  322. makeResponseBlock(
  323. '/owncloud/remote.php/webdav/path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/sub',
  324. {
  325. 'd:getlastmodified': 'Fri, 10 Jul 2015 14:00:00 GMT',
  326. 'd:getetag': '"66cfcabd79abb"',
  327. 'd:resourcetype': '<d:collection/>',
  328. 'oc:id': '00000015oc2d13a6a068',
  329. 'oc:fileid': '15',
  330. 'oc:permissions': 'RDNVCK',
  331. 'oc:size': '100'
  332. },
  333. [
  334. 'd:getcontenttype',
  335. 'd:getcontentlength'
  336. ]
  337. ) +
  338. '</d:multistatus>'
  339. );
  340. it('sends REPORT with filter information', function() {
  341. client.getFilteredFiles({
  342. systemTagIds: ['123', '456']
  343. });
  344. expect(requestStub.calledOnce).toEqual(true);
  345. expect(requestStub.lastCall.args[0]).toEqual('REPORT');
  346. expect(requestStub.lastCall.args[1]).toEqual(baseUrl);
  347. var body = requestStub.lastCall.args[3];
  348. var doc = (new window.DOMParser()).parseFromString(
  349. body,
  350. 'application/xml'
  351. );
  352. var ns = 'http://owncloud.org/ns';
  353. expect(doc.documentElement.localName).toEqual('filter-files');
  354. expect(doc.documentElement.namespaceURI).toEqual(ns);
  355. var filterRoots = doc.getElementsByTagNameNS(ns, 'filter-rules');
  356. var rulesList = filterRoots[0] = doc.getElementsByTagNameNS(ns, 'systemtag');
  357. expect(rulesList.length).toEqual(2);
  358. expect(rulesList[0].localName).toEqual('systemtag');
  359. expect(rulesList[0].namespaceURI).toEqual(ns);
  360. expect(rulesList[0].textContent).toEqual('123');
  361. expect(rulesList[1].localName).toEqual('systemtag');
  362. expect(rulesList[1].namespaceURI).toEqual(ns);
  363. expect(rulesList[1].textContent).toEqual('456');
  364. });
  365. it('sends REPORT with explicit properties to filter file list', function() {
  366. client.getFilteredFiles({
  367. systemTagIds: ['123', '456']
  368. });
  369. expect(requestStub.calledOnce).toEqual(true);
  370. expect(requestStub.lastCall.args[0]).toEqual('REPORT');
  371. expect(requestStub.lastCall.args[1]).toEqual(baseUrl);
  372. var props = getRequestedProperties(requestStub.lastCall.args[3]);
  373. expect(props).toContain('{DAV:}getlastmodified');
  374. expect(props).toContain('{DAV:}getcontentlength');
  375. expect(props).toContain('{DAV:}getcontenttype');
  376. expect(props).toContain('{DAV:}getetag');
  377. expect(props).toContain('{DAV:}resourcetype');
  378. expect(props).toContain('{http://owncloud.org/ns}fileid');
  379. expect(props).toContain('{http://owncloud.org/ns}size');
  380. expect(props).toContain('{http://owncloud.org/ns}permissions');
  381. expect(props).toContain('{http://nextcloud.org/ns}is-encrypted');
  382. });
  383. it('parses the result list into a FileInfo array', function() {
  384. var promise = client.getFilteredFiles({
  385. systemTagIds: ['123', '456']
  386. });
  387. expect(requestStub.calledOnce).toEqual(true);
  388. requestDeferred.resolve({
  389. status: 207,
  390. body: folderContentsXml
  391. });
  392. promise.then(function(status, response) {
  393. expect(status).toEqual(207);
  394. expect(_.isArray(response)).toEqual(true);
  395. // returns all entries
  396. expect(response.length).toEqual(3);
  397. // file entry
  398. var info = response[0];
  399. expect(info instanceof OC.Files.FileInfo).toEqual(true);
  400. expect(info.id).toEqual(11);
  401. // file entry
  402. info = response[1];
  403. expect(info instanceof OC.Files.FileInfo).toEqual(true);
  404. expect(info.id).toEqual(51);
  405. // sub entry
  406. info = response[2];
  407. expect(info instanceof OC.Files.FileInfo).toEqual(true);
  408. expect(info.id).toEqual(15);
  409. });
  410. });
  411. it('throws exception if arguments are missing', function() {
  412. var thrown = null;
  413. try {
  414. client.getFilteredFiles({});
  415. } catch (e) {
  416. thrown = true;
  417. }
  418. expect(thrown).toEqual(true);
  419. });
  420. });
  421. describe('file info', function() {
  422. var responseXml = dav.Client.prototype.parseMultiStatus(
  423. '<?xml version="1.0" encoding="utf-8"?>' +
  424. '<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns">' +
  425. makeResponseBlock(
  426. '/owncloud/remote.php/webdav/path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/',
  427. {
  428. 'd:getlastmodified': 'Fri, 10 Jul 2015 10:00:05 GMT',
  429. 'd:getetag': '"56cfcabd79abb"',
  430. 'd:resourcetype': '<d:collection/>',
  431. 'oc:id': '00000011oc2d13a6a068',
  432. 'oc:fileid': '11',
  433. 'oc:permissions': 'GRDNVCK',
  434. 'oc:size': '120',
  435. 'nc:is-encrypted': '1'
  436. },
  437. [
  438. 'd:getcontenttype',
  439. 'd:getcontentlength'
  440. ]
  441. ) +
  442. '</d:multistatus>'
  443. );
  444. it('sends PROPFIND with zero depth to get single file info', function() {
  445. client.getFileInfo('path/to space/文件夹');
  446. expect(requestStub.calledOnce).toEqual(true);
  447. expect(requestStub.lastCall.args[0]).toEqual('PROPFIND');
  448. expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9');
  449. expect(requestStub.lastCall.args[2].Depth).toEqual('0');
  450. var props = getRequestedProperties(requestStub.lastCall.args[3]);
  451. expect(props).toContain('{DAV:}getlastmodified');
  452. expect(props).toContain('{DAV:}getcontentlength');
  453. expect(props).toContain('{DAV:}getcontenttype');
  454. expect(props).toContain('{DAV:}getetag');
  455. expect(props).toContain('{DAV:}resourcetype');
  456. expect(props).toContain('{http://owncloud.org/ns}fileid');
  457. expect(props).toContain('{http://owncloud.org/ns}size');
  458. expect(props).toContain('{http://owncloud.org/ns}permissions');
  459. expect(props).toContain('{http://nextcloud.org/ns}is-encrypted');
  460. });
  461. it('parses the result into a FileInfo', function() {
  462. var promise = client.getFileInfo('path/to space/文件夹');
  463. expect(requestStub.calledOnce).toEqual(true);
  464. requestDeferred.resolve({
  465. status: 207,
  466. body: responseXml
  467. });
  468. promise.then(function(status, response) {
  469. expect(status).toEqual(207);
  470. expect(_.isArray(response)).toEqual(false);
  471. var info = response;
  472. expect(info instanceof OC.Files.FileInfo).toEqual(true);
  473. expect(info.id).toEqual(11);
  474. expect(info.path).toEqual('/path/to space');
  475. expect(info.name).toEqual('文件夹');
  476. expect(info.permissions).toEqual(31);
  477. expect(info.size).toEqual(120);
  478. expect(info.mtime).toEqual(1436522405000);
  479. expect(info.mimetype).toEqual('httpd/unix-directory');
  480. expect(info.etag).toEqual('56cfcabd79abb');
  481. expect(info.isEncrypted).toEqual(true);
  482. });
  483. });
  484. it('properly parses entry inside root', function() {
  485. var responseXml = dav.Client.prototype.parseMultiStatus(
  486. '<?xml version="1.0" encoding="utf-8"?>' +
  487. '<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns">' +
  488. makeResponseBlock(
  489. '/owncloud/remote.php/webdav/in%20root',
  490. {
  491. 'd:getlastmodified': 'Fri, 10 Jul 2015 10:00:05 GMT',
  492. 'd:getetag': '"56cfcabd79abb"',
  493. 'd:resourcetype': '<d:collection/>',
  494. 'oc:id': '00000011oc2d13a6a068',
  495. 'oc:fileid': '11',
  496. 'oc:permissions': 'GRDNVCK',
  497. 'oc:size': '120'
  498. },
  499. [
  500. 'd:getcontenttype',
  501. 'd:getcontentlength'
  502. ]
  503. ) +
  504. '</d:multistatus>'
  505. );
  506. var promise = client.getFileInfo('in root');
  507. expect(requestStub.calledOnce).toEqual(true);
  508. requestDeferred.resolve({
  509. status: 207,
  510. body: responseXml
  511. });
  512. promise.then(function(status, response) {
  513. expect(status).toEqual(207);
  514. expect(_.isArray(response)).toEqual(false);
  515. var info = response;
  516. expect(info instanceof OC.Files.FileInfo).toEqual(true);
  517. expect(info.id).toEqual(11);
  518. expect(info.path).toEqual('/');
  519. expect(info.name).toEqual('in root');
  520. expect(info.permissions).toEqual(31);
  521. expect(info.size).toEqual(120);
  522. expect(info.mtime).toEqual(1436522405000);
  523. expect(info.mimetype).toEqual('httpd/unix-directory');
  524. expect(info.etag).toEqual('56cfcabd79abb');
  525. expect(info.isEncrypted).toEqual(false);
  526. });
  527. });
  528. it('rejects promise when an error occurred', function() {
  529. var promise = client.getFileInfo('path/to space/文件夹');
  530. respondAndCheckError(promise, 404);
  531. });
  532. it('throws exception if arguments are missing', function() {
  533. // TODO
  534. });
  535. });
  536. describe('permissions', function() {
  537. function getFileInfoWithPermission(webdavPerm, isFile) {
  538. var props = {
  539. 'd:getlastmodified': 'Fri, 10 Jul 2015 13:38:05 GMT',
  540. 'd:getetag': '"559fcabd79a38"',
  541. 'd:getcontentlength': 250,
  542. 'oc:id': '00000051oc2d13a6a068',
  543. 'oc:fileid': '51',
  544. 'oc:permissions': webdavPerm,
  545. };
  546. if (isFile) {
  547. props['d:getcontenttype'] = 'text/plain';
  548. } else {
  549. props['d:resourcetype'] = '<d:collection/>';
  550. }
  551. var def = new $.Deferred();
  552. requestStub.reset();
  553. requestStub.returns(def);
  554. var responseXml = dav.Client.prototype.parseMultiStatus(
  555. '<?xml version="1.0" encoding="utf-8"?>' +
  556. '<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns">' +
  557. makeResponseBlock(
  558. '/owncloud/remote.php/webdav/file.txt',
  559. props
  560. ) +
  561. '</d:multistatus>'
  562. );
  563. var promise = client.getFileInfo('file.txt');
  564. expect(requestStub.calledOnce).toEqual(true);
  565. def.resolve({
  566. status: 207,
  567. body: responseXml
  568. });
  569. return promise;
  570. }
  571. function testPermission(permission, isFile, expectedPermissions) {
  572. var promise = getFileInfoWithPermission(permission, isFile);
  573. promise.then(function(status, result) {
  574. expect(result.permissions).toEqual(expectedPermissions);
  575. });
  576. }
  577. function testMountType(permission, isFile, expectedMountType) {
  578. var promise = getFileInfoWithPermission(permission, isFile);
  579. promise.then(function(status, result) {
  580. expect(result.mountType).toEqual(expectedMountType);
  581. });
  582. }
  583. it('properly parses file permissions', function() {
  584. // permission, isFile, expectedPermissions
  585. var testCases = [
  586. ['', true, OC.PERMISSION_NONE],
  587. ['C', true, OC.PERMISSION_CREATE],
  588. ['K', true, OC.PERMISSION_CREATE],
  589. ['G', true, OC.PERMISSION_READ],
  590. ['W', true, OC.PERMISSION_UPDATE],
  591. ['D', true, OC.PERMISSION_DELETE],
  592. ['R', true, OC.PERMISSION_SHARE],
  593. ['CKGWDR', true, OC.PERMISSION_ALL]
  594. ];
  595. _.each(testCases, function(testCase) {
  596. return testPermission.apply(this, testCase);
  597. });
  598. });
  599. it('properly parses mount types', function() {
  600. var testCases = [
  601. ['CKGWDR', false, null],
  602. ['M', false, 'external'],
  603. ['S', false, 'shared'],
  604. ['SM', false, 'shared']
  605. ];
  606. _.each(testCases, function(testCase) {
  607. return testMountType.apply(this, testCase);
  608. });
  609. });
  610. });
  611. describe('get file contents', function() {
  612. it('returns file contents', function() {
  613. var promise = client.getFileContents('path/to space/文件夹/One.txt');
  614. expect(requestStub.calledOnce).toEqual(true);
  615. expect(requestStub.lastCall.args[0]).toEqual('GET');
  616. expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/One.txt');
  617. requestDeferred.resolve({
  618. status: 200,
  619. body: 'some contents'
  620. });
  621. promise.then(function(status, response) {
  622. expect(status).toEqual(200);
  623. expect(response).toEqual('some contents');
  624. });
  625. });
  626. it('rejects promise when an error occurred', function() {
  627. var promise = client.getFileContents('path/to space/文件夹/One.txt');
  628. respondAndCheckError(promise, 409);
  629. });
  630. it('throws exception if arguments are missing', function() {
  631. // TODO
  632. });
  633. });
  634. describe('put file contents', function() {
  635. it('sends PUT with file contents', function() {
  636. var promise = client.putFileContents(
  637. 'path/to space/文件夹/One.txt',
  638. 'some contents'
  639. );
  640. expect(requestStub.calledOnce).toEqual(true);
  641. expect(requestStub.lastCall.args[0]).toEqual('PUT');
  642. expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/One.txt');
  643. expect(requestStub.lastCall.args[2]['If-None-Match']).toEqual('*');
  644. expect(requestStub.lastCall.args[2]['Content-Type']).toEqual('text/plain;charset=utf-8');
  645. expect(requestStub.lastCall.args[3]).toEqual('some contents');
  646. respondAndCheckStatus(promise, 201);
  647. });
  648. it('sends PUT with file contents with headers matching options', function() {
  649. var promise = client.putFileContents(
  650. 'path/to space/文件夹/One.txt',
  651. 'some contents',
  652. {
  653. overwrite: false,
  654. contentType: 'text/markdown'
  655. }
  656. );
  657. expect(requestStub.calledOnce).toEqual(true);
  658. expect(requestStub.lastCall.args[0]).toEqual('PUT');
  659. expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/One.txt');
  660. expect(requestStub.lastCall.args[2]['If-None-Match']).not.toBeDefined();
  661. expect(requestStub.lastCall.args[2]['Content-Type']).toEqual('text/markdown');
  662. expect(requestStub.lastCall.args[3]).toEqual('some contents');
  663. respondAndCheckStatus(promise, 201);
  664. });
  665. it('rejects promise when an error occurred', function() {
  666. var promise = client.putFileContents(
  667. 'path/to space/文件夹/One.txt',
  668. 'some contents'
  669. );
  670. respondAndCheckError(promise, 409);
  671. });
  672. it('throws exception if arguments are missing', function() {
  673. // TODO
  674. });
  675. });
  676. describe('create directory', function() {
  677. it('sends MKCOL with specified path', function() {
  678. var promise = client.createDirectory('path/to space/文件夹/new dir');
  679. expect(requestStub.calledOnce).toEqual(true);
  680. expect(requestStub.lastCall.args[0]).toEqual('MKCOL');
  681. expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/new%20dir');
  682. respondAndCheckStatus(promise, 201);
  683. });
  684. it('rejects promise when an error occurred', function() {
  685. var promise = client.createDirectory('path/to space/文件夹/new dir');
  686. respondAndCheckError(promise, 404);
  687. });
  688. it('throws exception if arguments are missing', function() {
  689. // TODO
  690. });
  691. });
  692. describe('deletion', function() {
  693. it('sends DELETE with specified path', function() {
  694. var promise = client.remove('path/to space/文件夹');
  695. expect(requestStub.calledOnce).toEqual(true);
  696. expect(requestStub.lastCall.args[0]).toEqual('DELETE');
  697. expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9');
  698. respondAndCheckStatus(promise, 201);
  699. });
  700. it('rejects promise when an error occurred', function() {
  701. var promise = client.remove('path/to space/文件夹');
  702. respondAndCheckError(promise, 404);
  703. });
  704. it('throws exception if arguments are missing', function() {
  705. // TODO
  706. });
  707. });
  708. describe('move', function() {
  709. it('sends MOVE with specified paths with fail on overwrite by default', function() {
  710. var promise = client.move(
  711. 'path/to space/文件夹',
  712. 'path/to space/anotherdir/文件夹'
  713. );
  714. expect(requestStub.calledOnce).toEqual(true);
  715. expect(requestStub.lastCall.args[0]).toEqual('MOVE');
  716. expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9');
  717. expect(requestStub.lastCall.args[2].Destination)
  718. .toEqual(baseUrl + 'path/to%20space/anotherdir/%E6%96%87%E4%BB%B6%E5%A4%B9');
  719. expect(requestStub.lastCall.args[2].Overwrite)
  720. .toEqual('F');
  721. respondAndCheckStatus(promise, 201);
  722. });
  723. it('sends MOVE with silent overwrite mode when specified', function() {
  724. var promise = client.move(
  725. 'path/to space/文件夹',
  726. 'path/to space/anotherdir/文件夹',
  727. {allowOverwrite: true}
  728. );
  729. expect(requestStub.calledOnce).toEqual(true);
  730. expect(requestStub.lastCall.args[0]).toEqual('MOVE');
  731. expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9');
  732. expect(requestStub.lastCall.args[2].Destination)
  733. .toEqual(baseUrl + 'path/to%20space/anotherdir/%E6%96%87%E4%BB%B6%E5%A4%B9');
  734. expect(requestStub.lastCall.args[2].Overwrite)
  735. .not.toBeDefined();
  736. respondAndCheckStatus(promise, 201);
  737. });
  738. it('rejects promise when an error occurred', function() {
  739. var promise = client.move(
  740. 'path/to space/文件夹',
  741. 'path/to space/anotherdir/文件夹',
  742. {allowOverwrite: true}
  743. );
  744. respondAndCheckError(promise, 404);
  745. });
  746. it('throws exception if arguments are missing', function() {
  747. // TODO
  748. });
  749. });
  750. });