Bug 1286798 - Part 51: Add tests for archive and shadow database clearing; r=asuth draft
authorJan Varga <jan.varga@gmail.com>
Wed, 24 Oct 2018 06:59:11 +0200
changeset 481729 b1a665f1536be293d4157c4fd06ca6d76d5b3f79
parent 481728 3f2af2a900c14028bdb1b4e81ea081627ee43cf1
child 481730 0b53500e43327a1f6e929652aa3fed7589be2063
push id10
push userbugmail@asutherland.org
push dateSun, 18 Nov 2018 18:57:42 +0000
reviewersasuth
bugs1286798
milestone65.0a1
Bug 1286798 - Part 51: Add tests for archive and shadow database clearing; r=asuth
dom/localstorage/moz.build
dom/localstorage/test/unit/databaseShadowing-shared.js
dom/localstorage/test/unit/head.js
dom/localstorage/test/unit/migration_profile.zip
dom/localstorage/test/unit/test_databaseShadowing1.js
dom/localstorage/test/unit/test_databaseShadowing2.js
dom/localstorage/test/unit/test_databaseShadowing_clearOrigin1.js
dom/localstorage/test/unit/test_databaseShadowing_clearOrigin2.js
dom/localstorage/test/unit/test_databaseShadowing_clearOriginsByPattern1.js
dom/localstorage/test/unit/test_databaseShadowing_clearOriginsByPattern2.js
dom/localstorage/test/unit/test_databaseShadowing_clearOriginsByPrefix1.js
dom/localstorage/test/unit/test_databaseShadowing_clearOriginsByPrefix2.js
dom/localstorage/test/unit/test_migration.js
dom/localstorage/test/unit/xpcshell.ini
--- a/dom/localstorage/moz.build
+++ b/dom/localstorage/moz.build
@@ -3,16 +3,20 @@
 # 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/.
 
 XPCSHELL_TESTS_MANIFESTS += [
     'test/unit/xpcshell.ini'
 ]
 
