Bug 1203253 - Add back/port the tests that got removed from bug 1140495. r=gijs
☠☠ backed out by cb4bff637489 ☠ ☠
authorJared Wein <jwein@mozilla.com>
Thu, 24 Sep 2015 11:03:54 -0400
changeset 264294 8045d8fcbfe5474276037faccb5863746830326b
parent 264293 cafa078ece955e6df4dc7acb1dfd8113da931ef0
child 264295 82fd00bfb1dd714660b060465642f103c2d72f08
push id65590
push userkwierso@gmail.com
push dateFri, 25 Sep 2015 00:14:23 +0000
treeherdermozilla-inbound@0ab67cace54f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgijs
bugs1203253, 1140495
milestone44.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 1203253 - Add back/port the tests that got removed from bug 1140495. r=gijs
browser/components/preferences/in-content/tests/browser.ini
browser/components/preferences/in-content/tests/browser_bug705422.js
browser/components/preferences/in-content/tests/browser_chunk_permissions.js
browser/components/preferences/in-content/tests/browser_cookies_exceptions.js
browser/components/preferences/in-content/tests/browser_permissions.js
--- a/browser/components/preferences/in-content/tests/browser.ini
+++ b/browser/components/preferences/in-content/tests/browser.ini
@@ -2,25 +2,29 @@
 skip-if = buildapp == "mulet"
 support-files =
   head.js
   privacypane_tests_perwindow.js
 
 [browser_advanced_update.js]
 [browser_basic_rebuild_fonts_test.js]
 [browser_bug410900.js]
+[browser_bug705422.js]
 [browser_bug731866.js]
 [browser_bug795764_cachedisabled.js]
 [browser_bug1018066_resetScrollPosition.js]
 [browser_bug1020245_openPreferences_to_paneContent.js]
 [browser_change_app_handler.js]
+[browser_chunk_permissions.js]
 skip-if = os != "win" # This test tests the windows-specific app selection dialog, so can't run on non-Windows
 [browser_connection.js]
 [browser_connection_bug388287.js]
+[browser_cookies_exceptions.js]
 [browser_healthreport.js]
