Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/toolkit/components/extensions/test/xpcshell/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 17 kB image not shown  

Quelle  head.js   Sprache: JAVA

 
"use strict";
/* exported createHttpServer, cleanupDir, clearCache, optionalPermissionsPromptHandler, promiseConsoleOutput,
            promiseQuotaManagerServiceReset, promiseQuotaManagerServiceClear,
            runWithPrefs, testEnv, withHandlingUserInput, resetHandlingUserInput,
            assertPersistentListeners, promiseExtensionEvent, assertHasPersistedScriptsCachedFlag,
            assertIsPersistedScriptsCachedFlag,
            setup_crash_reporter_override_and_cleaner, crashFrame, crashExtensionBackground,
            makeRkvDatabaseDir
*/


var { AppConstants } = ChromeUtils.importESModule(
  "resource://gre/modules/AppConstants.sys.mjs"
);
var { XPCOMUtils } = ChromeUtils.importESModule(
  "resource://gre/modules/XPCOMUtils.sys.mjs"
);
var {
  clearInterval,
  clearTimeout,
  setInterval,
  setIntervalWithTarget,
  setTimeout,
  setTimeoutWithTarget,
} = ChromeUtils.importESModule("resource://gre/modules/Timer.sys.mjs");
var { AddonTestUtils, MockAsyncShutdown } = ChromeUtils.importESModule(
  "resource://testing-common/AddonTestUtils.sys.mjs"
);

ChromeUtils.defineESModuleGetters(this, {
  ContentTask: "resource://testing-common/ContentTask.sys.mjs",
  Extension: "resource://gre/modules/Extension.sys.mjs",
  ExtensionData: "resource://gre/modules/Extension.sys.mjs",
  ExtensionParent: "resource://gre/modules/ExtensionParent.sys.mjs",
  ExtensionTestUtils:
    "resource://testing-common/ExtensionXPCShellUtils.sys.mjs",
  FileUtils: "resource://gre/modules/FileUtils.sys.mjs",
  Management: "resource://gre/modules/Extension.sys.mjs",
  MessageChannel: "resource://testing-common/MessageChannel.sys.mjs",
  MockRegistrar: "resource://testing-common/MockRegistrar.sys.mjs",
  NetUtil: "resource://gre/modules/NetUtil.sys.mjs",
  PromiseTestUtils: "resource://testing-common/PromiseTestUtils.sys.mjs",
  Schemas: "resource://gre/modules/Schemas.sys.mjs",
  TestUtils: "resource://testing-common/TestUtils.sys.mjs",
});

PromiseTestUtils.allowMatchingRejectionsGlobally(
  /Message manager disconnected/
);

// Persistent Listener test functionality
const { assertPersistentListeners } = ExtensionTestUtils.testAssertions;

// https_first automatically upgrades http to https, but the tests are not
// designed to expect that. And it is not easy to change that because
// nsHttpServer does not support https (bug 1742061). So disable https_first.
Services.prefs.setBoolPref("dom.security.https_first"false);

// These values may be changed in later head files and tested in check_remote
// below.
Services.prefs.setBoolPref("extensions.webextensions.remote"false);
const testEnv = {
  expectRemote: false,
};

add_setup(function check_remote() {
  Assert.equal(
    WebExtensionPolicy.useRemoteWebExtensions,
    testEnv.expectRemote,
    "useRemoteWebExtensions matches"
  );
  Assert.equal(
    WebExtensionPolicy.isExtensionProcess,
    !testEnv.expectRemote,
    "testing from extension process"
  );
});

ExtensionTestUtils.init(this);

var createHttpServer = (...args) => {
  AddonTestUtils.maybeInit(this);
  return AddonTestUtils.createHttpServer(...args);
};

async function makeRkvDatabaseDir(name, { mockCorrupted = false } = {}) {
  const databaseDir = PathUtils.join(PathUtils.profileDir, name);
  await IOUtils.makeDirectory(databaseDir);
  if (mockCorrupted) {
    // Mock a corrupted db.
    await IOUtils.write(
      PathUtils.join(databaseDir, "data.safe.bin"),
      new Uint8Array([0x00, 0x00, 0x00, 0x00])
    );
  }
  return databaseDir;
}

