Commit 637ec703 authored by Harshit Sohaney's avatar Harshit Sohaney
Browse files

Bug 1907783 - Use the new clear on shutdown branch to prevent losing pending...

Bug 1907783 - Use the new clear on shutdown branch to prevent losing pending shutdown items on unexpected shutdown. r=pbz,places-reviewers,Standard8, a=dmeehan

Differential Revision: https://phabricator.services.mozilla.com/D216616
parent c5ec0851
Loading
Loading
Loading
Loading
+181 −0
Original line number Diff line number Diff line
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */

/**
 * Tests that requesting clear history at shutdown will really clear history.
 */

const URIS = [
  "http://a.example1.com/",
  "http://b.example1.com/",
  "http://b.example2.com/",
  "http://c.example3.com/",
];

const FTP_URL = "ftp://localhost/clearHistoryOnShutdown/";

const { Sanitizer } = ChromeUtils.importESModule(
  "resource:///modules/Sanitizer.sys.mjs"
);

// Send the profile-after-change notification to the form history component to ensure
// that it has been initialized.
var formHistoryStartup = Cc[
  "@mozilla.org/satchel/form-history-startup;1"
].getService(Ci.nsIObserver);
formHistoryStartup.observe(null, "profile-after-change", null);
ChromeUtils.defineESModuleGetters(this, {
  FormHistory: "resource://gre/modules/FormHistory.sys.mjs",
});

var timeInMicroseconds = Date.now() * 1000;

add_task(async function test_execute() {
  info("Initialize browserglue before Places");

  // Avoid default bookmarks import.
  let glue = Cc["@mozilla.org/browser/browserglue;1"].getService(
    Ci.nsIObserver
  );
  glue.observe(null, "initial-migration-will-import-default-bookmarks", null);
  Sanitizer.onStartup();

  Services.prefs.setBoolPref(Sanitizer.PREF_SHUTDOWN_BRANCH + "cache", true);
  Services.prefs.setBoolPref(
    Sanitizer.PREF_SHUTDOWN_BRANCH + "cookiesAndStorage",
    true
  );
  Services.prefs.setBoolPref(
    Sanitizer.PREF_SHUTDOWN_BRANCH + "historyFormDataAndDownloads",
    true
  );
  Services.prefs.setBoolPref(
    Sanitizer.PREF_SHUTDOWN_BRANCH + "cookiesAndStorage",
    true
  );
  Services.prefs.setBoolPref(
    Sanitizer.PREF_SHUTDOWN_BRANCH + "siteSettings",
    true
  );

  Services.prefs.setBoolPref(Sanitizer.PREF_SANITIZE_ON_SHUTDOWN, true);

  info("Add visits.");
  for (let aUrl of URIS) {
    await PlacesTestUtils.addVisits({
      uri: uri(aUrl),
      visitDate: timeInMicroseconds++,
      transition: PlacesUtils.history.TRANSITION_TYPED,
    });
  }
  info("Add cache.");
  await storeCache(FTP_URL, "testData");
  info("Add form history.");
  await addFormHistory();
  Assert.equal(await getFormHistoryCount(), 1, "Added form history");

  info("Simulate and wait shutdown.");
  await shutdownPlaces();

  Assert.equal(await getFormHistoryCount(), 0, "Form history cleared");

  let stmt = DBConn(true).createStatement(
    "SELECT id FROM moz_places WHERE url = :page_url "
  );

  try {
    URIS.forEach(function (aUrl) {
      stmt.params.page_url = aUrl;
      Assert.ok(!stmt.executeStep());
      stmt.reset();
    });
  } finally {
    stmt.finalize();
  }

  info("Check cache");
  // Check cache.
  await checkCache(FTP_URL);
});

function addFormHistory() {
  let now = Date.now() * 1000;
  return FormHistory.update({
    op: "add",
    fieldname: "testfield",
    value: "test",
    timesUsed: 1,
    firstUsed: now,
    lastUsed: now,
  });
}

async function getFormHistoryCount() {
  return FormHistory.count({ fieldname: "testfield" });
}