+[browser_permissions.js]
 skip-if = !healthreport || (os == 'linux' && debug)
 [browser_proxy_backup.js]
 [browser_privacypane_1.js]
 [browser_privacypane_3.js]
 [browser_privacypane_4.js]
 [browser_privacypane_5.js]
 [browser_privacypane_8.js]
 skip-if = e10s # Bug ?????? -  "leaked until shutdown [nsGlobalWindow #99 about:preferences]"
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/in-content/tests/browser_bug705422.js
@@ -0,0 +1,144 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  waitForExplicitFinish();
+  // Allow all cookies, then actually set up the test
+  SpecialPowers.pushPrefEnv({"set": [["network.cookie.cookieBehavior", 0]]}, initTest);
+}
+
+function initTest() {
+    const searchTerm = "example";
+    const dummyTerm = "elpmaxe";
+
+    var cm =  Components.classes["@mozilla.org/cookiemanager;1"]
+                        .getService(Components.interfaces.nsICookieManager);
+
+    // delete all cookies (might be left over from other tests)
+    cm.removeAll();
+
+    // data for cookies
+    var vals = [[searchTerm+".com", dummyTerm, dummyTerm],          // match
+                [searchTerm+".org", dummyTerm, dummyTerm],          // match
+                [dummyTerm+".com", searchTerm, dummyTerm],          // match
+                [dummyTerm+".edu", searchTerm+dummyTerm, dummyTerm],// match
+                [dummyTerm+".net", dummyTerm, searchTerm],          // match
+                [dummyTerm+".org", dummyTerm, searchTerm+dummyTerm],// match
+                [dummyTerm+".int", dummyTerm, dummyTerm]];          // no match
+
+    // matches must correspond to above data
+    const matches = 6;
+
+    var ios = Components.classes["@mozilla.org/network/io-service;1"]
+                        .getService(Components.interfaces.nsIIOService);
+    var cookieSvc = Components.classes["@mozilla.org/cookieService;1"]
+                              .getService(Components.interfaces.nsICookieService);
+    var v;
+    // inject cookies
+    for (v in vals) {
+        let [host, name, value] = vals[v];
+        var cookieUri = ios.newURI("http://"+host, null, null);
+        cookieSvc.setCookieString(cookieUri, null, name+"="+value+";", null);
+    }
+
+    // open cookie manager
+    var cmd = window.openDialog("chrome://browser/content/preferences/cookies.xul",
+                                "Browser:Cookies", "", {});
+
+    // when it has loaded, run actual tests
+    cmd.addEventListener("load", function() {executeSoon(function() {runTest(cmd, searchTerm, vals.length, matches);});}, false);
+}
+
+function isDisabled(win, expectation) {
+    var disabled = win.document.getElementById("removeAllCookies").disabled;
+    is(disabled, expectation, "Remove all cookies button has correct state: "+(expectation?"disabled":"enabled"));
+}
+
+function runTest(win, searchTerm, cookies, matches) {
+    var cm =  Components.classes["@mozilla.org/cookiemanager;1"]
+                        .getService(Components.interfaces.nsICookieManager);
+
+
+    // number of cookies should match injected cookies
+    var cnt = 0,
+        enumerator = cm.enumerator;
+    while (enumerator.hasMoreElements()) {
+        cnt++;
+        enumerator.getNext();
+    }
+    is(cnt, cookies, "Number of cookies match injected cookies");
+
+    // "delete all cookies" should be enabled
+    isDisabled(win, false);
+
+    // filter cookies and count matches
+    win.gCookiesWindow.setFilter(searchTerm);
+    is(win.gCookiesWindow._view.rowCount, matches, "Correct number of cookies shown after filter is applied");
+
+    // "delete all cookies" should be enabled
+    isDisabled(win, false);
+
+
+    // select first cookie and delete
+    var tree = win.document.getElementById("cookiesList");
+    var deleteButton = win.document.getElementById("removeSelectedCookies");
+    var rect = tree.treeBoxObject.getCoordsForCellItem(0, tree.columns[0], "cell");
+    EventUtils.synthesizeMouse(tree.body, rect.x + rect.width / 2, rect.y + rect.height / 2, {}, win);
+    EventUtils.synthesizeMouseAtCenter(deleteButton, {}, win);
+
+    // count cookies should be matches-1
+    is(win.gCookiesWindow._view.rowCount, matches-1, "Deleted selected cookie");
+
+    // select two adjacent cells and delete
+    EventUtils.synthesizeMouse(tree.body, rect.x + rect.width / 2, rect.y + rect.height / 2, {}, win);
+    var eventObj = {};
+    if (navigator.platform.indexOf("Mac") >= 0)
+        eventObj.metaKey = true;
+    else
+        eventObj.ctrlKey = true;
+    rect = tree.treeBoxObject.getCoordsForCellItem(1, tree.columns[0], "cell");
+    EventUtils.synthesizeMouse(tree.body, rect.x + rect.width / 2, rect.y + rect.height / 2, eventObj, win);
+    EventUtils.synthesizeMouseAtCenter(deleteButton, {}, win);
+
+    // count cookies should be matches-3
+    is(win.gCookiesWindow._view.rowCount, matches-3, "Deleted selected two adjacent cookies");
+
+    // "delete all cookies" should be enabled
+    isDisabled(win, false);
+
+    // delete all cookies and count
+    var deleteAllButton = win.document.getElementById("removeAllCookies");
+    EventUtils.synthesizeMouseAtCenter(deleteAllButton, {}, win);
+    is(win.gCookiesWindow._view.rowCount, 0, "Deleted all matching cookies");
+
+    // "delete all cookies" should be disabled
+    isDisabled(win, true);
+
+    // clear filter and count should be cookies-matches
+    win.gCookiesWindow.setFilter("");
+    is(win.gCookiesWindow._view.rowCount, cookies-matches, "Unmatched cookies remain");
+
+    // "delete all cookies" should be enabled
+    isDisabled(win, false);
+
+    // delete all cookies and count should be 0
+    EventUtils.synthesizeMouseAtCenter(deleteAllButton, {}, win);
+    is(win.gCookiesWindow._view.rowCount, 0, "Deleted all cookies");
+
+    // check that datastore is also at 0
+    var cnt = 0,
+        enumerator = cm.enumerator;
+    while (enumerator.hasMoreElements()) {
+        cnt++;
+        enumerator.getNext();
+    }
+    is(cnt, 0, "Zero cookies remain");
+
+    // "delete all cookies" should be disabled
+    isDisabled(win, true);
+
+    // clean up
+    win.close();
+    finish();
+}
+
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/in-content/tests/browser_chunk_permissions.js
@@ -0,0 +1,140 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Components.utils.import("resource://gre/modules/NetUtil.jsm");
+Components.utils.import("resource://gre/modules/ForgetAboutSite.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils",
+  "resource://testing-common/PlacesTestUtils.jsm");
+
+const ABOUT_PERMISSIONS_SPEC = "about:permissions";
+
+const TEST_URI_1 = NetUtil.newURI("http://mozilla.com/");
+const TEST_URI_2 = NetUtil.newURI("http://mozilla.org/");
+const TEST_URI_3 = NetUtil.newURI("http://wikipedia.org/");
+
+// values from DefaultPermissions object
+const PERM_UNKNOWN = 0;
+const PERM_ALLOW = 1;
+const PERM_DENY = 2;
+
+// used to set permissions on test sites
+const TEST_PERMS = {
+  "password": PERM_ALLOW,
+  "cookie": PERM_ALLOW,
+  "geo": PERM_UNKNOWN,
+  "indexedDB": PERM_UNKNOWN,
+  "popup": PERM_DENY
+};
+
+function test() {
+  waitForExplicitFinish();
+  registerCleanupFunction(cleanUp);
+  setup(function() {
+    runNextTest();
+  });
+}
+
+function setup(aCallback) {
+  // add test history visit
+  PlacesTestUtils.addVisits(TEST_URI_1).then(() => {
+    // set permissions ourselves to avoid problems with different defaults
+    // from test harness configuration
+    for (let type in TEST_PERMS) {
+      if (type == "password") {
+        Services.logins.setLoginSavingEnabled(TEST_URI_2.prePath, true);
+      } else {
+        // set permissions on a site without history visits to test enumerateServices
+        Services.perms.add(TEST_URI_2, type, TEST_PERMS[type]);
+      }
+    }
+
+    Services.perms.add(TEST_URI_3, "popup", TEST_PERMS["popup"]);
+    aCallback();
+  });
+}
+
+function cleanUp() {
+  for (let type in TEST_PERMS) {
+    if (type != "password") {
+      Services.perms.remove(TEST_URI_1, type);
+      Services.perms.remove(TEST_URI_2, type);
+      Services.perms.remove(TEST_URI_3, type);
+    }
+  }
+}
+
+function runNextTest() {
+  if (gTestIndex == tests.length) {
+    PlacesTestUtils.clearHistory().then(finish);
+    return;
+  }
+
+  let nextTest = tests[gTestIndex++];
+  info(nextTest.desc);
+
+  function preinit_observer() {
+    Services.obs.removeObserver(preinit_observer, "browser-permissions-preinit");
+    nextTest.preInit();
+  }
+  Services.obs.addObserver(preinit_observer, "browser-permissions-preinit", false);
+
+  function init_observer() {
+    Services.obs.removeObserver(init_observer, "browser-permissions-initialized");
+    nextTest.run();
+  }
+  Services.obs.addObserver(init_observer, "browser-permissions-initialized", false);
+
+  // open about:permissions
+  let tab = gBrowser.selectedTab = gBrowser.addTab("about:permissions");
+  registerCleanupFunction(function() {
+    gBrowser.removeTab(tab);
+  });
+}
+
+var gSitesList;
+
+var gTestIndex = 0;
+var tests = [
+  // 'preInit' occurs after opening about:permissions, before sites-list is populated
+  // 'run' occurs after sites-list is populated
+  {
+    desc: "test filtering before sites-list is fully constructed.",
+    preInit: function() {
+      let sitesFilter = gBrowser.contentDocument.getElementById("sites-filter");
+      sitesFilter.value = TEST_URI_2.host;
+      sitesFilter.doCommand();
+    },
+    run: function() {
+      let testSite1 = getSiteItem(TEST_URI_1.prePath);
+      ok(testSite1.collapsed, "test site 1 is collapsed after early filtering");
+      let testSite2 = getSiteItem(TEST_URI_2.prePath);
+      ok(!testSite2.collapsed, "test site 2 is not collapsed after early filtering");
+      let testSite3 = getSiteItem(TEST_URI_3.prePath);
+      ok(testSite3.collapsed, "test site 3 is collapsed after early filtering");
+
+      runNextTest();
+    }
+  },
+  {
+    desc: "test removing from sites-list before it is fully constructed.",
+    preInit: function() {
+      ForgetAboutSite.removeDataFromDomain(TEST_URI_2.host);
+    },
+    run: function() {
+      let testSite1 = getSiteItem(TEST_URI_1.prePath);
+      ok(testSite1, "test site 1 was not removed from sites list");
+      let testSite2 = getSiteItem(TEST_URI_2.prePath);
+      ok(!testSite2, "test site 2 was pre-removed from sites list");
+      let testSite3 = getSiteItem(TEST_URI_3.prePath);
+      ok(testSite3, "test site 3 was not removed from sites list");
+
+      runNextTest();
+    }
+  }
+];
+
+function getSiteItem(aPrePath) {
+  return gBrowser.contentDocument.
+                  querySelector(".site[value='" + aPrePath + "']");
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/in-content/tests/browser_cookies_exceptions.js
@@ -0,0 +1,304 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  waitForExplicitFinish();
+  testRunner.runTests();
+}
+
+var testRunner = {
+
+  tests:
+    [
+      {
+        test: function(params) {
+          params.url.value = "test.com";
+          params.btnAllow.doCommand();
+          is(params.tree.view.rowCount, 1, "added exception shows up in treeview");
+          is(params.tree.view.getCellText(0, params.nameCol), "http://test.com",
+                                          "origin name should be set correctly");
+          is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
+                                          "permission text should be set correctly");
+          params.btnApplyChanges.doCommand();
+        },
+        observances: [{ type: "cookie", origin: "http://test.com", data: "added",
+                        capability: Ci.nsIPermissionManager.ALLOW_ACTION }],
+      },
+      {
+        test: function(params) {
+          params.url.value = "test.com";
+          params.btnBlock.doCommand();
+          is(params.tree.view.getCellText(0, params.nameCol), "http://test.com",
+                                          "origin name should be set correctly");
+          is(params.tree.view.getCellText(0, params.statusCol), params.denyText,
+                                          "permission should change to deny in UI");
+          params.btnApplyChanges.doCommand();
+        },
+        observances: [{ type: "cookie", origin: "http://test.com", data: "changed",
+                        capability: Ci.nsIPermissionManager.DENY_ACTION  }],
+      },
+      {
+        test: function(params) {
+          params.url.value = "test.com";
+          params.btnAllow.doCommand();
+          is(params.tree.view.getCellText(0, params.nameCol), "http://test.com",
+                                          "origin name should be set correctly");
+          is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
+                                          "permission should revert back to allow");
+          params.btnApplyChanges.doCommand();
+        },
+        observances: [{ type: "cookie", origin: "http://test.com", data: "changed",
+                        capability: Ci.nsIPermissionManager.ALLOW_ACTION }],
+      },
+      {
+        test: function(params) {
+          params.url.value = "test.com";
+          params.btnRemove.doCommand();
+          is(params.tree.view.rowCount, 0, "exception should be removed");
+          params.btnApplyChanges.doCommand();
+        },
+        observances: [{ type: "cookie", origin: "http://test.com", data: "deleted" }],
+      },
+      {
+        expectPermObservancesDuringTestFunction: true,
+        test: function(params) {
+          let uri = params.ioService.newURI("http://test.com", null, null);
+          params.pm.add(uri, "popup", Ci.nsIPermissionManager.DENY_ACTION);
+          is(params.tree.view.rowCount, 0, "adding unrelated permission should not change display");
+          params.btnApplyChanges.doCommand();
+        },
+        observances: [{ type: "popup", origin: "http://test.com", data: "added",
+                        capability: Ci.nsIPermissionManager.DENY_ACTION }],
+        cleanUp: function(params) {
+          let uri = params.ioService.newURI("http://test.com", null, null);
+          params.pm.remove(uri, "popup");
+        },
+      },
+      {
+        test: function(params) {
+          params.url.value = "https://test.com:12345";
+          params.btnAllow.doCommand();
+          is(params.tree.view.rowCount, 1, "added exception shows up in treeview");
+          is(params.tree.view.getCellText(0, params.nameCol), "https://test.com:12345",
+                                          "origin name should be set correctly");
+          is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
+                                          "permission text should be set correctly");
+          params.btnApplyChanges.doCommand();
+        },
+        observances: [{ type: "cookie", origin: "https://test.com:12345", data: "added",
+                        capability: Ci.nsIPermissionManager.ALLOW_ACTION }],
+      },
+      {
+        test: function(params) {
+          params.url.value = "https://test.com:12345";
+          params.btnBlock.doCommand();
+          is(params.tree.view.getCellText(0, params.nameCol), "https://test.com:12345",
+                                          "origin name should be set correctly");
+          is(params.tree.view.getCellText(0, params.statusCol), params.denyText,
+                                          "permission should change to deny in UI");
+          params.btnApplyChanges.doCommand();
+        },
+        observances: [{ type: "cookie", origin: "https://test.com:12345", data: "changed",
+                        capability: Ci.nsIPermissionManager.DENY_ACTION  }],
+      },
+      {
+        test: function(params) {
+          params.url.value = "https://test.com:12345";
+          params.btnAllow.doCommand();
+          is(params.tree.view.getCellText(0, params.nameCol), "https://test.com:12345",
+                                          "origin name should be set correctly");
+          is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
+                                          "permission should revert back to allow");
+          params.btnApplyChanges.doCommand();
+        },
+        observances: [{ type: "cookie", origin: "https://test.com:12345", data: "changed",
+                        capability: Ci.nsIPermissionManager.ALLOW_ACTION }],
+      },
+      {
+        test: function(params) {
+          params.url.value = "https://test.com:12345";
+          params.btnRemove.doCommand();
+          is(params.tree.view.rowCount, 0, "exception should be removed");
+          params.btnApplyChanges.doCommand();
+        },
+        observances: [{ type: "cookie", origin: "https://test.com:12345", data: "deleted" }],
+      },
+      {
+        test: function(params) {
+          params.url.value = "localhost:12345";
+          params.btnAllow.doCommand();
+          is(params.tree.view.rowCount, 1, "added exception shows up in treeview");
+          is(params.tree.view.getCellText(0, params.nameCol), "http://localhost:12345",
+                                          "origin name should be set correctly");
+          is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
+                                          "permission text should be set correctly");
+          params.btnApplyChanges.doCommand();
+        },
+        observances: [{ type: "cookie", origin: "http://localhost:12345", data: "added",
+                        capability: Ci.nsIPermissionManager.ALLOW_ACTION }],
+      },
+      {
+        test: function(params) {
+          params.url.value = "localhost:12345";
+          params.btnBlock.doCommand();
+          is(params.tree.view.getCellText(0, params.nameCol), "http://localhost:12345",
+                                          "origin name should be set correctly");
+          is(params.tree.view.getCellText(0, params.statusCol), params.denyText,
+                                          "permission should change to deny in UI");
+          params.btnApplyChanges.doCommand();
+        },
+        observances: [{ type: "cookie", origin: "http://localhost:12345", data: "changed",
+                        capability: Ci.nsIPermissionManager.DENY_ACTION  }],
+      },
+      {
+        test: function(params) {
+          params.url.value = "localhost:12345";
+          params.btnAllow.doCommand();
+          is(params.tree.view.getCellText(0, params.nameCol), "http://localhost:12345",
+                                          "origin name should be set correctly");
+          is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
+                                          "permission should revert back to allow");
+          params.btnApplyChanges.doCommand();
+        },
+        observances: [{ type: "cookie", origin: "http://localhost:12345", data: "changed",
+                        capability: Ci.nsIPermissionManager.ALLOW_ACTION }],
+      },
+      {
+        test: function(params) {
+          params.url.value = "localhost:12345";
+          params.btnRemove.doCommand();
+          is(params.tree.view.rowCount, 0, "exception should be removed");
+          params.btnApplyChanges.doCommand();
+        },
+        observances: [{ type: "cookie", origin: "http://localhost:12345", data: "deleted" }],
+      },
+    ],
+
+  _currentTest: -1,
+
+  runTests: function() {
+    this._currentTest++;
+
+    info("Running test #" + (this._currentTest + 1) + "\n");
+    let that = this;
+    let p = this.runCurrentTest(this._currentTest + 1);
+    p.then(function() {
+      if (that._currentTest == that.tests.length - 1) {
+        finish();
+      }
+      else {
+        that.runTests();
+      }
+    });
+  },
+
+  runCurrentTest: function(testNumber) {
+    return new Promise(function(resolve, reject) {
+
+      let helperFunctions = {
+        windowLoad: function(win) {
+          let doc = win.document;
+          let params = {
+            doc,
+            tree: doc.getElementById("permissionsTree"),
+            nameCol: doc.getElementById("permissionsTree").treeBoxObject.columns.getColumnAt(0),
+            statusCol: doc.getElementById("permissionsTree").treeBoxObject.columns.getColumnAt(1),
+            url: doc.getElementById("url"),
+            btnAllow: doc.getElementById("btnAllow"),
+            btnBlock: doc.getElementById("btnBlock"),
+            btnApplyChanges: doc.getElementById("btnApplyChanges"),
+            btnRemove: doc.getElementById("removePermission"),
+            pm: Cc["@mozilla.org/permissionmanager;1"]
+                       .getService(Ci.nsIPermissionManager),
+            ioService: Cc["@mozilla.org/network/io-service;1"]
+                              .getService(Ci.nsIIOService),
+            allowText: win.gPermissionManager._getCapabilityString(
+                                Ci.nsIPermissionManager.ALLOW_ACTION),
+            denyText: win.gPermissionManager._getCapabilityString(
+                               Ci.nsIPermissionManager.DENY_ACTION),
+            allow: Ci.nsIPermissionManager.ALLOW_ACTION,
+            deny: Ci.nsIPermissionManager.DENY_ACTION,
+          };
+
+          let permObserver = {
+            observe: function(aSubject, aTopic, aData) {
+              if (aTopic != "perm-changed")
+                return;
+
+              if (testRunner.tests[testRunner._currentTest].observances.length == 0) {
+                // Should fail here as we are not expecting a notification, but we don't.
+                // See bug 1063410.
+                return;
+              }
+
+              let permission = aSubject.QueryInterface(Ci.nsIPermission);
+              let expected = testRunner.tests[testRunner._currentTest].observances.shift();
+
+              is(aData, expected.data, "type of message should be the same");
+              for each (let prop in ["type", "capability"]) {
+                if (expected[prop])
+                  is(permission[prop], expected[prop],
+                    "property: \"" + prop  + "\" should be equal");
+              }
+
+              if (expected.origin) {
+                is(permission.principal.origin, expected.origin,
+                   "property: \"origin\" should be equal");
+              }
+
+              os.removeObserver(permObserver, "perm-changed");
+
+              let test = testRunner.tests[testRunner._currentTest];
+              if (!test.expectPermObservancesDuringTestFunction) {
+                if (test.cleanUp) {
+                  test.cleanUp(params);
+                }
+
+                gBrowser.removeCurrentTab();
+                resolve();
+              }
+            },
+          };
+
+          let os = Cc["@mozilla.org/observer-service;1"]
+                     .getService(Ci.nsIObserverService);
+
+          os.addObserver(permObserver, "perm-changed", false);
+
+          if (testRunner._currentTest == 0) {
+            is(params.tree.view.rowCount, 0, "no cookie exceptions");
+          }
+
+          try {
+            let test = testRunner.tests[testRunner._currentTest];
+            test.test(params);
+            if (test.expectPermObservancesDuringTestFunction) {
+              if (test.cleanUp) {
+                test.cleanUp(params);
+              }
+
+              gBrowser.removeCurrentTab();
+              resolve();
+            }
+          } catch (ex) {
+            ok(false, "exception while running test #" +
+                      testNumber + ": " + ex);
+          }
+        },
+      };
+
+      openPreferencesViaOpenPreferencesAPI("panePrivacy", null, {leaveOpen: true}).then(function() {
+        let doc = gBrowser.contentDocument;
+        let historyMode = doc.getElementById("historyMode");
+        historyMode.value = "custom";
+        historyMode.doCommand();
+        doc.getElementById("cookieExceptions").doCommand();
+
+        let subDialogURL = "chrome://browser/content/preferences/permissions.xul";
+        promiseLoadSubDialog(subDialogURL).then(function(win) {
+          helperFunctions.windowLoad(win);
+        });
+      });
+    });
+  },
+};
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/in-content/tests/browser_permissions.js
@@ -0,0 +1,334 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Components.utils.import("resource://gre/modules/NetUtil.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils",
+  "resource://testing-common/PlacesTestUtils.jsm");
+
+const ABOUT_PERMISSIONS_SPEC = "about:permissions";
+
+const TEST_URI_1 = NetUtil.newURI("http://mozilla.com/");
+const TEST_URI_2 = NetUtil.newURI("http://mozilla.org/");
+
+const TEST_PRINCIPAL_1 =
+  Services.scriptSecurityManager.createCodebasePrincipal(TEST_URI_1, {});
+const TEST_PRINCIPAL_2 =
+  Services.scriptSecurityManager.createCodebasePrincipal(TEST_URI_2, {});
+
+// values from DefaultPermissions object
+const PERM_UNKNOWN = 0;
+const PERM_ALLOW = 1;
+const PERM_DENY = 2;
+// cookie specific permissions
+const PERM_FIRST_PARTY_ONLY = 9;
+
+// used to set permissions on test sites
+const TEST_PERMS = {
+  "password": PERM_ALLOW,
+  "cookie": PERM_ALLOW,
+  "geo": PERM_UNKNOWN,
+  "push": PERM_DENY,
+  "indexedDB": PERM_UNKNOWN,
+  "popup": PERM_DENY,
+  "camera": PERM_UNKNOWN,
+  "microphone": PERM_UNKNOWN
+};
+
+const NO_GLOBAL_ALLOW = [
+  "geo",
+  "indexedDB",
+];
+
+// number of managed permissions in the interface
+const TEST_PERMS_COUNT = 8;
+
+function test() {
+  waitForExplicitFinish();
+  registerCleanupFunction(cleanUp);
+
+  // add test history visit
+  PlacesTestUtils.addVisits(TEST_URI_1).then(() => {
+    // set permissions ourselves to avoid problems with different defaults
+    // from test harness configuration
+    for (let type in TEST_PERMS) {
+      if (type == "password") {
+        Services.logins.setLoginSavingEnabled(TEST_URI_2.prePath, true);
+      } else {
+        // set permissions on a site without history visits to test enumerateServices
+        Services.perms.addFromPrincipal(TEST_PRINCIPAL_2, type, TEST_PERMS[type]);
+      }
+    }
+
+    // open about:permissions
+    gBrowser.selectedTab = gBrowser.addTab("about:permissions");
+  });
+
+  function observer() {
+    Services.obs.removeObserver(observer, "browser-permissions-initialized");
+    runNextTest();
+  }
+  Services.obs.addObserver(observer, "browser-permissions-initialized", false);
+}
+
+function cleanUp() {
+  for (let type in TEST_PERMS) {
+    if (type != "password") {
+      Services.perms.removeFromPrincipal(TEST_PRINCIPAL_1, type);
+      Services.perms.removeFromPrincipal(TEST_PRINCIPAL_2, type);
+    }
+  }
+
+  gBrowser.removeTab(gBrowser.selectedTab);
+}
+
+function runNextTest() {
+  if (gTestIndex == tests.length) {
+    PlacesTestUtils.clearHistory().then(finish);
+    return;
+  }
+
+  let nextTest = tests[gTestIndex++];
+  info("[" + nextTest.name + "] running test");
+  nextTest();
+}
+
+var gSitesList;
+var gHeaderDeck;
+var gSiteLabel;
+
+var gTestIndex = 0;
+var tests = [
+  function test_page_load() {
+    is(gBrowser.currentURI.spec, ABOUT_PERMISSIONS_SPEC, "about:permissions loaded");
+
+    gSitesList = gBrowser.contentDocument.getElementById("sites-list");
+    ok(gSitesList, "got sites list");
+
+    gHeaderDeck = gBrowser.contentDocument.getElementById("header-deck");
+    ok(gHeaderDeck, "got header deck");
+
+    gSiteLabel = gBrowser.contentDocument.getElementById("site-label");
+    ok(gSiteLabel, "got site label");
+
+    runNextTest();
+  },
+
+  function test_sites_list() {
+    is(gSitesList.firstChild.id, "all-sites-item",
+       "all sites is the first item in the sites list");
+
+    ok(getSiteItem(TEST_URI_1.prePath), "site item from places db exists");
+    ok(getSiteItem(TEST_URI_2.prePath), "site item from enumerating services exists");
+
+    runNextTest();
+  },
+
+  function test_filter_sites_list() {
+    // set filter to test host
+    let sitesFilter = gBrowser.contentDocument.getElementById("sites-filter");
+    sitesFilter.value = TEST_URI_1.host;
+    sitesFilter.doCommand();
+
+    // make sure correct sites are collapsed/showing
+    let testSite1 = getSiteItem(TEST_URI_1.prePath);
+    ok(!testSite1.collapsed, "test site 1 is not collapsed");
+    let testSite2 = getSiteItem(TEST_URI_2.prePath);
+    ok(testSite2.collapsed, "test site 2 is collapsed");
+
+    // clear filter
+    sitesFilter.value = "";
+    sitesFilter.doCommand();
+
+    runNextTest();
+  },
+
+  function test_all_sites() {
+    // "All Sites" item should be selected when the page is first loaded
+    is(gSitesList.selectedItem, gBrowser.contentDocument.getElementById("all-sites-item"),
+       "all sites item is selected");
+
+    let defaultsHeader = gBrowser.contentDocument.getElementById("defaults-header");
+    is(defaultsHeader, gHeaderDeck.selectedPanel,
+       "correct header shown for all sites");
+
+    ok(gBrowser.contentDocument.getElementById("passwords-count").hidden,
+       "passwords count is hidden");
+    ok(gBrowser.contentDocument.getElementById("cookies-count").hidden,
+       "cookies count is hidden");
+
+    // Test to make sure "Allow" items hidden for certain permission types
+    NO_GLOBAL_ALLOW.forEach(function(aType) {
+      let menuitem = gBrowser.contentDocument.getElementById(aType + "-" + PERM_ALLOW);
+      ok(menuitem.hidden, aType + " allow menuitem hidden for all sites");
+    });
+
+    runNextTest();
+  },
+
+  function test_all_sites_permission() {
+    // apply the old default of allowing all cookies
+    Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
+
+    // there should be no user-set pref for cookie behavior
+    is(Services.prefs.getIntPref("network.cookie.cookieBehavior"), PERM_UNKNOWN,
+       "network.cookie.cookieBehavior is expected default");
+
+    // the default behavior is to allow cookies
+    let cookieMenulist = getPermissionMenulist("cookie");
+    is(cookieMenulist.value, PERM_ALLOW,
+       "menulist correctly shows that cookies are allowed");
+
+    // set the pref to block cookies
+    Services.prefs.setIntPref("network.cookie.cookieBehavior", PERM_DENY);
+    // check to make sure this change is reflected in the UI
+    is(cookieMenulist.value, PERM_DENY, "menulist correctly shows that cookies are blocked");
+
+    // clear the pref
+    Services.prefs.clearUserPref("network.cookie.cookieBehavior");
+
+    runNextTest();
+  },
+
+  function test_manage_all_passwords() {
+    // make sure "Manage All Passwords..." button opens the correct dialog
+    addWindowListener("chrome://passwordmgr/content/passwordManager.xul", runNextTest);
+    gBrowser.contentDocument.getElementById("passwords-manage-all-button").doCommand();
+
+  },
+
+  function test_manage_all_cookies() {
+    // make sure "Manage All Cookies..." button opens the correct dialog
+    addWindowListener("chrome://browser/content/preferences/cookies.xul", runNextTest);
+    gBrowser.contentDocument.getElementById("cookies-manage-all-button").doCommand();
+  },
+
+  function test_select_site() {
+    // select the site that has the permissions we set at the beginning of the test
+    let testSiteItem = getSiteItem(TEST_URI_2.prePath);
+    gSitesList.selectedItem = testSiteItem;
+
+    let siteHeader = gBrowser.contentDocument.getElementById("site-header");
+    is(siteHeader, gHeaderDeck.selectedPanel,
+       "correct header shown for a specific site");
+    is(gSiteLabel.value, TEST_URI_2.prePath, "header updated for selected site");
+
+    ok(!gBrowser.contentDocument.getElementById("passwords-count").hidden,
+       "passwords count is not hidden");
+    ok(!gBrowser.contentDocument.getElementById("cookies-count").hidden,
+       "cookies count is not hidden");
+
+    // Test to make sure "Allow" items are *not* hidden for certain permission types
+    NO_GLOBAL_ALLOW.forEach(function(aType) {
+      let menuitem = gBrowser.contentDocument.getElementById(aType + "-" + PERM_ALLOW);
+      ok(!menuitem.hidden, aType  + " allow menuitem not hidden for single site");
+    });
+
+    runNextTest();
+  },
+
+  function test_permissions() {
+    let menulists = gBrowser.contentDocument.getElementsByClassName("pref-menulist");
+    is(menulists.length, TEST_PERMS_COUNT, "got expected number of managed permissions");
+
+    for (let i = 0; i < menulists.length; i++) {
+      let permissionMenulist = menulists.item(i);
+      let permissionType = permissionMenulist.getAttribute("type");
+
+      // permissions should reflect what we set at the beginning of the test
+      is(permissionMenulist.value, TEST_PERMS[permissionType],
+        "got expected value for " + permissionType + " permission");
+    }
+
+    runNextTest();
+  },
+
+  function test_permission_change() {
+    let geoMenulist = getPermissionMenulist("geo");
+    is(geoMenulist.value, PERM_UNKNOWN, "menulist correctly shows that geolocation permission is unspecified");
+
+    // change a permission programatically
+    Services.perms.addFromPrincipal(TEST_PRINCIPAL_2, "geo", PERM_DENY);
+    // check to make sure this change is reflected in the UI
+    is(geoMenulist.value, PERM_DENY, "menulist shows that geolocation is blocked");
+
+    // change a permisssion in the UI
+    let geoAllowItem = gBrowser.contentDocument.getElementById("geo-" + PERM_ALLOW);
+    geoMenulist.selectedItem = geoAllowItem;
+    geoMenulist.doCommand();
+    // check to make sure this change is reflected in the permission manager
+    is(Services.perms.testPermissionFromPrincipal(TEST_PRINCIPAL_2, "geo"), PERM_ALLOW,
+       "permission manager shows that geolocation is allowed");
+
+
+    // change a site-specific cookie permission, just for fun
+    let cookieMenuList = getPermissionMenulist("cookie");
+    let cookieItem = gBrowser.contentDocument.getElementById("cookie-" + PERM_FIRST_PARTY_ONLY);
+    cookieMenuList.selectedItem = cookieItem;
+    cookieMenuList.doCommand();
+    is(cookieMenuList.value, PERM_FIRST_PARTY_ONLY, "menulist correctly shows that " +
+       "first party only cookies are allowed");
+    is(Services.perms.testPermissionFromPrincipal(TEST_PRINCIPAL_2, "cookie"),
+       PERM_FIRST_PARTY_ONLY, "permission manager shows that first party cookies " +
+       "are allowed");
+
+    runNextTest();
+  },
+
+  function test_forget_site() {
+    // click "Forget About This Site" button
+    gBrowser.contentDocument.getElementById("forget-site-button").doCommand();
+    PlacesTestUtils.clearHistory().then(() => {
+      is(gSiteLabel.value, "", "site label cleared");
+
+      let allSitesItem = gBrowser.contentDocument.getElementById("all-sites-item");
+      is(gSitesList.selectedItem, allSitesItem,
+         "all sites item selected after forgetting selected site");
+
+      // check to make sure site is gone from sites list
+      let testSiteItem = getSiteItem(TEST_URI_2.prePath);
+      ok(!testSiteItem, "site removed from sites list");
+
+      // check to make sure we forgot all permissions corresponding to site
+      for (let type in TEST_PERMS) {
+        if (type == "password") {
+          ok(Services.logins.getLoginSavingEnabled(TEST_URI_2.prePath),
+             "password saving should be enabled by default");
+        } else {
+          is(Services.perms.testPermissionFromPrincipal(TEST_PRINCIPAL_2, type), PERM_UNKNOWN,
+             type + " permission should not be set for test site 2");
+        }
+      }
+
+      runNextTest();
+    });
+  }
+];
+
+function getPermissionMenulist(aType) {
+  return gBrowser.contentDocument.getElementById(aType + "-menulist");
+}
+
+function getSiteItem(aHost) {
+  return gBrowser.contentDocument.
+                  querySelector(".site[value='" + aHost + "']");
+}
+
+function addWindowListener(aURL, aCallback) {
+  Services.wm.addListener({
+    onOpenWindow: function(aXULWindow) {
+      info("window opened, waiting for focus");
+      Services.wm.removeListener(this);
+
+      var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                                .getInterface(Ci.nsIDOMWindow);
+      waitForFocus(function() {
+        is(domwindow.document.location.href, aURL, "should have seen the right window open");
+        domwindow.close();
+        aCallback();
+      }, domwindow);
+    },
+    onCloseWindow: function(aXULWindow) { },
+    onWindowTitleChange: function(aXULWindow, aNewTitle) { }
+  });
+}