From 8782004742db8759e1ad1b5e13acfe17cd14cb93 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Thu, 4 Feb 2016 15:38:54 +0100 Subject: [PATCH 1/2] Small fixes in Dav files client Remove double leading slash in path. Add utf-8 in default content type. --- core/js/files/client.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/js/files/client.js b/core/js/files/client.js index 3d31f974ff..b736447d65 100644 --- a/core/js/files/client.js +++ b/core/js/files/client.js @@ -239,7 +239,7 @@ path = path.substr(0, path.length - 1); } - path = '/' + decodeURIComponent(path); + path = decodeURIComponent(path); if (response.propStat.length === 1 && response.propStat[0].status !== 200) { return null; @@ -505,7 +505,7 @@ var promise = deferred.promise(); options = options || {}; var headers = _.extend({}, this._defaultHeaders); - var contentType = 'text/plain'; + var contentType = 'text/plain;charset=utf-8'; if (options.contentType) { contentType = options.contentType; } From 23f0515771acc29dc4feb7c8829ade0b424336d0 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Thu, 4 Feb 2016 15:39:18 +0100 Subject: [PATCH 2/2] Fix JS DAV files client unit tests Instead of trying to mock the promise, just stub davclient.js' request object. --- core/js/tests/specs/files/clientSpec.js | 288 ++++++++++++------------ 1 file changed, 141 insertions(+), 147 deletions(-) diff --git a/core/js/tests/specs/files/clientSpec.js b/core/js/tests/specs/files/clientSpec.js index 61cff0a66e..b945e1bb4d 100644 --- a/core/js/tests/specs/files/clientSpec.js +++ b/core/js/tests/specs/files/clientSpec.js @@ -19,12 +19,18 @@ * */ +/* global dav */ + describe('OC.Files.Client tests', function() { var Client = OC.Files.Client; var baseUrl; var client; + var requestStub; + var requestDeferred; beforeEach(function() { + requestDeferred = new $.Deferred(); + requestStub = sinon.stub(dav.Client.prototype, 'request').returns(requestDeferred.promise()); baseUrl = 'https://testhost/owncloud/remote.php/webdav/'; client = new Client({ @@ -35,6 +41,7 @@ describe('OC.Files.Client tests', function() { }); afterEach(function() { client = null; + requestStub.restore(); }); /** @@ -51,11 +58,10 @@ describe('OC.Files.Client tests', function() { promise.done(successHandler); promise.fail(failHandler); - fakeServer.requests[0].respond( - status, - {'Content-Type': 'application/xml'}, - '' - ); + requestDeferred.resolve({ + status: status, + body: '' + }); promise.then(function() { expect(successHandler.calledOnce).toEqual(true); @@ -81,19 +87,16 @@ describe('OC.Files.Client tests', function() { promise.done(successHandler); promise.fail(failHandler); - fakeServer.requests[0].respond( - status, - {'Content-Type': 'application/xml'}, - '' - ); + requestDeferred.resolve({ + status: status, + body: '' + }); promise.then(function() { expect(failHandler.calledOnce).toEqual(true); expect(failHandler.calledWith(status)).toEqual(true); expect(successHandler.notCalled).toEqual(true); - - fulfill(); }); return promise; @@ -149,7 +152,8 @@ describe('OC.Files.Client tests', function() { describe('file listing', function() { - var folderContentsXml = + // TODO: switch this to the already parsed structure + var folderContentsXml = dav.Client.prototype.parseMultiStatus( '' + '' + makeResponseBlock( @@ -159,8 +163,9 @@ describe('OC.Files.Client tests', function() { 'd:getetag': '"56cfcabd79abb"', 'd:resourcetype': '', 'oc:id': '00000011oc2d13a6a068', + 'oc:fileid': '11', 'oc:permissions': 'RDNVCK', - 'oc:size': 120 + 'oc:size': '120' }, [ 'd:getcontenttype', @@ -176,6 +181,7 @@ describe('OC.Files.Client tests', function() { 'd:getcontentlength': 250, 'd:resourcetype': '', 'oc:id': '00000051oc2d13a6a068', + 'oc:fileid': '51', 'oc:permissions': 'RDNVW' }, [ @@ -189,25 +195,27 @@ describe('OC.Files.Client tests', function() { 'd:getetag': '"66cfcabd79abb"', 'd:resourcetype': '', 'oc:id': '00000015oc2d13a6a068', + 'oc:fileid': '15', 'oc:permissions': 'RDNVCK', - 'oc:size': 100 + 'oc:size': '100' }, [ 'd:getcontenttype', 'd:getcontentlength' ] ) + - ''; + '' + ); it('sends PROPFIND with explicit properties to get file list', function() { client.getFolderContents('path/to space/文件夹'); - expect(fakeServer.requests.length).toEqual(1); - expect(fakeServer.requests[0].method).toEqual('PROPFIND'); - expect(fakeServer.requests[0].url).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9'); - expect(fakeServer.requests[0].requestHeaders.Depth).toEqual(1); + expect(requestStub.calledOnce).toEqual(true); + expect(requestStub.lastCall.args[0]).toEqual('PROPFIND'); + expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9'); + expect(requestStub.lastCall.args[2].Depth).toEqual(1); - var props = getRequestedProperties(fakeServer.requests[0].requestBody); + var props = getRequestedProperties(requestStub.lastCall.args[3]); expect(props).toContain('{DAV:}getlastmodified'); expect(props).toContain('{DAV:}getcontentlength'); expect(props).toContain('{DAV:}getcontenttype'); @@ -219,24 +227,23 @@ describe('OC.Files.Client tests', function() { }); it('sends PROPFIND to base url when empty path given', function() { client.getFolderContents(''); - expect(fakeServer.requests.length).toEqual(1); - expect(fakeServer.requests[0].url).toEqual(baseUrl); + expect(requestStub.calledOnce).toEqual(true); + expect(requestStub.lastCall.args[1]).toEqual(baseUrl); }); it('sends PROPFIND to base url when root path given', function() { client.getFolderContents('/'); - expect(fakeServer.requests.length).toEqual(1); - expect(fakeServer.requests[0].url).toEqual(baseUrl); + expect(requestStub.calledOnce).toEqual(true); + expect(requestStub.lastCall.args[1]).toEqual(baseUrl); }); it('parses the result list into a FileInfo array', function() { var promise = client.getFolderContents('path/to space/文件夹'); - expect(fakeServer.requests.length).toEqual(1); + expect(requestStub.calledOnce).toEqual(true); - fakeServer.requests[0].respond( - 207, - {'Content-Type': 'application/xml'}, - folderContentsXml - ); + requestDeferred.resolve({ + status: 207, + body: folderContentsXml + }); promise.then(function(status, response) { expect(status).toEqual(207); @@ -250,7 +257,7 @@ describe('OC.Files.Client tests', function() { expect(info.id).toEqual(51); expect(info.path).toEqual('/path/to space/文件夹'); expect(info.name).toEqual('One.txt'); - expect(info.permissions).toEqual(31); + expect(info.permissions).toEqual(27); expect(info.size).toEqual(250); expect(info.mtime).toEqual(1436535485000); expect(info.mimetype).toEqual('text/plain'); @@ -268,18 +275,16 @@ describe('OC.Files.Client tests', function() { expect(info.mimetype).toEqual('httpd/unix-directory'); expect(info.etag).toEqual('66cfcabd79abb'); }); - return promise.promise(); }); it('returns parent node in result if specified', function() { var promise = client.getFolderContents('path/to space/文件夹', {includeParent: true}); - expect(fakeServer.requests.length).toEqual(1); + expect(requestStub.calledOnce).toEqual(true); - fakeServer.requests[0].respond( - 207, - {'Content-Type': 'application/xml'}, - folderContentsXml - ); + requestDeferred.resolve({ + status: 207, + body: folderContentsXml + }); promise.then(function(status, response) { expect(status).toEqual(207); @@ -303,12 +308,10 @@ describe('OC.Files.Client tests', function() { expect(response[1].id).toEqual(51); expect(response[2].id).toEqual(15); }); - - return promise; }); it('rejects promise when an error occurred', function() { var promise = client.getFolderContents('path/to space/文件夹', {includeParent: true}); - return respondAndCheckError(promise, 404); + respondAndCheckError(promise, 404); }); it('throws exception if arguments are missing', function() { // TODO @@ -316,7 +319,7 @@ describe('OC.Files.Client tests', function() { }); describe('file info', function() { - var responseXml = + var responseXml = dav.Client.prototype.parseMultiStatus( '' + '' + makeResponseBlock( @@ -326,25 +329,27 @@ describe('OC.Files.Client tests', function() { 'd:getetag': '"56cfcabd79abb"', 'd:resourcetype': '', 'oc:id': '00000011oc2d13a6a068', + 'oc:fileid': '11', 'oc:permissions': 'RDNVCK', - 'oc:size': 120 + 'oc:size': '120' }, [ 'd:getcontenttype', 'd:getcontentlength' ] ) + - ''; + '' + ); it('sends PROPFIND with zero depth to get single file info', function() { client.getFileInfo('path/to space/文件夹'); - expect(fakeServer.requests.length).toEqual(1); - expect(fakeServer.requests[0].method).toEqual('PROPFIND'); - expect(fakeServer.requests[0].url).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9'); - expect(fakeServer.requests[0].requestHeaders.Depth).toEqual(0); + expect(requestStub.calledOnce).toEqual(true); + expect(requestStub.lastCall.args[0]).toEqual('PROPFIND'); + expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9'); + expect(requestStub.lastCall.args[2].Depth).toEqual(0); - var props = getRequestedProperties(fakeServer.requests[0].requestBody); + var props = getRequestedProperties(requestStub.lastCall.args[3]); expect(props).toContain('{DAV:}getlastmodified'); expect(props).toContain('{DAV:}getcontentlength'); expect(props).toContain('{DAV:}getcontenttype'); @@ -357,13 +362,12 @@ describe('OC.Files.Client tests', function() { it('parses the result into a FileInfo', function() { var promise = client.getFileInfo('path/to space/文件夹'); - expect(fakeServer.requests.length).toEqual(1); + expect(requestStub.calledOnce).toEqual(true); - fakeServer.requests[0].respond( - 207, - {'Content-Type': 'application/xml'}, - responseXml - ); + requestDeferred.resolve({ + status: 207, + body: responseXml + }); promise.then(function(status, response) { expect(status).toEqual(207); @@ -380,11 +384,9 @@ describe('OC.Files.Client tests', function() { expect(info.mimetype).toEqual('httpd/unix-directory'); expect(info.etag).toEqual('56cfcabd79abb'); }); - - return promise; }); it('properly parses entry inside root', function() { - var responseXml = + var responseXml = dav.Client.prototype.parseMultiStatus( '' + '' + makeResponseBlock( @@ -394,25 +396,26 @@ describe('OC.Files.Client tests', function() { 'd:getetag': '"56cfcabd79abb"', 'd:resourcetype': '', 'oc:id': '00000011oc2d13a6a068', + 'oc:fileid': '11', 'oc:permissions': 'RDNVCK', - 'oc:size': 120 + 'oc:size': '120' }, [ 'd:getcontenttype', 'd:getcontentlength' ] ) + - ''; + '' + ); var promise = client.getFileInfo('in root'); - expect(fakeServer.requests.length).toEqual(1); + expect(requestStub.calledOnce).toEqual(true); - fakeServer.requests[0].respond( - 207, - {'Content-Type': 'application/xml'}, - responseXml - ); + requestDeferred.resolve({ + status: 207, + body: responseXml + }); promise.then(function(status, response) { expect(status).toEqual(207); @@ -429,12 +432,10 @@ describe('OC.Files.Client tests', function() { expect(info.mimetype).toEqual('httpd/unix-directory'); expect(info.etag).toEqual('56cfcabd79abb'); }); - - return promise; }); it('rejects promise when an error occurred', function() { var promise = client.getFileInfo('path/to space/文件夹'); - return respondAndCheckError(promise, 404); + respondAndCheckError(promise, 404); }); it('throws exception if arguments are missing', function() { // TODO @@ -449,6 +450,7 @@ describe('OC.Files.Client tests', function() { 'd:getetag': '"559fcabd79a38"', 'd:getcontentlength': 250, 'oc:id': '00000051oc2d13a6a068', + 'oc:fileid': '51', 'oc:permissions': webdavPerm, }; @@ -458,25 +460,28 @@ describe('OC.Files.Client tests', function() { props['d:resourcetype'] = ''; } - var responseXml = + var def = new $.Deferred(); + requestStub.reset(); + requestStub.returns(def); + + var responseXml = dav.Client.prototype.parseMultiStatus( '' + '' + makeResponseBlock( '/owncloud/remote.php/webdav/file.txt', props ) + - ''; - var promise = client.getFileInfo('file.txt'); - - expect(fakeServer.requests.length).toEqual(1); - fakeServer.requests[0].respond( - 207, - {'Content-Type': 'application/xml'}, - responseXml + '' ); - fakeServer.restore(); - fakeServer = sinon.fakeServer.create(); + var promise = client.getFileInfo('file.txt'); + + expect(requestStub.calledOnce).toEqual(true); + + def.resolve({ + status: 207, + body: responseXml + }); return promise; } @@ -486,7 +491,6 @@ describe('OC.Files.Client tests', function() { promise.then(function(result) { expect(result.permissions).toEqual(expectedPermissions); }); - return promise; } function testMountType(permission, isFile, expectedMountType) { @@ -494,7 +498,6 @@ describe('OC.Files.Client tests', function() { promise.then(function(result) { expect(result.mountType).toEqual(expectedMountType); }); - return promise; } it('properly parses file permissions', function() { @@ -508,11 +511,9 @@ describe('OC.Files.Client tests', function() { ['R', true, OC.PERMISSION_READ | OC.PERMISSION_SHARE], ['CKWDR', true, OC.PERMISSION_ALL] ]; - return Promise.all( - _.map(testCases, function(testCase) { - return testPermission.apply(testCase); - }) - ); + _.each(testCases, function(testCase) { + return testPermission.apply(testCase); + }); }); it('properly parses folder permissions', function() { var testCases = [ @@ -525,11 +526,9 @@ describe('OC.Files.Client tests', function() { ['CKWDR', false, OC.PERMISSION_ALL] ]; - return Promise.all( - _.map(testCases, function(testCase) { - return testPermission.apply(testCase); - }) - ); + _.each(testCases, function(testCase) { + return testPermission.apply(testCase); + }); }); it('properly parses mount types', function() { var testCases = [ @@ -539,11 +538,9 @@ describe('OC.Files.Client tests', function() { ['SM', false, 'shared'] ]; - return Promise.all( - _.map(testCases, function(testCase) { - return testMountType.apply(testCase); - }) - ); + _.each(testCases, function(testCase) { + return testMountType.apply(testCase); + }); }); }); @@ -551,26 +548,23 @@ describe('OC.Files.Client tests', function() { it('returns file contents', function() { var promise = client.getFileContents('path/to space/文件夹/One.txt'); - expect(fakeServer.requests.length).toEqual(1); - expect(fakeServer.requests[0].method).toEqual('GET'); - expect(fakeServer.requests[0].url).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/One.txt'); + expect(requestStub.calledOnce).toEqual(true); + expect(requestStub.lastCall.args[0]).toEqual('GET'); + expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/One.txt'); - fakeServer.requests[0].respond( - 200, - {'Content-Type': 'text/plain'}, - 'some contents' - ); + requestDeferred.resolve({ + status: 200, + body: 'some contents' + }); promise.then(function(status, response) { expect(status).toEqual(200); expect(response).toEqual('some contents'); }); - - return promise; }); it('rejects promise when an error occurred', function() { var promise = client.getFileContents('path/to space/文件夹/One.txt'); - return respondAndCheckError(promise, 409); + respondAndCheckError(promise, 409); }); it('throws exception if arguments are missing', function() { // TODO @@ -584,14 +578,14 @@ describe('OC.Files.Client tests', function() { 'some contents' ); - expect(fakeServer.requests.length).toEqual(1); - expect(fakeServer.requests[0].method).toEqual('PUT'); - expect(fakeServer.requests[0].url).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/One.txt'); - expect(fakeServer.requests[0].requestBody).toEqual('some contents'); - expect(fakeServer.requests[0].requestHeaders['If-None-Match']).toEqual('*'); - expect(fakeServer.requests[0].requestHeaders['Content-Type']).toEqual('text/plain;charset=utf-8'); + expect(requestStub.calledOnce).toEqual(true); + expect(requestStub.lastCall.args[0]).toEqual('PUT'); + expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/One.txt'); + expect(requestStub.lastCall.args[2]['If-None-Match']).toEqual('*'); + expect(requestStub.lastCall.args[2]['Content-Type']).toEqual('text/plain;charset=utf-8'); + expect(requestStub.lastCall.args[3]).toEqual('some contents'); - return respondAndCheckStatus(promise, 201); + respondAndCheckStatus(promise, 201); }); it('sends PUT with file contents with headers matching options', function() { var promise = client.putFileContents( @@ -603,21 +597,21 @@ describe('OC.Files.Client tests', function() { } ); - expect(fakeServer.requests.length).toEqual(1); - expect(fakeServer.requests[0].method).toEqual('PUT'); - expect(fakeServer.requests[0].url).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/One.txt'); - expect(fakeServer.requests[0].requestBody).toEqual('some contents'); - expect(fakeServer.requests[0].requestHeaders['If-None-Match']).not.toBeDefined(); - expect(fakeServer.requests[0].requestHeaders['Content-Type']).toEqual('text/markdown;charset=utf-8'); + expect(requestStub.calledOnce).toEqual(true); + expect(requestStub.lastCall.args[0]).toEqual('PUT'); + expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/One.txt'); + expect(requestStub.lastCall.args[2]['If-None-Match']).not.toBeDefined(); + expect(requestStub.lastCall.args[2]['Content-Type']).toEqual('text/markdown'); + expect(requestStub.lastCall.args[3]).toEqual('some contents'); - return respondAndCheckStatus(promise, 201); + respondAndCheckStatus(promise, 201); }); it('rejects promise when an error occurred', function() { var promise = client.putFileContents( 'path/to space/文件夹/One.txt', 'some contents' ); - return respondAndCheckError(promise, 409); + respondAndCheckError(promise, 409); }); it('throws exception if arguments are missing', function() { // TODO @@ -628,15 +622,15 @@ describe('OC.Files.Client tests', function() { it('sends MKCOL with specified path', function() { var promise = client.createDirectory('path/to space/文件夹/new dir'); - expect(fakeServer.requests.length).toEqual(1); - expect(fakeServer.requests[0].method).toEqual('MKCOL'); - expect(fakeServer.requests[0].url).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/new%20dir'); + expect(requestStub.calledOnce).toEqual(true); + expect(requestStub.lastCall.args[0]).toEqual('MKCOL'); + expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/new%20dir'); - return respondAndCheckStatus(promise, 201); + respondAndCheckStatus(promise, 201); }); it('rejects promise when an error occurred', function() { var promise = client.createDirectory('path/to space/文件夹/new dir'); - return respondAndCheckError(promise, 404); + respondAndCheckError(promise, 404); }); it('throws exception if arguments are missing', function() { // TODO @@ -647,15 +641,15 @@ describe('OC.Files.Client tests', function() { it('sends DELETE with specified path', function() { var promise = client.remove('path/to space/文件夹'); - expect(fakeServer.requests.length).toEqual(1); - expect(fakeServer.requests[0].method).toEqual('DELETE'); - expect(fakeServer.requests[0].url).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9'); + expect(requestStub.calledOnce).toEqual(true); + expect(requestStub.lastCall.args[0]).toEqual('DELETE'); + expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9'); - return respondAndCheckStatus(promise, 201); + respondAndCheckStatus(promise, 201); }); it('rejects promise when an error occurred', function() { var promise = client.remove('path/to space/文件夹'); - return respondAndCheckError(promise, 404); + respondAndCheckError(promise, 404); }); it('throws exception if arguments are missing', function() { // TODO @@ -669,15 +663,15 @@ describe('OC.Files.Client tests', function() { 'path/to space/anotherdir/文件夹' ); - expect(fakeServer.requests.length).toEqual(1); - expect(fakeServer.requests[0].method).toEqual('MOVE'); - expect(fakeServer.requests[0].url).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9'); - expect(fakeServer.requests[0].requestHeaders.Destination) + expect(requestStub.calledOnce).toEqual(true); + expect(requestStub.lastCall.args[0]).toEqual('MOVE'); + expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9'); + expect(requestStub.lastCall.args[2].Destination) .toEqual(baseUrl + 'path/to%20space/anotherdir/%E6%96%87%E4%BB%B6%E5%A4%B9'); - expect(fakeServer.requests[0].requestHeaders.Overwrite) + expect(requestStub.lastCall.args[2].Overwrite) .toEqual('F'); - return respondAndCheckStatus(promise, 201); + respondAndCheckStatus(promise, 201); }); it('sends MOVE with silent overwrite mode when specified', function() { var promise = client.move( @@ -686,15 +680,15 @@ describe('OC.Files.Client tests', function() { {allowOverwrite: true} ); - expect(fakeServer.requests.length).toEqual(1); - expect(fakeServer.requests[0].method).toEqual('MOVE'); - expect(fakeServer.requests[0].url).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9'); - expect(fakeServer.requests[0].requestHeaders.Destination) + expect(requestStub.calledOnce).toEqual(true); + expect(requestStub.lastCall.args[0]).toEqual('MOVE'); + expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9'); + expect(requestStub.lastCall.args[2].Destination) .toEqual(baseUrl + 'path/to%20space/anotherdir/%E6%96%87%E4%BB%B6%E5%A4%B9'); - expect(fakeServer.requests[0].requestHeaders.Overwrite) + expect(requestStub.lastCall.args[2].Overwrite) .not.toBeDefined(); - return respondAndCheckStatus(promise, 201); + respondAndCheckStatus(promise, 201); }); it('rejects promise when an error occurred', function() { var promise = client.move( @@ -702,7 +696,7 @@ describe('OC.Files.Client tests', function() { 'path/to space/anotherdir/文件夹', {allowOverwrite: true} ); - return respondAndCheckError(promise, 404); + respondAndCheckError(promise, 404); }); it('throws exception if arguments are missing', function() { // TODO