Bug 1277803 - Part 8 : Add a test case of favicon loading of private browsing. r=ehsan
authorTim Huang <tihuang@mozilla.com>
Thu, 13 Oct 2016 15:44:05 +0800
changeset 317850 60137e6c353000f41aeed0bc4b63c43da718f951
parent 317849 b6b99627c2daabb0b0941b9ba1bf575860164a7a
child 317851 2782494a3f16f3bdeebf77e46ee12243696a9bbd
push id33170
push usercbook@mozilla.com
push dateFri, 14 Oct 2016 10:37:07 +0000
treeherderautoland@0d101ebfd95c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs1277803
milestone52.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 1277803 - Part 8 : Add a test case of favicon loading of private browsing. r=ehsan
browser/components/privatebrowsing/test/browser/browser.ini
browser/components/privatebrowsing/test/browser/browser_privatebrowsing_favicon.js
browser/components/privatebrowsing/test/browser/file_favicon.html
browser/components/privatebrowsing/test/browser/file_favicon.png
browser/components/privatebrowsing/test/browser/file_favicon.png^headers^
--- a/browser/components/privatebrowsing/test/browser/browser.ini
+++ b/browser/components/privatebrowsing/test/browser/browser.ini
@@ -10,30 +10,34 @@ support-files =
   browser_privatebrowsing_localStorage_page2.html
   browser_privatebrowsing_placesTitleNoUpdate.html
   browser_privatebrowsing_protocolhandler_page.html
   browser_privatebrowsing_windowtitle_page.html
   head.js
   popup.html
   title.sjs
   empty_file.html
+  file_favicon.html
+  file_favicon.png
+  file_favicon.png^headers^
 
 [browser_privatebrowsing_DownloadLastDirWithCPS.js]
 [browser_privatebrowsing_about.js]
 tags = trackingprotection
 [browser_privatebrowsing_aboutHomeButtonAfterWindowClose.js]
 [browser_privatebrowsing_aboutSessionRestore.js]
 [browser_privatebrowsing_cache.js]
 [browser_privatebrowsing_certexceptionsui.js]
 [browser_privatebrowsing_concurrent.js]
 [browser_privatebrowsing_context_and_chromeFlags.js]
 [browser_privatebrowsing_crh.js]
 [browser_privatebrowsing_downloadLastDir.js]
 [browser_privatebrowsing_downloadLastDir_c.js]
 [browser_privatebrowsing_downloadLastDir_toggle.js]
