Browse Source

Merge pull request #12128 from tomasz-grobelny/fix_file_move

Fix file move operation for large number of files
tags/v15.0.0beta1
Morris Jobke 5 years ago
parent
commit
f350f2e3ec
No account linked to committer's email address
2 changed files with 106 additions and 58 deletions
  1. 43
    4
      apps/files/js/filelist.js
  2. 63
    54
      apps/files/tests/js/filelistSpec.js

+ 43
- 4
apps/files/js/filelist.js View File

}); });
} }


this.move(_.pluck(files, 'name'), targetPath);
var movePromise = this.move(_.pluck(files, 'name'), targetPath);


// re-enable td elements to be droppable // re-enable td elements to be droppable
// sometimes the filename drop handler is still called after re-enable, // sometimes the filename drop handler is still called after re-enable,
setTimeout(function() { setTimeout(function() {
self.$el.find('td.filename.ui-droppable').droppable('enable'); self.$el.find('td.filename.ui-droppable').droppable('enable');
}, 10); }, 10);

return movePromise;
}, },


/** /**
if (!_.isArray(fileNames)) { if (!_.isArray(fileNames)) {
fileNames = [fileNames]; fileNames = [fileNames];
} }
_.each(fileNames, function(fileName) {

function Semaphore(max) {
var counter = 0;
var waiting = [];

this.acquire = function() {
if(counter < max) {
counter++;
return new Promise(function(resolve) { resolve(); });
} else {
return new Promise(function(resolve) { waiting.push(resolve); });
}
};

this.release = function() {
counter--;
if (waiting.length > 0 && counter < max) {
counter++;
var promise = waiting.shift();
promise();
}
};
}

var moveFileFunction = function(fileName) {
var $tr = self.findFileEl(fileName); var $tr = self.findFileEl(fileName);
self.showFileBusyState($tr, true); self.showFileBusyState($tr, true);
if (targetPath.charAt(targetPath.length - 1) !== '/') { if (targetPath.charAt(targetPath.length - 1) !== '/') {
// not overwrite it // not overwrite it
targetPath = targetPath + '/'; targetPath = targetPath + '/';
} }
self.filesClient.move(dir + fileName, targetPath + fileName)
return self.filesClient.move(dir + fileName, targetPath + fileName)
.done(function() { .done(function() {
// if still viewing the same directory // if still viewing the same directory
if (OC.joinPaths(self.getCurrentDirectory(), '/') === dir) { if (OC.joinPaths(self.getCurrentDirectory(), '/') === dir) {
.always(function() { .always(function() {
self.showFileBusyState($tr, false); self.showFileBusyState($tr, false);
}); });
};

var mcSemaphore = new Semaphore(10);
var counter = 0;
var promises = _.map(fileNames, function(arg) {
return mcSemaphore.acquire().then(function(){
moveFileFunction(arg).then(function(){
mcSemaphore.release();
counter++;
});
});
});

return Promise.all(promises).then(function(){
if (callback) { if (callback) {
callback(); callback();
} }
}); });

}, },


/** /**

+ 63
- 54
apps/files/tests/js/filelistSpec.js View File

moveStub.restore(); moveStub.restore();
}); });


it('Moves single file to target folder', function() {
fileList.move('One.txt', '/somedir');
it('Moves single file to target folder', function(done) {
return fileList.move('One.txt', '/somedir').then(function(){


expect(moveStub.calledOnce).toEqual(true);
expect(moveStub.getCall(0).args[0]).toEqual('/subdir/One.txt');
expect(moveStub.getCall(0).args[1]).toEqual('/somedir/One.txt');
expect(moveStub.calledOnce).toEqual(true);
expect(moveStub.getCall(0).args[0]).toEqual('/subdir/One.txt');
expect(moveStub.getCall(0).args[1]).toEqual('/somedir/One.txt');


deferredMove.resolve(201);
deferredMove.resolve(201);


expect(fileList.findFileEl('One.txt').length).toEqual(0);
expect(fileList.findFileEl('One.txt').length).toEqual(0);


// folder size has increased
expect(fileList.findFileEl('somedir').data('size')).toEqual(262);
expect(fileList.findFileEl('somedir').find('.filesize').text()).toEqual('262 B');
// folder size has increased
expect(fileList.findFileEl('somedir').data('size')).toEqual(262);
expect(fileList.findFileEl('somedir').find('.filesize').text()).toEqual('262 B');


expect(notificationStub.notCalled).toEqual(true);
expect(notificationStub.notCalled).toEqual(true);
done();
});
}); });
it('Moves list of files to target folder', function() {
it('Moves list of files to target folder', function(done) {
var deferredMove1 = $.Deferred(); var deferredMove1 = $.Deferred();
var deferredMove2 = $.Deferred(); var deferredMove2 = $.Deferred();
moveStub.onCall(0).returns(deferredMove1.promise()); moveStub.onCall(0).returns(deferredMove1.promise());
moveStub.onCall(1).returns(deferredMove2.promise()); moveStub.onCall(1).returns(deferredMove2.promise());


fileList.move(['One.txt', 'Two.jpg'], '/somedir');
return fileList.move(['One.txt', 'Two.jpg'], '/somedir').then(function(){


expect(moveStub.calledTwice).toEqual(true);
expect(moveStub.getCall(0).args[0]).toEqual('/subdir/One.txt');
expect(moveStub.getCall(0).args[1]).toEqual('/somedir/One.txt');
expect(moveStub.getCall(1).args[0]).toEqual('/subdir/Two.jpg');
expect(moveStub.getCall(1).args[1]).toEqual('/somedir/Two.jpg');
expect(moveStub.calledTwice).toEqual(true);
expect(moveStub.getCall(0).args[0]).toEqual('/subdir/One.txt');
expect(moveStub.getCall(0).args[1]).toEqual('/somedir/One.txt');
expect(moveStub.getCall(1).args[0]).toEqual('/subdir/Two.jpg');
expect(moveStub.getCall(1).args[1]).toEqual('/somedir/Two.jpg');


deferredMove1.resolve(201);
deferredMove1.resolve(201);


expect(fileList.findFileEl('One.txt').length).toEqual(0);
expect(fileList.findFileEl('One.txt').length).toEqual(0);


// folder size has increased during move
expect(fileList.findFileEl('somedir').data('size')).toEqual(262);
expect(fileList.findFileEl('somedir').find('.filesize').text()).toEqual('262 B');
// folder size has increased during move
expect(fileList.findFileEl('somedir').data('size')).toEqual(262);
expect(fileList.findFileEl('somedir').find('.filesize').text()).toEqual('262 B');


deferredMove2.resolve(201);
deferredMove2.resolve(201);


expect(fileList.findFileEl('Two.jpg').length).toEqual(0);
expect(fileList.findFileEl('Two.jpg').length).toEqual(0);


// folder size has increased
expect(fileList.findFileEl('somedir').data('size')).toEqual(12311);
expect(fileList.findFileEl('somedir').find('.filesize').text()).toEqual('12 KB');
// folder size has increased
expect(fileList.findFileEl('somedir').data('size')).toEqual(12311);
expect(fileList.findFileEl('somedir').find('.filesize').text()).toEqual('12 KB');


expect(notificationStub.notCalled).toEqual(true);
expect(notificationStub.notCalled).toEqual(true);
done();
});
}); });
it('Shows notification if a file could not be moved', function() {
fileList.move('One.txt', '/somedir');
it('Shows notification if a file could not be moved', function(done) {
return fileList.move('One.txt', '/somedir').then(function(){


expect(moveStub.calledOnce).toEqual(true);
expect(moveStub.calledOnce).toEqual(true);


deferredMove.reject(409);
deferredMove.reject(409);


expect(fileList.findFileEl('One.txt').length).toEqual(1);
expect(fileList.findFileEl('One.txt').length).toEqual(1);


expect(notificationStub.calledOnce).toEqual(true);
expect(notificationStub.getCall(0).args[0]).toEqual('Could not move "One.txt"');
expect(notificationStub.calledOnce).toEqual(true);
expect(notificationStub.getCall(0).args[0]).toEqual('Could not move "One.txt"');
done();
});
}); });
it('Restores thumbnail if a file could not be moved', function() { it('Restores thumbnail if a file could not be moved', function() {
fileList.move('One.txt', '/somedir');
return fileList.move('One.txt', '/somedir').then(function(){


expect(fileList.findFileEl('One.txt').find('.thumbnail').parent().attr('class'))
.toContain('icon-loading-small');
expect(fileList.findFileEl('One.txt').find('.thumbnail').parent().attr('class'))
.toContain('icon-loading-small');


expect(moveStub.calledOnce).toEqual(true);
expect(moveStub.calledOnce).toEqual(true);


deferredMove.reject(409);
deferredMove.reject(409);


expect(fileList.findFileEl('One.txt').length).toEqual(1);
expect(fileList.findFileEl('One.txt').length).toEqual(1);


expect(notificationStub.calledOnce).toEqual(true);
expect(notificationStub.getCall(0).args[0]).toEqual('Could not move "One.txt"');
expect(notificationStub.calledOnce).toEqual(true);
expect(notificationStub.getCall(0).args[0]).toEqual('Could not move "One.txt"');


expect(OC.TestUtil.getImageUrl(fileList.findFileEl('One.txt').find('.thumbnail')))
.toEqual(OC.imagePath('core', 'filetypes/text.svg'));
expect(OC.TestUtil.getImageUrl(fileList.findFileEl('One.txt').find('.thumbnail')))
.toEqual(OC.imagePath('core', 'filetypes/text.svg'));
});
}); });
}); });


expect(changeDirStub.getCall(0).args[0]).toEqual('/subdir/two/three with space'); expect(changeDirStub.getCall(0).args[0]).toEqual('/subdir/two/three with space');
changeDirStub.restore(); changeDirStub.restore();
}); });
it('dropping files on breadcrumb calls move operation', function() {
it('dropping files on breadcrumb calls move operation', function(done) {
var testDir = '/subdir/two/three with space/four/five'; var testDir = '/subdir/two/three with space/four/five';
var moveStub = sinon.stub(filesClient, 'move').returns($.Deferred().promise()); var moveStub = sinon.stub(filesClient, 'move').returns($.Deferred().promise());
fileList.changeDirectory(testDir); fileList.changeDirectory(testDir);
$('<tr data-file="Two.jpg" data-dir="' + testDir + '"></tr>') $('<tr data-file="Two.jpg" data-dir="' + testDir + '"></tr>')
]); ]);
// simulate drop event // simulate drop event
fileList._onDropOnBreadCrumb(new $.Event('drop', {target: $crumb}), ui);
return fileList._onDropOnBreadCrumb(new $.Event('drop', {target: $crumb}), ui).then(function(){


expect(moveStub.callCount).toEqual(2);
expect(moveStub.getCall(0).args[0]).toEqual(testDir + '/One.txt');
expect(moveStub.getCall(0).args[1]).toEqual('/subdir/two/three with space/One.txt');
expect(moveStub.getCall(1).args[0]).toEqual(testDir + '/Two.jpg');
expect(moveStub.getCall(1).args[1]).toEqual('/subdir/two/three with space/Two.jpg');
moveStub.restore();
expect(moveStub.callCount).toEqual(2);
expect(moveStub.getCall(0).args[0]).toEqual(testDir + '/One.txt');
expect(moveStub.getCall(0).args[1]).toEqual('/subdir/two/three with space/One.txt');
expect(moveStub.getCall(1).args[0]).toEqual(testDir + '/Two.jpg');
expect(moveStub.getCall(1).args[1]).toEqual('/subdir/two/three with space/Two.jpg');
moveStub.restore();
done();
});
}); });
it('dropping files on same dir breadcrumb does nothing', function() { it('dropping files on same dir breadcrumb does nothing', function() {
var testDir = '/subdir/two/three with space/four/five'; var testDir = '/subdir/two/three with space/four/five';

Loading…
Cancel
Save