Bug 335545 - Count FD instead of looking for clipboardcache in test_bug1123480.xul r=mstange
authorRob Wu <rob@robwu.nl>
Sun, 25 Feb 2018 17:30:13 +0100
changeset 461636 a9eca77bd638babb8de38824f1e61b4bbd8424f6
parent 461635 28a5bbda5231a3d0932fe80fdf0783e880ef2250
child 461637 5469af7e5a36d3c34b876ba6fccf17647bc258a7
push id1683
push usersfraser@mozilla.com
push dateThu, 26 Apr 2018 16:43:40 +0000
treeherdermozilla-release@5af6cb21869d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs335545, 1123480
milestone60.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 335545 - Count FD instead of looking for clipboardcache in test_bug1123480.xul r=mstange - Count open file descriptors instead of testing the existence of a file (because the clipboard is now only reachable through file descriptors, and not through a file path). - Use a fixed string instead of a random string. The previous way of generating a string was non-deterministic, and there was a very small chance that the generated string was not large enough to trigger the cache-to-disk-mode. - Use "text/unicode" instead of "text/plain", because JavaScript strings use two bytes, not one bytes each. - The cache file is already created when the Transferable is created, so check the cache file after assigning data to the nsITransferable, but before copying it to the clipboard. MozReview-Commit-ID: KOkYOm280Oh
widget/tests/test_bug1123480.xul
--- a/widget/tests/test_bug1123480.xul
+++ b/widget/tests/test_bug1123480.xul
@@ -8,72 +8,136 @@ https://bugzilla.mozilla.org/show_bug.cg
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         onload="RunTest();">
   <title>nsTransferable PBM Overflow Selection Test</title>
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
 
   <script type="application/javascript">
   <![CDATA[
-  // Boilerplate constructs
-  var SmallDataset = 100000; // Hundred thousand bytes
+  // Create over 1 MB of sample garbage text. JavaScript strings are represented by
+  // UTF16 strings, so the size is twice as much as the actual string length.
+  // This value is chosen such that the size of the memory for the string exceeds
+  // the kLargeDatasetSize threshold in nsTransferable.h.
+  // It is also not a round number to reduce the odds of having an accidental
+  // collisions with another file (since the test below looks at the file size
+  // to identify the file).
+  var Ipsum = "0123456789".repeat(1234321);
+  var IpsumByteLength = Ipsum.length * 2;
+  var SHORT_STRING_NO_CACHE = "short string that will never be cached to the disk";
+
+  function isWindows() {
+    ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
+    return AppConstants.platform === 'win';
+  }
 
-  // Create 1 Mo of sample garbage text
-  var Ipsum = ""; // Select text from this
-  for (var Iter = 0; Iter < SmallDataset; Iter++) {
-      Ipsum += Math.random().toString(36) + ' ';
+  // Get a list of open file descriptors that refer to a file with the same size as
+  // the expected data (and assume that any mutations in file descriptor counts
+  // are caused by our test).
+  function getClipboardCacheFDCount() {
+    var dir;
+    if (isWindows()) {
+      // On Windows, nsAnonymousTemporaryFile does not immediately delete the file.
+      // Instead, the Windows-specific FILE_FLAG_DELETE_ON_CLOSE flag is used,
+      // which means that the file is deleted when the last handle is closed.
+      // Apparently, this flag is unreliable (e.g. when the application crashes),
+      // so nsAnonymousTemporaryFile stores the temporary files in a subdirectory,
+      // which is cleaned up some time after start-up.
+
+      // This is just a test, and during the test we deterministically close the
+      // handles, so if FILE_FLAG_DELETE_ON_CLOSE does the thing it promises, the
+      // file is actually removed when the handle is closed.
+
+      ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
+      // Path from nsAnonymousTemporaryFile.cpp, GetTempDir.
+      dir = FileUtils.getFile("TmpD", ["mozilla-temp-files"]);
+    } else {
+      dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+      dir.initWithPath("/dev/fd");
+    }
+    var count = 0;
+    for (var de = dir.directoryEntries; de.hasMoreElements(); ) {
+      var fdFile = de.getNext().QueryInterface(Ci.nsIFile);
+      var fileSize;
+      try {
+        fileSize = fdFile.fileSize;
+      } catch (e) {
+        // This can happen on macOS.
+        continue;
+      }
+      if (fileSize === IpsumByteLength) {
+        // Assume that the file was created by us if the size matches.
+        ++count;
+      }
+    }
+    return count;
   }
 
   function RunTest() {
-    // Construct a nsIFile object for access to file methods
-    ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
-    var clipboardFile = FileUtils.getFile("TmpD", ["clipboardcache"]);
+    const gClipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
+    ChromeUtils.import("resource://gre/modules/Services.jsm");
 
     // Sanitize environment
-    if (clipboardFile.exists()) {
-        clipboardFile.remove(false);
-    }
-    ok(!clipboardFile.exists(), "failed to presanitize the environment");
+    gClipboardHelper.copyString(SHORT_STRING_NO_CACHE);
+
+    var initialFdCount = getClipboardCacheFDCount();
 
     // Overflow a nsTransferable region by using the clipboard helper
-    const gClipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
     gClipboardHelper.copyString(Ipsum);
 
     // Undefined private browsing mode should not cache to disk
-    ok(!clipboardFile.exists(), "correctly avoided caching to disk when PBM is undefined");
+    is(getClipboardCacheFDCount(), initialFdCount, "should avoid caching to disk when PBM is undefined");
+
+    // Sanitize environment again.
+    gClipboardHelper.copyString(SHORT_STRING_NO_CACHE);
+    is(getClipboardCacheFDCount(), initialFdCount, "should have cleared the clipboard data");
 
     // Repeat procedure of plain text selection with private browsing
     // disabled and enabled
     ChromeUtils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
     ChromeUtils.import('resource://gre/modules/Services.jsm');
     for (let private of [false, true]) {
-      // Sanitize environment again
-      if (clipboardFile.exists()) {
-          clipboardFile.remove(false);
-      }
-      ok(!clipboardFile.exists(), "failed to postsanitize the environment");
-
       var win = window.open("about:blank", "_blank", "chrome, width=500, height=200" + (private ? ", private" : ""));
-      ok(win, "failed to open private window");
+      ok(win, private ? "should open private window" : "should open non-private window");
       is(PrivateBrowsingUtils.isContentWindowPrivate(win), private, "used correct window context");
 
-      // Select plaintext in private channel
+      // Select plaintext in private/non-private channel
       const nsTransferable = Components.Constructor("@mozilla.org/widget/transferable;1", "nsITransferable");
       const nsSupportsString = Components.Constructor("@mozilla.org/supports-string;1", "nsISupportsString");
       var Loadctx = PrivateBrowsingUtils.privacyContextFromWindow(win);
       var Transfer = nsTransferable();
       var Suppstr = nsSupportsString();
       Suppstr.data = Ipsum;
       Transfer.init(Loadctx);
-      Transfer.addDataFlavor("text/plain");
-      Transfer.setTransferData("text/plain", Suppstr, Ipsum.length);
-      Services.clipboard.setData(Transfer, null, Services.clipboard.kGlobalClipboard);
+      Transfer.addDataFlavor("text/unicode");
+      Transfer.setTransferData("text/unicode", Suppstr, IpsumByteLength);
 
       // Enabled private browsing mode should not cache any selection to disk; disabled should
-      is(!clipboardFile.exists(), private, "did not violate private browsing mode");
+      if (private) {
+        is(getClipboardCacheFDCount(), initialFdCount, "did not violate private browsing mode");
+      } else {
+        is(getClipboardCacheFDCount(), initialFdCount + 1, "should save memory by caching non-private clipboard data to disk");
+      }
+
+      // Share the transferable with the system.
+      Services.clipboard.setData(Transfer, null, Services.clipboard.kGlobalClipboard);
+      if (private) {
+        is(getClipboardCacheFDCount(), initialFdCount, "did not violate private browsing mode");
+      } else {
+        is(getClipboardCacheFDCount(), initialFdCount + 1, "should save memory by caching non-private clipboard data to disk");
+      }
+
+      // Sanitize the environment.
+      Suppstr = nsSupportsString();
+      Suppstr.data = SHORT_STRING_NO_CACHE;
+      Transfer.setTransferData("text/unicode", Suppstr, SHORT_STRING_NO_CACHE.length * 2);
+      is(getClipboardCacheFDCount(), initialFdCount, "should drop the cache file, if any.");
+
+      Services.clipboard.setData(Transfer, null, Services.clipboard.kGlobalClipboard);
+      is(getClipboardCacheFDCount(), initialFdCount, "should postsanitize the environment");
     }
   }
   ]]>
   </script>
 
   <!-- test results are displayed in the html:body -->
   <body xmlns="http://www.w3.org/1999/xhtml">
   <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1123480"