Bug 1572711 - Added blocklist.lastModified_xml telemetry scalar to record extensions.blocklist.lastModified value. r=janerik,leplatrem,Gijs

Differential Revision: https://phabricator.services.mozilla.com/D41733

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Luca Greco 2019-08-21 19:51:52 +00:00
Родитель 98e92a1a7b
Коммит 23344811d9
4 изменённых файлов: 261 добавлений и 0 удалений

Просмотреть файл

@ -4465,6 +4465,28 @@ qm:
record_in_processes:
- 'main'
blocklist:
lastModified_xml:
bug_numbers:
- 1572711
description: >
Keep track of the lastupdate datetime from a successfully loaded xml blocklist,
set to "Invalid Date" or "Missing Date" when the timestamp is invalid or missing.
(based on the lastupdate attribute set on the XML document element,
converted from a milliseconds timestamp into a datetime string in UTC format).
expires: "75"
kind: string
release_channel_collection: opt-out
notification_emails:
- addons-dev-internal@mozilla.com
- lgreco@mozilla.com
- awagner@mozilla.com
products:
- 'firefox'
- 'fennec'
record_in_processes:
- main
# The following section is for probes testing the Telemetry system. They will not be
# submitted in pings and are only used for testing.
telemetry.test:

Просмотреть файл

