browser/metro/base/tests/mochitest/browser_downloads.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 et sw=2 tw=80: */
     3 /* Any copyright is dedicated to the Public Domain.
     4    http://creativecommons.org/publicdomain/zero/1.0/ */
     6 "use strict";
     8 /**
     9  * Provides infrastructure for automated download components tests.
    10  * (adapted from browser/component/downloads test's head.js)
    11  */
    13 ////////////////////////////////////////////////////////////////////////////////
    14 //// Globals
    16 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
    17                                   "resource://gre/modules/FileUtils.jsm");
    19 const nsIDM = Ci.nsIDownloadManager;
    21 ////////////////////////////////////////////////////////////////////////////////
    22 // Test Helpers
    24 var { spawn } = Task;
    26 function equalStrings(){
    27   let ref = ""+arguments[0];
    28   for (let i=1; i<arguments.length; i++){
    29     if (ref !== ""+arguments[i]) {
    30       info("equalStrings failure: " + ref + " != " + arguments[i]);
    31       return false
    32     }
    33   }
    34   return true;
    35 }
    37 function equalNumbers(){
    38   let ref = Number(arguments[0]);
    39   for (let i=1; i<arguments.length; i++){
    40     if (ref !== Number(arguments[i])) return false;
    41     if (ref !== Number(arguments[i])) {
    42       info("equalNumbers failure: " + ref + " != " + Number(arguments[i]));
    43       return false
    44     }
    45   }
    46   return true;
    47 }
    49 function getPromisedDbResult(aStatement) {
    50   let dbConnection = MetroDownloadsView.manager.DBConnection;
    51   let statement = ("string" == typeof aStatement) ?
    52         dbConnection.createAsyncStatement(
    53           aStatement
    54         ) : aStatement;
    56   let deferred = Promise.defer(),
    57       resultRows = [],
    58       err = null;
    59   try {
    60     statement.executeAsync({
    61       handleResult: function(aResultSet) {
    62         let row;
    63         if(!aResultSet) {
    64           return;
    65         }
    66         while ((row = aResultSet.getNextRow())){
    67           resultRows.push(row);
    68         }
    69       },
    70       handleError: function(aError) {
    71         Cu.reportError(aError);
    72         err = aError;
    73       },
    74       handleCompletion: function(){
    75         if (err) {
    76           deferred.reject(err);
    77         } else {
    78           deferred.resolve(resultRows);
    79         }
    80      }
    81     });
    82   } finally {
    83     statement.finalize();
    84   }
    85   return deferred.promise;
    86 }
    88 let gTestTargetFile = FileUtils.getFile("TmpD", ["dm-ui-test.file"]);
    89 gTestTargetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
    90 registerCleanupFunction(function () {
    91   gTestTargetFile.remove(false);
    92   PanelUI.hide();
    93 });
    95 /**
    96  * This object contains a property for each column in the downloads table.
    97  */
    98 let gDownloadRowTemplate = {
    99   name: "test-download.txt",
   100   source: "http://www.example.com/test-download.txt",
   101   target: NetUtil.newURI(gTestTargetFile).spec,
   102   startTime: 1180493839859230,
   103   endTime: 1180493839859234,
   104   state: nsIDM.DOWNLOAD_FINISHED,
   105   currBytes: 0,
   106   maxBytes: -1,
   107   preferredAction: 0,
   108   autoResume: 0
   109 };
   111 ////////////////////////////////////////////////////////////////////////////////
   112 // Test Infrastructure
   114 function test() {
   115   runTests();
   116 }
   118 /////////////////////////////////////
   119 // shared test setup
   120 function resetDownloads(){
   121   // clear out existing and any pending downloads in the db
   122   // returns a promise
   124   let promisedResult = getPromisedDbResult(
   125     "DELETE FROM moz_downloads"
   126   );
   127   return promisedResult.then(function(aResult){
   128     // // Reset any prefs that might have been changed.
   129     // Services.prefs.clearUserPref("browser.download.panel.shown");
   131     // Ensure that data is unloaded.
   132     let dlMgr = MetroDownloadsView.manager;
   133     let dlsToRemove = [];
   134     // Clear all completed/cancelled downloads
   135     dlMgr.cleanUp();
   136     dlMgr.cleanUpPrivate();
   138     // Queue up all active ones as well
   139     for (let dlsEnum of [dlMgr.activeDownloads, dlMgr.activePrivateDownloads]) {
   140       while (dlsEnum.hasMoreElements()) {
   141         dlsToRemove.push(dlsEnum.next());
   142       }
   143     }
   144     // Remove any queued up active downloads
   145     dlsToRemove.forEach(function (dl) {
   146       dl.remove();
   147     });
   148   });
   149 }
   151 function addDownloadRow(aDataRow) {
   152   let deferredInsert = Promise.defer();
   153   let dataRow = aDataRow;
   155   let dm = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager);
   156   let db = dm.DBConnection;
   158   let columnNames = Object.keys(gDownloadRowTemplate).join(", ");
   159   let parameterNames = Object.keys(gDownloadRowTemplate)
   160                              .map(function(n) ":" + n)
   161                              .join(", ");
   163   let statement = db.createAsyncStatement(
   164                   "INSERT INTO moz_downloads (" + columnNames +
   165                   ", guid) VALUES(" + parameterNames + ", GENERATE_GUID())");
   167   // Populate insert parameters from the provided data.
   168   for (let columnName in gDownloadRowTemplate) {
   169     if (!(columnName in dataRow)) {
   170       // Update the provided row object with data from the global template,
   171       // for columns whose value is not provided explicitly.
   172       dataRow[columnName] = gDownloadRowTemplate[columnName];
   173     }
   174     statement.params[columnName] = dataRow[columnName];
   175   }
   177   // Run the statement asynchronously and wait.
   178   let promisedDownloads = getPromisedDbResult(
   179     statement
   180   );
   181   yield promisedDownloads.then(function(){
   182       let newItemId = db.lastInsertRowID;
   183       let download = dm.getDownload(newItemId);
   184       deferredInsert.resolve(download);
   185   });
   186 }
   188 function gen_addDownloadRows(aDataRows){
   189   if (!aDataRows.length) {
   190     yield null;
   191   }
   193   try {
   194     // Add each of the provided downloads in reverse.
   195     for (let i = aDataRows.length - 1; i >= 0; i--) {
   196       let dataRow = aDataRows[i];
   197       let download = yield addDownloadRow(dataRow);
   199       // At each iteration, ensure that the start and end time in the global
   200       // template is distinct, as these column are used to sort each download
   201       // in its category.
   202       gDownloadRowTemplate.startTime++;
   203       gDownloadRowTemplate.endTime++;
   204     }
   205   } finally {
   206     info("gen_addDownloadRows, finally");
   207   }
   208 }
   210 /////////////////////////////////////
   211 // Test implementations
   213 gTests.push({
   214   desc: "zero downloads",
   215   run: function () {
   216     yield resetDownloads();
   217     todo(false, "Test there are no visible notifications with an empty db.");
   218   }
   219 });
   221 /**
   222  * Make sure the downloads panel can display items in the right order and
   223  * contains the expected data.
   224  */
   225 gTests.push({
   226   desc: "Show downloads",
   227   run: function(){
   228     // Display one of each download state.
   229     let DownloadData = [
   230       { endTime: 1180493839859239, state: nsIDM.DOWNLOAD_NOTSTARTED },
   231       { endTime: 1180493839859238, state: nsIDM.DOWNLOAD_DOWNLOADING },
   232       { endTime: 1180493839859237, state: nsIDM.DOWNLOAD_PAUSED },
   233       { endTime: 1180493839859236, state: nsIDM.DOWNLOAD_SCANNING },
   234       { endTime: 1180493839859235, state: nsIDM.DOWNLOAD_QUEUED },
   235       { endTime: 1180493839859234, state: nsIDM.DOWNLOAD_FINISHED },
   236       { endTime: 1180493839859233, state: nsIDM.DOWNLOAD_FAILED },
   237       { endTime: 1180493839859232, state: nsIDM.DOWNLOAD_CANCELED },
   238       { endTime: 1180493839859231, state: nsIDM.DOWNLOAD_BLOCKED_PARENTAL },
   239       { endTime: 1180493839859230, state: nsIDM.DOWNLOAD_DIRTY },
   240       { endTime: 1180493839859229, state: nsIDM.DOWNLOAD_BLOCKED_POLICY }
   241     ];
   243     yield resetDownloads();
   245     try {
   246       // Populate the downloads database with the data required by this test.
   247       // we're going to add stuff to the downloads db.
   248       yield spawn( gen_addDownloadRows( DownloadData ) );
   250       todo( false, "Check that MetroDownloadsView._progressNotificationInfo and MetroDownloadsView._downloadCount \
   251         have the correct length (DownloadData.length) \
   252         May also test that the correct notifications show up for various states.");
   254       todo(false, "Iterate through download objects in MetroDownloadsView._progressNotificationInfo \
   255         and confirm that the downloads they refer to are the same as those in \
   256         DownloadData.");
   257     } catch(e) {
   258       info("Show downloads, some error: " + e);
   259     }
   260     finally {
   261       // Clean up when the test finishes.
   262       yield resetDownloads();
   263     }
   264   }
   265 });
   267 /**
   268  * Make sure the downloads can be removed with the expected result on the notifications
   269  */
   270 gTests.push({
   271   desc: "Remove downloads",
   272   run: function(){
   273     // Push a few items into the downloads db.
   274     let DownloadData = [
   275       { endTime: 1180493839859239, state: nsIDM.DOWNLOAD_FINISHED },
   276       { endTime: 1180493839859238, state: nsIDM.DOWNLOAD_FINISHED },
   277       { endTime: 1180493839859237, state: nsIDM.DOWNLOAD_FINISHED }
   278     ];
   280     yield resetDownloads();
   282     try {
   283       // Populate the downloads database with the data required by this test.
   284       yield spawn( gen_addDownloadRows( DownloadData ) );
   286       let downloadRows = null,
   287           promisedDownloads;
   288       // get all the downloads from the db
   289       promisedDownloads = getPromisedDbResult(
   290         "SELECT guid "
   291       + "FROM moz_downloads "
   292       + "ORDER BY startTime DESC"
   293       ).then(function(aRows){
   294         downloadRows = aRows;
   295       }, function(aError){
   296         throw aError;
   297       });
   298       yield promisedDownloads;
   300       is(downloadRows.length, 3, "Correct number of downloads in the db before removal");
   302       todo(false, "Get some download from MetroDownloadsView._progressNotificationInfo, \
   303         confirm that its file exists, then remove it.");
   305       // remove is async(?), wait a bit
   306       yield waitForMs(0);
   308       // get all the downloads from the db
   309       downloadRows = null;
   310       promisedDownloads = getPromisedDbResult(
   311         "SELECT guid "
   312       + "FROM moz_downloads "
   313       + "ORDER BY startTime DESC"
   314       ).then(function(aRows){
   315         downloadRows = aRows;
   316       }, function(aError){
   317         throw aError;
   318       });
   319       yield promisedDownloads;
   321       todo(false, "confirm that the removed download is no longer in the database \
   322         and its file no longer exists.");
   324     } catch(e) {
   325       info("Remove downloads, some error: " + e);
   326     }
   327     finally {
   328       // Clean up when the test finishes.
   329       yield resetDownloads();
   330     }
   331   }
   332 });
   334 /**
   335  * Make sure the cancelled/aborted downloads are handled correctly.
   336  */
   337 gTests.push({
   338   desc: "Cancel/Abort Downloads",
   339   run: function(){
   340     todo(false, "Ensure that a cancelled/aborted download is in the correct state \
   341       including correct values for state variables (e.g. _downloadCount, _downloadsInProgress) \
   342       and the existence of the downloaded file.");
   343   }
   344 });
   346 /**
   347  * Make sure download notifications are moved when we close tabs.
   348  */
   349 gTests.push({
   350   desc: "Download notifications in closed tabs",
   351   setUp: function() {
   352     // put up a couple notifications on the initial tab
   353     let notificationBox = Browser.getNotificationBox();
   354     notificationBox.appendNotification("not important", "low-priority-thing", "", notificationBox.PRIORITY_INFO_LOW, []);
   355     notificationBox.appendNotification("so important", "high-priority-thing", "", notificationBox.PRIORITY_CRITICAL_HIGH, []);
   357     // open a new tab where we'll conduct the test
   358     yield addTab("about:mozilla");
   359   },
   360   run: function(){
   361     let notificationBox = Browser.getNotificationBox();
   362     let notn = MetroDownloadsView.showNotification("download-progress", "test message", [],
   363            notificationBox.PRIORITY_WARNING_LOW);
   364     Browser.closeTab(Browser.selectedTab);
   366     yield waitForEvent(Elements.tabList, "TabRemove");
   368     // expected behavior when a tab is closed while a download notification is showing:
   369     // * the notification remains visible as long as a next tab/browser exists
   370     // * normal rules about priority apply
   371     // * notifications - including any pre-existing ones - display in expected order
   372     let nextBox = Browser.getNotificationBox();
   373     let currentNotification;
   375     ok(nextBox.getNotificationWithValue("download-progress"), "notification was moved to next tab");
   377     currentNotification = nextBox.currentNotification;
   378     is(currentNotification.value, "high-priority-thing", "high priority notification is current");
   379     currentNotification.close();
   381     currentNotification = nextBox.currentNotification;
   382     is(currentNotification.value, "download-progress", "download notification is next");
   383     currentNotification.close();
   385     currentNotification = nextBox.currentNotification;
   386     is(currentNotification.value, "low-priority-thing", "low priority notification is next");
   387     currentNotification.close();
   388   }
   389 });

mercurial