Backed out changeset a1c1b0943294 (bug 1245603) for failing own test. r=failure
authorSebastian Hengst <archaeopteryx@coole-files.de>
Wed, 02 Mar 2016 15:09:16 +0100
changeset 322758 99aeeaac03ac1fc77dc5e0943b1b663899716766
parent 322757 1db864e863ed710a3e51ef795b32e070fd9cc145
child 322759 f601b789e1e1cb118a9b4186011a6c208aeae1df
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfailure
bugs1245603
milestone47.0a1
backs outa1c1b09432940839e162d7132bc69fb901754431
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
Backed out changeset a1c1b0943294 (bug 1245603) for failing own test. r=failure
toolkit/components/extensions/ext-downloads.js
toolkit/components/extensions/schemas/downloads.json
toolkit/components/extensions/test/mochitest/file_download.html
toolkit/components/extensions/test/mochitest/mochitest.ini
toolkit/components/extensions/test/mochitest/test_ext_downloads_search.html
--- a/toolkit/components/extensions/ext-downloads.js
+++ b/toolkit/components/extensions/ext-downloads.js
@@ -15,272 +15,17 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
 
 Cu.import("resource://gre/modules/ExtensionUtils.jsm");
 const {
   ignoreEvent,
 } = ExtensionUtils;
 