+[browser_privatebrowsing_favicon.js]
 [browser_privatebrowsing_geoprompt.js]
 [browser_privatebrowsing_lastpbcontextexited.js]
 [browser_privatebrowsing_localStorage.js]
 [browser_privatebrowsing_localStorage_before_after.js]
 [browser_privatebrowsing_noSessionRestoreMenuOption.js]
 [browser_privatebrowsing_nonbrowser.js]
 [browser_privatebrowsing_opendir.js]
 [browser_privatebrowsing_placesTitleNoUpdate.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_favicon.js
@@ -0,0 +1,293 @@
+/* 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/. */
+
+// This test make sure that the favicon of the private browsing is isolated.
+
+const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
+
+const TEST_SITE = "http://mochi.test:8888";
+const TEST_CACHE_SITE = "http://www.example.com";
+const TEST_DIRECTORY = "/browser/browser/components/privatebrowsing/test/browser/";
+
+const TEST_PAGE = TEST_SITE + TEST_DIRECTORY + "file_favicon.html";
+const TEST_CACHE_PAGE = TEST_CACHE_SITE + TEST_DIRECTORY + "file_favicon.html";
+const FAVICON_URI = TEST_SITE + TEST_DIRECTORY + "file_favicon.png";
+const FAVICON_CACHE_URI = TEST_CACHE_SITE + TEST_DIRECTORY + "file_favicon.png";
+
+let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
+let makeURI = Cu.import("resource://gre/modules/BrowserUtils.jsm", {}).BrowserUtils.makeURI;
+
+function clearAllImageCaches() {
+  let tools = SpecialPowers.Cc["@mozilla.org/image/tools;1"]
+                             .getService(SpecialPowers.Ci.imgITools);
+  let imageCache = tools.getImgCacheForDocument(window.document);
+  imageCache.clearCache(true);  // true=chrome
+  imageCache.clearCache(false); // false=content
+}
+
+function clearAllPlacesFavicons() {
+  let faviconService = Cc["@mozilla.org/browser/favicon-service;1"]
+                          .getService(Ci.nsIFaviconService);
+
+  return new Promise(resolve => {
+    let observer = {
+      observe(aSubject, aTopic, aData) {
+        if (aTopic === "places-favicons-expired") {
+          resolve();
+          Services.obs.removeObserver(observer, "places-favicons-expired", false);
+        }
+      }
+    };
+
+    Services.obs.addObserver(observer, "places-favicons-expired", false);
+    faviconService.expireAllFavicons();
+  });
+}
+
+function observeFavicon(aIsPrivate, aExpectedCookie, aPageURI) {
+  let faviconReqXUL = false;
+  let faviconReqPlaces = false;
+  let attr = {};
+
+  if (aIsPrivate) {
+    attr.privateBrowsingId = 1;
+  }
+
+  let expectedPrincipal = Services.scriptSecurityManager
+                                  .createCodebasePrincipal(aPageURI, attr);
+
+  return new Promise(resolve => {
+    let observer = {
+      observe(aSubject, aTopic, aData) {
+        // Make sure that the topic is 'http-on-modify-request'.
+        if (aTopic === "http-on-modify-request") {
+          // We check the privateBrowsingId for the originAttributes of the loading
+          // channel. All requests for the favicon should contain the correct
+          // privateBrowsingId. There are two requests for a favicon loading, one
+          // from the Places library and one from the XUL image. The difference
+          // of them is the loading principal. The Places will use the content
+          // principal and the XUL image will use the system principal.
+
+          let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
+          let reqLoadInfo = httpChannel.loadInfo;
+          let loadingPrincipal = reqLoadInfo.loadingPrincipal;
+          let triggeringPrincipal = reqLoadInfo.triggeringPrincipal;
+
+          // Make sure this is a favicon request.
+          if (httpChannel.URI.spec !== FAVICON_URI) {
+            return;
+          }
+
+          // Check the privateBrowsingId.
+          if (aIsPrivate) {
+            is(reqLoadInfo.originAttributes.privateBrowsingId, 1, "The loadInfo has correct privateBrowsingId");
+          } else {
+            is(reqLoadInfo.originAttributes.privateBrowsingId, 0, "The loadInfo has correct privateBrowsingId");
+          }
+
+          if (loadingPrincipal.equals(systemPrincipal)) {
+            faviconReqXUL = true;
+            ok(triggeringPrincipal.equals(expectedPrincipal),
+              "The triggeringPrincipal of favicon loading from XUL should be the content principal.");
+          } else {
+            faviconReqPlaces = true;
+            ok(loadingPrincipal.equals(expectedPrincipal),
+              "The loadingPrincipal of favicon loading from Places should be the content prinicpal");
+          }
+
+          let faviconCookie = httpChannel.getRequestHeader("cookie");
+
+          is(faviconCookie, aExpectedCookie, "The cookie of the favicon loading is correct.");
+        } else {
+          ok(false, "Received unexpected topic: ", aTopic);
+        }
+
+        if (faviconReqXUL && faviconReqPlaces) {
+          resolve();
+          Services.obs.removeObserver(observer, "http-on-modify-request", false);
+        }
+      }
+    };
+
+    Services.obs.addObserver(observer, "http-on-modify-request", false);
+  });
+}
+
+function waitOnFaviconResponse(aFaviconURL) {
+  return new Promise(resolve => {
+    let observer = {
+      observe(aSubject, aTopic, aData) {
+        if (aTopic === "http-on-examine-response" ||
+            aTopic === "http-on-examine-cached-response") {
+
+          let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
+          let loadInfo = httpChannel.loadInfo;
+
+          if (httpChannel.URI.spec !== aFaviconURL) {
+            return;
+          }
+
+          let result = {
+            topic: aTopic,
+            privateBrowsingId: loadInfo.originAttributes.privateBrowsingId
+          };
+
+          resolve(result);
+          Services.obs.removeObserver(observer, "http-on-examine-response", false);
+          Services.obs.removeObserver(observer, "http-on-examine-cached-response", false);
+        }
+      }
+    };
+
+    Services.obs.addObserver(observer, "http-on-examine-response", false);
+    Services.obs.addObserver(observer, "http-on-examine-cached-response", false);
+  });
+}
+
+function waitOnFaviconLoaded(aFaviconURL) {
+  return new Promise(resolve => {
+    let observer = {
+      onPageChanged(uri, attr, value, id) {
+
+        if (attr === Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON &&
+            value === aFaviconURL) {
+          resolve();
+          PlacesUtils.history.removeObserver(observer, false);
+        }
+      },
+    };
+
+    PlacesUtils.history.addObserver(observer, false);
+  });
+}
+
+function* assignCookies(aBrowser, aURL, aCookieValue){
+  let tabInfo = yield openTab(aBrowser, aURL);
+
+  yield ContentTask.spawn(tabInfo.browser, aCookieValue, function* (value) {
+    content.document.cookie = value;
+  });
+
+  yield BrowserTestUtils.removeTab(tabInfo.tab);
+}
+
+function* openTab(aBrowser, aURL) {
+  let tab = aBrowser.addTab(aURL);
+
+  // Select tab and make sure its browser is focused.
+  aBrowser.selectedTab = tab;
+  tab.ownerGlobal.focus();
+
+  let browser = aBrowser.getBrowserForTab(tab);
+  yield BrowserTestUtils.browserLoaded(browser);
+  return {tab, browser};
+}
+
+// A clean up function to prevent affecting other tests.
+registerCleanupFunction(() => {
+  // Clear all cookies.
+  let cookieMgr = Cc["@mozilla.org/cookiemanager;1"]
+                     .getService(Ci.nsICookieManager);
+  cookieMgr.removeAll();
+
+  // Clear all image caches and network caches.
+  clearAllImageCaches();
+
+  let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
+                        .getService(Ci.nsICacheStorageService);
+  networkCache.clear();
+});
+
+add_task(function* test_favicon_privateBrowsing() {
+  // Clear all image caches before running the test.
+  clearAllImageCaches();
+
+  // Clear all favicons in Places.
+  yield clearAllPlacesFavicons();
+
+  // Create a private browsing window.
+  let privateWindow = yield BrowserTestUtils.openNewBrowserWindow({ private: true });
+  let pageURI = makeURI(TEST_PAGE);
+
+  // Generate two random cookies for non-private window and private window
+  // respectively.
+  let cookies = [];
+  cookies.push(Math.random().toString());
+  cookies.push(Math.random().toString());
+
+  // Open a tab in private window and add a cookie into it.
+  yield assignCookies(privateWindow.gBrowser, TEST_SITE, cookies[0]);
+
+  // Open a tab in non-private window and add a cookie into it.
+  yield assignCookies(gBrowser, TEST_SITE, cookies[1]);
+
+  // Add the observer earlier in case we don't capture events in time.
+  let promiseObserveFavicon = observeFavicon(true, cookies[0], pageURI);
+
+  // Open a tab for the private window.
+  let tabInfo = yield openTab(privateWindow.gBrowser, TEST_PAGE);
+
+  // Waiting until favicon requests are all made.
+  yield promiseObserveFavicon;
+
+  // Close the tab.
+  yield BrowserTestUtils.removeTab(tabInfo.tab);
+
+  // Add the observer earlier in case we don't capture events in time.
+  promiseObserveFavicon = observeFavicon(false, cookies[1], pageURI);
+
+  // Open a tab for the non-private window.
+  tabInfo = yield openTab(gBrowser, TEST_PAGE);
+
+  // Waiting until favicon requests are all made.
+  yield promiseObserveFavicon;
+
+  // Close the tab.
+  yield BrowserTestUtils.removeTab(tabInfo.tab);
+  yield BrowserTestUtils.closeWindow(privateWindow);
+});
+
+add_task(function* test_favicon_cache_privateBrowsing() {
+  // Clear all image cahces and network cache before running the test.
+  clearAllImageCaches();
+
+  let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
+                        .getService(Ci.nsICacheStorageService);
+  networkCache.clear();
+
+  // Clear all favicons in Places.
+  yield clearAllPlacesFavicons();
+
+  // Add an observer for making sure the favicon has been loaded and cached.
+  let promiseFaviconLoaded = waitOnFaviconLoaded(FAVICON_CACHE_URI);
+
+  // Open a tab for the non-private window.
+  let tabInfoNonPrivate = yield openTab(gBrowser, TEST_CACHE_PAGE);
+
+  let response = yield waitOnFaviconResponse(FAVICON_CACHE_URI);
+
+  yield promiseFaviconLoaded;
+
+  // Check that the favicon response has come from the network and it has the
+  // correct privateBrowsingId.
+  is(response.topic, "http-on-examine-response", "The favicon image should be loaded through network.");
+  is(response.privateBrowsingId, 0, "We should observe the network response for the non-private tab.");
+
+  // Create a private browsing window.
+  let privateWindow = yield BrowserTestUtils.openNewBrowserWindow({ private: true });
+
+  // Open a tab for the private window.
+  let tabInfoPrivate = yield openTab(privateWindow.gBrowser, TEST_CACHE_PAGE);
+
+  // Wait for the favicon response of the private tab.
+  response = yield waitOnFaviconResponse(FAVICON_CACHE_URI);
+
+  // Make sure the favicon is loaded through the network and its privateBrowsingId is correct.
+  is(response.topic, "http-on-examine-response", "The favicon image should be loaded through the network again.");
+  is(response.privateBrowsingId, 1, "We should observe the network response for the private tab.");
+
+  yield BrowserTestUtils.removeTab(tabInfoPrivate.tab);
+  yield BrowserTestUtils.removeTab(tabInfoNonPrivate.tab);
+  yield BrowserTestUtils.closeWindow(privateWindow);
+});
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/file_favicon.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <meta charset='utf-8'>
+    <title>Favicon Test for originAttributes</title>
+    <link rel="icon" type="image/png" href="file_favicon.png" />
+  </head>
+  <body>
+    Favicon!!
+  </body>
+</html>
\ No newline at end of file
new file mode 100644
index 0000000000000000000000000000000000000000..5535363c94df7314765551f65311ec6f98729d8e
GIT binary patch
literal 344
zc$@)P0jK_nP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80003WNkl<ZSi@ud
z|NsAgh5-aj3<C^C9l%0R#sBwE#yKee29*B}N^?LcMg=I}1WL<7#aV`G2>ibbr58i#
zeNc((P#P98>`-}V2r!yL=>({_1(eS*I75IDqa1+6`Tu4pJs&FZfkdNSpkC~N^7XN%
ziNTl#4nlptmQ0_+z#gbM8_{x!@L&&t|69@WIcn7X|AQkj;gW}$#~3qYLI76MeMc4k
zL!iLKDUaQ}p<fv>vJfohhiYxer~!@C3s8YCB*r;9fSSj^Ib=e>8|uYfC?P<0IRG;c
zE&mVZy1*Xl@?ezO@c*9=cpEsFAp@-q8U3Mr{vneF1fh&<D9wk`BKrRaM~jF7M~jF-
q8*kfi5VnX$TC13Gv~M`#9RL8-wO_*zBf!o80000<MNUMnLSTX;M3C|T
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/file_favicon.png^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-cache