chromium/chrome/test/data/extensions/api_test/file_browser/app_file_handler_multi/test.js

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

/**
 * Promise of the volume list.
 * @type {Promise}
 */
var volumeListPromise = new Promise(function(fulfill, reject) {
  chrome.fileManagerPrivate.getVolumeMetadataList(fulfill);
});

/**
 * Obtains file system of the volume type.
 * @param {string} volumeType VolumeType.
 * @return {Promise} Promise to be fulfilled with a file system.
 */
function getFileSystem(volumeType) {
  return volumeListPromise.then(function(list) {
    for (var i = 0; i < list.length; i++) {
      if (list[i].volumeType == volumeType) {
        return new Promise(function(fulfill) {
          chrome.fileSystem.requestFileSystem(
              {volumeId: list[i].volumeId, writable: true}, fulfill);
        });
      }
    }
    throw new Error('The volume is not found: ' + volumeType + '.');
  });
}

/**
 * Prepares a file on the file system.
 * @param {FileSystem} filesystem File system.
 * @param {string} name Name of the file.
 * @param {Blob} contents Contents of the file.
 * @return {Promise} Promise to be fulfilled with FileEntry of the new file.
 */
function prepareFile(filesystem, name, contents) {
  return new Promise(function(fulfill, reject) {
    filesystem.root.getFile(name, {create: true}, function(file) {
      file.createWriter(function(writer) {
        writer.write(contents);
        writer.onwrite = fulfill.bind(null, file);
        writer.onerror = reject;
      });
      fulfill(file);
    }, reject);
  });
}

/**
 * Prepares a directory on the file system.
 * @param {FileSystem} filesystem File system.
 * @param {string} name Name of the directory.
 * @param {Blob} contents Contents of the file.
 * @return {Promise} Promise to be fulfilled with DirectoryEntry of the new
 *     directory.
 */
function prepareDirectory(filesystem, name) {
  return new Promise(function(fulfill, reject) {
    filesystem.root.getDirectory(name, {create: true}, function(dirEntry) {
      fulfill(dirEntry);
    }, reject);
  });
}

/**
 * Prepares two test files on the file system.
 * @param {FileSystem} filesystem File system.
 * @return {Promise} Promise to be fullfilled with an object {filesystem:
 *     FileSystem, entries: Array<FileEntry>} that contains the passed file
 *     system and the created entries.
 */
function prepareFiles(filesystem) {
  var testFileA =
      prepareFile(filesystem, 'test_file_a.txt', TEST_FILE_CONTENTS);
  var testFileB =
      prepareFile(filesystem, 'test_file_b.txt', TEST_FILE_CONTENTS);
  return Promise.all([testFileA, testFileB]).then(function(entries) {
    return {filesystem: filesystem, entries: entries};
  });
}

/**
 * Prepares two test directories on the file system.
 * @param {FileSystem} filesystem File system.
 * @return {Promise} Promise to be fullfilled with an object {filesystem:
 *     FileSystem, entries: Array<DirectoryEntry>} that contains the passed file
 *     system and the created entries.
 */
function prepareDirectories(filesystem) {
  var testDirA = prepareDirectory(filesystem, 'dir1');
  var testDirB = prepareDirectory(filesystem, 'dir2');
  return Promise.all([testDirA, testDirB]).then(function(entries) {
    return {filesystem: filesystem, entries: entries};
  });
}

/**
 * Contents of the test file.
 * @type {Blob}
 * @const
 */
var TEST_FILE_CONTENTS = new Blob(['This is a test file.']);

/**
 * File system of the drive volume for files.
 * @type {Promise}
 */
var driveFileSystemPromise = getFileSystem('drive').then(prepareFiles);

/**
 * File system of the local volume for files.
 * @type {Promise}
 */
var localFileSystemPromise = getFileSystem('testing').then(prepareFiles);

/**
 * File system of the drive volume for directories.
 * @type {Promise}
 */
var driveDirSystemPromise = getFileSystem('drive').then(prepareDirectories);

/**
 * File system of the local volume for directories.
 * @type {Promise}
 */
var localDirSystemPromise = getFileSystem('drive').then(prepareDirectories);

/**
 * Calls test functions depends on the result of the promise.
 * @param {Promise} promise Promise to be fulfilled or to be rejected depends on
 *     the test results.
 */
function testPromise(promise) {
  promise.then(
      chrome.test.callbackPass(),
      function(error) {
        chrome.test.fail(error.stack || error);
      });
}

