clientSpec.js 27 KB

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