// Some tests load non-moz-extension:-URLs in their extension document. When
// extensions run in-process (extensions.webextensions.remote set to false),
// that fails.
// For details, see: https://bugzilla.mozilla.org/show_bug.cgi?id=1724099
// To avoid skip-if on the whole file, use this:
//
//   add_task(async function test_description_here() {
//     // Comment explaining why.
//     allow_unsafe_parent_loads_when_extensions_not_remote();
//     ...
//     revert_allow_unsafe_parent_loads_when_extensions_not_remote();
//   });
var private_upl_cleanup_handlers = [];
function allow_unsafe_parent_loads_when_extensions_not_remote() {
  if (WebExtensionPolicy.useRemoteWebExtensions) {
    // We should only allow remote iframes in the main process.
    return;
  }
  if (!Cu.isInAutomation) {
    // isInAutomation is false by default in xpcshell (bug 1598804). Flip pref.
    Services.prefs.setBoolPref(
      "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer",
      true
    );
    private_upl_cleanup_handlers.push(() => {
      Services.prefs.setBoolPref(
        "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer",
        false
      );
    });
    // Sanity check: Fail immediately if setting the above pref does somehow
    // not flip the isInAutomation flag.
    if (!Cu.isInAutomation) {
      // This condition is unexpected, because it is enforced at:
      // https://searchfox.org/mozilla-central/rev/ea65de7c/js/xpconnect/src/xpcpublic.h#753-759
      throw new Error("Failed to set isInAutomation to true");
    }
  }
  // Note: The following pref requires the isInAutomation flag to be set.
  // When unset, the pref is ignored, and tests would encounter bug 1724099.
  if (!Services.prefs.getBoolPref("security.allow_unsafe_parent_loads")) {
    info("Setting pref security.allow_unsafe_parent_loads to true");
    Services.prefs.setBoolPref("security.allow_unsafe_parent_loads"true);
    private_upl_cleanup_handlers.push(() => {
      info("Reverting pref security.allow_unsafe_parent_loads to false");
      Services.prefs.setBoolPref("security.allow_unsafe_parent_loads"false);
    });
  }

  registerCleanupFunction(
    // eslint-disable-next-line no-use-before-define
    revert_allow_unsafe_parent_loads_when_extensions_not_remote
  );
}

function revert_allow_unsafe_parent_loads_when_extensions_not_remote() {
  for (let revert of private_upl_cleanup_handlers.splice(0)) {
    revert();
  }
}

/**
 * Clears the HTTP and content image caches.
 */

function clearCache() {
  Services.cache2.clear();

  let imageCache = Cc["@mozilla.org/image/tools;1"]
    .getService(Ci.imgITools)
    .getImgCacheForDocument(null);
  imageCache.clearCache(false);
}

var promiseConsoleOutput = async function (task) {
  const DONE = `=== console listener ${Math.random()} done ===`;

  let listener;
  let messages = [];
  let awaitListener = new Promise(resolve => {
    listener = msg => {
      if (msg == DONE) {
        resolve();
      } else {
        void (msg instanceof Ci.nsIConsoleMessage);
        void (msg instanceof Ci.nsIScriptError);
        messages.push(msg);
      }
    };
  });

  Services.console.registerListener(listener);
  try {
    let result = await task();

    Services.console.logStringMessage(DONE);
    await awaitListener;

    return { messages, result };
  } finally {
    Services.console.unregisterListener(listener);
  }
};

// Attempt to remove a directory.  If the Windows OS is still using the
// file sometimes remove() will fail.  So try repeatedly until we can
// remove it or we give up.
function cleanupDir(dir) {
  let count = 0;
  return new Promise((resolve, reject) => {
    function tryToRemoveDir() {
      count += 1;
      try {
        dir.remove(true);
      } catch (e) {
        // ignore
      }
      if (!dir.exists()) {
        return resolve();
      }
      if (count >= 25) {
        return reject(`Failed to cleanup directory: ${dir}`);
      }
      setTimeout(tryToRemoveDir, 100);
    }
    tryToRemoveDir();
  });
}

// Run a test with the specified preferences and then restores their initial values
// right after the test function run (whether it passes or fails).
async function runWithPrefs(prefsToSet, testFn) {
  const setPrefs = prefs => {
    for (let [pref, value] of prefs) {
      if (value === undefined) {
        // Clear any pref that didn't have a user value.
        info(`Clearing pref "${pref}"`);
        Services.prefs.clearUserPref(pref);
        continue;
      }

      info(`Setting pref "${pref}": ${value}`);
      switch (typeof value) {
        case "boolean":
          Services.prefs.setBoolPref(pref, value);
          break;
        case "number":
          Services.prefs.setIntPref(pref, value);
          break;
        case "string":
          Services.prefs.setStringPref(pref, value);
          break;
        default:
          throw new Error("runWithPrefs doesn't support this pref type yet");
      }
    }
  };

  const getPrefs = prefs => {
    return prefs.map(([pref, value]) => {
      info(`Getting initial pref value for "${pref}"`);
      if (!Services.prefs.prefHasUserValue(pref)) {
        // Check if the pref doesn't have a user value.
        return [pref, undefined];
      }
      switch (typeof value) {
        case "boolean":
          return [pref, Services.prefs.getBoolPref(pref)];
        case "number":
          return [pref, Services.prefs.getIntPref(pref)];
        case "string":
          return [pref, Services.prefs.getStringPref(pref)];
        default:
          throw new Error("runWithPrefs doesn't support this pref type yet");
      }
    });
  };

  let initialPrefsValues = [];

  try {
    initialPrefsValues = getPrefs(prefsToSet);

    setPrefs(prefsToSet);

    await testFn();
  } finally {
    info("Restoring initial preferences values on exit");
    setPrefs(initialPrefsValues);
  }
}