/**
 * Calls the executeTask API with the entries and checks the launch data passed
 * to onLaunched events.
 * @param {Array<Entry>} isolatedEntries Entries to be tested.
 * @return {Promise} Promise to be fulfilled on success.
 */
function launchWithEntries(isolatedEntries) {
  // TODO(mtomasz): Remove this hack once chrome.FileManager API can work on
  // isolated entries.
  return new Promise(function(fulfill, reject) {
           chrome.fileManagerPrivate.resolveIsolatedEntries(
               isolatedEntries, function(entries) {
                 fulfill(entries);
               });
         })
      .then(
          function(entries) {
            const dlpSourceUrls = entries.map(_ => '');
            var tasksPromise = new Promise(function(fulfill) {
                                 chrome.fileManagerPrivate.getFileTasks(
                                     entries, dlpSourceUrls, fulfill);
                               }).then(function(resultingTasks) {
              const tasks = resultingTasks.tasks;
              chrome.test.assertEq(1, tasks.length);
              chrome.test.assertEq("ChromeOS File handler extension",
                                   tasks[0].title);
              chrome.test.assertEq(
                  'pkplfbidichfdicaijlchgnapepdginl',
                  tasks[0].descriptor.appId);
              chrome.test.assertEq('app', tasks[0].descriptor.taskType);
              chrome.test.assertEq('textAction', tasks[0].descriptor.actionId);
              return tasks[0];
            });
            var launchDataPromise = new Promise(function(fulfill) {
              chrome.app.runtime.onLaunched.addListener(
                  function handler(launchData) {
                    chrome.app.runtime.onLaunched.removeListener(handler);
                    fulfill(launchData);
                  });
            });
            var taskExecutedPromise = tasksPromise.then(function(task) {
              return new Promise(function(fulfill, reject) {
                chrome.fileManagerPrivate.executeTask(
                  task.descriptor, entries,
                    function(result) {
                      if (result)
                        fulfill();
                      else
                        reject();
                    });
              });
            });
            var resolvedEntriesPromise = launchDataPromise.then(
                function(launchData) {
                  var entries = launchData.items.map(
                      function(item) { return item.entry; });
                  return new Promise(function(fulfill) {
                    chrome.fileManagerPrivate.resolveIsolatedEntries(
                        entries, fulfill);
                  });
                });
            return Promise.all([
              taskExecutedPromise,
              launchDataPromise,
              resolvedEntriesPromise
            ]).then(function(args) {
              chrome.test.assertEq(entries.length, args[1].items.length);
              chrome.test.assertEq(
                  entries.map(entry => entry.name).sort(),
                  args[1].items.map(item => item.entry.name).sort(),
                  'Wrong entries are passed to the application handler.');
              chrome.test.assertEq(
                  entries.map(entry => entry.toURL()).sort(),
                  args[2].map(entry => entry.toURL()).sort(),
                  'Entries passed to the application handler cannot be ' +
                      'resolved.');
            })
          });
}

/**
 * Tests the file handler feature with entries on the local volume.
 */
function testForLocalFiles() {
  testPromise(localFileSystemPromise.then(function(volume) {
    return launchWithEntries(volume.entries);
  }));
}

/**
 * Tests the file handler feature with entries on the drive volume.
 */
function testForDriveFiles() {
  testPromise(driveFileSystemPromise.then(function(volume) {
    return launchWithEntries(volume.entries);
  }));
}

/**
 * Tests the directory handler feature with entries on the local volume.
 */
function testForLocalDirectories() {
  testPromise(localDirSystemPromise.then(function(volume) {
    return launchWithEntries(volume.entries);
  }));
}

/**
 * Tests the directory handler feature with entries on the local volume.
 */
function testForDriveDirectories() {
  testPromise(driveDirSystemPromise.then(function(volume) {
    return launchWithEntries(volume.entries);
  }));
}

/**
 * Tests the file and directory handler with entries both on the local and on
 * the drive volumes.
 */
function testForMixedFilesAndDirectories() {
  testPromise(
      Promise.all([localFileSystemPromise, driveFileSystemPromise,
                   localDirSystemPromise, driveDirSystemPromise]).then(
          function(args) {
            return launchWithEntries(args[0].entries.concat(args[1].entries)
                .concat(args[2].entries).concat(args[3].entries));
          }));
}

// Run the tests.
chrome.test.runTests([
  testForLocalFiles,
  testForDriveFiles,
  testForLocalDirectories,
  testForDriveDirectories,
  testForMixedFilesAndDirectories,
]);