fune/browser/modules/test/unit/test_InstallationTelemetry.js
Ben Hearsum 3e28c91b15 Bug 1743465: send additional information about existing installations in installation.first_seen Telemetry event. r=nalexander
This patch does two things:
1) Adds a few new pieces of information to the installation "first_seen" event. Specifically:
    * other_inst - true when any non-MSIX installation other than the running one was present when this event was prepared
    * other_msix_inst - true when any MSIX installation other that the running one was present when this event was prepared
2) Begins sending this event for MSIX installations

Differential Revision: https://phabricator.services.mozilla.com/D134326
2022-01-20 23:34:52 +00:00

208 lines
5.5 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
"use strict";
const { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
const { BrowserUsageTelemetry } = ChromeUtils.import(
"resource:///modules/BrowserUsageTelemetry.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { TelemetryTestUtils } = ChromeUtils.import(
"resource://testing-common/TelemetryTestUtils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"FileUtils",
"resource://gre/modules/FileUtils.jsm"
);
const TIMESTAMP_PREF = "app.installation.timestamp";
function encodeUtf16(str) {
const buf = new ArrayBuffer(str.length * 2);
const utf16 = new Uint16Array(buf);
for (let i = 0; i < str.length; i++) {
utf16[i] = str.charCodeAt(i);
}
return new Uint8Array(buf);
}
// Returns Promise
function writeJsonUtf16(fileName, obj) {
const str = JSON.stringify(obj);
return IOUtils.write(fileName, encodeUtf16(str));
}
async function runReport(
dataFile,
installType,
{ clearTS, setTS, assertRejects, expectExtra, expectTS, msixPrefixes }
) {
// Setup timestamp
if (clearTS) {
Services.prefs.clearUserPref(TIMESTAMP_PREF);
}
if (typeof setTS == "string") {
Services.prefs.setStringPref(TIMESTAMP_PREF, setTS);
}
// Init events
Services.telemetry.clearEvents();
// Exercise reportInstallationTelemetry
if (typeof assertRejects != "undefined") {
await Assert.rejects(
BrowserUsageTelemetry.reportInstallationTelemetry(dataFile),
assertRejects
);
} else if (!msixPrefixes) {
await BrowserUsageTelemetry.reportInstallationTelemetry(dataFile);
} else {
await BrowserUsageTelemetry.reportInstallationTelemetry(
dataFile,
msixPrefixes
);
}
// Check events
TelemetryTestUtils.assertEvents(
expectExtra
? [{ object: installType, value: null, extra: expectExtra }]
: [],
{ category: "installation", method: "first_seen" }
);
// Check timestamp
if (typeof expectTS == "string") {
Assert.equal(expectTS, Services.prefs.getStringPref(TIMESTAMP_PREF));
}
}
add_task(async function testInstallationTelemetry() {
let dataFilePath = await IOUtils.createUniqueFile(
Services.dirsvc.get("TmpD", Ci.nsIFile).path,
"installation-telemetry-test-data" + Math.random() + ".json"
);
let dataFile = new FileUtils.File(dataFilePath);
registerCleanupFunction(async () => {
try {
await IOUtils.remove(dataFilePath);
} catch (ex) {
// Ignore remove failure, file may not exist by now
}
Services.prefs.clearUserPref(TIMESTAMP_PREF);
});
// Test with normal stub data
let stubData = {
version: "99.0abc",
build_id: "123",
installer_type: "stub",
admin_user: true,
install_existed: false,
profdir_existed: false,
install_timestamp: "0",
};
let stubExtra = {
version: "99.0abc",
build_id: "123",
admin_user: "true",
install_existed: "false",
other_inst: "false",
other_msix_inst: "false",
profdir_existed: "false",
};
await writeJsonUtf16(dataFilePath, stubData);
await runReport(dataFile, "stub", {
clearTS: true,
expectExtra: stubExtra,
expectTS: "0",
});
// Check that it doesn't generate another event when the timestamp is unchanged
await runReport(dataFile, "stub", { expectTS: "0" });
// New timestamp
stubData.install_timestamp = "1";
await writeJsonUtf16(dataFilePath, stubData);
await runReport(dataFile, "stub", {
expectExtra: stubExtra,
expectTS: "1",
});
// Test with normal full data
let fullData = {
version: "99.0abc",
build_id: "123",
installer_type: "full",
admin_user: false,
install_existed: true,
profdir_existed: true,
silent: false,
from_msi: false,
default_path: true,
install_timestamp: "1",
};
let fullExtra = {
version: "99.0abc",
build_id: "123",
admin_user: "false",
install_existed: "true",
other_inst: "false",
other_msix_inst: "false",
profdir_existed: "true",
silent: "false",
from_msi: "false",
default_path: "true",
};
await writeJsonUtf16(dataFilePath, fullData);
await runReport(dataFile, "full", {
clearTS: true,
expectExtra: fullExtra,
expectTS: "1",
});
// Check that it doesn't generate another event when the timestamp is unchanged
await runReport(dataFile, "full", { expectTS: "1" });
// New timestamp and a check to make sure we can find installed MSIX packages
// by overriding the prefixes a bit further down.
fullData.install_timestamp = "2";
// This check only works on Windows 10 and above
if (AppConstants.isPlatformAndVersionAtLeast("win", "10")) {
fullExtra.other_msix_inst = "true";
}
await writeJsonUtf16(dataFilePath, fullData);
await runReport(dataFile, "full", {
expectExtra: fullExtra,
expectTS: "2",
msixPrefixes: ["Microsoft"],
});
// Missing field
delete fullData.install_existed;
fullData.install_timestamp = "3";
await writeJsonUtf16(dataFilePath, fullData);
await runReport(dataFile, "full", { assertRejects: /install_existed/ });
// Malformed JSON
await IOUtils.write(dataFilePath, encodeUtf16("hello"));
await runReport(dataFile, "stub", {
assertRejects: /unexpected character/,
});
// Missing file, should return with no exception
await IOUtils.remove(dataFilePath);
await runReport(dataFile, "stub", { setTS: "3", expectTS: "3" });
// bug 1750581 tracks testing this when we're able to run tests in
// an MSIX package environment
});