Backed out 2 changesets (bug 1411979) for failing xpcshell's toolkit/components/jsdownloads/test/unit/test_PrivateTemp.js. r=backout on a CLOSED TREE
authorSebastian Hengst <archaeopteryx@coole-files.de>
Mon, 30 Oct 2017 19:19:45 +0100
changeset 439915 bdb364ba3e05ea651d932b0f4c38ab5a7804dee7
parent 439914 ef4f0721733f7c1e7613c99fae6b3c9899c6d81d
child 439916 e29ef925886304fb2008b6cedce84d76499aa93d
push id8114
push userjlorenzo@mozilla.com
push dateThu, 02 Nov 2017 16:33:21 +0000
treeherdermozilla-beta@73e0d89a540f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1411979
milestone58.0a1
backs out7a4f33d16b9e40788ecdad7cb35582c2abf3ee5c
68e85782bbcab3c06e729551643bdc602cf8de71
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 2 changesets (bug 1411979) for failing xpcshell's toolkit/components/jsdownloads/test/unit/test_PrivateTemp.js. r=backout on a CLOSED TREE Backed out changeset 7a4f33d16b9e (bug 1411979) *** Backed out changeset 68e85782bbca (bug 1411979)
browser/extensions/formautofill/test/unit/head.js
netwerk/test/unit/test_backgroundfilesaver.js
netwerk/test/unit/test_signature_extraction.js
testing/modules/FileTestUtils.jsm
testing/modules/TestUtils.jsm
testing/modules/moz.build
toolkit/components/jsdownloads/test/browser/head.js
toolkit/components/jsdownloads/test/unit/head.js
toolkit/components/jsdownloads/test/unit/test_DownloadPaths.js
toolkit/components/passwordmgr/test/unit/head.js
toolkit/components/reputationservice/test/unit/test_app_rep_windows.js
toolkit/modules/tests/xpcshell/test_JSONFile.js
uriloader/exthandler/tests/mochitest/browser_download_privatebrowsing.js
--- a/browser/extensions/formautofill/test/unit/head.js
+++ b/browser/extensions/formautofill/test/unit/head.js
@@ -10,17 +10,16 @@
 
 var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource://gre/modules/ObjectUtils.jsm");
 Cu.import("resource://gre/modules/FormLikeFactory.jsm");