+TEST_HARNESS_FILES.xpcshell.dom.localstorage.test.unit += [
+    'test/unit/databaseShadowing-shared.js',
+]
+
 XPIDL_SOURCES += [
     'nsILocalStorageManager.idl',
 ]
 
 XPIDL_MODULE = 'dom_localstorage'
 
 EXPORTS.mozilla.dom.localstorage += [
     'ActorsParent.h',
new file mode 100644
--- /dev/null
+++ b/dom/localstorage/test/unit/databaseShadowing-shared.js
@@ -0,0 +1,114 @@
+const principalInfos = [
+  { url: "http://example.com", attrs: {} },
+
+  { url: "http://origin.test", attrs: {} },
+
+  { url: "http://prefix.test", attrs: {} },
+  { url: "http://prefix.test", attrs: { userContextId: 10 } },
+
+  { url: "http://pattern.test", attrs: { userContextId: 15 } },
+  { url: "http://pattern.test:8080", attrs: { userContextId: 15 } },
+  { url: "https://pattern.test", attrs: { userContextId: 15 } },
+];
+
+function enableNextGenLocalStorage()
+{
+  info("Setting pref");
+
+  Services.prefs.setBoolPref("dom.storage.next_gen", true);
+}
+
+function disableNextGenLocalStorage()
+{
+  info("Setting pref");
+
+  Services.prefs.setBoolPref("dom.storage.next_gen", false);
+}
+
+function storeData()
+{
+  for (let i = 0; i < principalInfos.length; i++) {
+    let principalInfo = principalInfos[i];
+    let principal = getPrincipal(principalInfo.url, principalInfo.attrs);
+
+    info("Getting storage");
+
+    let storage = getLocalStorage(principal);
+
+    info("Adding data");
+
+    storage.setItem("key0", "value0");
+    storage.clear();
+    storage.setItem("key1", "value1");
+    storage.removeItem("key1");
+    storage.setItem("key2", "value2");
+
+    info("Closing storage");
+
+    storage.close();
+  }
+}
+
+function exportShadowDatabase(name)
+{
+  info("Verifying shadow database");
+
+  let profileDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
+  let shadowDatabase = profileDir.clone();
+  shadowDatabase.append("webappsstore.sqlite");
+
+  let exists = shadowDatabase.exists();
+  ok(exists, "Shadow database does exist");
+
+  info("Copying shadow database");
+
+  let currentDir = Services.dirsvc.get("CurWorkD", Ci.nsIFile);
+  shadowDatabase.copyTo(currentDir, name);
+}
+
+function importShadowDatabase(name)
+{
+  info("Verifying shadow database");
+
+  let currentDir = Services.dirsvc.get("CurWorkD", Ci.nsIFile);
+  let shadowDatabase = currentDir.clone();
+  shadowDatabase.append(name);
+
+  let exists = shadowDatabase.exists();
+  if (!exists) {
+    return false;
+  }
+
+  info("Copying shadow database");
+
+  let profileDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
+  shadowDatabase.copyTo(profileDir, "webappsstore.sqlite");
+
+  return true;
+}
+
+function verifyData(clearedOrigins)
+{
+  for (let i = 0; i < principalInfos.length; i++) {
+    let principalInfo = principalInfos[i];
+    let principal = getPrincipal(principalInfo.url, principalInfo.attrs);
+
+    info("Getting storage");
+
+    let storage = getLocalStorage(principal);
+
+    info("Verifying data");
+
+    if (clearedOrigins.includes(i)) {
+      ok(storage.getItem("key2") == null, "Correct value");
+    } else {
+      ok(storage.getItem("key0") == null, "Correct value");
+      ok(storage.getItem("key1") == null, "Correct value");
+      ok(storage.getItem("key2") == "value2", "Correct value");
+    }
+
+    info("Closing storage");
+
+    storage.close();
+  }
+}
--- a/dom/localstorage/test/unit/head.js
+++ b/dom/localstorage/test/unit/head.js
@@ -99,16 +99,49 @@ function getOriginUsage(principal, callb
 function clear(callback)
 {
   let request = Services.qms.clear();
   request.callback = callback;
 
   return request;
 }
 
+function clearOriginsByPattern(pattern, callback)
+{
+  let request = Services.qms.clearStoragesForPattern(pattern);
+  request.callback = callback;
+
+  return request;
+}
+
+function clearOriginsByPrefix(principal, persistence, callback)
+{
+  let request =
+    Services.qms.clearStoragesForPrincipal(principal, persistence, null, true);
+  request.callback = callback;
+
+  return request;
+}
+
+function clearOrigin(principal, persistence, callback)
+{
+  let request = Services.qms.clearStoragesForPrincipal(principal, persistence);
+  request.callback = callback;
+
+  return request;
+}
+
+function reset(callback)
+{
+  let request = Services.qms.reset();
+  request.callback = callback;
+
+  return request;
+}
+
 function resetOrigin(principal, callback)
 {
   let request =
     Services.qms.resetStoragesForPrincipal(principal, "default", "ls");
   request.callback = callback;
 
   return request;
 }
@@ -222,8 +255,15 @@ function getCurrentPrincipal()
 function getLocalStorage(principal)
 {
   if (!principal) {
     principal = getCurrentPrincipal();
   }
 
   return Services.domStorageManager.createStorage(null, principal, "");
 }
+
+function loadSubscript(path)
+{
+  let file = do_get_file(path, false);
+  let uri = Services.io.newFileURI(file);
+  Services.scriptloader.loadSubScript(uri.spec);
+}
index ff1cd89602076ad5bd332b0da22aee4e498c6648..19dc3d480537b14daef5f22fa74d6114d23b91f9
GIT binary patch
literal 2026
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
--- a/dom/localstorage/test/unit/test_databaseShadowing1.js
+++ b/dom/localstorage/test/unit/test_databaseShadowing1.js
@@ -1,54 +1,27 @@
 /**
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
+loadSubscript("databaseShadowing-shared.js");
+
 function* testSteps()
 {
-  const url = "http://example.com";
-
-  info("Setting pref");
-
-  Services.prefs.setBoolPref("dom.storage.next_gen", true);
+  enableNextGenLocalStorage();
 
-  let principal = getPrincipal(url);
-
-  info("Getting storage");
-
-  let storage = getLocalStorage(principal);
+  storeData();
 
-  info("Adding data");
+  verifyData([]);
 
-  storage.setItem("key0", "value0");
-  storage.clear();
-  storage.setItem("key1", "value1");
-  storage.removeItem("key1");
-  storage.setItem("key2", "value2");
-
-  info("Closing storage");
-
-  storage.close();
-
-  resetOrigin(principal, continueToNextStepSync);
+  // Wait for all database connections to close.
+  reset(continueToNextStepSync);
   yield undefined;
 
-  info("Verifying shadow database");
-
-  let profileDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
-  let shadowDatabase = profileDir.clone();
-  shadowDatabase.append("webappsstore.sqlite");
-
-  let exists = shadowDatabase.exists();
-  ok(exists, "Shadow database does exist");
-
-  info("Copying shadow database");
-
-  let currentDir = Services.dirsvc.get("CurWorkD", Ci.nsIFile);
-  shadowDatabase.copyTo(currentDir, "");
+  exportShadowDatabase("shadowdb.sqlite");
 
   // The shadow database is now prepared for test_databaseShadowing2.js
 
   finishTest();
 }
--- a/dom/localstorage/test/unit/test_databaseShadowing2.js
+++ b/dom/localstorage/test/unit/test_databaseShadowing2.js
@@ -1,46 +1,24 @@
 /**
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
+loadSubscript("databaseShadowing-shared.js");
+
 function* testSteps()
 {
-  const url = "http://example.com";
-
-  // The shadow database is prepared in test_databaseShadowing1.js
-
-  info("Setting pref");
-
-  Services.prefs.setBoolPref("dom.storage.next_gen", false);
+  // The shadow database was prepared in test_databaseShadowing1.js
 
-  info("Verifying shadow database");
+  disableNextGenLocalStorage();
 
-  let currentDir = Services.dirsvc.get("CurWorkD", Ci.nsIFile);
-  let shadowDatabase = currentDir.clone();
-  shadowDatabase.append("webappsstore.sqlite");
-
-  let exists = shadowDatabase.exists();
-  if (!exists) {
+  if (!importShadowDatabase("shadowdb.sqlite")) {
     finishTest();
     return;
   }
 
-  info("Copying shadow database");
-
-  let profileDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
-  shadowDatabase.copyTo(profileDir, "");
-
-  info("Getting storage");
-
-  let storage = getLocalStorage(getPrincipal(url));
-
-  info("Verifying data");
-
-  ok(storage.getItem("key0") == null, "Correct value");
-  ok(storage.getItem("key1") == null, "Correct value");
-  ok(storage.getItem("key2") == "value2", "Correct value");
+  verifyData([]);
 
   finishTest();
 }
new file mode 100644
--- /dev/null
+++ b/dom/localstorage/test/unit/test_databaseShadowing_clearOrigin1.js
@@ -0,0 +1,34 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var testGenerator = testSteps();
+
+loadSubscript("databaseShadowing-shared.js");
+
+function* testSteps()
+{
+  enableNextGenLocalStorage();
+
+  storeData();
+
+  verifyData([]);
+
+  let principal = getPrincipal("http://origin.test", {});
+  clearOrigin(principal, "default", continueToNextStepSync);
+  yield undefined;
+
+  verifyData([1]);
+
+  // Wait for all database connections to close.
+  reset(continueToNextStepSync);
+  yield undefined;
+
+  exportShadowDatabase("shadowdb_clearedOrigin.sqlite");
+
+  // The shadow database is now prepared for
+  // test_databaseShadowing_clearOrigin2.js
+
+  finishTest();
+}
new file mode 100644
--- /dev/null
+++ b/dom/localstorage/test/unit/test_databaseShadowing_clearOrigin2.js
@@ -0,0 +1,24 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var testGenerator = testSteps();
+
+loadSubscript("databaseShadowing-shared.js");
+
+function* testSteps()
+{
+  // The shadow database was prepared in test_databaseShadowing_clearOrigin1.js
+
+  disableNextGenLocalStorage();
+
+  if (!importShadowDatabase("shadowdb-clearedOrigin.sqlite")) {
+    finishTest();
+    return;
+  }
+
+  verifyData([1]);
+
+  finishTest();
+}
new file mode 100644
--- /dev/null
+++ b/dom/localstorage/test/unit/test_databaseShadowing_clearOriginsByPattern1.js
@@ -0,0 +1,34 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var testGenerator = testSteps();
+
+loadSubscript("databaseShadowing-shared.js");
+
+function* testSteps()
+{
+  enableNextGenLocalStorage();
+
+  storeData();
+
+  verifyData([]);
+
+  clearOriginsByPattern(JSON.stringify({ userContextId: 15 }),
+                        continueToNextStepSync);
+  yield undefined;
+
+  verifyData([4,5,6]);
+
+  // Wait for all database connections to close.
+  reset(continueToNextStepSync);
+  yield undefined;
+
+  exportShadowDatabase("shadowdb-clearedOriginsByPattern.sqlite");
+
+  // The shadow database is now prepared for
+  // test_databaseShadowing_clearOriginsByPattern2.js
+
+  finishTest();
+}
new file mode 100644
--- /dev/null
+++ b/dom/localstorage/test/unit/test_databaseShadowing_clearOriginsByPattern2.js
@@ -0,0 +1,25 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var testGenerator = testSteps();
+
+loadSubscript("databaseShadowing-shared.js");
+
+function* testSteps()
+{
+  // The shadow database was prepared in
+  // test_databaseShadowing_clearOriginsByPattern1.js
+
+  disableNextGenLocalStorage();
+
+  if (!importShadowDatabase("shadowdb-clearedOriginsByPattern.sqlite")) {
+    finishTest();
+    return;
+  }
+
+  verifyData([4,5,6]);
+
+  finishTest();
+}
new file mode 100644
--- /dev/null
+++ b/dom/localstorage/test/unit/test_databaseShadowing_clearOriginsByPrefix1.js
@@ -0,0 +1,32 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var testGenerator = testSteps();
+
+loadSubscript("databaseShadowing-shared.js");
+
+function* testSteps()
+{
+  enableNextGenLocalStorage();
+
+  storeData();
+
+  verifyData([]);
+
+  let principal = getPrincipal("http://prefix.test", {});
+  clearOriginsByPrefix(principal, "default", continueToNextStepSync);
+  yield undefined;
+
+  // Wait for all database connections to close.
+  reset(continueToNextStepSync);
+  yield undefined;
+
+  exportShadowDatabase("shadowdb-clearedOriginsByPrefix.sqlite");
+
+  // The shadow database is now prepared for
+  // test_databaseShadowing_clearOriginsByPrefix2.js
+
+  finishTest();
+}
new file mode 100644
--- /dev/null
+++ b/dom/localstorage/test/unit/test_databaseShadowing_clearOriginsByPrefix2.js
@@ -0,0 +1,25 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var testGenerator = testSteps();
+
+loadSubscript("databaseShadowing-shared.js");
+
+function* testSteps()
+{
+  // The shadow database was prepared in
+  // test_databaseShadowing_clearOriginsByPrefix1.js
+
+  disableNextGenLocalStorage();
+
+  if (!importShadowDatabase("shadowdb-clearedOriginsByPrefix.sqlite")) {
+    finishTest();
+    return;
+  }
+
+  verifyData([2,3]);
+
+  finishTest();
+}
--- a/dom/localstorage/test/unit/test_migration.js
+++ b/dom/localstorage/test/unit/test_migration.js
@@ -6,52 +6,125 @@
 var testGenerator = testSteps();
 
 function* testSteps()
 {
   const principalInfos = [
     { url: "http://localhost", attrs: {} },
     { url: "http://www.mozilla.org", attrs: {} },
     { url: "http://example.com", attrs: {} },
-    { url: "http://example.org", attrs: { userContextId: 5 } }
+    { url: "http://example.org", attrs: { userContextId: 5 } },
+
+    { url: "http://origin.test", attrs: {} },
+
+    { url: "http://prefix.test", attrs: {} },
+    { url: "http://prefix.test", attrs: { userContextId: 10 } },
+
+    { url: "http://pattern.test", attrs: { userContextId: 15 } },
+    { url: "http://pattern.test:8080", attrs: { userContextId: 15 } },
+    { url: "https://pattern.test", attrs: { userContextId: 15 } },
   ];
 
   const data = {
     key: "foo",
     value: "bar"
   };
 
+  function verifyData(clearedOrigins) {
+    info("Getting storages");
+
+    let storages = [];
+    for (let i = 0; i < principalInfos.length; i++) {
+      let principalInfo = principalInfos[i];
+      let principal = getPrincipal(principalInfo.url, principalInfo.attrs);
+      let storage = getLocalStorage(principal);
+      storages.push(storage);
+    }
+
+    info("Verifying data");
+
+    for (let i = 0; i < storages.length; i++) {
+      let value = storages[i].getItem(data.key + i);
+      if (clearedOrigins.includes(i)) {
+        is(value, null, "Correct value");
+      } else {
+        is(value, data.value + i, "Correct value");
+      }
+    }
+  }
+
   info("Setting pref");
 
   Services.prefs.setBoolPref("dom.storage.next_gen", true);
 
+  info("Stage 1 - Testing archived data migration");
+
   info("Clearing");
 
   clear(continueToNextStepSync);
   yield undefined;
 
   info("Installing package");
 
   // The profile contains storage.sqlite and webappsstore.sqlite. The file
   // create_db.js in the package was run locally, specifically it was
   // temporarily added to xpcshell.ini and then executed:
   // mach xpcshell-test --interactive dom/localstorage/test/unit/create_db.js
   installPackage("migration_profile");
 
-  info("Getting storages");
+  verifyData([]);
+
+  info("Stage 2 - Testing archived data clearing");
+
+  for (let type of ["origin", "prefix", "pattern"]) {
+    info("Clearing");
+
+    clear(continueToNextStepSync);
+    yield undefined;
+
+    info("Installing package");
+
+    // See the comment for the first installPackage() call.
+    installPackage("migration_profile");
+
+    let clearedOrigins = [];
+
+    switch (type) {
+      case "origin": {
+        let principal = getPrincipal("http://origin.test", {});
+        clearOrigin(principal, "default", continueToNextStepSync);
+        yield undefined;
+
+        clearedOrigins.push(4);
 
-  let storages = [];
-  for (let i = 0; i < principalInfos.length; i++) {
-    let principalInfo = principalInfos[i];
-    let principal = getPrincipal(principalInfo.url, principalInfo.attrs);
-    let storage = getLocalStorage(principal);
-    storages.push(storage);
-  }
+        break;
+      }
+
+      case "prefix": {
+        let principal = getPrincipal("http://prefix.test", {});
+        clearOriginsByPrefix(principal, "default", continueToNextStepSync);
+        yield undefined;
+
+        clearedOrigins.push(5, 6);
+
+        break;
+      }
 
-  info("Verifying data");
+      case "pattern": {
+        clearOriginsByPattern(JSON.stringify({ userContextId: 15 }),
+                              continueToNextStepSync);
+        yield undefined;
+
+        clearedOrigins.push(7, 8, 9);
 
-  for (let i = 0; i < storages.length; i++) {
-    let value = storages[i].getItem(data.key + i);
-    is(value, data.value + i, "Correct value");
+        break;
+      }
+
+      default: {
+        throw("Unknown type: " + type);
+      }
+    }
+
+    verifyData(clearedOrigins);
   }
 
   finishTest();
 }
--- a/dom/localstorage/test/unit/xpcshell.ini
+++ b/dom/localstorage/test/unit/xpcshell.ini
@@ -8,12 +8,24 @@ support-files =
   archive_profile.zip
   migration_profile.zip
 
 [test_archive.js]
 [test_databaseShadowing1.js]
 run-sequentially = test_databaseShadowing2.js depends on a file produced by this test
 [test_databaseShadowing2.js]
 run-sequentially = this test depends on a file produced by test_databaseShadowing1.js
+[test_databaseShadowing_clearOrigin1.js]
+run-sequentially = test_databaseShadowing_clearOrigin2.js depends on a file produced by this test
+[test_databaseShadowing_clearOrigin2.js]
+run-sequentially = this test depends on a file produced by test_databaseShadowing_clearOrigin1.js
+[test_databaseShadowing_clearOriginsByPattern1.js]
+run-sequentially = test_databaseShadowing_clearOriginsByPattern2.js depends on a file produced by this test
+[test_databaseShadowing_clearOriginsByPattern2.js]
+run-sequentially = this test depends on a file produced by test_databaseShadowing_clearOriginsByPattern1.js
+[test_databaseShadowing_clearOriginsByPrefix1.js]
+run-sequentially = test_databaseShadowing_clearOriginsByPrefix2.js depends on a file produced by this test
+[test_databaseShadowing_clearOriginsByPrefix2.js]
+run-sequentially = this test depends on a file produced by test_databaseShadowing_clearOriginsByPrefix1.js
 [test_eviction.js]
 [test_groupLimit.js]
 [test_migration.js]
 [test_snapshotting.js]