gecko-dev/toolkit/components/telemetry/tests/unit/test_ModulesPing.js
Nathan Froyd b3dcc1032e Bug 1525417 - add aarch64 files for test_ModulesPing.js; r=marco
This test wasn't accounting for the existence of aarch64 windows, and
was trying to load x86-64 DLLs on aarch64, which wouldn't end very
well.  Compile appropriate DLLs, modify the compilation instructions,
and add these new files to the test so everything works out.
2019-02-25 08:29:55 -05:00

226 lines
7.5 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const {Preferences} = ChromeUtils.import("resource://gre/modules/Preferences.jsm");
const {ctypes} = ChromeUtils.import("resource://gre/modules/ctypes.jsm");
const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm");
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 = OS.Path.basename(OS.Constants.Path.libxul);
const libModulesFile = do_get_file(libModules).path;
const libUnicodeFile = OS.Path.join(OS.Path.dirname(libModulesFile), libUnicode);
const libLongNameFile = OS.Path.join(OS.Path.dirname(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 if (AppConstants.platform === "android") {
// Listing shared libraries doesn't work in Android xpcshell tests.
// https://hg.mozilla.org/mozilla-central/file/0eef1d5a39366059677c6d7944cfe8a97265a011/tools/profiler/core/shared-libraries-linux.cc#l95
expectedLibs = [];
} 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 OS.File.copy(libModulesFile, libUnicodeFile);
await OS.File.copy(libModulesFile, libLongName);
if (AppConstants.platform !== "android") {
libModulesHandle = ctypes.open(libModulesFile);
libUnicodeHandle = ctypes.open(libUnicodeFile);
libLongNameHandle = ctypes.open(libLongNameFile);
if (AppConstants.platform === "win") {
libUnicodePDBHandle = ctypes.open(libUnicodePDBFile);
libNoPDBHandle = ctypes.open(libNoPDBFile);
}
}
// 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 OS.File.remove(libUnicodeFile)
.then(() => OS.File.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.");
});