chromium/chrome/test/data/extensions/api_test/file_browser/multi_profile_copy/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.

const kSecondaryDriveMountPointName = 'drive-fileBrowserApiTestProfile2';

/**
 * @param {function(...?)} fn
 * @param {...?} args
 * @returns {!Promise<?>}
 */
async function promisifyWithLastError(fn, ...args) {
  return new Promise((resolve, reject) => {
    fn(...args, (result) => {
      const error = chrome.runtime.lastError;
      if (error) {
        reject(new Error(error.message));
      } else {
        resolve(result);
      }
    });
  });
}
/**
 * Get a file entry from the root of the mounted filesystem.
 *
 * @param {DirectoryEntry} root
 * @param {string} path
 * @param {{create: (boolean|undefined), exclusive: (boolean|undefined)}}
 *     options
 * @returns {!Promise<!Entry>}
 */
async function getFileEntry(root, path, options) {
  return new Promise(
      (resolve, reject) => root.getFile(path, options, resolve, reject));
}

/**
 * Get a directory entry from the root of the mounted filesystem.
 *
 * @param {DirectoryEntry} root
 * @param {string} path
 * @param {{create: (boolean|undefined), exclusive: (boolean|undefined)}}
 *  options
 * @returns {!Promise<!DirectoryEntry>}
 */
async function getDirectoryEntry(root, path, options) {
  return new Promise(
      (resolve, reject) => root.getDirectory(path, options, resolve, reject));
}


/**
 * Returns a callback that works as an error handler in file system API
 * functions and invokes |callback| with specified message string.
 *
 * @param {function(string)} callback Wrapped callback function object.
 * @param {string} message Error message.
 * @return {function(DOMError)} Resulting callback function object.
 */
function fileErrorCallback(callback, message) {
  return function(error){
    callback(message + ": " + error.name);
  };
}

/**
 * Copies an entry using chrome.fileManagerPrivate.startCopy().
 *
 * @param {!Entry} fromRoot Root entry of the copy source file system.
 * @param {string} fromPath Relative path from fromRoot of the source entry.
 * @param {!Entry} toRoot Root entry of the copy destination file system.
 * @param {string} toPath Relative path from toRoot of the target directory.
 * @param {function()} successCallback Callback invoked when copy succeed.
 * @param {function(string)} errorCallback Callback invoked in error case.
 */
async function fileCopy(
    fromRoot, fromPath, toRoot, toPath, successCallback, errorCallback) {
  const from = await getFileEntry(fromRoot, fromPath, {create: false});
  const to = await getDirectoryEntry(toRoot, toPath, {create: false});
  let copyId = null;
  const onProgress = function(event) {
    const id = event.taskId;
    if (id !== copyId) {
      // The first progress update comes before the `copyId` is assigned.
      // So here we just ignore the first update.
      return;
    }
    switch (event.state) {
      case chrome.fileManagerPrivate.IoTaskState.ERROR:
      case chrome.fileManagerPrivate.IoTaskState.CANCELLED:
        chrome.fileManagerPrivate.onIOTaskProgressStatus.removeListener(
            onProgress);
        errorCallback('Copy failed.');
        return;
      case chrome.fileManagerPrivate.IoTaskState.SUCCESS:
        chrome.fileManagerPrivate.onIOTaskProgressStatus.removeListener(
            onProgress);
        successCallback();
    }
  };

  chrome.fileManagerPrivate.onIOTaskProgressStatus.addListener(onProgress);

  copyId = await promisifyWithLastError(
      chrome.fileManagerPrivate.startIOTask,
      chrome.fileManagerPrivate.IoTaskType.COPY, [from],
      {destinationFolder: to});
}

/**
 * Verifies that a file exists on the specified location.
 *
 * @param {Entry} root Root entry of the file system.
 * @param {string} path Relative path of the file from the root entry,
 * @param {function()} successCallback Callback invoked when the file exists.
 * @param {function(string)} errorCallback Callback invoked in error case.
 */
function verifyFileExists(root, path, successCallback, errorCallback) {
  root.getFile(path, {create: false},
               successCallback,
               fileErrorCallback(errorCallback, path + ' does not exist.'));
}

/**
 * Collects all tests that should be run for the test volume.
 *
 * @param {!Entry} firstRoot Root entry of the first volume.
 * @param {!Entry} secondRoot Root entry of the second volume.
 * @return {!Array<function()>} The list of tests that should be run.
 */
function collectTests(firstRoot, secondRoot) {
  const testsToRun = [];

  testsToRun.push(function crossProfileNormalFileCopyTest() {
    fileCopy(
        secondRoot, 'root/test_dir/test_file.tiff', firstRoot, 'root/',
        verifyFileExists.bind(
            null, firstRoot, 'root/test_file.tiff', chrome.test.succeed,
            chrome.test.fail),
        chrome.test.fail);
  });

  testsToRun.push(function crossProfileHostedDocumentCopyTest() {
    fileCopy(
        secondRoot, 'root/test_dir/hosted_doc.gdoc', firstRoot, 'root/',
        verifyFileExists.bind(
            null, firstRoot, 'root/hosted_doc.gdoc', chrome.test.succeed,
            chrome.test.fail),
        chrome.test.fail);
  });

  return testsToRun;
}

async function main() {
  const volumeMetadataList = await promisifyWithLastError(
      chrome.fileManagerPrivate.getVolumeMetadataList);
  const driveVolumes =
      volumeMetadataList.filter((volume) => volume.volumeType == 'drive');

  if (driveVolumes.length !== 1) {
    chrome.test.fail('Unexpected number of Drive volumes.');
    return;
  }

  const primaryFileSystem = await promisifyWithLastError(
      chrome.fileSystem.requestFileSystem,
      {volumeId: driveVolumes[0].volumeId, writable: true});

  if (!primaryFileSystem) {
    chrome.test.fail('Failed to acquire the testing volume.');
    return;
  }

  // Resolving the isolated entry is necessary in order to fetch URL of an entry
  // from a different profile.
  const entries = await promisifyWithLastError(
      chrome.fileManagerPrivate.resolveIsolatedEntries,
      [primaryFileSystem.root]);
  const secondaryUrl =
      entries[0].toURL().replace(/[^\/]*\/?$/, kSecondaryDriveMountPointName);
  await promisifyWithLastError(
      chrome.fileManagerPrivate.grantAccess, [secondaryUrl]);
  const secondaryEntry = await promisifyWithLastError(
      webkitResolveLocalFileSystemURL, secondaryUrl);
  if (!secondaryEntry) {
    chrome.test.fail('Failed to acquire secondary profile\'s volume.');
    return;
  }

  const tests = collectTests(entries[0], secondaryEntry);
  chrome.test.runTests(tests);
}

main();