@ -165,6 +165,35 @@ const PREF_BLOCKLIST_ADDONS_CHECKED_SECONDS =
"services.blocklist.addons.checked";
const PREF_BLOCKLIST_ADDONS_SIGNER = "services.blocklist.addons.signer";
const BlocklistTelemetry = {
/**
* Record the XML Blocklist lastModified server time into the
* "blocklist.lastModified_xml scalar.
*
* @param {XMLDocument} xmlDoc
* The blocklist XML file to retrieve the lastupdate attribute
* and record it into the "blocklist.lastModified_xml" scalar.
* The scalar value is a datetime string in UTC format.
*/
recordXMLBlocklistLastModified(xmlDoc) {
const lastUpdate =
xmlDoc && xmlDoc.documentElement.getAttribute("lastupdate");
if (lastUpdate) {
Services.telemetry.scalarSet(
"blocklist.lastModified_xml",
// Date(...).toUTCString will return "Invalid Date" if the
// timestamp isn't valid (e.g. parseInt returns NaN).
new Date(parseInt(lastUpdate, 10)).toUTCString()
);
} else {
Services.telemetry.scalarSet(
"blocklist.lastModified_xml",
"Missing Date"
);
}
},
};
const Utils = {
/**
* Checks whether this entry is valid for the current OS and ABI.
@ -2137,6 +2166,10 @@ var BlocklistXML = {
"Blocklist::_loadBlocklistFromXML: Error constructing blocklist " + e
);
}
// Record the last modified timestamp right before notify the observers.
BlocklistTelemetry.recordXMLBlocklistLastModified(doc);
// Dispatch to mainthread because consumers may try to construct nsIPluginHost
// again based on this notification, while we were called from nsIPluginHost
// anyway, leading to re-entrancy.

Просмотреть файл

@ -0,0 +1,205 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { Blocklist } = ChromeUtils.import(
"resource://gre/modules/Blocklist.jsm"
);
const { TelemetryController } = ChromeUtils.import(
"resource://gre/modules/TelemetryController.jsm"
);
const { TelemetryTestUtils } = ChromeUtils.import(
"resource://testing-common/TelemetryTestUtils.jsm"
);
const PREF_BLOCKLIST_URL = "extensions.blocklist.url";
AddonTestUtils.init(this);
AddonTestUtils.createAppInfo(
"xpcshell@tests.mozilla.org",
"XPCShell",
"1",
"49"
);
const serverTime = new Date();
const lastUpdateTimestamp = serverTime.getTime() - 2000;
const lastUpdateUTCString = new Date(lastUpdateTimestamp).toUTCString();
let blocklistHandler;
const server = AddonTestUtils.createHttpServer({
hosts: ["example.com"],
});
server.registerPathHandler("/blocklist.xml", (request, response) => {
if (blocklistHandler) {
const handler = blocklistHandler;
blocklistHandler = null;
handler(request, response);
} else {
response.setStatusLine(
request.httpVersion,
501,
"test blocklist handler undefined"
);
response.write("");
}
});
function promiseConsoleMessage(regexp) {
return new Promise(resolve => {
const listener = entry => {
if (regexp.test(entry.message)) {
Services.console.unregisterListener(listener);
resolve(entry);
}
};
Services.console.registerListener(listener);
});
}
async function promiseBlocklistUpdateWithError({
serverBlocklistHandler,
expectedConsoleMessage,
}) {
let onceConsoleMessageLogged = promiseConsoleMessage(expectedConsoleMessage);
blocklistHandler = serverBlocklistHandler;
Blocklist.notify();
await onceConsoleMessageLogged;
}
async function promiseBlocklistUpdateSuccessful({ serverBlocklistHandler }) {
const promiseBlocklistLoaded = TestUtils.topicObserved(
"addon-blocklist-updated"
);
blocklistHandler = serverBlocklistHandler;
Blocklist.notify();
await promiseBlocklistLoaded;
}
function createBlocklistHandler({ lastupdate }) {
return (request, response) => {
response.setStatusLine(
request.httpVersion,
200,
"test successfull blocklist update"
);
response.setHeader("Last-Modified", serverTime.toUTCString());
response.write(`<?xml version='1.0' encoding='UTF-8'?>
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist"
lastupdate="${lastupdate}">
</blocklist>
`);
};
}
add_task(async function test_setup() {
Services.prefs.setCharPref(
PREF_BLOCKLIST_URL,
"http://example.com/blocklist.xml"
);
await AddonTestUtils.promiseStartupManager();
// Ensure that the telemetry event definition is loaded.
await TelemetryController.testSetup();
});
add_task(async function test_lastModifed_xml_on_blocklist_updates() {
Services.telemetry.clearScalars();
info(
"Verify lastModified_xml scalar is updated after a successfull blocklist update"
);
await promiseBlocklistUpdateSuccessful({
serverBlocklistHandler: createBlocklistHandler({
lastupdate: lastUpdateTimestamp,
}),
});
let scalars = TelemetryTestUtils.getProcessScalars("parent");
equal(
scalars["blocklist.lastModified_xml"],
lastUpdateUTCString,
"Got the expected value set on the telemetry scalar"
);
info(
"Verify lastModified_xml scalar is updated after a blocklist update failure"
);
await promiseBlocklistUpdateWithError({
serverBlocklistHandler(request, response) {
response.setStatusLine(
request.httpVersion,
501,
"test failed blocklist update"
);
response.write("");
},
expectedConsoleMessage: /^Blocklist::onXMLLoad: there was an error/,
});
scalars = TelemetryTestUtils.getProcessScalars("parent");
equal(
scalars["blocklist.lastModified_xml"],
lastUpdateUTCString,
"Expect the telemetry scalar to be unchanged after a failed blocklist update"
);
});
add_task(async function test_lastModifed_xml_on_blocklist_loaded_from_disk() {
Services.telemetry.clearScalars();
const { BlocklistXML } = ChromeUtils.import(
"resource://gre/modules/Blocklist.jsm",
null
);
// Force the blocklist to be read from file again.
BlocklistXML._clear();
await BlocklistXML.loadBlocklistAsync();
let scalars = TelemetryTestUtils.getProcessScalars("parent");
equal(
scalars["blocklist.lastModified_xml"],
lastUpdateUTCString,
"Got the expect the telemetry scalar value"
);
});
add_task(async function test_lastModified_xml_invalid_lastupdate_attribute() {
Services.telemetry.clearScalars();
await promiseBlocklistUpdateSuccessful({
serverBlocklistHandler: createBlocklistHandler({
lastupdate: "not a timestamp",
}),
});
let scalars = TelemetryTestUtils.getProcessScalars("parent");
equal(
scalars["blocklist.lastModified_xml"],
"Invalid Date",
"Expect the telemetry scalar to be unchanged"
);
});
add_task(async function test_lastModified_xml_on_empty_lastupdate_attribute() {
Services.telemetry.clearScalars();
await promiseBlocklistUpdateSuccessful({
serverBlocklistHandler: createBlocklistHandler({
lastupdate: "",
}),
});
let scalars = TelemetryTestUtils.getProcessScalars("parent");
equal(
scalars["blocklist.lastModified_xml"],
"Missing Date",
"Expect the telemetry scalar to be unchanged"
);
});

Просмотреть файл

@ -29,6 +29,7 @@ skip-if = os == "android"
[test_blocklist_severities.js]
# Bug 676992: test consistently hangs on Android
skip-if = os == "android"
[test_blocklist_telemetry.js]
[test_blocklist_url_parameters.js]
# Bug 676992: test consistently hangs on Android
skip-if = os == "android"