Bug 1245644 - Add chrome.downloads.removeFile. r=kmag
authorStuart Colville <scolville@mozilla.com>
Mon, 14 Mar 2016 16:22:24 +0100
changeset 289651 73977dc040ffd25eefd863df069ffab322d574d2
parent 289650 1aea33a2d87b0aaff041874c72fe4852f5c1b603
child 289652 73bef86f117222773ad2d06d55964915c41ad180
push id30108
push usercbook@mozilla.com
push dateTue, 22 Mar 2016 11:14:31 +0000
treeherdermozilla-central@ea6298e1b4f7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskmag
bugs1245644
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1245644 - Add chrome.downloads.removeFile. r=kmag MozReview-Commit-ID: 4picapXsv2x
toolkit/components/extensions/ext-downloads.js
toolkit/components/extensions/schemas/downloads.json
toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_misc.html
--- a/toolkit/components/extensions/ext-downloads.js
+++ b/toolkit/components/extensions/ext-downloads.js
@@ -469,16 +469,33 @@ extensions.registerSchemaAPI("downloads"
             download.tryToKeepPartialData = true;
             download.start();
 
             const item = DownloadMap.newFromDownload(download, extension);
             return item.id;
           });
       },
 
+      removeFile(id) {
+        return DownloadMap.lazyInit().then(() => {
+          let item;
+          try {
+            item = DownloadMap.fromId(id);
+          } catch (err) {
+            return Promise.reject({message: `Invalid download id ${id}`});
+          }
+          if (item.state !== "complete") {
+            return Promise.reject({message: `Cannot remove incomplete download id ${id}`});
+          }
+          return OS.File.remove(item.filename, {ignoreAbsent: false}).catch((err) => {
+            return Promise.reject({message: `Could not remove download id ${item.id} because the file doesn't exist`});
+          });
+        });
+      },
+
       search(query) {
         return queryHelper(query)
           .then(items => items.map(item => item.serialize()));
       },
 
       pause(id) {
         return DownloadMap.lazyInit().then(() => {
           let item = DownloadMap.fromId(id);
--- a/toolkit/components/extensions/schemas/downloads.json
+++ b/toolkit/components/extensions/schemas/downloads.json
@@ -622,18 +622,18 @@
                 "type": "array"
               }
             ]
           }
         ]
       },
       {
         "name": "removeFile",
+        "async": "callback",
         "type": "function",
-        "unsupported": true,
         "parameters": [
           {
             "name": "downloadId",
             "type": "integer"
           },
           {
             "name": "callback",
             "type": "function",
--- a/toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_misc.html
+++ b/toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_misc.html
@@ -460,16 +460,135 @@ add_task(function* test_pausecancel() {
   is(msg.result[0].state, "interrupted", "download.state is correct");
   is(msg.result[0].paused, false, "download.paused is correct");
   is(msg.result[0].canResume, false, "download.canResume is correct");
   is(msg.result[0].error, "USER_CANCELED", "download.error is correct");
   is(msg.result[0].totalBytes, INT_TOTAL_LEN, "download.totalBytes is correct");
   is(msg.result[0].exists, false, "download.exists is correct");
 });
 
+add_task(function* test_file_removal() {
+  let msg = yield runInExtension("download", {url: TXT_URL});
+  is(msg.status, "success", "download() succeeded");
+  const id = msg.result;
+
+  msg = yield runInExtension("waitForEvents", [
+    {type: "onCreated", data: {id, url: TXT_URL}},
+    {
+      type: "onChanged",
+      data: {
+        id,
+        state: {
+          previous: "in_progress",
+          current: "complete",
+        },
+      },
+    },
+  ]);
+
+  is(msg.status, "success", "got onCreated and onChanged events");
+
+  msg = yield runInExtension("removeFile", id);
+  is(msg.status, "success", "removeFile() succeeded");
+
+  msg = yield runInExtension("removeFile", id);
+  is(msg.status, "error", "removeFile() fails since the file was already removed.");
+  ok(/file doesn't exist/.test(msg.errmsg), "removeFile() failed on removed file.");
+
+  msg = yield runInExtension("removeFile", 1000);
+  ok(/Invalid download id/.test(msg.errmsg), "removeFile() failed due to non-existent id");
+});
+
+add_task(function* test_removal_of_incomplete_download() {
+  let msg = yield runInExtension("download", {url: INTERRUPTIBLE_URL});
+  is(msg.status, "success", "download() succeeded");
+  const id = msg.result;
+
+  let progressPromise = waitForProgress(INTERRUPTIBLE_URL, INT_PARTIAL_LEN);
+
+  msg = yield runInExtension("waitForEvents", [
+    {type: "onCreated", data: {id}},
+  ]);
+  is(msg.status, "success", "got created and changed events");
+
+  yield progressPromise;
+  info(`download reached ${INT_PARTIAL_LEN} bytes`);
+
+  msg = yield runInExtension("pause", id);
+  is(msg.status, "success", "pause() succeeded");
+
+  msg = yield runInExtension("waitForEvents", [
+    {
+      type: "onChanged",
+      data: {
+        id,
+        state: {
+          previous: "in_progress",
+          current: "interrupted",
+        },
+        paused: {
+          previous: false,
+          current: true,
+        },
+        canResume: {
+          previous: false,
+          current: true,
+        },
+      },
+    }]);
+  is(msg.status, "success", "got onChanged event corresponding to pause");
+
+  msg = yield runInExtension("removeFile", id);
+  is(msg.status, "error", "removeFile() on paused download failed");
+
+  ok(/Cannot remove incomplete download/.test(msg.errmsg), "removeFile() failed due to download being incomplete");
+
+  msg = yield runInExtension("resume", id);
+  is(msg.status, "success", "resume() succeeded");
+
+  msg = yield runInExtension("waitForEvents", [
+    {
+      type: "onChanged",
+      data: {
+        id,
+        state: {
+          previous: "interrupted",
+          current: "in_progress",
+        },
+        paused: {
+          previous: true,
+          current: false,
+        },
+        canResume: {
+          previous: true,
+          current: false,
+        },
+        error: {
+          previous: "USER_CANCELED",
+          current: null,
+        },
+      },
+    },
+    {
+      type: "onChanged",
+      data: {
+        id,
+        state: {
+          previous: "in_progress",
+          current: "complete",
+        },
+      },
+    },
+  ]);
+  is(msg.status, "success", "got onChanged events for resume and complete");
+
+  msg = yield runInExtension("removeFile", id);
+  is(msg.status, "success", "removeFile() succeeded following completion of resumed download.");
+});
+
 // Test erase().  We don't do elaborate testing of the query handling
 // since it uses the exact same engine as search() which is tested
 // more thoroughly in test_chrome_ext_downloads_search.html
 add_task(function* test_erase() {
   yield clearDownloads();
 
   let ids = {};
   let msg = yield runInExtension("download", {url: TXT_URL});