diff options
Diffstat (limited to 'toolkit/components/telemetry/tests/unit/test_ModulesPing.js')
-rw-r--r-- | toolkit/components/telemetry/tests/unit/test_ModulesPing.js | 300 |
1 files changed, 300 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..8196d67dba --- /dev/null +++ b/toolkit/components/telemetry/tests/unit/test_ModulesPing.js @@ -0,0 +1,300 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { Preferences } = ChromeUtils.importESModule( + "resource://gre/modules/Preferences.sys.mjs" +); +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", ""); + Preferences.set("toolkit.telemetry.modulesPing.interval", 0); + Preferences.set("app.update.url", "http://localhost"); + + // Start the local ping server and setup Telemetry to use it during the tests. + PingServer.start(); + Preferences.set( + 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."); + } +); |