/* 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."); } );