// "Handling User Input" test helpers.

let extensionHandlers = new WeakSet();

function handlingUserInputFrameScript() {
  /* globals content */
  // eslint-disable-next-line no-shadow
  const { MessageChannel } = ChromeUtils.importESModule(
    "resource://testing-common/MessageChannel.sys.mjs"
  );

  let handle;
  MessageChannel.addListener(this"ExtensionTest:HandleUserInput", {
    receiveMessage({ data }) {
      if (data) {
        handle = content.windowUtils.setHandlingUserInput(true);
      } else if (handle) {
        handle.destruct();
        handle = null;
      }
    },
  });
}

// If you use withHandlingUserInput then restart the addon manager,
// you need to reset this before using withHandlingUserInput again.
function resetHandlingUserInput() {
  extensionHandlers = new WeakSet();
}

async function withHandlingUserInput(extension, fn) {
  let { messageManager } = extension.extension.groupFrameLoader;

  if (!extensionHandlers.has(extension)) {
    messageManager.loadFrameScript(
      `data:,(${encodeURI(handlingUserInputFrameScript)}).call(this)`,
      false,
      true
    );
    extensionHandlers.add(extension);
  }

  await MessageChannel.sendMessage(
    messageManager,
    "ExtensionTest:HandleUserInput",
    true
  );
  await fn();
  await MessageChannel.sendMessage(
    messageManager,
    "ExtensionTest:HandleUserInput",
    false
  );
}

// QuotaManagerService test helpers.

function promiseQuotaManagerServiceReset() {
  info("Calling QuotaManagerService.reset to enforce new test storage limits");
  return new Promise(resolve => {
    Services.qms.reset().callback = resolve;
  });
}

function promiseQuotaManagerServiceClear() {
  info(
    "Calling QuotaManagerService.clear to empty the test data and refresh test storage limits"
  );
  return new Promise(resolve => {
    Services.qms.clear().callback = resolve;
  });
}

// Optional Permission prompt handling
const optionalPermissionsPromptHandler = {
  sawPrompt: false,
  acceptPrompt: false,

  init() {
    Services.prefs.setBoolPref(
      "extensions.webextOptionalPermissionPrompts",
      true
    );
    Services.obs.addObserver(this"webextension-optional-permission-prompt");
    registerCleanupFunction(() => {
      Services.obs.removeObserver(
        this,
        "webextension-optional-permission-prompt"
      );
      Services.prefs.clearUserPref(
        "extensions.webextOptionalPermissionPrompts"
      );
    });
  },

  observe(subject, topic) {
    if (topic == "webextension-optional-permission-prompt") {
      this.sawPrompt = true;
      let { resolve } = subject.wrappedJSObject;
      resolve(this.acceptPrompt);
    }
  },
};

function promiseExtensionEvent(wrapper, event) {
  return new Promise(resolve => {
    wrapper.extension.once(event, (...args) => resolve(args));
  });
}

async function assertHasPersistedScriptsCachedFlag(ext) {
  Assert.notEqual(ext.id, null"Expect a non-null extension id");
  Assert.notEqual(ext.version, null"Expect a non-null extension version");
  const { StartupCache } = ExtensionParent;
  const allCachedGeneral = StartupCache._data.get("general");
  equal(
    allCachedGeneral
      .get(ext.id)
      ?.get(ext.version)
      ?.get("scripting")
      ?.has("hasPersistedScripts"),
    true,
    "Expect the StartupCache to include hasPersistedScripts flag"
  );
}

async function assertIsPersistentScriptsCachedFlag(ext, expectedValue) {
  Assert.notEqual(ext.id, null"Expect a non-null extension id");
  Assert.notEqual(ext.version, null"Expect a non-null extension version");
  const { StartupCache } = ExtensionParent;
  const allCachedGeneral = StartupCache._data.get("general");
  equal(
    allCachedGeneral
      .get(ext.id)
      ?.get(ext.version)
      ?.get("scripting")
      ?.get("hasPersistedScripts"),
    expectedValue,
    "Expected cached value set on hasPersistedScripts flag"
  );
}

