Bug 593815 - Tests for download files with the same name. [r=sdwilsh, a=blocker]
authorWes Johnston <wjohnston@mozilla.com>
Mon, 22 Nov 2010 19:36:42 -0800
changeset 58405 bdd47e6e4f17fc8ea84c2a9abc469f16645aba44
parent 58404 17cecf2c18244b09dadd870e3aeede1f036e269c
child 58420 de97b959fca07405660d293f53e79dc3bdc3187a
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewerssdwilsh, blocker
bugs593815
milestone2.0b8pre
Bug 593815 - Tests for download files with the same name. [r=sdwilsh, a=blocker]
toolkit/components/downloads/test/unit/downloads_manifest.js
toolkit/components/downloads/test/unit/head_download_manager.js
toolkit/components/downloads/test/unit/test_cancel_download_files_removed.js
toolkit/components/downloads/test/unit/test_download_samename.js
toolkit/components/downloads/test/unit/test_downloads.manifest
new file mode 100644
--- /dev/null
+++ b/toolkit/components/downloads/test/unit/downloads_manifest.js
@@ -0,0 +1,24 @@
+/* Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Shared functions for files testing Bug 593815
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+function HelperAppDlg() { }
+HelperAppDlg.prototype = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog]),
+  classID: Components.ID("49456eda-4dc4-4d1a-b8e8-0b94749bf99e"),
+  show: function (launcher, ctx, reason) {
+    launcher.MIMEInfo.preferredAction = Ci.nsIMIMEInfo.saveToDisk;
+    launcher.launchWithApplication(null, false);
+  },
+
+  promptForSaveToFile: function (launcher, ctx, defaultFile, suggestedExtension, forcePrompt) { }
+}
+
+
+const NSGetFactory = XPCOMUtils.generateNSGetFactory([HelperAppDlg]);
--- a/toolkit/components/downloads/test/unit/head_download_manager.js
+++ b/toolkit/components/downloads/test/unit/head_download_manager.js
@@ -35,16 +35,24 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 // This file tests the download manager backend
 
 do_load_httpd_js();
 do_get_profile();
 
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+var downloadUtils = { };
+XPCOMUtils.defineLazyServiceGetter(downloadUtils,
+                                   "downloadManager",
+                                   "@mozilla.org/download-manager;1",
+                                   Ci.nsIDownloadManager);
+
 function createURI(aObj)
 {
   var ios = Cc["@mozilla.org/network/io-service;1"].
             getService(Ci.nsIIOService);
   return (aObj instanceof Ci.nsIFile) ? ios.newFileURI(aObj) :
                                         ios.newURI(aObj, null, null);
 }
 
new file mode 100644
--- /dev/null
+++ b/toolkit/components/downloads/test/unit/test_cancel_download_files_removed.js
@@ -0,0 +1,140 @@
+/* Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// This file tests Bug 593815 - specifically that downloaded files
+// are cleaned up correctly when a download is cancelled
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+Components.utils.import("resource://gre/modules/NetUtil.jsm");
+do_load_manifest("test_downloads.manifest");
+
+let httpserver = null;
+let currentTest = 0;
+
+function WindowContext() { }
+WindowContext.prototype = {
+  QueryInterface:  XPCOMUtils.generateQI([Ci.nsIInterfaceRequestor]),
+  getInterface: XPCOMUtils.generateQI([Ci.nsIURIContentListener,
+                                       Ci.nsILoadGroup]),
+
+  /* nsIURIContentListener */
+  onStartURIOpen: function (uri) { },
+  isPreferred: function (type, desiredtype) { return false; },
+
+  /* nsILoadGroup */
+  addRequest: function (request, context) { },
+  removeRequest: function (request, context, status) { }
+};
+
+let DownloadListener = {
+  set : null,
+  init: function () {
+    Services.obs.addObserver(this, "dl-start", true);
+    Services.obs.addObserver(this, "dl-done", true);
+    Services.obs.addObserver(this, "dl-cancel", true);
+    Services.obs.addObserver(this, "dl-fail", true);
+  },
+
+  // check that relevant cancel operations have been performed
+  // currently this just means removing the target file
+  onCancel: function(aSubject, aTopic, aData) {
+    let dl = aSubject.QueryInterface(Ci.nsIDownload);
+    do_check_false(dl.targetFile.exists());
+    runNextTest();
+  },
+
+  observe: function (aSubject, aTopic, aData) {
+    switch(aTopic) {
+      case "dl-start" :
+        // cancel, pause, or resume the download
+        // depending on parameters in this.set
+        let dl = aSubject.QueryInterface(Ci.nsIDownload);
+
+        if (this.set.doPause) {
+          downloadUtils.downloadManager.pauseDownload(dl.id);
+        }
+
+        if (this.set.doResume) {
+          downloadUtils.downloadManager.resumeDownload(dl.id);
+        }
+
+        downloadUtils.downloadManager.cancelDownload(dl.id);
+        break;
+      case "dl-cancel" :
+        this.onCancel(aSubject, aTopic, aData);
+        break;
+      case "dl-fail" :
+        do_throw("Download failed");
+        break;
+      case "dl-done" :
+        do_throw("Download finished");
+        break;
+    }
+  },
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
+                                         Ci.nsISupportsWeakReference])
+}
+
+// loads the uri given in tests[currentTest]
+// finishes tests if there are no more test files listed
+function runNextTest()
+{
+  if (currentTest == tests.length) {
+    httpserver.stop(do_test_finished);
+    return;
+  }
+
+  let set = DownloadListener.set = tests[currentTest];
+  currentTest++;
+
+  let channel = NetUtil.newChannel("http://localhost:4444" + set.serverPath);
+  let uriloader = Cc["@mozilla.org/uriloader;1"].getService(Ci.nsIURILoader);
+  uriloader.openURI(channel, true, new WindowContext());
+}
+
+// sends the responses for the files. sends the same content twice if we resume
+// the download
+function getResponse(aSet) {
+  return function(aMetadata, aResponse) {
+    aResponse.setHeader("Content-Type", "text/plain", false);
+    if (aMetadata.hasHeader("Range")) {
+      var matches = aMetadata.getHeader("Range").match(/^\s*bytes=(\d+)?-(\d+)?\s*$/);
+      aResponse.setStatusLine(aMetadata.httpVersion, 206, "Partial Content");
+      aResponse.bodyOutputStream.write(aSet.data, aSet.data.length);
+      return;
+    }
+    aResponse.setHeader("Accept-Ranges", "bytes", false);
+    aResponse.setHeader("Content-Disposition", "attachment; filename=test.txt;", false);
+    aResponse.bodyOutputStream.write(aSet.data, aSet.data.length);
+  }
+}
+
+// files to be downloaded. For these tests, files will be cancelled either:
+//   1.) during the download
+//   2.) while they are paused
+//   3.) after they have been resumed
+let tests = [
+  { serverPath: "/test1.html", data: "Test data 1" },
+  { serverPath: "/test2.html", data: "Test data 2", doPause: true },
+  { serverPath: "/test3.html", data: "Test data 3", doPause: true, doResume: true},
+];
+
+function run_test() {
+  // setup a download listener to run tests during and after the download
+  DownloadListener.init();
+  Services.prefs.setBoolPref("browser.download.manager.showWhenStarting", false);
+
+  httpserver = new nsHttpServer();
+  httpserver.start(4444);
+  do_test_pending();
+
+  // setup files to be download, each with the same suggested filename
+  // from the server, but with different contents
+  for(let i = 0; i < tests.length; i++) {
+    let set = tests[i];
+    httpserver.registerPathHandler(set.serverPath, getResponse(set));
+  }
+
+  runNextTest(); // start downloading the first file
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/components/downloads/test/unit/test_download_samename.js
@@ -0,0 +1,147 @@
+/* Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// This file tests Bug 593815 - specifically that after downloading two files
+// with the same name, the download manager still points to the correct files
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+Components.utils.import("resource://gre/modules/NetUtil.jsm");
+do_load_manifest("test_downloads.manifest");
+
+let httpserver = null;
+let currentTest = 0;
+
+function WindowContext() { }
+WindowContext.prototype = {
+  QueryInterface:  XPCOMUtils.generateQI([Ci.nsIInterfaceRequestor]),
+  getInterface: XPCOMUtils.generateQI([Ci.nsIURIContentListener,
+                                       Ci.nsILoadGroup]),
+
+  /* nsIURIContentListener */
+  onStartURIOpen: function (uri) { },
+  isPreferred: function (type, desiredtype) { return false; },
+
+  /* nsILoadGroup */
+  addRequest: function (request, context) { },
+  removeRequest: function (request, context, status) { }
+};
+
+let DownloadListener = {
+  set: null,
+  prevFiles : [],
+
+  init: function () {
+    Services.obs.addObserver(this, "dl-start", true);
+    Services.obs.addObserver(this, "dl-done", true);
+  },
+
+  observe: function (aSubject, aTopic, aData) {
+    
+    if (aTopic == "dl-start") {
+      // pause the download if requested
+      if (this.set.doPause) {
+        let dl = aSubject.QueryInterface(Ci.nsIDownload);
+        downloadUtils.downloadManager.pauseDownload(dl.id);
+        do_timeout(1000, function() {
+          downloadUtils.downloadManager.resumeDownload(dl.id);
+        });
+      }
+    } else if (aTopic == "dl-done") {
+      // check that no two files have the same filename in the download manager
+      let file = aSubject.QueryInterface(Ci.nsIDownload).targetFile;
+      for each (let prevFile in this.prevFiles) {
+        do_check_neq(file.leafName, prevFile.leafName);
+      }
+      this.prevFiles.push(file);
+    
+      // get the contents of the file
+      let fis = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
+      fis.init(file, -1, -1, 0);
+      var cstream = Cc["@mozilla.org/intl/converter-input-stream;1"].createInstance(Ci.nsIConverterInputStream);
+      cstream.init(fis, "UTF-8", 0, 0);
+    
+      let val = "";
+      let (str = {}) {  
+        let read = 0;
+        do {
+          read = cstream.readString(0xffffffff, str);
+          val += str.value;  
+        } while (read != 0);  
+      }
+      cstream.close();
+
+      // check if the file contents match the expected ones
+      if (this.set.doPause) {
+        do_check_eq(val, this.set.data + this.set.data); // files that have been paused have the same data twice
+      } else {
+        do_check_eq(val, this.set.data);
+      }
+      runNextTest(); // download the next file
+    }
+  },
+
+  QueryInterface:  XPCOMUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsISupportsWeakReference])
+}
+
+/*
+  Each test will download a file from the server.
+*/
+function runNextTest()
+{
+  if (currentTest == tests.length) {
+    httpserver.stop(do_test_finished);
+    return;
+  }
+  let set = DownloadListener.set = tests[currentTest];
+  currentTest++;
+
+  let channel = NetUtil.newChannel("http://localhost:4444" + set.serverURL);
+  let uriloader = Cc["@mozilla.org/uriloader;1"].getService(Ci.nsIURILoader);
+  uriloader.openURI(channel, true, new WindowContext());
+}
+
+// sends the responses for the files. sends the same content twice if we resume
+// the download
+function getResponse(aSet) {
+  return function(aMetadata, aResponse) {
+    aResponse.setHeader("Content-Type", "text/plain", false);
+    if (aMetadata.hasHeader("Range")) {
+      var matches = aMetadata.getHeader("Range").match(/^\s*bytes=(\d+)?-(\d+)?\s*$/);
+      aResponse.setStatusLine(aMetadata.httpVersion, 206, "Partial Content");
+      aResponse.bodyOutputStream.write(aSet.data, aSet.data.length);
+      return;
+    }
+    aResponse.setHeader("Accept-Ranges", "bytes", false);
+    aResponse.setHeader("Content-Disposition", "attachment; filename=test.txt;", false);
+    aResponse.bodyOutputStream.write(aSet.data, aSet.data.length);
+  }
+}
+
+// files to be downloaded. All files will have the same suggested filename, but
+// should contain different data. doPause will cause the download to pause and resume
+// itself
+let tests = [
+  { serverURL: "/test1.html", data: "Test data 1", doPause: false },
+  { serverURL: "/test2.html", data: "Test data 2", doPause: false },
+  { serverURL: "/test3.html", data: "Test data 3", doPause: true }
+];
+
+function run_test() {
+  // setup a download listener to run tests after each download finished
+  DownloadListener.init();
+  Services.prefs.setBoolPref("browser.download.manager.showWhenStarting", false);
+
+  httpserver = new nsHttpServer();
+  httpserver.start(4444);
+  do_test_pending();
+
+  // setup files to be download, each with the same suggested filename
+  // from the server, but with different contents
+  for(let i = 0; i < tests.length; i++) {
+    let set = tests[i];
+    httpserver.registerPathHandler(set.serverURL, getResponse(set));
+  }
+
+  runNextTest();  // start downloading the first file
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/components/downloads/test/unit/test_downloads.manifest
@@ -0,0 +1,2 @@
+component 49456eda-4dc4-4d1a-b8e8-0b94749bf99e downloads_manifest.js
+contract @mozilla.org/helperapplauncherdialog;1 49456eda-4dc4-4d1a-b8e8-0b94749bf99e