-Cu.import("resource://testing-common/FileTestUtils.jsm");
 Cu.import("resource://testing-common/MockDocument.jsm");
 Cu.import("resource://testing-common/TestUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "DownloadPaths",
                                   "resource://gre/modules/DownloadPaths.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 
@@ -47,20 +46,53 @@ let bootstrapURI = Services.io.newFileUR
 if (!extensionDir.exists()) {
   extensionDir = extensionDir.parent;
   extensionDir.append(EXTENSION_ID + ".xpi");
   let jarURI = Services.io.newFileURI(extensionDir);
   bootstrapURI = "jar:" + jarURI.spec + "!/bootstrap.js";
 }
 Components.manager.addBootstrappedManifestLocation(extensionDir);
 
-// Returns a reference to a temporary file that is guaranteed not to exist and
-// is cleaned up later. See FileTestUtils.getTempFile for details.
+// While the previous test file should have deleted all the temporary files it
+// used, on Windows these might still be pending deletion on the physical file
+// system.  Thus, start from a new base number every time, to make a collision
+// with a file that is still pending deletion highly unlikely.
+let gFileCounter = Math.floor(Math.random() * 1000000);
+
+/**
+ * Returns a reference to a temporary file, that is guaranteed not to exist, and
+ * to have never been created before.
+ *
+ * @param {string} leafName
+ *        Suggested leaf name for the file to be created.
+ *
+ * @returns {nsIFile} pointing to a non-existent file in a temporary directory.
+ *
+ * @note It is not enough to delete the file if it exists, or to delete the file
+ *       after calling nsIFile.createUnique, because on Windows the delete
+ *       operation in the file system may still be pending, preventing a new
+ *       file with the same name to be created.
+ */
 function getTempFile(leafName) {
-  return FileTestUtils.getTempFile(leafName);
+  // Prepend a serial number to the extension in the suggested leaf name.
+  let [base, ext] = DownloadPaths.splitBaseNameAndExtension(leafName);
+  let finalLeafName = base + "-" + gFileCounter + ext;
+  gFileCounter++;
+
+  // Get a file reference under the temporary directory for this test file.
+  let file = FileUtils.getFile("TmpD", [finalLeafName]);
+  do_check_false(file.exists());
+
+  do_register_cleanup(function() {
+    if (file.exists()) {
+      file.remove(false);
+    }
+  });
+
+  return file;
 }
 
 async function initProfileStorage(fileName, records, collectionName = "addresses") {
   let {ProfileStorage} = Cu.import("resource://formautofill/ProfileStorage.jsm", {});
   let path = getTempFile(fileName).path;
   let profileStorage = new ProfileStorage(path);
   await profileStorage.initialize();
 
--- a/netwerk/test/unit/test_backgroundfilesaver.js
+++ b/netwerk/test/unit/test_backgroundfilesaver.js
@@ -13,18 +13,16 @@
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
                                   "resource://gre/modules/Services.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "FileTestUtils",
-                                  "resource://testing-common/FileTestUtils.jsm");
 
 const BackgroundFileSaverOutputStream = Components.Constructor(
       "@mozilla.org/network/background-file-saver;1?mode=outputstream",
       "nsIBackgroundFileSaver");
 
 const BackgroundFileSaverStreamListener = Components.Constructor(
       "@mozilla.org/network/background-file-saver;1?mode=streamlistener",
       "nsIBackgroundFileSaver");
@@ -58,21 +56,27 @@ const gTextDecoder = new TextDecoder();
 
 // Generate a long string of data in a moderately fast way.
 const TEST_256_CHARS = new Array(257).join("-");
 const DESIRED_LENGTH = REQUEST_SUSPEND_AT * 2;
 const TEST_DATA_LONG = new Array(1 + DESIRED_LENGTH / 256).join(TEST_256_CHARS);
 do_check_eq(TEST_DATA_LONG.length, DESIRED_LENGTH);
 
 /**
- * Returns a reference to a temporary file that is guaranteed not to exist and
- * is cleaned up later. See FileTestUtils.getTempFile for details.
+ * Returns a reference to a temporary file.  If the file is then created, it
+ * will be removed when tests in this file finish.
  */
-function getTempFile(leafName) {
-  return FileTestUtils.getTempFile(leafName);
+function getTempFile(aLeafName) {
+  let file = FileUtils.getFile("TmpD", [aLeafName]);
+  do_register_cleanup(function GTF_cleanup() {
+    if (file.exists()) {
+      file.remove(false);
+    }
+  });
+  return file;
 }
 
 /**
  * Helper function for converting a binary blob to its hex equivalent.
  *
  * @param str
  *        String possibly containing non-printable chars.
  * @return A hex-encoded string.
--- a/netwerk/test/unit/test_signature_extraction.js
+++ b/netwerk/test/unit/test_signature_extraction.js
@@ -12,36 +12,40 @@
 //// Globals
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "FileTestUtils",
-                                  "resource://testing-common/FileTestUtils.jsm");
 
 const BackgroundFileSaverOutputStream = Components.Constructor(
       "@mozilla.org/network/background-file-saver;1?mode=outputstream",
       "nsIBackgroundFileSaver");
 
 const StringInputStream = Components.Constructor(
       "@mozilla.org/io/string-input-stream;1",
       "nsIStringInputStream",
       "setData");
 
 const TEST_FILE_NAME_1 = "test-backgroundfilesaver-1.txt";
 
 /**
- * Returns a reference to a temporary file that is guaranteed not to exist and
- * is cleaned up later. See FileTestUtils.getTempFile for details.
+ * Returns a reference to a temporary file.  If the file is then created, it
+ * will be removed when tests in this file finish.
  */
-function getTempFile(leafName) {
-  return FileTestUtils.getTempFile(leafName);
+function getTempFile(aLeafName) {
+  let file = FileUtils.getFile("TmpD", [aLeafName]);
+  do_register_cleanup(function GTF_cleanup() {
+    if (file.exists()) {
+      file.remove(false);
+    }
+  });
+  return file;
 }
 
 /**
  * Waits for the given saver object to complete.
  *
  * @param aSaver
  *        The saver, with the output stream or a stream listener implementation.
  * @param aOnTargetChangeFn
deleted file mode 100644
--- a/testing/modules/FileTestUtils.jsm
+++ /dev/null
@@ -1,74 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * Provides testing functions dealing with local files and their contents.
- */
-
-"use strict";
-
-this.EXPORTED_SYMBOLS = [
-  "FileTestUtils",
-];
-
-const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
-
-Cu.import("resource://gre/modules/AsyncShutdown.jsm", this);
-Cu.import("resource://gre/modules/DownloadPaths.jsm", this);
-Cu.import("resource://gre/modules/FileUtils.jsm", this);
-Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
-Cu.import("resource://testing-common/Assert.jsm", this);
-
-let gFileCounter = 1;
-
-this.FileTestUtils = {
-  /**
-   * Returns a reference to a temporary file that is guaranteed not to exist and
-   * to have never been created before. If a file or a directory with this name
-   * is created by the test, it will be deleted when all tests terminate.
-   *
-   * @param suggestedName [optional]
-   *        Any extension on this template file name will be preserved. If this
-   *        is unspecified, the returned file name will have the generic ".dat"
-   *        extension, which may indicate either a binary or a text data file.
-   *
-   * @return nsIFile pointing to a non-existent file in a temporary directory.
-   *
-   * @note It is not enough to delete the file if it exists, or to delete the
-   *       file after calling nsIFile.createUnique, because on Windows the
-   *       delete operation in the file system may still be pending, preventing
-   *       a new file with the same name to be created.
-   */
-  getTempFile(suggestedName = "test.dat") {
-    // Prepend a serial number to the extension in the suggested leaf name.
-    let [base, ext] = DownloadPaths.splitBaseNameAndExtension(suggestedName);
-    let leafName = base + "-" + gFileCounter + ext;
-    gFileCounter++;
-
-    // Get a file reference under the temporary directory for this test file.
-    let file = this._globalTemporaryDirectory.clone();
-    file.append(leafName);
-    Assert.ok(!file.exists(), "Sanity check the temporary file doesn't exist.");
-    return file;
-  },
-};
-
-/**
- * Returns a reference to a global temporary directory that will be deleted
- * when all tests terminate.
- */
-XPCOMUtils.defineLazyGetter(FileTestUtils, "_globalTemporaryDirectory", () => {
-  // While previous test runs should have deleted their temporary directories,
-  // on Windows they might still be pending deletion on the physical file
-  // system. This makes a simple nsIFile.createUnique call unreliable, and we
-  // have to use a random number to make a collision unlikely.
-  let randomNumber = Math.floor(Math.random() * 1000000);
-  let dir = FileUtils.getFile("TmpD", ["testdir-" + randomNumber]);
-  dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
-  AsyncShutdown.profileBeforeChange.addBlocker("Removing test files", () => {
-    // Note that this may fail if any test leaves inaccessible files behind.
-    dir.remove(true);
-  });
-  return dir;
-});
--- a/testing/modules/TestUtils.jsm
+++ b/testing/modules/TestUtils.jsm
@@ -1,24 +1,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-/**
- * Contains a limited number of testing functions that are commonly used in a
- * wide variety of situations, for example waiting for an event loop tick or an
- * observer notification.
+/*
+ * This module implements a number of utilities useful for testing.
  *
- * More complex functions are likely to belong to a separate test-only module.
- * Examples include Assert.jsm for generic assertions, FileTestUtils.jsm to work
- * with local files and their contents, and BrowserTestUtils.jsm to work with
- * browser windows and tabs.
- *
- * Individual components also offer testing functions to other components, for
- * example LoginTestUtils.jsm.
+ * Additions to this module should be generic and useful to testing multiple
+ * features. Utilities only useful to a sepcific testing framework should live
+ * in a module specific to that framework, such as BrowserTestUtils.jsm in the
+ * case of mochitest-browser-chrome.
  */
 
 "use strict";
 
 this.EXPORTED_SYMBOLS = [
   "TestUtils",
 ];
 
--- a/testing/modules/moz.build
+++ b/testing/modules/moz.build
@@ -8,17 +8,16 @@ XPCSHELL_TESTS_MANIFESTS += ['tests/xpcs
 BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']
 
 TESTING_JS_MODULES += [
     'ajv-4.1.1.js',
     'AppData.jsm',
     'AppInfo.jsm',
     'Assert.jsm',
     'CoverageUtils.jsm',
-    'FileTestUtils.jsm',
     'MockRegistrar.jsm',
     'sinon-2.3.2.js',
     'StructuredLog.jsm',
     'TestUtils.jsm',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     TESTING_JS_MODULES += [
--- a/toolkit/components/jsdownloads/test/browser/head.js
+++ b/toolkit/components/jsdownloads/test/browser/head.js
@@ -25,29 +25,58 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
                                   "resource://gre/modules/Services.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "HttpServer",
                                   "resource://testing-common/httpd.js");
 XPCOMUtils.defineLazyModuleGetter(this, "OS",
                                   "resource://gre/modules/osfile.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "FileTestUtils",
-                                  "resource://testing-common/FileTestUtils.jsm");
 
 const TEST_TARGET_FILE_NAME_PDF = "test-download.pdf";
 
 // Support functions
 
+// While the previous test file should have deleted all the temporary files it
+// used, on Windows these might still be pending deletion on the physical file
+// system.  Thus, start from a new base number every time, to make a collision
+// with a file that is still pending deletion highly unlikely.
+var gFileCounter = Math.floor(Math.random() * 1000000);
+
 /**
- * Returns a reference to a temporary file that is guaranteed not to exist and
- * is cleaned up later. See FileTestUtils.getTempFile for details.
+ * Returns a reference to a temporary file, that is guaranteed not to exist, and
+ * to have never been created before.
+ *
+ * @param aLeafName
+ *        Suggested leaf name for the file to be created.
+ *
+ * @return nsIFile pointing to a non-existent file in a temporary directory.
+ *
+ * @note It is not enough to delete the file if it exists, or to delete the file
+ *       after calling nsIFile.createUnique, because on Windows the delete
+ *       operation in the file system may still be pending, preventing a new
+ *       file with the same name to be created.
  */
-function getTempFile(leafName) {
-  return FileTestUtils.getTempFile(leafName);
+function getTempFile(aLeafName) {
+  // Prepend a serial number to the extension in the suggested leaf name.
+  let [base, ext] = DownloadPaths.splitBaseNameAndExtension(aLeafName);
+  let leafName = base + "-" + gFileCounter + ext;
+  gFileCounter++;
+
+  // Get a file reference under the temporary directory for this test file.
+  let file = FileUtils.getFile("TmpD", [leafName]);
+  ok(!file.exists(), "Temp file does not exist");
+
+  registerCleanupFunction(function() {
+    if (file.exists()) {
+      file.remove(false);
+    }
+  });
+
+  return file;
 }
 
 function promiseBrowserLoaded(browser) {
   return new Promise(resolve => {
     browser.addEventListener("load", function onLoad(event) {
       if (event.target == browser.contentDocument) {
         browser.removeEventListener("load", onLoad, true);
         resolve();
--- a/toolkit/components/jsdownloads/test/unit/head.js
+++ b/toolkit/components/jsdownloads/test/unit/head.js
@@ -32,18 +32,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
                                   "resource://gre/modules/PlacesUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
                                   "resource://gre/modules/Promise.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
                                   "resource://gre/modules/Services.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "OS",
                                   "resource://gre/modules/osfile.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "FileTestUtils",
-                                  "resource://testing-common/FileTestUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "MockRegistrar",
                                   "resource://testing-common/MockRegistrar.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gExternalHelperAppService",
            "@mozilla.org/uriloader/external-helper-app-service;1",
            Ci.nsIExternalHelperAppService);
 
 /* global DownloadIntegration */
@@ -98,22 +96,64 @@ var gHttpServer;
  * Given a file name, returns a string containing an URI that points to the file
  * on the currently running instance of the test HTTP server.
  */
 function httpUrl(aFileName) {
   return "http://localhost:" + gHttpServer.identity.primaryPort + "/" +
          aFileName;
 }
 
+// While the previous test file should have deleted all the temporary files it
+// used, on Windows these might still be pending deletion on the physical file
+// system.  Thus, start from a new base number every time, to make a collision
+// with a file that is still pending deletion highly unlikely.
+var gFileCounter = Math.floor(Math.random() * 1000000);
+
 /**
- * Returns a reference to a temporary file that is guaranteed not to exist and
- * is cleaned up later. See FileTestUtils.getTempFile for details.
+ * Returns a reference to a temporary file, that is guaranteed not to exist, and
+ * to have never been created before.
+ *
+ * @param aLeafName
+ *        Suggested leaf name for the file to be created.
+ *
+ * @return nsIFile pointing to a non-existent file in a temporary directory.
+ *
+ * @note It is not enough to delete the file if it exists, or to delete the file
+ *       after calling nsIFile.createUnique, because on Windows the delete
+ *       operation in the file system may still be pending, preventing a new
+ *       file with the same name to be created.
  */
-function getTempFile(leafName) {
-  return FileTestUtils.getTempFile(leafName);
+function getTempFile(aLeafName) {
+  // Prepend a serial number to the extension in the suggested leaf name.
+  let [base, ext] = DownloadPaths.splitBaseNameAndExtension(aLeafName);
+  let leafName = base + "-" + gFileCounter + ext;
+  gFileCounter++;
+
+  // Get a file reference under the temporary directory for this test file.
+  let file = FileUtils.getFile("TmpD", [leafName]);
+  do_check_false(file.exists());
+
+  do_register_cleanup(function() {
+    try {
+      file.remove(false);
+    } catch (e) {
+      if (!(e instanceof Components.Exception &&
+            (e.result == Cr.NS_ERROR_FILE_ACCESS_DENIED ||
+             e.result == Cr.NS_ERROR_FILE_TARGET_DOES_NOT_EXIST ||
+             e.result == Cr.NS_ERROR_FILE_NOT_FOUND))) {
+        throw e;
+      }
+      // On Windows, we may get an access denied error if the file existed before,
+      // and was recently deleted.
+      // Don't bother checking file.exists() as that may also cause an access
+      // denied error.
+    }
+  });
+
+  return file;
 }
 
 /**
  * Waits for pending events to be processed.
  *
  * @return {Promise}
  * @resolves When pending events have been processed.
  * @rejects Never.
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadPaths.js
+++ b/toolkit/components/jsdownloads/test/unit/test_DownloadPaths.js
@@ -2,16 +2,31 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests for the "DownloadPaths.jsm" JavaScript module.
  */
 
 Cu.import("resource://gre/modules/AppConstants.jsm");
 
+/**
+ * Provides a temporary save directory.
+ *
+ * @returns nsIFile pointing to the new or existing directory.
+ */
+function createTemporarySaveDirectory() {
+  var saveDir = Cc["@mozilla.org/file/directory_service;1"].
+                getService(Ci.nsIProperties).get("TmpD", Ci.nsIFile);
+  saveDir.append("testsavedir");
+  if (!saveDir.exists()) {
+    saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
+  }
+  return saveDir;
+}
+
 function testSanitize(leafName, expectedLeafName) {
   do_check_eq(DownloadPaths.sanitize(leafName), expectedLeafName);
 }
 
 function testSplitBaseNameAndExtension(aLeafName, [aBase, aExt]) {
   var [base, ext] = DownloadPaths.splitBaseNameAndExtension(aLeafName);
   do_check_eq(base, aBase);
   do_check_eq(ext, aExt);
@@ -111,41 +126,44 @@ add_task(async function test_splitBaseNa
   testSplitBaseNameAndExtension(" . ", [" ", ". "]);
   testSplitBaseNameAndExtension(" .. ", [" .", ". "]);
   testSplitBaseNameAndExtension(" .ext", [" ", ".ext"]);
   testSplitBaseNameAndExtension(" .ext. ", [" .ext", ". "]);
   testSplitBaseNameAndExtension(" .ext.gz ", [" .ext", ".gz "]);
 });
 
 add_task(async function test_createNiceUniqueFile() {
-  var destDir = FileTestUtils.getTempFile("destdir");
-  destDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
+  var destDir = createTemporarySaveDirectory();
+  try {
+    // Single extension.
+    var tempFile = destDir.clone();
+    tempFile.append("test.txt");
+    testCreateNiceUniqueFile(tempFile, "test.txt");
+    testCreateNiceUniqueFile(tempFile, "test(1).txt");
+    testCreateNiceUniqueFile(tempFile, "test(2).txt");
 
-  // Single extension.
-  var tempFile = destDir.clone();
-  tempFile.append("test.txt");
-  testCreateNiceUniqueFile(tempFile, "test.txt");
-  testCreateNiceUniqueFile(tempFile, "test(1).txt");
-  testCreateNiceUniqueFile(tempFile, "test(2).txt");
-
-  // Double extension.
-  tempFile.leafName = "test.tar.gz";
-  testCreateNiceUniqueFile(tempFile, "test.tar.gz");
-  testCreateNiceUniqueFile(tempFile, "test(1).tar.gz");
-  testCreateNiceUniqueFile(tempFile, "test(2).tar.gz");
+    // Double extension.
+    tempFile.leafName = "test.tar.gz";
+    testCreateNiceUniqueFile(tempFile, "test.tar.gz");
+    testCreateNiceUniqueFile(tempFile, "test(1).tar.gz");
+    testCreateNiceUniqueFile(tempFile, "test(2).tar.gz");
 
-  // Test automatic shortening of long file names. We don't know exactly how
-  // many characters are removed, because it depends on the name of the folder
-  // where the file is located.
-  tempFile.leafName = new Array(256).join("T") + ".txt";
-  var newFile = DownloadPaths.createNiceUniqueFile(tempFile);
-  do_check_true(newFile.leafName.length < tempFile.leafName.length);
-  do_check_eq(newFile.leafName.slice(-4), ".txt");
+    // Test automatic shortening of long file names. We don't know exactly how
+    // many characters are removed, because it depends on the name of the folder
+    // where the file is located.
+    tempFile.leafName = new Array(256).join("T") + ".txt";
+    var newFile = DownloadPaths.createNiceUniqueFile(tempFile);
+    do_check_true(newFile.leafName.length < tempFile.leafName.length);
+    do_check_eq(newFile.leafName.slice(-4), ".txt");
 
-  // Creating a valid file name from an invalid one is not always possible.
-  tempFile.append("file-under-long-directory.txt");
-  try {
-    DownloadPaths.createNiceUniqueFile(tempFile);
-    do_throw("Exception expected with a long parent directory name.");
-  } catch (e) {
-    // An exception is expected, but we don't know which one exactly.
+    // Creating a valid file name from an invalid one is not always possible.
+    tempFile.append("file-under-long-directory.txt");
+    try {
+      DownloadPaths.createNiceUniqueFile(tempFile);
+      do_throw("Exception expected with a long parent directory name.");
+    } catch (e) {
+      // An exception is expected, but we don't know which one exactly.
+    }
+  } finally {
+    // Clean up the temporary directory.
+    destDir.remove(true);
   }
 });
--- a/toolkit/components/passwordmgr/test/unit/head.js
+++ b/toolkit/components/passwordmgr/test/unit/head.js
@@ -7,17 +7,16 @@
 // Globals
 
 let { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/LoginRecipes.jsm");
 Cu.import("resource://gre/modules/LoginHelper.jsm");
-Cu.import("resource://testing-common/FileTestUtils.jsm");
 Cu.import("resource://testing-common/LoginTestUtils.jsm");
 Cu.import("resource://testing-common/MockDocument.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "DownloadPaths",
                                   "resource://gre/modules/DownloadPaths.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "OS",
@@ -36,22 +35,57 @@ const newPropertyBag = LoginHelper.newPr
 function run_test()
 {
   do_get_profile();
   run_next_test();
 }
 
 // Global helpers
 
+// Some of these functions are already implemented in other parts of the source
+// tree, see bug 946708 about sharing more code.
+
+// While the previous test file should have deleted all the temporary files it
+// used, on Windows these might still be pending deletion on the physical file
+// system.  Thus, start from a new base number every time, to make a collision
+// with a file that is still pending deletion highly unlikely.
+let gFileCounter = Math.floor(Math.random() * 1000000);
+
 /**
- * Returns a reference to a temporary file that is guaranteed not to exist and
- * is cleaned up later. See FileTestUtils.getTempFile for details.
+ * Returns a reference to a temporary file, that is guaranteed not to exist, and
+ * to have never been created before.
+ *
+ * @param aLeafName
+ *        Suggested leaf name for the file to be created.
+ *
+ * @return nsIFile pointing to a non-existent file in a temporary directory.
+ *
+ * @note It is not enough to delete the file if it exists, or to delete the file
+ *       after calling nsIFile.createUnique, because on Windows the delete
+ *       operation in the file system may still be pending, preventing a new
+ *       file with the same name to be created.
  */
-function getTempFile(leafName) {
-  return FileTestUtils.getTempFile(leafName);
+function getTempFile(aLeafName)
+{
+  // Prepend a serial number to the extension in the suggested leaf name.
+  let [base, ext] = DownloadPaths.splitBaseNameAndExtension(aLeafName);
+  let leafName = base + "-" + gFileCounter + ext;
+  gFileCounter++;
+
+  // Get a file reference under the temporary directory for this test file.
+  let file = FileUtils.getFile("TmpD", [leafName]);
+  do_check_false(file.exists());
+
+  do_register_cleanup(function() {
+    if (file.exists()) {
+      file.remove(false);
+    }
+  });
+
+  return file;
 }
 
 const RecipeHelpers = {
   initNewParent() {
     return (new LoginRecipesParent({ defaults: null })).initializationPromise;
   },
 };
 
--- a/toolkit/components/reputationservice/test/unit/test_app_rep_windows.js
+++ b/toolkit/components/reputationservice/test/unit/test_app_rep_windows.js
@@ -11,18 +11,16 @@
 // Globals
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "FileTestUtils",
-                                  "resource://testing-common/FileTestUtils.jsm");
 
 const BackgroundFileSaverOutputStream = Components.Constructor(
       "@mozilla.org/network/background-file-saver;1?mode=outputstream",
       "nsIBackgroundFileSaver");
 
 const StringInputStream = Components.Constructor(
       "@mozilla.org/io/string-input-stream;1",
       "nsIStringInputStream",
@@ -34,16 +32,30 @@ const gAppRep = Cc["@mozilla.org/reputat
                   getService(Ci.nsIApplicationReputationService);
 var gStillRunning = true;
 var gTables = {};
 var gHttpServer = null;
 
 const appRepURLPref = "browser.safebrowsing.downloads.remote.url";
 const remoteEnabledPref = "browser.safebrowsing.downloads.remote.enabled";
 
+/**
+ * Returns a reference to a temporary file.  If the file is then created, it
+ * will be removed when tests in this file finish.
+ */
+function getTempFile(aLeafName) {
+  let file = FileUtils.getFile("TmpD", [aLeafName]);
+  do_register_cleanup(function GTF_cleanup() {
+    if (file.exists()) {
+      file.remove(false);
+    }
+  });
+  return file;
+}
+
 function readFileToString(aFilename) {
   let f = do_get_file(aFilename);
   let stream = Cc["@mozilla.org/network/file-input-stream;1"]
                  .createInstance(Ci.nsIFileInputStream);
   stream.init(f, -1, 0, 0);
   let buf = NetUtil.readInputStreamToString(stream, stream.available());
   return buf;
 }
@@ -301,17 +313,17 @@ add_task(async function() {
 add_task(async function test_signature_whitelists() {
   // We should never get to the remote server.
   Services.prefs.setBoolPref(remoteEnabledPref,
                              true);
   Services.prefs.setCharPref(appRepURLPref,
                              "http://localhost:4444/throw");
 
   // Use BackgroundFileSaver to extract the signature on Windows.
-  let destFile = FileTestUtils.getTempFile(TEST_FILE_NAME_1);
+  let destFile = getTempFile(TEST_FILE_NAME_1);
 
   let data = readFileToString("data/signed_win.exe");
   let saver = new BackgroundFileSaverOutputStream();
   let completionPromise = promiseSaverComplete(saver);
   saver.enableSignatureInfo();
   saver.setTarget(destFile, false);
   await promiseCopyToSaver(data, saver, true);
 
--- a/toolkit/modules/tests/xpcshell/test_JSONFile.js
+++ b/toolkit/modules/tests/xpcshell/test_JSONFile.js
@@ -10,25 +10,50 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "DownloadPaths",
                                   "resource://gre/modules/DownloadPaths.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "OS",
                                   "resource://gre/modules/osfile.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "JSONFile",
                                   "resource://gre/modules/JSONFile.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "FileTestUtils",
-                                  "resource://testing-common/FileTestUtils.jsm");
+
+let gFileCounter = Math.floor(Math.random() * 1000000);
 
 /**
- * Returns a reference to a temporary file that is guaranteed not to exist and
- * is cleaned up later. See FileTestUtils.getTempFile for details.
+ * Returns a reference to a temporary file, that is guaranteed not to exist, and
+ * to have never been created before.
+ *
+ * @param aLeafName
+ *        Suggested leaf name for the file to be created.
+ *
+ * @return nsIFile pointing to a non-existent file in a temporary directory.
+ *
+ * @note It is not enough to delete the file if it exists, or to delete the file
+ *       after calling nsIFile.createUnique, because on Windows the delete
+ *       operation in the file system may still be pending, preventing a new
+ *       file with the same name to be created.
  */
-function getTempFile(leafName) {
-  return FileTestUtils.getTempFile(leafName);
+function getTempFile(aLeafName) {
+  // Prepend a serial number to the extension in the suggested leaf name.
+  let [base, ext] = DownloadPaths.splitBaseNameAndExtension(aLeafName);
+  let leafName = base + "-" + gFileCounter + ext;
+  gFileCounter++;
+
+  // Get a file reference under the temporary directory for this test file.
+  let file = FileUtils.getFile("TmpD", [leafName]);
+  do_check_false(file.exists());
+
+  do_register_cleanup(function() {
+    if (file.exists()) {
+      file.remove(false);
+    }
+  });
+
+  return file;
 }
 
 const TEST_STORE_FILE_NAME = "test-store.json";
 
 const TEST_DATA = {
   number: 123,
   string: "test",
   object: {
--- a/uriloader/exthandler/tests/mochitest/browser_download_privatebrowsing.js
+++ b/uriloader/exthandler/tests/mochitest/browser_download_privatebrowsing.js
@@ -5,29 +5,78 @@
  * Tests that downloads started from a private window by clicking on a link end
  * up in the global list of private downloads (see bug 1367581).
  */
 
 "use strict";
 
 Cu.import("resource://gre/modules/Downloads.jsm", this);
 Cu.import("resource://gre/modules/DownloadPaths.jsm", this);
-Cu.import("resource://testing-common/FileTestUtils.jsm", this);
 Cu.import("resource://testing-common/MockRegistrar.jsm", this);
 
+const TEST_TARGET_FILE_NAME = "test-download.txt";
+
+// While the previous test file should have deleted all the temporary files it
+// used, on Windows these might still be pending deletion on the physical file
+// system.  Thus, start from a new base number every time, to make a collision
+// with a file that is still pending deletion highly unlikely.
+let gFileCounter = Math.floor(Math.random() * 1000000);
+
+/**
+ * Returns a reference to a temporary file, that is guaranteed not to exist, and
+ * to have never been created before.
+ *
+ * @param aLeafName
+ *        Suggested leaf name for the file to be created.
+ *
+ * @return nsIFile pointing to a non-existent file in a temporary directory.
+ *
+ * @note It is not enough to delete the file if it exists, or to delete the file
+ *       after calling nsIFile.createUnique, because on Windows the delete
+ *       operation in the file system may still be pending, preventing a new
+ *       file with the same name to be created.
+ */
+function getTempFile(aLeafName) {
+  // Prepend a serial number to the extension in the suggested leaf name.
+  let [base, ext] = DownloadPaths.splitBaseNameAndExtension(aLeafName);
+  let leafName = base + "-" + gFileCounter + ext;
+  gFileCounter++;
+
+  // Get a file reference under the temporary directory for this test file.
+  let file = FileUtils.getFile("TmpD", [leafName]);
+  Assert.ok(!file.exists());
+
+  registerCleanupFunction(() => {
+    try {
+      file.remove(false);
+    } catch (ex) {
+      // On Windows, we may get an access denied error if the file existed
+      // before, and was recently deleted.
+      if (!(ex instanceof Components.Exception &&
+            (ex.result == Cr.NS_ERROR_FILE_ACCESS_DENIED ||
+             ex.result == Cr.NS_ERROR_FILE_TARGET_DOES_NOT_EXIST ||
+             ex.result == Cr.NS_ERROR_FILE_NOT_FOUND))) {
+        throw ex;
+      }
+    }
+  });
+
+  return file;
+}
+
 add_task(async function test_setup() {
   // Save downloads to disk without showing the dialog.
   let cid = MockRegistrar.register("@mozilla.org/helperapplauncherdialog;1", {
     QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog]),
     show(launcher) {
       launcher.saveToDisk(null, false);
     },
     promptForSaveToFileAsync(launcher) {
       // The dialog should create the empty placeholder file.
-      let file = FileTestUtils.getTempFile();
+      let file = getTempFile(TEST_TARGET_FILE_NAME);
       file.create(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
       launcher.saveDestinationAvailable(file);
     },
   });
   registerCleanupFunction(() => {
     MockRegistrar.unregister(cid);
   });
 });