-const DOWNLOAD_ITEM_FIELDS = ["id", "url", "referrer", "filename", "incognito",
-                              "danger", "mime", "startTime", "endTime",
-                              "estimatedEndTime", "state", "canResume",
-                              "error", "bytesReceived", "totalBytes",
-                              "fileSize", "exists",
-                              "byExtensionId", "byExtensionName"];
-
-class DownloadItem {
-  constructor(id, download, extension) {
-    this.id = id;
-    this.download = download;
-    this.extension = extension;
-  }
-
-  get url() { return this.download.source.url; }
-  get referrer() { return this.download.source.referrer; }
-  get filename() { return this.download.target.path; }
-  get incognito() { return this.download.source.isPrivate; }
-  get danger() { return "safe"; } // TODO
-  get mime() { return this.download.contentType; }
-  get startTime() { return this.download.startTime; }
-  get endTime() { return null; } // TODO
-  get estimatedEndTime() { return null; } // TODO
-  get state() {
-    if (this.download.succeeded) {
-      return "complete";
-    }
-    if (this.download.stopped) {
-      return "interrupted";
-    }
-    return "in_progress";
-  }
-  get canResume() {
-    return this.download.stopped && this.download.hasPartialData;
-  }
-  get error() {
-    if (!this.download.stopped || this.download.succeeded) {
-      return null;
-    }
-    // TODO store this instead of calculating it
-
-    if (this.download.error) {
-      if (this.download.error.becauseSourceFailed) {
-        return "NETWORK_FAILED"; // TODO
-      }
-      if (this.download.error.becauseTargetFailed) {
-        return "FILE_FAILED"; // TODO
-      }
-      return "CRASH";
-    }
-    return "USER_CANCELED";
-  }
-  get bytesReceived() {
-    return this.download.currentBytes;
-  }
-  get totalBytes() {
-    return this.download.hasProgress ? this.download.totalBytes : -1;
-  }
-  get fileSize() {
-    // todo: this is supposed to be post-compression
-    return this.download.succeeded ? this.download.target.size : -1;
-  }
-  get exists() { return this.download.target.exists; }
-  get byExtensionId() { return this.extension.id; }
-  get byExtensionName() { return this.extension.name; }
-
-  /**
-   * Create a cloneable version of this object by pulling all the
-   * fields into simple properties (instead of getters).
-   *
-   * @returns {object} A DownloadItem with flat properties,
-   *                   suitable for cloning.
-   */
-  serialize() {
-    let obj = {};
-    for (let field of DOWNLOAD_ITEM_FIELDS) {
-      obj[field] = this[field];
-    }
-    if (obj.startTime) {
-      obj.startTime = obj.startTime.toISOString();
-    }
-    return obj;
-  }
-}
-
-
-// DownloadMap maps back and forth betwen the numeric identifiers used in
-// the downloads WebExtension API and a Download object from the Downloads jsm.
-// todo: make id and extension info persistent (bug 1247794)
-const DownloadMap = {
-  currentId: 0,
-  loadPromise: null,
-
-  // Maps numeric id -> DownloadItem
-  byId: new Map(),
-
-  // Maps Download object -> DownloadItem
-  byDownload: new WeakMap(),
-
-  lazyInit() {
-    return Downloads.getList(Downloads.ALL).then(list => {
-      return list.getAll().then(downloads => {
-        downloads.forEach(download => {
-          this.newFromDownload(download, null);
-        });
-        let self = this;
-        return list.addView({
-          onDownloadAdded(download) {
-            self.newFromDownload(download, null);
-          },
-
-          onDownloadRemoved(download) {
-            const item = self.byDownload.get(download);
-            if (item != null) {
-              self.byDownload.delete(download);
-              self.byId.delete(item.id);
-            }
-          },
-        });
-      });
-    });
-  },
-
-  getAll() {
-    if (this.loadPromise == null) {
-      this.loadPromise = this.lazyInit();
-    }
-    return this.loadPromise.then(() => this.byId.values());
-  },
-
-  fromId(id) {
-    const download = this.byId.get(id);
-    if (!download) {
-      throw new Error(`Invalid download id ${id}`);
-    }
-    return download;
-  },
-
-  newFromDownload(download, extension) {
-    if (this.byDownload.has(download)) {
-      return this.byDownload.get(download);
-    }
-
-    const id = ++this.currentId;
-    let item = new DownloadItem(id, download, extension);
-    this.byId.set(id, item);
-    this.byDownload.set(download, item);
-    return item;
-  },
-};
-
-// Create a callable function that filters a DownloadItem based on a
-// query object of the type passed to search() or erase().
-function downloadQuery(query) {
-  let queryTerms = [];
-  let queryNegativeTerms = [];
-  if (query.query != null) {
-    for (let term of query.query) {
-      if (term[0] == "-") {
-        queryNegativeTerms.push(term.slice(1).toLowerCase());
-      } else {
-        queryTerms.push(term.toLowerCase());
-      }
-    }
-  }
-
-  function normalizeTime(arg, before) {
-    if (arg == null) {
-      return before ? Number.MAX_VALUE : 0;
-    }
-    return parseInt(arg, 10);
-  }
-
-  const startedBefore = normalizeTime(query.startedBefore, true);
-  const startedAfter = normalizeTime(query.startedAfter, false);
-  // const endedBefore = normalizeTime(query.endedBefore, true);
-  // const endedAfter = normalizeTime(query.endedAfter, false);
-
-  const totalBytesGreater = query.totalBytesGreater || 0;
-  const totalBytesLess = (query.totalBytesLess != null)
-        ? query.totalBytesLess : Number.MAX_VALUE;
-
-  // Handle options for which we can have a regular expression and/or
-  // an explicit value to match.
-  function makeMatch(regex, value, field) {
-    if (value == null && regex == null) {
-      return input => true;
-    }
-
-    let re;
-    try {
-      re = new RegExp(regex || "", "i");
-    } catch (err) {
-      throw new Error(`Invalid ${field}Regex: ${err.message}`);
-    }
-    if (value == null) {
-      return input => re.test(input);
-    }
-
-    value = value.toLowerCase();
-    if (re.test(value)) {
-      return input => (value == input);
-    } else {
-      return input => false;
-    }
-  }
-
-  const matchFilename = makeMatch(query.filenameRegex, query.filename, "filename");
-  const matchUrl = makeMatch(query.urlRegex, query.url, "url");
-
-  return function(item) {
-    const url = item.url.toLowerCase();
-    const filename = item.filename.toLowerCase();
-
-    if (!queryTerms.every(term => url.includes(term) || filename.includes(term))) {
-      return false;
-    }
-
-    if (queryNegativeTerms.some(term => url.includes(term) || filename.includes(term))) {
-      return false;
-    }
-
-    if (!matchFilename(filename) || !matchUrl(url)) {
-      return false;
-    }
-
-    if (!item.startTime) {
-      if (query.startedBefore != null || query.startedAfter != null) {
-        return false;
-      }
-    } else if (item.startTime > startedBefore || item.startTime < startedAfter) {
-      return false;
-    }
-
-    // todo endedBefore, endedAfter
-
-    if (item.totalBytes == -1) {
-      if (query.totalBytesGreater != null || query.totalBytesLess != null) {
-        return false;
-      }
-    } else if (item.totalBytes <= totalBytesGreater || item.totalBytes >= totalBytesLess) {
-      return false;
-    }
-
-    // todo: include danger, paused, error
-    const SIMPLE_ITEMS = ["id", "mime", "startTime", "endTime", "state",
-                          "bytesReceived", "totalBytes", "fileSize", "exists"];
-    for (let field of SIMPLE_ITEMS) {
-      if (query[field] != null && item[field] != query[field]) {
-        return false;
-      }
-    }
-
-    return true;
-  };
-}
+let currentId = 0;
 
 extensions.registerSchemaAPI("downloads", "downloads", (extension, context) => {
   return {
     downloads: {
       download(options) {
         if (options.filename != null) {
           if (options.filename.length == 0) {
             return Promise.reject({message: "filename must not be empty"});
@@ -344,74 +89,22 @@ extensions.registerSchemaAPI("downloads"
             return Downloads.getList(Downloads.ALL);
           }).then(list => {
             list.add(download);
 
             // This is necessary to make pause/resume work.
             download.tryToKeepPartialData = true;
             download.start();
 
-            const item = DownloadMap.newFromDownload(download, extension);
-            return item.id;
+            // Without other chrome.downloads methods, we can't actually
+            // do anything with the id so just return a dummy value for now.
+            return currentId++;
           });
       },
 
-      search(query) {
-        let matchFn;
-        try {
-          matchFn = downloadQuery(query);
-        } catch (err) {
-          return Promise.reject({message: err.message});
-        }
-
-        let compareFn;
-        if (query.orderBy != null) {
-          const fields = query.orderBy.map(field => field[0] == "-"
-                                           ? {reverse: true, name: field.slice(1)}
-                                           : {reverse: false, name: field});
-
-          for (let field of fields) {
-            if (!DOWNLOAD_ITEM_FIELDS.includes(field.name)) {
-              return Promise.reject({message: `Invalid orderBy field ${field.name}`});
-            }
-          }
-
-          compareFn = (dl1, dl2) => {
-            for (let field of fields) {
-              const val1 = dl1[field.name];
-              const val2 = dl2[field.name];
-
-              if (val1 < val2) {
-                return field.reverse ? 1 : -1;
-              } else if (val1 > val2) {
-                return field.reverse ? -1 : 1;
-              }
-            }
-            return 0;
-          };
-        }
-
-        return DownloadMap.getAll().then(downloads => {
-          if (compareFn) {
-            downloads = Array.from(downloads);
-            downloads.sort(compareFn);
-          }
-          let results = [];
-          for (let download of downloads) {
-            if (query.limit && results.length >= query.limit) {
-              break;
-            }
-            if (matchFn(download)) {
-              results.push(download.serialize());
-            }
-          }
-          return results;
-        });
-      },
-
       // When we do open(), check for additional downloads.open permission.
       // i.e.:
       // open(downloadId) {
       //   if (!extension.hasPermission("downloads.open")) {
       //     throw new context.cloneScope.Error("Permission denied because 'downloads.open' permission is missing.");
       //   }
       //   ...
       // }
--- a/toolkit/components/extensions/schemas/downloads.json
+++ b/toolkit/components/extensions/schemas/downloads.json
@@ -290,52 +290,48 @@
               }
             ]
           }
         ]
       },
       {
         "name": "search",
         "type": "function",
-        "async": "callback",
+        "unsupported": true,
         "description": "Find <a href='#type-DownloadItem'>DownloadItems</a>. Set <code>query</code> to the empty object to get all <a href='#type-DownloadItem'>DownloadItems</a>. To get a specific <a href='#type-DownloadItem'>DownloadItem</a>, set only the <code>id</code> field.",
         "parameters": [
           {
             "name": "query",
             "type": "object",
             "properties": {
               "query": {
                 "description": "This array of search terms limits results to <a href='#type-DownloadItem'>DownloadItems</a> whose <code>filename</code> or <code>url</code> contain all of the search terms that do not begin with a dash '-' and none of the search terms that do begin with a dash.",
                 "optional": true,
                 "type": "array",
                 "items": { "type": "string" }
               },
               "startedBefore": {
                 "description": "Limits results to downloads that started before the given ms since the epoch.",
                 "optional": true,
-                "type": "string",
-                "pattern": "^[1-9]\\d*$"
+                "type": "string"
               },
               "startedAfter": {
                 "description": "Limits results to downloads that started after the given ms since the epoch.",
                 "optional": true,
-                "type": "string",
-                "pattern": "^[1-9]\\d*$"
+                "type": "string"
               },
               "endedBefore": {
                 "description": "Limits results to downloads that ended before the given ms since the epoch.",
                 "optional": true,
-                "type": "string",
-                "pattern": "^[1-9]\\d*$"
+                "type": "string"
               },
               "endedAfter": {
                 "description": "Limits results to downloads that ended after the given ms since the epoch.",
                 "optional": true,
-                "type": "string",
-                "pattern": "^[1-9]\\d*$"
+                "type": "string"
               },
               "totalBytesGreater": {
                 "description": "Limits results to downloads whose totalBytes is greater than the given integer.",
                 "optional": true,
                 "type": "number"
               },
               "totalBytesLess": {
                 "description": "Limits results to downloads whose totalBytes is less than the given integer.",
deleted file mode 100644
--- a/toolkit/components/extensions/test/mochitest/file_download.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE HTML>
-
-<html>
-<head>
-<meta charset="utf-8">
-</head>
-<body>
-
-<div>Download HTML File</div>
-
-</body>
-</html>
--- a/toolkit/components/extensions/test/mochitest/mochitest.ini
+++ b/toolkit/components/extensions/test/mochitest/mochitest.ini
@@ -17,29 +17,26 @@ support-files =
   file_script_bad.js
   file_script_redirect.js
   file_script_xhr.js
   file_sample.html
   redirection.sjs
   file_privilege_escalation.html
   file_ext_test_api_injection.js
   file_permission_xhr.html
-  file_download.html
-  file_download.txt
 
 [test_ext_simple.html]
 [test_ext_schema.html]
 skip-if = e10s # Uses a console montitor. Actual code does not depend on e10s.
 [test_ext_geturl.html]
 [test_ext_contentscript.html]
 skip-if = buildapp == 'b2g' # runat != document_idle is not supported.
 [test_ext_contentscript_create_iframe.html]
 [test_ext_contentscript_api_injection.html]
 [test_ext_downloads.html]
-[test_ext_downloads_search.html]
 [test_ext_i18n_css.html]
 [test_ext_generate.html]
 [test_ext_idle.html]
 [test_ext_localStorage.html]
 [test_ext_onmessage_removelistener.html]
 [test_ext_notifications.html]
 [test_ext_permission_xhr.html]
 skip-if = buildapp == 'b2g' # JavaScript error: jar:remoteopenfile:///data/local/tmp/generated-extension.xpi!/content.js, line 46: NS_ERROR_ILLEGAL_VALUE:
deleted file mode 100644
--- a/toolkit/components/extensions/test/mochitest/test_ext_downloads_search.html
+++ /dev/null
@@ -1,366 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>WebExtension test</title>
-  <script src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script src="/tests/SimpleTest/SpawnTask.js"></script>
-  <script src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
-  <script type="text/javascript" src="head.js"></script>
-  <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-
-<script type="text/javascript">
-"use strict";
-
-const {FileUtils} = SpecialPowers.Cu.import("resource://gre/modules/FileUtils.jsm", {});
-
-const BASE = "http://mochi.test:8888/tests/toolkit/components/extensions/test/mochitest";
-const TXT_FILE = "file_download.txt";
-const TXT_URL = BASE + "/" + TXT_FILE;
-const TXT_LEN = 46;
-const HTML_FILE = "file_download.html";
-const HTML_URL = BASE + "/" + HTML_FILE;
-const HTML_LEN = 117;
-const BIG_LEN = 1000;  // something bigger both TXT_LEN and HTML_LEN
-
-function backgroundScript() {
-  browser.test.onMessage.addListener(function(msg) {
-    // extension functions throw on bad arguments, we can remove the extra
-    // promise when bug 1250223 is fixed.
-    if (msg == "download.request") {
-      Promise.resolve().then(() => browser.downloads.download(arguments[1]))
-                       .then(id => {
-                         browser.test.sendMessage("download.done", {status: "success", id});
-                       })
-                       .catch(error => {
-                         browser.test.sendMessage("download.done", {status: "error", errmsg: error.message});
-                       });
-    } else if (msg == "search.request") {
-      Promise.resolve().then(() => browser.downloads.search(arguments[1]))
-                       .then(downloads => {
-                         browser.test.sendMessage("search.done", {status: "success", downloads});
-                       })
-                       .catch(error => {
-                         browser.test.sendMessage("search.done", {status: "error", errmsg: error.message});
-                       });
-    }
-  });
-
-  browser.test.sendMessage("ready");
-}
-
-add_task(function* test_search() {
-  const nsIFile = SpecialPowers.Ci.nsIFile;
-  let downloadDir = FileUtils.getDir("TmpD", ["downloads"]);
-  downloadDir.createUnique(nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
-  info(`downloadDir ${downloadDir.path}`);
-
-  function downloadPath(filename) {
-    let path = downloadDir.clone();
-    path.append(filename);
-    return path.path;
-  }
-
-  SpecialPowers.setIntPref("browser.download.folderList", 2);
-  SpecialPowers.Services.prefs.setComplexValue("browser.download.dir", nsIFile, downloadDir);
-  SimpleTest.registerCleanupFunction(() => {
-    SpecialPowers.clearUserPref("browser.download.folderList");
-    SpecialPowers.clearUserPref("browser.download.dir");
-    downloadDir.remove(true);
-  });
-
-  let extension = ExtensionTestUtils.loadExtension({
-    background: `(${backgroundScript})()`,
-    manifest: {
-      permissions: ["downloads"],
-    },
-  });
-
-  function download(options) {
-    extension.sendMessage("download.request", options);
-    return extension.awaitMessage("download.done");
-  }
-
-  function search(query) {
-    extension.sendMessage("search.request", query);
-    return extension.awaitMessage("search.done");
-  }
-
-  yield extension.startup();
-  yield extension.awaitMessage("ready");
-  info("extension started");
-
-  // Do some downloads...
-  const time1 = new Date();
-
-  let downloadIds = {};
-  let msg = yield download({url: TXT_URL});
-  is(msg.status, "success", "download() succeeded");
-  downloadIds.txt1 = msg.id;
-
-  const TXT_FILE2 = "NewFile.txt";
-  msg = yield download({url: TXT_URL, filename: TXT_FILE2});
-  is(msg.status, "success", "download() succeeded");
-  downloadIds.txt2 = msg.id;
-
-  const time2 = new Date();
-
-  msg = yield download({url: HTML_URL});
-  is(msg.status, "success", "download() succeeded");
-  downloadIds.html1 = msg.id;
-
-  const HTML_FILE2 = "renamed.html";
-  msg = yield download({url: HTML_URL, filename: HTML_FILE2});
-  is(msg.status, "success", "download() succeeded");
-  downloadIds.html2 = msg.id;
-
-  const time3 = new Date();
-
-  // Yuck, until we have onChanged, poll for downloads to finish.
-  // Since there are just 4 small downloads, this shouldn't be a big deal.
-  for (let attempt = 0; attempt < 5; attempt++) {
-    let msg = yield search({});
-    if (msg.status == "success" && msg.downloads.length == 4
-        && msg.downloads.every(download => download.state == "complete")) {
-      info("4 downloads complete, proceeding");
-      break;
-    }
-    info("downloads aren't finished, checking again");
-  }
-
-  // Search for each individual download and check
-  // the corresponding DownloadItem.
-  function* checkDownloadItem(id, expect) {
-    let msg = yield search({id});
-    is(msg.status, "success", "search() succeeded");
-    is(msg.downloads.length, 1, "search() found exactly 1 download");
-
-    Object.keys(expect).forEach(function(field) {
-      is(msg.downloads[0][field], expect[field], `DownloadItem.${field} is correct"`);
-    });
-  }
-  yield checkDownloadItem(downloadIds.txt1, {
-    url: TXT_URL,
-    filename: downloadPath(TXT_FILE),
-    mime: "text/plain",
-    state: "complete",
-    bytesReceived: TXT_LEN,
-    totalBytes: TXT_LEN,
-    fileSize: TXT_LEN,
-    exists: true,
-  });
-
-  yield checkDownloadItem(downloadIds.txt2, {
-    url: TXT_URL,
-    filename: downloadPath(TXT_FILE2),
-    mime: "text/plain",
-    state: "complete",
-    bytesReceived: TXT_LEN,
-    totalBytes: TXT_LEN,
-    fileSize: TXT_LEN,
-    exists: true,
-  });
-
-  yield checkDownloadItem(downloadIds.html1, {
-    url: HTML_URL,
-    filename: downloadPath(HTML_FILE),
-    mime: "text/html",
-    state: "complete",
-    bytesReceived: HTML_LEN,
-    totalBytes: HTML_LEN,
-    fileSize: HTML_LEN,
-    exists: true,
-  });
-
-  yield checkDownloadItem(downloadIds.html2, {
-    url: HTML_URL,
-    filename: downloadPath(HTML_FILE2),
-    mime: "text/html",
-    state: "complete",
-    bytesReceived: HTML_LEN,
-    totalBytes: HTML_LEN,
-    fileSize: HTML_LEN,
-    exists: true,
-  });
-
-  function* checkSearch(query, expected, description, exact) {
-    let msg = yield search(query);
-    is(msg.status, "success", "search() succeeded");
-    is(msg.downloads.length, expected.length, `search() for ${description} found exactly ${expected.length} downloads`);
-
-    let receivedIds = msg.downloads.map(item => item.id);
-    if (exact) {
-      receivedIds.forEach((id, idx) => {
-        is(id, downloadIds[expected[idx]], `search() for ${description} returned ${expected[idx]} in position ${idx}`);
-      });
-    } else {
-      Object.keys(downloadIds).forEach(key => {
-        const id = downloadIds[key];
-        const thisExpected = expected.includes(key);
-        is(receivedIds.includes(id), thisExpected,
-           `search() for ${description} ${thisExpected ? "includes" : "does not include"} ${key}`);
-      });
-    }
-  }
-
-  // Check that search with an invalid id returns nothing.
-  // NB: for now ids are not persistent and we start numbering them at 1
-  //     so a sufficiently large number will be unused.
-  const INVALID_ID = 1000;
-  yield checkSearch({id: INVALID_ID}, [], "invalid id");
-
-  // Check that search on url works.
-  yield checkSearch({url: TXT_URL}, ["txt1", "txt2"], "url");
-
-  // Check that regexp on url works.
-  const HTML_REGEX = "[downlad]{8}\.html+$";
-  yield checkSearch({urlRegex: HTML_REGEX}, ["html1", "html2"], "url regexp");
-
-  // Check that compatible url+regexp works
-  yield checkSearch({url: HTML_URL, urlRegex: HTML_REGEX}, ["html1", "html2"], "compatible url+urlRegex");
-
-  // Check that incompatible url+regexp works
-  yield checkSearch({url: TXT_URL, urlRegex: HTML_REGEX}, [], "incompatible url+urlRegex");
-
-  // Check that search on filename works.
-  yield checkSearch({filename: downloadPath(TXT_FILE)}, ["txt1"], "filename");
-
-  // Check that regexp on filename works.
-  yield checkSearch({filenameRegex: HTML_REGEX}, ["html1"], "filename regex");
-
-  // Check that compatible filename+regexp works
-  yield checkSearch({filename: downloadPath(HTML_FILE), filenameRegex: HTML_REGEX}, ["html1"], "compatible filename+filename regex");
-
-  // Check that incompatible filename+regexp works
-  yield checkSearch({filename: downloadPath(TXT_FILE), filenameRegex: HTML_REGEX}, [], "incompatible filename+filename regex");
-
-  // Check that simple positive search terms work.
-  yield checkSearch({query: ["file_download"]}, ["txt1", "txt2", "html1", "html2"],
-                    "term file_download");
-  yield checkSearch({query: ["NewFile"]}, ["txt2"], "term NewFile");
-
-  // Check that positive search terms work case-insensitive.
-  yield checkSearch({query: ["nEwfILe"]}, ["txt2"], "term nEwfiLe");
-
-  // Check that negative search terms work.
-  yield checkSearch({query: ["-txt"]}, ["html1", "html2"], "term -txt");
-
-  // Check that positive and negative search terms together work.
-  yield checkSearch({query: ["html", "-renamed"]}, ["html1"], "postive and negative terms");
-
-  // Check that startedBefore works with stringified milliseconds.
-  yield checkSearch({startedBefore: time1.valueOf().toString()}, [], "before time1");
-  yield checkSearch({startedBefore: time2.valueOf().toString()}, ["txt1", "txt2"], "before time2");
-  yield checkSearch({startedBefore: time3.valueOf().toString()}, ["txt1", "txt2", "html1", "html2"], "before time3");
-
-  // Check that startedBefore works with iso string.
-  // enable with fix for bug 1251766
-  // yield checkSearch({startedBefore: time1.toISOString()}, [], "before time1");
-  // yield checkSearch({startedBefore: time2.toISOString()}, ["txt1", "txt2"], "before time2");
-  // yield checkSearch({startedBefore: time3.toISOString()}, ["txt1", "txt2", "html1", "html2"], "before time3");
-
-  // Check that startedAfter works with stringified milliseconds.
-  yield checkSearch({startedAfter: time1.valueOf().toString()}, ["txt1", "txt2", "html1", "html2"], "after time1");
-  yield checkSearch({startedAfter: time2.valueOf().toString()}, ["html1", "html2"], "after time2");
-  yield checkSearch({startedAfter: time3.valueOf().toString()}, [], "after time3");
-
-  // Check that startedAfter works with iso string.
-  // enable with fix for bug 1251766
-  // yield checkSearch({startedAfter: time1.toISOString()}, ["txt1", "txt2", "html1", "html2"], "after time1");
-  // yield checkSearch({startedAfter: time2.toISOString()}, ["html1", "html2"], "after time2");
-  // yield checkSearch({startedAfter: time3.toISOString()}, [], "after time3");
-
-  // Check simple search on totalBytes
-  yield checkSearch({totalBytes: TXT_LEN}, ["txt1", "txt2"], "totalBytes");
-  yield checkSearch({totalBytes: HTML_LEN}, ["html1", "html2"], "totalBytes");
-
-  // Check simple test on totalBytes{Greater,Less}
-  // (NB: TXT_LEN < HTML_LEN < BIG_LEN)
-  yield checkSearch({totalBytesGreater: 0}, ["txt1", "txt2", "html1", "html2"], "totalBytesGreater than 0");
-  yield checkSearch({totalBytesGreater: TXT_LEN}, ["html1", "html2"], `totalBytesGreater than ${TXT_LEN}`);
-  yield checkSearch({totalBytesGreater: HTML_LEN}, [], `totalBytesGreater than ${HTML_LEN}`);
-  yield checkSearch({totalBytesLess: TXT_LEN}, [], `totalBytesLess than ${TXT_LEN}`);
-  yield checkSearch({totalBytesLess: HTML_LEN}, ["txt1", "txt2"], `totalBytesLess than ${HTML_LEN}`);
-  yield checkSearch({totalBytesLess: BIG_LEN}, ["txt1", "txt2", "html1", "html2"], `totalBytesLess than ${BIG_LEN}`);
-
-  // Check good combinations of totalBytes*.
-  yield checkSearch({totalBytes: HTML_LEN, totalBytesGreater: TXT_LEN}, ["html1", "html2"], "totalBytes and totalBytesGreater");
-  yield checkSearch({totalBytes: TXT_LEN, totalBytesLess: HTML_LEN}, ["txt1", "txt2"], "totalBytes and totalBytesGreater");
-  yield checkSearch({totalBytes: HTML_LEN, totalBytesLess: BIG_LEN, totalBytesGreater: 0}, ["html1", "html2"], "totalBytes and totalBytesLess and totalBytesGreater");
-
-  // Check bad combination of totalBytes*.
-  yield checkSearch({totalBytesLess: TXT_LEN, totalBytesGreater: HTML_LEN}, [], "bad totalBytesLess, totalBytesGreater combination");
-  yield checkSearch({totalBytes: TXT_LEN, totalBytesGreater: HTML_LEN}, [], "bad totalBytes, totalBytesGreater combination");
-  yield checkSearch({totalBytes: HTML_LEN, totalBytesLess: TXT_LEN}, [], "bad totalBytes, totalBytesLess combination");
-
-  // Check mime.
-  yield checkSearch({mime: "text/plain"}, ["txt1", "txt2"], "mime text/plain");
-  yield checkSearch({mime: "text/html"}, ["html1", "html2"], "mime text/htmlplain");
-  yield checkSearch({mime: "video/webm"}, [], "mime video/webm");
-
-  // Check fileSize.
-  yield checkSearch({fileSize: TXT_LEN}, ["txt1", "txt2"], "fileSize");
-  yield checkSearch({fileSize: HTML_LEN}, ["html1", "html2"], "fileSize");
-
-  // Fields like bytesReceived, paused, state, exists are meaningful
-  // for downloads that are in progress but have not yet completed.
-  // todo: add tests for these when we have better support for in-progress
-  // downloads (e.g., after pause(), resume() and cancel() are implemented)
-
-  // Check multiple query properties.
-  // We could make this testing arbitrarily complicated...
-  // We already tested combining fields with obvious interactions above
-  // (e.g., filename and filenameRegex or startTime and startedBefore/After)
-  // so now just throw as many fields as we can at a single search and
-  // make sure a simple case still works.
-  yield checkSearch({
-    url: TXT_URL,
-    urlRegex: "download",
-    filename: downloadPath(TXT_FILE),
-    filenameRegex: "download",
-    query: ["download"],
-    startedAfter: time1.valueOf().toString(),
-    startedBefore: time2.valueOf().toString(),
-    totalBytes: TXT_LEN,
-    totalBytesGreater: 0,
-    totalBytesLess: BIG_LEN,
-    mime: "text/plain",
-    fileSize: TXT_LEN,
-  }, ["txt1"], "many properties");
-
-  // Check simple orderBy (forward and backward).
-  yield checkSearch({orderBy: ["startTime"]}, ["txt1", "txt2", "html1", "html2"], "orderBy startTime", true);
-  yield checkSearch({orderBy: ["-startTime"]}, ["html2", "html1", "txt2", "txt1"], "orderBy -startTime", true);
-
-  // Check orderBy with multiple fields.
-  // NB: TXT_URL and HTML_URL differ only in extension and .html precedes .txt
-  yield checkSearch({orderBy: ["url", "-startTime"]}, ["html2", "html1", "txt2", "txt1"], "orderBy with multiple fields", true);
-
-  // Check orderBy with limit.
-  yield checkSearch({orderBy: ["url"], limit: 1}, ["html1"], "orderBy with limit", true);
-
-  // Check bad arguments.
-  function* checkBadSearch(query, pattern, description) {
-    let msg = yield search(query);
-    is(msg.status, "error", "search() failed");
-    ok(pattern.test(msg.errmsg), `error message for ${description} was correct (${msg.errmsg}).`);
-  }
-
-  yield checkBadSearch("myquery", /Incorrect argument type/, "query is not an object");
-  yield checkBadSearch({bogus: "boo"}, /Unexpected property/, "query contains an unknown field");
-  yield checkBadSearch({query: "query string"}, /Expected array/, "query.query is a string");
-  yield checkBadSearch({startedBefore: "i am not a number"}, /Type error/, "query.startedBefore is not a valid time");
-  yield checkBadSearch({startedAfter: "i am not a number"}, /Type error/, "query.startedAfter is not a valid time");
-  yield checkBadSearch({endedBefore: "i am not a number"}, /Type error/, "query.endedBefore is not a valid time");
-  yield checkBadSearch({endedAfter: "i am not a number"}, /Type error/, "query.endedAfter is not a valid time");
-  yield checkBadSearch({urlRegex: "["}, /Invalid urlRegex/, "query.urlRegexp is not a valid regular expression");
-  yield checkBadSearch({filenameRegex: "["}, /Invalid filenameRegex/, "query.filenameRegexp is not a valid regular expression");
-  yield checkBadSearch({orderBy: "startTime"}, /Expected array/, "query.orderBy is not an array");
-  yield checkBadSearch({orderBy: ["bogus"]}, /Invalid orderBy field/, "query.orderBy references a non-existent field");
-});
-
-</script>
-
-</body>
-</html>