Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(721)

Unified Diff: ui/file_manager/file_manager/background/js/file_operation_manager_unittest.js

Issue 1085823002: Run copy operations in parallel when destinations are different volumes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fails with an error when volume info is not available. Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/file_manager/file_manager/background/js/file_operation_manager_unittest.html ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/file_manager/file_manager/background/js/file_operation_manager_unittest.js
diff --git a/ui/file_manager/file_manager/background/js/file_operation_manager_unittest.js b/ui/file_manager/file_manager/background/js/file_operation_manager_unittest.js
index e266d7f842593741b47291b0d3f21e38445cfe24..7638022bff4158026395cc2ba05a5b837265bfc9 100644
--- a/ui/file_manager/file_manager/background/js/file_operation_manager_unittest.js
+++ b/ui/file_manager/file_manager/background/js/file_operation_manager_unittest.js
@@ -45,22 +45,122 @@ chrome.fileManagerPrivate = {
};
/**
- * Reports the result of promise to the test system.
- * @param {Promise} promise Promise to be fulfilled or rejected.
- * @param {function(boolean:hasError)} callback Callback to be passed true on
- * error.
+ * Logs events of file operation manager.
+ * @param {!FileOperationManager} fileOperationManager A target file operation
+ * manager.
+ * @constructor
+ * @struct
*/
-function reportPromise(promise, callback) {
- promise.then(
- callback.bind(null, false),
- function(error) {
- if (error instanceof fileOperationUtil.Error) {
- console.error('fileOperationUtil.Error: code=' + error.code);
- } else {
- console.error(error.stack || error.name || error);
- }
- callback(true);
- });
+function EventLogger(fileOperationManager) {
+ this.events = [];
+ this.numberOfBeginEvents = 0;
+ this.numberOfErrorEvents = 0;
+ this.numberOfSuccessEvents = 0;
+ fileOperationManager.addEventListener('copy-progress',
+ this.onCopyProgress_.bind(this));
+}
+
+/**
+ * Handles copy-progress event.
+ * @param {Event} event An event.
+ * @private
+ */
+EventLogger.prototype.onCopyProgress_ = function(event) {
+ if (event.reason === 'BEGIN') {
+ this.events.push(event);
+ this.numberOfBeginEvents++;
+ }
+ if (event.reason === 'ERROR') {
+ this.events.push(event);
+ this.numberOfErrorEvents++;
+ }
+ if (event.reason === 'SUCCESS') {
+ this.events.push(event);
+ this.numberOfSuccessEvents++;
+ }
+};
+
+/**
+ * Provides fake implementation of chrome.fileManagerPrivate.startCopy.
+ * @param {string} blockedDestination Destination url of an entry whose request
+ * should be blocked.
+ * @param {!Entry} sourceEntry Source entry. Single source entry is supported.
+ * @param {!Array<!FakeFileSystem>} fileSystems File systems.
+ * @constructor
+ * @struct
+ */
+function BlockableFakeStartCopy(blockedDestination, sourceEntry, fileSystems) {
+ this.resolveBlockedOperationCallback = null;
+ this.blockedDestination_ = blockedDestination;
+ this.sourceEntry_ = sourceEntry;
+ this.fileSystems_ = fileSystems;
+ this.startCopyId_ = 0;
+}
+
+/**
+ * A fake implemencation of startCopy function.
+ * @param {string} source
+ * @param {string} destination
+ * @param {string} newName
+ * @param {function(number)} callback
+ */
+BlockableFakeStartCopy.prototype.startCopyFunc = function(
+ source, destination, newName, callback) {
+ var makeStatus = function(type) {
+ return {type: type, sourceUrl: source, destinationUrl: destination};
+ };
+
+ var completeCopyOperation = function(copyId) {
+ var newPath = joinPath('/', newName);
+ var fileSystem = getFileSystemForURL(this.fileSystems_, destination);
+ fileSystem.entries[newPath] = this.sourceEntry_.clone(newPath);
+ listener(copyId, makeStatus('end_copy_entry'));
+ listener(copyId, makeStatus('success'));
+ }.bind(this);
+
+ this.startCopyId_++;
+
+ callback(this.startCopyId_);
+ var listener = chrome.fileManagerPrivate.onCopyProgress.listener_;
+ listener(this.startCopyId_, makeStatus('begin_copy_entry'));
+ listener(this.startCopyId_, makeStatus('progress'));
+
+ if (destination === this.blockedDestination_) {
+ this.resolveBlockedOperation =
+ completeCopyOperation.bind(this, this.startCopyId_);
+ } else {
+ completeCopyOperation(this.startCopyId_);
+ }
+};
+
+/**
+ * Fake volume manager.
+ * @constructor
+ * @structs
+ */
+function FakeVolumeManager() {}
+
+/**
+ * Returns fake volume info.
+ * @param {!Entry} entry
+ * @return {VolumeInfo} A fake volume info.
+ */
+FakeVolumeManager.prototype.getVolumeInfo = function(entry) {
+ return { volumeId: entry.filesystem.name };
+}
+
+/**
+ * Returns file system of the url.
+ * @param {!Array<!FakeFileSystem>} fileSystems
+ * @param {string} url
+ * @return {!FakeFileSystem}
+ */
+function getFileSystemForURL(fileSystems, url) {
+ for (var i = 0; i < fileSystems.length; i++) {
+ if (new RegExp('^filesystem:' + fileSystems[i].name + '/').test(url))
+ return fileSystems[i];
+ }
+ throw new Error('Unexpected url.');
}
/**
@@ -360,6 +460,8 @@ function testCopy(callback) {
listener(1, makeStatus('success'));
};
+ fileOperationManager = new FileOperationManager(new FakeVolumeManager());
+
// Observing manager's events.
var eventsPromise = waitForEvents(fileOperationManager);
@@ -395,6 +497,205 @@ function testCopy(callback) {
}
/**
+ * Tests the fileOperationUtil.paste for copying files in sequential. When
+ * destination volumes are same, copy operations should run in sequential.
+ */
+function testCopyInSequential(callback) {
+ var fileSystem = createTestFileSystem('testVolume', {
+ '/': DIRECTORY_SIZE,
+ '/dest': DIRECTORY_SIZE,
+ '/test.txt': 10
+ });
+
+ window.webkitResolveLocalFileSystemURL =
+ resolveTestFileSystemURL.bind(null, fileSystem);
+
+ var blockableFakeStartCopy = new BlockableFakeStartCopy(
+ 'filesystem:testVolume/dest',
+ fileSystem.entries['/test.txt'],
+ [fileSystem]);
+ chrome.fileManagerPrivate.startCopy =
+ blockableFakeStartCopy.startCopyFunc.bind(blockableFakeStartCopy);
+
+ fileOperationManager = new FileOperationManager(new FakeVolumeManager());
+
+ var eventLogger = new EventLogger(fileOperationManager);
+
+ // Copy test.txt to /dest. This operation will be blocked.
+ fileOperationManager.paste([fileSystem.entries['/test.txt']],
+ fileSystem.entries['/dest'],
+ false);
+
+ var firstOperationTaskId;
+ reportPromise(waitUntil(function() {
+ // Wait until the first operation is blocked.
+ return blockableFakeStartCopy.resolveBlockedOperation !== null
+ }).then(function() {
+ assertEquals(1, eventLogger.events.length);
+ assertEquals('BEGIN', eventLogger.events[0].reason);
+ firstOperationTaskId = eventLogger.events[0].taskId;
+
+ // Copy test.txt to /. This operation should be blocked.
+ fileOperationManager.paste([fileSystem.entries['/test.txt']],
+ fileSystem.entries['/'],
+ false);
+
+ return waitUntil(function() {
+ return fileOperationManager.getPendingCopyTasksForTesting().length === 1;
+ });
+ }).then(function() {
+ // Asserts that the second operation is added to pending copy tasks. Current
+ // implementation run tasks synchronusly after adding it to pending tasks.
+ // TODO(yawano) This check deeply depends on the implementation. Find a
+ // better way to test this.
+ var pendingTask = fileOperationManager.getPendingCopyTasksForTesting()[0];
+ assertEquals(fileSystem.entries['/'], pendingTask.targetDirEntry);
+
+ blockableFakeStartCopy.resolveBlockedOperation();
+
+ return waitUntil(function() {
+ return eventLogger.numberOfSuccessEvents === 2;
+ });
+ }).then(function() {
+ // Events should be the following.
+ // BEGIN: first operation
+ // BEGIN: second operation
+ // SUCCESS: first operation
+ // SUCCESS: second operation
+ var events = eventLogger.events;
+ assertEquals(4, events.length);
+ assertEquals('BEGIN', events[0].reason);
+ assertEquals(firstOperationTaskId, events[0].taskId);
+ assertEquals('BEGIN', events[1].reason);
+ assertTrue(events[1].taskId !== firstOperationTaskId);
+ assertEquals('SUCCESS', events[2].reason);
+ assertEquals(firstOperationTaskId, events[2].taskId);
+ assertEquals('SUCCESS', events[3].reason);
+ assertEquals(events[1].taskId, events[3].taskId);
+ }), callback);
+}
+
+/**
+ * Tests the fileOperationUtil.paste for copying files in paralell. When
+ * destination volumes are different, copy operations can run in paralell.
+ */
+function testCopyInParallel(callback) {
+ var fileSystemA = createTestFileSystem('volumeA', {
+ '/': DIRECTORY_SIZE,
+ '/test.txt': 10
+ });
+ var fileSystemB = createTestFileSystem('volumeB', {
+ '/': DIRECTORY_SIZE,
+ });
+ var fileSystems = [fileSystemA, fileSystemB];
+
+ window.webkitResolveLocalFileSystemURL = function(url, success, failure) {
+ return resolveTestFileSystemURL(
+ getFileSystemForURL(fileSystems, url), url, success, failure);
+ };
+
+ var blockableFakeStartCopy = new BlockableFakeStartCopy(
+ 'filesystem:volumeB/',
+ fileSystemA.entries['/test.txt'],
+ fileSystems);
+ chrome.fileManagerPrivate.startCopy =
+ blockableFakeStartCopy.startCopyFunc.bind(blockableFakeStartCopy);
+
+ fileOperationManager = new FileOperationManager(new FakeVolumeManager());
+
+ var eventLogger = new EventLogger(fileOperationManager);
+
+ // Copy test.txt from volume A to volume B.
+ fileOperationManager.paste([fileSystemA.entries['/test.txt']],
+ fileSystemB.entries['/'],
+ false);
+
+ var firstOperationTaskId;
+ reportPromise(waitUntil(function() {
+ return blockableFakeStartCopy.resolveBlockedOperation !== null;
+ }).then(function() {
+ assertEquals(1, eventLogger.events.length);
+ assertEquals('BEGIN', eventLogger.events[0].reason);
+ firstOperationTaskId = eventLogger.events[0].taskId;
+
+ // Copy test.txt from volume A to volume A. This should not be blocked by
+ // the previous operation.
+ fileOperationManager.paste([fileSystemA.entries['/test.txt']],
+ fileSystemA.entries['/'],
+ false);
+
+ // Wait until the second operation is completed.
+ return waitUntil(function() {
+ return eventLogger.numberOfSuccessEvents === 1;
+ });
+ }).then(function() {
+ // Resolve the blocked operation.
+ blockableFakeStartCopy.resolveBlockedOperation();
+
+ // Wait until the blocked operation is completed.
+ return waitUntil(function() {
+ return eventLogger.numberOfSuccessEvents === 2;
+ });
+ }).then(function() {
+ // Events should be following.
+ // BEGIN: first operation
+ // BEGIN: second operation
+ // SUCCESS: second operation
+ // SUCCESS: first operation
+ var events = eventLogger.events;
+ assertEquals(4, events.length);
+ assertEquals('BEGIN', events[0].reason);
+ assertEquals(firstOperationTaskId, events[0].taskId);
+ assertEquals('BEGIN', events[1].reason);
+ assertTrue(firstOperationTaskId !== events[1].taskId);
+ assertEquals('SUCCESS', events[2].reason);
+ assertEquals(events[1].taskId, events[2].taskId);
+ assertEquals('SUCCESS', events[3].reason);
+ assertEquals(firstOperationTaskId, events[3].taskId);
+ }), callback);
+}
+
+/**
+ * Test case that a copy fails since destination volume is not available.
+ */
+function testCopyFails(callback) {
+ var fileSystem = createTestFileSystem('testVolume', {
+ '/': DIRECTORY_SIZE,
+ '/test.txt': 10
+ });
+
+ fileOperationManager = new FileOperationManager({
+ /* Mocking volume manager. */
+ getVolumeInfo: function() {
+ // Return null to simulate that the volume info is not available.
+ return null;
+ }
+ });
+
+ var eventLogger = new EventLogger(fileOperationManager);
+
+ // Copy test.txt to /.
+ fileOperationManager.paste([fileSystem.entries['/test.txt']],
+ fileSystem.entries['/'],
+ false);
+
+ reportPromise(waitUntil(function() {
+ return eventLogger.numberOfErrorEvents === 1;
+ }).then(function() {
+ // Since the task fails with an error, pending copy tasks should be empty.
+ assertEquals(0,
+ fileOperationManager.getPendingCopyTasksForTesting().length);
+
+ // Check events.
+ var events = eventLogger.events;
+ assertEquals(2, events.length);
+ assertEquals('BEGIN', events[0].reason);
+ assertEquals('ERROR', events[1].reason);
+ assertEquals(events[0].taskId, events[1].taskId);
+ }), callback);
+}
+
+/**
* Tests the fileOperationUtil.paste for move.
* @param {function(boolean:hasError)} callback Callback to be passed true on
* error.
@@ -409,6 +710,8 @@ function testMove(callback) {
window.webkitResolveLocalFileSystemURL =
resolveTestFileSystemURL.bind(null, fileSystem);
+ fileOperationManager = new FileOperationManager(new FakeVolumeManager());
+
// Observing manager's events.
var eventsPromise = waitForEvents(fileOperationManager);
@@ -505,6 +808,8 @@ function testZip(callback) {
success(newEntry);
};
+ fileOperationManager = new FileOperationManager(new FakeVolumeManager());
+
// Observing manager's events.
reportPromise(waitForEvents(fileOperationManager).then(function(events) {
assertEquals('copy-progress', events[0].type);
« no previous file with comments | « ui/file_manager/file_manager/background/js/file_operation_manager_unittest.html ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698