function storeCache(aURL, aContent) {
  let cache = Services.cache2;
  let storage = cache.diskCacheStorage(Services.loadContextInfo.default);

  return new Promise(resolve => {
    let storeCacheListener = {
      onCacheEntryCheck() {
        return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED;
      },

      onCacheEntryAvailable(entry, isnew, status) {
        Assert.equal(status, Cr.NS_OK);

        entry.setMetaDataElement("servertype", "0");
        var os = entry.openOutputStream(0, -1);

        var written = os.write(aContent, aContent.length);
        if (written != aContent.length) {
          do_throw(
            "os.write has not written all data!\n" +
              "  Expected: " +
              written +
              "\n" +
              "  Actual: " +
              aContent.length +
              "\n"
          );
        }
        os.close();
        resolve();
      },
    };

    storage.asyncOpenURI(
      Services.io.newURI(aURL),
      "",
      Ci.nsICacheStorage.OPEN_NORMALLY,
      storeCacheListener
    );
  });
}

function checkCache(aURL) {
  let cache = Services.cache2;
  let storage = cache.diskCacheStorage(Services.loadContextInfo.default);

  return new Promise(resolve => {
    let checkCacheListener = {
      onCacheEntryAvailable(entry, isnew, status) {
        Assert.equal(status, Cr.NS_ERROR_CACHE_KEY_NOT_FOUND);
        resolve();
      },
    };

    storage.asyncOpenURI(
      Services.io.newURI(aURL),
      "",
      Ci.nsICacheStorage.OPEN_READONLY,
      checkCacheListener
    );
  });
}
+4 −0
Original line number Diff line number Diff line
@@ -32,6 +32,10 @@ support-files = [
["test_browserGlue_restore.js"]

["test_clearHistory_shutdown.js"]
prefs = ["privacy.sanitize.useOldClearHistoryDialog=true"]

["test_clearHistory_shutdown_v2.js"]
prefs = ["privacy.sanitize.useOldClearHistoryDialog=false"]

["test_interactions_blocklist.js"]

+13 −6
Original line number Diff line number Diff line
@@ -58,8 +58,15 @@ export var Sanitizer = {
   * Pref branches to fetch sanitization options from.
   */
  PREF_CPD_BRANCH: "privacy.cpd.",
  PREF_SHUTDOWN_BRANCH: "privacy.clearOnShutdown.",
  PREF_SHUTDOWN_V2_BRANCH: "privacy.clearOnShutdown_v2.",
  /*
   * We need to choose between two branches for shutdown since there are separate prefs for the new
   * clear history dialog
   */
  get PREF_SHUTDOWN_BRANCH() {
    return lazy.useOldClearHistoryDialog
      ? "privacy.clearOnShutdown."
      : "privacy.clearOnShutdown_v2.";
  },

  /**
   * The fallback timestamp used when no argument is given to
@@ -1119,10 +1126,10 @@ async function sanitizeOnShutdown(progress) {
  if (Sanitizer.shouldSanitizeOnShutdown) {
    // Need to sanitize upon shutdown
    progress.advancement = "shutdown-cleaner";
    let shutdownBranch = lazy.useOldClearHistoryDialog
      ? Sanitizer.PREF_SHUTDOWN_BRANCH
      : Sanitizer.PREF_SHUTDOWN_V2_BRANCH;
    let itemsToClear = getItemsToClearFromPrefBranch(shutdownBranch);

    let itemsToClear = getItemsToClearFromPrefBranch(
      Sanitizer.PREF_SHUTDOWN_BRANCH
    );
    await Sanitizer.sanitize(itemsToClear, { progress });

    // We didn't crash during shutdown sanitization, so annotate it to avoid
+144 −0
Original line number Diff line number Diff line
/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

do_get_profile();

// Test that interrupted sanitizations are properly tracked.

add_task(async function () {
  const { Sanitizer } = ChromeUtils.importESModule(
    "resource:///modules/Sanitizer.sys.mjs"
  );

  Services.prefs.setBoolPref(Sanitizer.PREF_NEWTAB_SEGREGATION, false);

  registerCleanupFunction(() => {
    Services.prefs.clearUserPref(Sanitizer.PREF_SANITIZE_ON_SHUTDOWN);
    Services.prefs.clearUserPref(
      Sanitizer.PREF_SHUTDOWN_BRANCH + "cookiesAndStorage"
    );
    Services.prefs.clearUserPref(Sanitizer.PREF_NEWTAB_SEGREGATION);
  });
  Services.prefs.setBoolPref(Sanitizer.PREF_SANITIZE_ON_SHUTDOWN, true);
  Services.prefs.setBoolPref(
    Sanitizer.PREF_SHUTDOWN_BRANCH + "cookiesAndStorage",
    true
  );

  await Sanitizer.onStartup();
  Assert.ok(Sanitizer.shouldSanitizeOnShutdown, "Should sanitize on shutdown");

  let pendingSanitizations = JSON.parse(
    Services.prefs.getStringPref(Sanitizer.PREF_PENDING_SANITIZATIONS, "[]")
  );
  Assert.equal(
    pendingSanitizations.length,
    1,
    "Should have 1 pending sanitization"
  );
  Assert.equal(
    pendingSanitizations[0].id,
    "shutdown",
    "Should be the shutdown sanitization"
  );
  Assert.ok(
    pendingSanitizations[0].itemsToClear.includes("cookiesAndStorage"),
    "Pref has been setup"
  );
  Assert.ok(
    !pendingSanitizations[0].options.isShutdown,
    "Shutdown option is not present"
  );

  // Check the preference listeners.
  Services.prefs.setBoolPref(Sanitizer.PREF_SANITIZE_ON_SHUTDOWN, false);
  pendingSanitizations = JSON.parse(
    Services.prefs.getStringPref(Sanitizer.PREF_PENDING_SANITIZATIONS, "[]")
  );
  Assert.equal(
    pendingSanitizations.length,
    0,
    "Should not have pending sanitizations"
  );
  Assert.ok(
    !Sanitizer.shouldSanitizeOnShutdown,
    "Should not sanitize on shutdown"
  );
  Services.prefs.setBoolPref(Sanitizer.PREF_SANITIZE_ON_SHUTDOWN, true);
  pendingSanitizations = JSON.parse(
    Services.prefs.getStringPref(Sanitizer.PREF_PENDING_SANITIZATIONS, "[]")
  );
  Assert.equal(
    pendingSanitizations.length,
    1,
    "Should have 1 pending sanitization"
  );
  Assert.equal(
    pendingSanitizations[0].id,
    "shutdown",
    "Should be the shutdown sanitization"
  );

  Assert.ok(
    pendingSanitizations[0].itemsToClear.includes("cookiesAndStorage"),
    "Pending sanitizations should include cookiesAndStorage"
  );
  Services.prefs.setBoolPref(
    Sanitizer.PREF_SHUTDOWN_BRANCH + "cookiesAndStorage",
    false
  );
  pendingSanitizations = JSON.parse(
    Services.prefs.getStringPref(Sanitizer.PREF_PENDING_SANITIZATIONS, "[]")
  );
  Assert.equal(
    pendingSanitizations.length,
    1,
    "Should have 1 pending sanitization"
  );
  Assert.ok(
    !pendingSanitizations[0].itemsToClear.includes("cookiesAndStorage"),
    "Pending sanitizations should have been updated"
  );

  // Check a sanitization properly rebuilds the pref.
  await Sanitizer.sanitize(["cookiesAndStorage"]);
  pendingSanitizations = JSON.parse(
    Services.prefs.getStringPref(Sanitizer.PREF_PENDING_SANITIZATIONS, "[]")
  );
  Assert.equal(
    pendingSanitizations.length,
    1,
    "Should have 1 pending sanitization"
  );
  Assert.equal(
    pendingSanitizations[0].id,
    "shutdown",
    "Should be the shutdown sanitization"
  );

  // Startup should run the pending one and setup a new shutdown sanitization.
  Services.prefs.setBoolPref(
    Sanitizer.PREF_SHUTDOWN_BRANCH + "cookiesAndStorage",
    false
  );
  await Sanitizer.onStartup();
  pendingSanitizations = JSON.parse(
    Services.prefs.getStringPref(Sanitizer.PREF_PENDING_SANITIZATIONS, "[]")
  );
  Assert.equal(
    pendingSanitizations.length,
    1,
    "Should have 1 pending sanitization"
  );
  Assert.equal(
    pendingSanitizations[0].id,
    "shutdown",
    "Should be the shutdown sanitization"
  );
  Assert.ok(
    !pendingSanitizations[0].itemsToClear.includes("cookiesAndStorage"),
    "Pref has been setup"
  );
});
+4 −0
Original line number Diff line number Diff line
@@ -27,6 +27,10 @@ run-if = ["os == 'win'"] # Test of a Windows-specific feature
run-if = ["os == 'win'"] # Test of a Windows-specific feature

["test_Sanitizer_interrupted.js"]
prefs = ["privacy.sanitize.useOldClearHistoryDialog=true"]

["test_Sanitizer_interrupted_v2.js"]
prefs = ["privacy.sanitize.useOldClearHistoryDialog=false"]

["test_SiteDataManager.js"]

Loading