| 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);
|
|
|