function setup_crash_reporter_override_and_cleaner() {
  const crashIds = [];
  // Override CrashService.sys.mjs to intercept crash dumps, for two reasons:
  //
  // - The standard CrashService.sys.mjs implementation uses nsICrashReporter
  //   through Services.appinfo. Because appinfo has been overridden with an
  //   incomplete implementation, a promise rejection is triggered when a
  //   missing method is called at https://searchfox.org/mozilla-central/rev/c615dc4db129ece5cce6c96eb8cab8c5a3e26ac3/toolkit/components/crashes/CrashService.sys.mjs#183
  //
  // - We want to intercept the generated crash dumps for expected crashes and
  //   remove them, to prevent the xpcshell test runner from misinterpreting
  //   them as "CRASH" failures.
  let mockClassId = MockRegistrar.register("@mozilla.org/crashservice;1", {
    addCrash(processType, crashType, id) {
      // The files are ready to be removed now. We however postpone cleanup
      // until the end of the test, to minimize noise during the test, and to
      // ensure that the cleanup completes fully.
      crashIds.push(id);
    },
    QueryInterface: ChromeUtils.generateQI(["nsICrashService"]),
  });
  registerCleanupFunction(async () => {
    MockRegistrar.unregister(mockClassId);

    // Cannot use Services.appinfo because createAppInfo overrides it.
    // eslint-disable-next-line mozilla/use-services
    const appinfo = Cc["@mozilla.org/toolkit/crash-reporter;1"].getService(
      Ci.nsICrashReporter
    );

    info(`Observed ${crashIds.length} crash dump(s).`);
    let deletedCount = 0;
    for (let id of crashIds) {
      info(`Checking whether dumpID ${id} should be removed`);
      let minidumpFile = appinfo.getMinidumpForID(id);
      let extraFile = appinfo.getExtraFileForID(id);
      let extra;
      try {
        extra = await IOUtils.readJSON(extraFile.path);
      } catch (e) {
        info(`Cannot parse crash metadata from ${extraFile.path} :: ${e}\n`);
        continue;
      }
      // The "BrowserTestUtils:CrashFrame" handler annotates the crash
      // report before triggering a crash.
      if (extra.TestKey !== "CrashFrame") {
        info(`Keeping ${minidumpFile.path}; we did not trigger the crash`);
        continue;
      }
      info(`Deleting minidump ${minidumpFile.path} and ${extraFile.path}`);
      minidumpFile.remove(false);
      extraFile.remove(false);
      ++deletedCount;
    }
    info(`Removed ${deletedCount} crash dumps out of ${crashIds.length}`);
  });
}

// Crashes a <browser>'s remote process.
// Based on BrowserTestUtils.crashFrame.
function crashFrame(browser) {
  if (!browser.isRemoteBrowser) {
    // The browser should be remote, or the test runner would be killed.
    throw new Error(" must be remote");
  }

  const { BrowserTestUtils } = ChromeUtils.importESModule(
    "resource://testing-common/BrowserTestUtils.sys.mjs"
  );

  // Trigger crash by sending a message to BrowserTestUtils actor.
  BrowserTestUtils.sendAsyncMessage(
    browser.browsingContext,
    "BrowserTestUtils:CrashFrame",
    {}
  );
}

/**
 * Crash background page of browser and wait for the crash to have been
 * detected and processed by ext-backgroundPage.js.
 *
 * @param {ExtensionWrapper} extension
 * @param {XULElement} [bgBrowser] - The background browser. Optional, but must
 *   be set if the background's ProxyContextParent has not been initialized yet.
 */

async function crashExtensionBackground(extension, bgBrowser) {
  bgBrowser ??= extension.extension.backgroundContext.xulBrowser;

  let byeProm = promiseExtensionEvent(extension, "shutdown-background-script");
  if (WebExtensionPolicy.useRemoteWebExtensions) {
    info("Killing background page through process crash.");
    crashFrame(bgBrowser);
  } else {
    // If extensions are not running in out-of-process mode, then the
    // non-remote process should not be killed (or the test runner dies).
    // Remove <browser> instead, to simulate the immediate disconnection
    // of the message manager (that would happen if the process crashed).
    info("Closing background page by destroying .");

    if (extension.extension.backgroundState === "running") {
      // TODO bug 1844217: remove this whole if-block When close() is hooked up
      // to setBgStateStopped. It currently is not, and browser destruction is
      // currently not detected by the implementation.
      let messageManager = bgBrowser.messageManager;
      TestUtils.topicObserved(
        "message-manager-close",
        subject => subject === messageManager
      ).then(() => {
        Management.emit("extension-process-crash", { childID: 1337 });
      });
    }
    bgBrowser.remove();
  }

  info("Waiting for crash to be detected by the internals");
  await byeProm;
}

Messung V0.5
C=90 H=98 G=94

¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.