summaryrefslogtreecommitdiffstats
path: root/toolkit/components/telemetry/tests/unit/test_ModulesPing.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/telemetry/tests/unit/test_ModulesPing.js')
-rw-r--r--toolkit/components/telemetry/tests/unit/test_ModulesPing.js297
1 files changed, 297 insertions, 0 deletions
diff --git a/toolkit/components/telemetry/tests/unit/test_ModulesPing.js b/toolkit/components/telemetry/tests/unit/test_ModulesPing.js
new file mode 100644
index 0000000000..f533d753e9
--- /dev/null
+++ b/toolkit/components/telemetry/tests/unit/test_ModulesPing.js
@@ -0,0 +1,297 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const { ctypes } = ChromeUtils.importESModule(
+ "resource://gre/modules/ctypes.sys.mjs"
+);
+
+const MAX_NAME_LENGTH = 64;
+
+// The following libraries (except libxul) are all built from the
+// toolkit/components/telemetry/tests/modules-test.cpp file, which contains
+// instructions on how to build them.
+const libModules = ctypes.libraryName("modules-test");
+const libUnicode = ctypes.libraryName("modμles-test");
+const libLongName =
+ "lorem_ipsum_dolor_sit_amet_consectetur_adipiscing_elit_Fusce_sit_amet_tellus_non_magna_euismod_vestibulum_Vivamus_turpis_duis.dll";
+
+function chooseDLL(x86, x64, aarch64) {
+ let xpcomabi = Services.appinfo.XPCOMABI;
+ let cpu = xpcomabi.split("-")[0];
+ switch (cpu) {
+ case "aarch64":
+ return aarch64;
+ case "x86_64":
+ return x64;
+ case "x86":
+ return x86;
+ // This case only happens on Android, which gets skipped below. The previous
+ // code was returning the x86 version when testing for arm.
+ case "arm":
+ return x86;
+ default:
+ Assert.ok(false, "unexpected CPU type: " + cpu);
+ return x86;
+ }
+}
+
+const libUnicodePDB = chooseDLL(
+ "testUnicodePDB32.dll",
+ "testUnicodePDB64.dll",
+ "testUnicodePDBAArch64.dll"
+);
+const libNoPDB = chooseDLL(
+ "testNoPDB32.dll",
+ "testNoPDB64.dll",
+ "testNoPDBAArch64.dll"
+);
+const libxul = PathUtils.filename(PathUtils.xulLibraryPath);
+
+const libModulesFile = do_get_file(libModules).path;
+const libUnicodeFile = PathUtils.join(
+ PathUtils.parent(libModulesFile),
+ libUnicode
+);
+const libLongNameFile = PathUtils.join(
+ PathUtils.parent(libModulesFile),
+ libLongName
+);
+const libUnicodePDBFile = do_get_file(libUnicodePDB).path;
+const libNoPDBFile = do_get_file(libNoPDB).path;
+
+let libModulesHandle,
+ libUnicodeHandle,
+ libLongNameHandle,
+ libUnicodePDBHandle,
+ libNoPDBHandle;
+
+let expectedLibs;
+if (AppConstants.platform === "win") {
+ const version = AppConstants.MOZ_APP_VERSION.substring(
+ 0,
+ AppConstants.MOZ_APP_VERSION.indexOf(".") + 2
+ );
+
+ expectedLibs = [
+ {
+ name: libxul,
+ debugName: libxul.replace(".dll", ".pdb"),
+ version,
+ },
+ {
+ name: libModules,
+ debugName: libModules.replace(".dll", ".pdb"),
+ version,
+ },
+ {
+ name: libUnicode,
+ debugName: libModules.replace(".dll", ".pdb"),
+ version,
+ },
+ {
+ name: libLongName.substring(0, MAX_NAME_LENGTH - 1) + "…",
+ debugName: libModules.replace(".dll", ".pdb"),
+ version,
+ },
+ {
+ name: libUnicodePDB,
+ debugName: "libmodμles.pdb",
+ version: null,
+ },
+ {
+ name: libNoPDB,
+ debugName: null,
+ version: null,
+ },
+ {
+ // We choose this DLL because it's guaranteed to exist in our process and
+ // be signed on all Windows versions that we support.
+ name: "ntdll.dll",
+ // debugName changes depending on OS version and is irrelevant to this test
+ // version changes depending on OS version and is irrelevant to this test
+ certSubject: "Microsoft Windows",
+ },
+ ];
+} else {
+ expectedLibs = [
+ {
+ name: libxul,
+ debugName: libxul,
+ version: null,
+ },
+ {
+ name: libModules,
+ debugName: libModules,
+ version: null,
+ },
+ {
+ name: libUnicode,
+ debugName: libUnicode,
+ version: null,
+ },
+ {
+ name: libLongName.substring(0, MAX_NAME_LENGTH - 1) + "…",
+ debugName: libLongName.substring(0, MAX_NAME_LENGTH - 1) + "…",
+ version: null,
+ },
+ ];
+}
+
+add_task(async function setup() {
+ do_get_profile();
+
+ await IOUtils.copy(libModulesFile, libUnicodeFile);
+ await IOUtils.copy(libModulesFile, libLongNameFile);
+
+ libModulesHandle = ctypes.open(libModulesFile);
+ libUnicodeHandle = ctypes.open(libUnicodeFile);
+ libLongNameHandle = ctypes.open(libLongNameFile);
+ if (AppConstants.platform === "win") {
+ libUnicodePDBHandle = ctypes.open(libUnicodePDBFile);
+ libNoPDBHandle = ctypes.open(libNoPDBFile);
+ }
+
+ // Pretend the untrustedmodules ping has already been sent now to get it out
+ // of the way and avoid confusing the test with our PingServer receiving two
+ // pings during our test.
+ Services.prefs.setIntPref(
+ "app.update.lastUpdateTime.telemetry_untrustedmodules_ping",
+ Math.round(Date.now() / 1000)
+ );
+
+ // Force the timer to fire (using a small interval).
+ Cc["@mozilla.org/updates/timer-manager;1"]
+ .getService(Ci.nsIObserver)
+ .observe(null, "utm-test-init", "");
+ Services.prefs.setIntPref("toolkit.telemetry.modulesPing.interval", 0);
+ Services.prefs.setStringPref("app.update.url", "http://localhost");
+
+ // Start the local ping server and setup Telemetry to use it during the tests.
+ PingServer.start();
+ Services.prefs.setStringPref(
+ TelemetryUtils.Preferences.Server,
+ "http://localhost:" + PingServer.port
+ );
+});
+
+registerCleanupFunction(function () {
+ if (libModulesHandle) {
+ libModulesHandle.close();
+ }
+ if (libUnicodeHandle) {
+ libUnicodeHandle.close();
+ }
+ if (libLongNameHandle) {
+ libLongNameHandle.close();
+ }
+ if (libUnicodePDBHandle) {
+ libUnicodePDBHandle.close();
+ }
+ if (libNoPDBHandle) {
+ libNoPDBHandle.close();
+ }
+
+ return IOUtils.remove(libUnicodeFile)
+ .then(() => IOUtils.remove(libLongNameFile))
+ .then(() => PingServer.stop());
+});
+
+add_task(
+ {
+ skip_if: () => !AppConstants.MOZ_GECKO_PROFILER,
+ },
+ async function test_send_ping() {
+ await TelemetryController.testSetup();
+
+ let found = await PingServer.promiseNextPing();
+ Assert.ok(!!found, "Telemetry ping submitted.");
+ Assert.strictEqual(found.type, "modules", "Ping type is 'modules'");
+ Assert.ok(found.environment, "'modules' ping has an environment.");
+ Assert.ok(!!found.clientId, "'modules' ping has a client ID.");
+ Assert.ok(
+ !!found.payload.modules,
+ "Telemetry ping payload contains the 'modules' array."
+ );
+
+ let nameComparator;
+ if (AppConstants.platform === "win") {
+ // Do case-insensitive checking of file/module names on Windows
+ nameComparator = function (a, b) {
+ if (typeof a === "string" && typeof b === "string") {
+ return a.toLowerCase() === b.toLowerCase();
+ }
+
+ return a === b;
+ };
+ } else {
+ nameComparator = function (a, b) {
+ return a === b;
+ };
+ }
+
+ for (let lib of expectedLibs) {
+ let test_lib = found.payload.modules.find(module =>
+ nameComparator(module.name, lib.name)
+ );
+
+ Assert.ok(!!test_lib, "There is a '" + lib.name + "' module.");
+
+ if ("version" in lib) {
+ if (lib.version !== null) {
+ Assert.ok(
+ test_lib.version.startsWith(lib.version),
+ "The version of the " +
+ lib.name +
+ " module (" +
+ test_lib.version +
+ ") is correct (it starts with '" +
+ lib.version +
+ "')."
+ );
+ } else {
+ Assert.strictEqual(
+ test_lib.version,
+ null,
+ "The version of the " + lib.name + " module is null."
+ );
+ }
+ }
+
+ if ("debugName" in lib) {
+ Assert.ok(
+ nameComparator(test_lib.debugName, lib.debugName),
+ "The " + lib.name + " module has the correct debug name."
+ );
+ }
+
+ if (lib.debugName === null) {
+ Assert.strictEqual(
+ test_lib.debugID,
+ null,
+ "The " + lib.name + " module doesn't have a debug ID."
+ );
+ } else {
+ Assert.greater(
+ test_lib.debugID.length,
+ 0,
+ "The " + lib.name + " module has a debug ID."
+ );
+ }
+
+ if ("certSubject" in lib) {
+ Assert.strictEqual(
+ test_lib.certSubject,
+ lib.certSubject,
+ "The " + lib.name + " module has the expected cert subject."
+ );
+ }
+ }
+
+ let test_lib = found.payload.modules.find(
+ module => module.name === libLongName
+ );
+ Assert.ok(!test_lib, "There isn't a '" + libLongName + "' module.");
+ }
+);