Merge mozilla-central to mozilla-inbound.

This commit is contained in:
Cosmin Sabou 2019-04-19 19:36:21 +03:00
Родитель 57c7c5a365 dc89b1825c
Коммит ee0e94e991
62 изменённых файлов: 2311 добавлений и 287 удалений

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

@ -1294,6 +1294,8 @@ class UrlbarInput {
_on_input() {
let value = this.textValue;
this.valueIsTyped = true;
let valueIsPasted = this._valueIsPasted;
this._valueIsPasted = false;
this._untrimmedValue = value;
this.window.gBrowser.userTypedValue = value;
@ -1351,7 +1353,7 @@ class UrlbarInput {
return;
}
let allowAutofill =
let allowAutofill = !valueIsPasted &&
this._maybeAutofillOnInput(value, deletedAutofilledSubstring);
this.startQuery({
@ -1417,7 +1419,7 @@ class UrlbarInput {
if (!originalPasteData) {
return;
}
this._valueIsPasted = true;
let oldValue = this.inputField.value;
let oldStart = oldValue.substring(0, this.selectionStart);
// If there is already non-whitespace content in the URL bar

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

@ -27,6 +27,7 @@ skip-if = os != "mac" # Mac only feature
[browser_autoFill_canonize.js]
[browser_autoFill_caretNotAtEnd.js]
[browser_autoFill_firstResult.js]
[browser_autoFill_paste.js]
[browser_autoFill_placeholder.js]
[browser_autoFill_preserve.js]
[browser_autoFill_trimURLs.js]

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

@ -0,0 +1,52 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// This test checks we don't autofill on paste.
"use strict";
async function paste(str) {
await SimpleTest.promiseClipboardChange(str, () => {
Cc["@mozilla.org/widget/clipboardhelper;1"]
.getService(Ci.nsIClipboardHelper)
.copyString(str);
});
gURLBar.select();
document.commandDispatcher.getControllerForCommand("cmd_paste")
.doCommand("cmd_paste");
}
add_task(async function test() {
await PlacesUtils.bookmarks.eraseEverything();
await PlacesUtils.history.clear();
await PlacesTestUtils.addVisits([
"http://example.com/",
]);
registerCleanupFunction(async () => {
await PlacesUtils.history.clear();
});
// Search for "e". It should autofill to example.com/.
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
waitForFocus,
value: "e",
fireInputEvent: true,
});
let details = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
Assert.ok(details.autofill);
Assert.equal(gURLBar.value, "example.com/");
Assert.equal(gURLBar.selectionStart, "e".length);
Assert.equal(gURLBar.selectionEnd, "example.com/".length);
// Now paste.
await paste("ex");
// Nothing should have been autofilled.
await UrlbarTestUtils.promiseSearchComplete(window);
details = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
Assert.ok(!details.autofill);
Assert.equal(gURLBar.value, "ex");
Assert.equal(gURLBar.selectionStart, "ex".length);
Assert.equal(gURLBar.selectionEnd, "ex".length);
});

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

@ -57,11 +57,12 @@
border.
*/
#navigator-toolbox::after {
content: "";
display: -moz-box;
-moz-appearance: toolbox;
height: 1px;
/* use inset box-shadow instead of border because -moz-appearance hides the border */
border: none;
box-shadow: inset 0 -1px var(--chrome-content-separator-color);
margin-top: -1px;
opacity: 0;
}
#tabbrowser-tabs {

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

@ -39,13 +39,11 @@
/* Toolbar / content area border */
#navigator-toolbox::after {
content: "";
display: -moz-box;
#navigator-toolbox {
border-bottom: 1px solid var(--chrome-content-separator-color);
}
:root[customizing] #navigator-toolbox::after {
:root[customizing] #navigator-toolbox {
border-bottom-style: none;
}

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

@ -308,7 +308,18 @@
background-clip: padding-box;
}
#main-window[sizemode=normal] #navigator-toolbox::after {
#navigator-toolbox::after {
content: "";
display: -moz-box;
border-bottom: 1px solid var(--chrome-content-separator-color);
}
#navigator-toolbox,
:root[customizing] #navigator-toolbox::after {
border-bottom-style: none;
}
:root[sizemode=normal] #navigator-toolbox::after {
box-shadow: 1px 0 0 @glassShadowColor@, -1px 0 0 @glassShadowColor@;
margin-left: 1px;
margin-right: 1px;

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

@ -959,6 +959,14 @@ netmonitor.context.copyAsCurl=Copy as cURL
# for the Copy as cURL menu item displayed in the context menu for a request
netmonitor.context.copyAsCurl.accesskey=C
# LOCALIZATION NOTE (netmonitor.context.copyAsFetch): This is the label displayed
# on the context menu that copies the selected request as a fetch request.
netmonitor.context.copyAsFetch=Copy as Fetch
# LOCALIZATION NOTE (netmonitor.context.copyAsFetch.accesskey): This is the access key
# for the Copy as fetch menu item displayed in the context menu for a request
netmonitor.context.copyAsFetch.accesskey=F
# LOCALIZATION NOTE (netmonitor.context.copyRequestHeaders): This is the label displayed
# on the context menu that copies the selected item's request headers
netmonitor.context.copyRequestHeaders=Copy Request Headers
@ -991,6 +999,14 @@ netmonitor.context.copyImageAsDataUri=Copy Image as Data URI
# for the Copy Image As Data URI menu item displayed in the context menu for a request
netmonitor.context.copyImageAsDataUri.accesskey=I
# LOCALIZATION NOTE (netmonitor.context.useAsFetch): This is the label displayed
# on the context menu that copies the selected request as a fetch command.
netmonitor.context.useAsFetch=Use as Fetch in Console
# LOCALIZATION NOTE (netmonitor.context.useAsFetch.accesskey): This is the access key
# for the Copy as fetch menu item displayed in the context menu for a request
netmonitor.context.useAsFetch.accesskey=F
# LOCALIZATION NOTE (netmonitor.context.saveImageAs): This is the label displayed
# on the context menu that save the Image
netmonitor.context.saveImageAs=Save Image As

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

@ -90,6 +90,15 @@ class RequestListContextMenu {
this.copyAsCurl(id, url, method, httpVersion, requestHeaders, requestPostData),
});
copySubmenu.push({
id: "request-list-context-copy-as-fetch",
label: L10N.getStr("netmonitor.context.copyAsFetch"),
accesskey: L10N.getStr("netmonitor.context.copyAsFetch.accesskey"),
visible: !!selectedRequest,
click: () =>
this.copyAsFetch(id, url, method, requestHeaders, requestPostData),
});
copySubmenu.push({
type: "separator",
visible: copySubmenu.slice(0, 4).some((subMenu) => subMenu.visible),
@ -231,6 +240,19 @@ class RequestListContextMenu {
click: () => openStatistics(true),
});
menu.push({
type: "separator",
});
menu.push({
id: "request-list-context-use-as-fetch",
label: L10N.getStr("netmonitor.context.useAsFetch"),
accesskey: L10N.getStr("netmonitor.context.useAsFetch.accesskey"),
visible: !!selectedRequest,
click: () =>
this.useAsFetch(id, url, method, requestHeaders, requestPostData),
});
showMenu(menu, {
screenX: event.screenX,
screenY: event.screenY,
@ -324,6 +346,107 @@ class RequestListContextMenu {
copyString(Curl.generateCommand(data));
}
/**
* Generate fetch string
*/
async generateFetchString(id, url, method, requestHeaders, requestPostData) {
requestHeaders = requestHeaders ||
await this.props.connector.requestData(id, "requestHeaders");
requestPostData = requestPostData ||
await this.props.connector.requestData(id, "requestPostData");
// https://fetch.spec.whatwg.org/#forbidden-header-name
const forbiddenHeaders = {
"accept-charset": 1,
"accept-encoding": 1,
"access-control-request-headers": 1,
"access-control-request-method": 1,
"connection": 1,
"content-length": 1,
"cookie": 1,
"cookie2": 1,
"date": 1,
"dnt": 1,
"expect": 1,
"host": 1,
"keep-alive": 1,
"origin": 1,
"referer": 1,
"te": 1,
"trailer": 1,
"transfer-encoding": 1,
"upgrade": 1,
"via": 1,
};
const credentialHeaders = {"cookie": 1, "authorization": 1};
const headers = {};
for (const {name, value} of requestHeaders.headers) {
if (!forbiddenHeaders[name.toLowerCase()]) {
headers[name] = value;
}
}
const referrerHeader = requestHeaders.headers.find(
({ name }) => name.toLowerCase() === "referer"
);
const referrerPolicy = requestHeaders.headers.find(
({ name }) => name.toLowerCase() === "referrer-policy"
);
const referrer = referrerHeader ? referrerHeader.value : undefined;
const credentials = requestHeaders.headers.some(
({name}) => credentialHeaders[name.toLowerCase()]
) ? "include" : "omit";
const fetchOptions = {
credentials,
headers,
referrer,
referrerPolicy,
body: requestPostData.postData.text,
method: method,
mode: "cors",
};
const options = JSON.stringify(fetchOptions, null, 4);
const fetchString = `await fetch("${url}", ${options});`;
return fetchString;
}
/**
* Copy the currently selected item as fetch request.
*/
async copyAsFetch(id, url, method, requestHeaders, requestPostData) {
const fetchString = await this.generateFetchString(
id,
url,
method,
requestHeaders,
requestPostData
);
copyString(fetchString);
}
/**
* Open split console and fill it with fetch command for selected item
*/
async useAsFetch(id, url, method, requestHeaders, requestPostData) {
const fetchString = await this.generateFetchString(
id,
url,
method,
requestHeaders,
requestPostData
);
const toolbox = gDevTools.getToolbox(this.props.connector.getTabTarget());
await toolbox.openSplitConsole();
const { hud } = await toolbox.getPanel("webconsole");
hud.setInputValue(fetchString);
}
/**
* Copy the raw request headers from the currently selected item.
*/

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

@ -116,6 +116,9 @@ subsuite = clipboard
skip-if = (verify && debug && os == 'win')
[browser_net_copy_as_curl.js]
subsuite = clipboard
[browser_net_copy_as_fetch.js]
subsuite = clipboard
[browser_net_use_as_fetch.js]
[browser_net_cors_requests.js]
[browser_net_cyrillic-01.js]
[browser_net_cyrillic-02.js]

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

@ -0,0 +1,73 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Tests if Copy as Fetch works.
*/
add_task(async function() {
const { tab, monitor } = await initNetMonitor(CURL_URL);
info("Starting test... ");
// GET request, no cookies (first request)
await performRequest("GET");
await testClipboardContent(`await fetch("http://example.com/browser/devtools/client/netmonitor/test/sjs_simple-test-server.sjs", {
"credentials": "omit",
"headers": {
"User-Agent": "${navigator.userAgent}",
"Accept": "*/*",
"Accept-Language": "en-US",
"X-Custom-Header-1": "Custom value",
"X-Custom-Header-2": "8.8.8.8",
"X-Custom-Header-3": "Mon, 3 Mar 2014 11:11:11 GMT",
"Pragma": "no-cache",
"Cache-Control": "no-cache"
},
"referrer": "http://example.com/browser/devtools/client/netmonitor/test/html_copy-as-curl.html",
"method": "GET",
"mode": "cors"
});`);
await teardown(monitor);
async function performRequest(method, payload) {
const waitRequest = waitForNetworkEvents(monitor, 1);
await ContentTask.spawn(tab.linkedBrowser, {
url: SIMPLE_SJS,
method_: method,
payload_: payload,
}, async function({url, method_, payload_}) {
content.wrappedJSObject.performRequest(url, method_, payload_);
});
await waitRequest;
}
async function testClipboardContent(expectedResult) {
const { document } = monitor.panelWin;
const items = document.querySelectorAll(".request-list-item");
EventUtils.sendMouseEvent({ type: "mousedown" }, items[items.length - 1]);
EventUtils.sendMouseEvent({ type: "contextmenu" },
document.querySelectorAll(".request-list-item")[0]);
/* Ensure that the copy as fetch option is always visible */
const copyAsFetchNode = monitor.panelWin.parent.document
.querySelector("#request-list-context-copy-as-fetch");
is(!!copyAsFetchNode, true,
"The \"Copy as Fetch\" context menu item should not be hidden.");
await waitForClipboardPromise(function setup() {
copyAsFetchNode.click();
}, function validate(result) {
if (typeof result !== "string") {
return false;
}
return expectedResult === result;
});
info("Clipboard contains a fetch command for item " + (items.length - 1));
}
});

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

@ -0,0 +1,69 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Tests if Use as Fetch works.
*/
add_task(async function() {
const { tab, monitor, toolbox } = await initNetMonitor(CURL_URL);
info("Starting test... ");
// GET request, no cookies (first request)
await performRequest("GET");
await testConsoleInput(`await fetch("http://example.com/browser/devtools/client/netmonitor/test/sjs_simple-test-server.sjs", {
"credentials": "omit",
"headers": {
"User-Agent": "${navigator.userAgent}",
"Accept": "*/*",
"Accept-Language": "en-US",
"X-Custom-Header-1": "Custom value",
"X-Custom-Header-2": "8.8.8.8",
"X-Custom-Header-3": "Mon, 3 Mar 2014 11:11:11 GMT",
"Pragma": "no-cache",
"Cache-Control": "no-cache"
},
"referrer": "http://example.com/browser/devtools/client/netmonitor/test/html_copy-as-curl.html",
"method": "GET",
"mode": "cors"
});`);
await teardown(monitor);
async function performRequest(method, payload) {
const waitRequest = waitForNetworkEvents(monitor, 1);
await ContentTask.spawn(tab.linkedBrowser, {
url: SIMPLE_SJS,
method_: method,
payload_: payload,
}, async function({url, method_, payload_}) {
content.wrappedJSObject.performRequest(url, method_, payload_);
});
await waitRequest;
}
async function testConsoleInput(expectedResult) {
const { document } = monitor.panelWin;
const items = document.querySelectorAll(".request-list-item");
EventUtils.sendMouseEvent({ type: "mousedown" }, items[items.length - 1]);
EventUtils.sendMouseEvent({ type: "contextmenu" },
document.querySelectorAll(".request-list-item")[0]);
/* Ensure that the use as fetch option is always visible */
const useAsFetchNode = monitor.panelWin.parent.document
.querySelector("#request-list-context-use-as-fetch");
is(!!useAsFetchNode, true,
"The \"Use as Fetch\" context menu item should not be hidden.");
useAsFetchNode.click();
await toolbox.once("split-console");
const hud = toolbox.getPanel("webconsole").hud;
await hud.jsterm.once("set-input-value");
is(hud.getInputValue(), expectedResult,
"Console input contains fetch request for item " + (items.length - 1));
}
});

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

@ -419,8 +419,9 @@ AsyncCubebTask::AsyncCubebTask(AudioCallbackDriver* aDriver,
mDriver(aDriver),
mOperation(aOperation),
mShutdownGrip(aDriver->GraphImpl()) {
NS_WARNING_ASSERTION(mDriver->mAudioStream || aOperation == INIT,
"No audio stream!");
NS_WARNING_ASSERTION(
mDriver->mAudioStream || aOperation == AsyncCubebOperation::INIT,
"No audio stream!");
}
AsyncCubebTask::~AsyncCubebTask() {}
@ -441,6 +442,22 @@ AsyncCubebTask::Run() {
mDriver->CompleteAudioContextOperations(mOperation);
break;
}
case AsyncCubebOperation::START: {
LOG(LogLevel::Debug, ("%p: AsyncCubebOperation::START driver=%p",
mDriver->GraphImpl(), mDriver.get()));
if (!mDriver->StartStream()) {
LOG(LogLevel::Warning,
("%p: AsyncCubebOperation couldn't start the driver=%p.",
mDriver->GraphImpl(), mDriver.get()));
}
break;
}
case AsyncCubebOperation::STOP: {
LOG(LogLevel::Debug, ("%p: AsyncCubebOperation::STOP driver=%p",
mDriver->GraphImpl(), mDriver.get()));
mDriver->Stop();
break;
}
case AsyncCubebOperation::SHUTDOWN: {
LOG(LogLevel::Debug, ("%p: AsyncCubebOperation::SHUTDOWN driver=%p",
mDriver->GraphImpl(), mDriver.get()));
@ -713,6 +730,7 @@ void AudioCallbackDriver::Stop() {
if (cubeb_stream_stop(mAudioStream) != CUBEB_OK) {
NS_WARNING("Could not stop cubeb stream for MSG.");
}
mStarted = false;
}
void AudioCallbackDriver::Revive() {
@ -728,9 +746,16 @@ void AudioCallbackDriver::Revive() {
LOG(LogLevel::Debug,
("Starting audio threads for MediaStreamGraph %p from a new thread.",
mGraphImpl.get()));
RefPtr<AsyncCubebTask> initEvent =
new AsyncCubebTask(this, AsyncCubebOperation::INIT);
initEvent->Dispatch();
if (IsStarted()) {
RefPtr<AsyncCubebTask> stopEvent =
new AsyncCubebTask(this, AsyncCubebOperation::STOP);
// This dispatches to a thread pool with a maximum of one thread thus it
// is guaranteed to be executed before the start event, right below.
stopEvent->Dispatch();
}
RefPtr<AsyncCubebTask> startEvent =
new AsyncCubebTask(this, AsyncCubebOperation::START);
startEvent->Dispatch();
}
}

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

@ -322,7 +322,7 @@ struct StreamAndPromiseForOperation {
dom::AudioContextOperationFlags mFlags;
};
enum AsyncCubebOperation { INIT, SHUTDOWN };
enum class AsyncCubebOperation { INIT, START, STOP, SHUTDOWN };
enum class AudioInputType { Unknown, Voice };
/**

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

@ -761,14 +761,7 @@ void MediaStreamGraphImpl::OpenAudioInputImpl(CubebUtils::AudioDeviceID aID,
nsresult MediaStreamGraphImpl::OpenAudioInput(CubebUtils::AudioDeviceID aID,
AudioDataListener* aListener) {
// So, so, so annoying. Can't AppendMessage except on Mainthread
if (!NS_IsMainThread()) {
RefPtr<nsIRunnable> runnable =
WrapRunnable(this, &MediaStreamGraphImpl::OpenAudioInput, aID,
RefPtr<AudioDataListener>(aListener));
mAbstractMainThread->Dispatch(runnable.forget());
return NS_OK;
}
MOZ_ASSERT(NS_IsMainThread());
class Message : public ControlMessage {
public:
Message(MediaStreamGraphImpl* aGraph, CubebUtils::AudioDeviceID aID,
@ -845,14 +838,7 @@ void MediaStreamGraphImpl::CloseAudioInputImpl(
void MediaStreamGraphImpl::CloseAudioInput(
Maybe<CubebUtils::AudioDeviceID>& aID, AudioDataListener* aListener) {
// So, so, so annoying. Can't AppendMessage except on Mainthread
if (!NS_IsMainThread()) {
RefPtr<nsIRunnable> runnable =
WrapRunnable(this, &MediaStreamGraphImpl::CloseAudioInput, aID,
RefPtr<AudioDataListener>(aListener));
mAbstractMainThread->Dispatch(runnable.forget());
return;
}
MOZ_ASSERT(NS_IsMainThread());
class Message : public ControlMessage {
public:
Message(MediaStreamGraphImpl* aGraph, Maybe<CubebUtils::AudioDeviceID>& aID,
@ -2421,25 +2407,32 @@ SourceMediaStream::SourceMediaStream()
nsresult SourceMediaStream::OpenAudioInput(CubebUtils::AudioDeviceID aID,
AudioDataListener* aListener) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(GraphImpl());
MOZ_ASSERT(!mInputListener);
mInputListener = aListener;
return GraphImpl()->OpenAudioInput(aID, aListener);
}
void SourceMediaStream::CloseAudioInput(Maybe<CubebUtils::AudioDeviceID>& aID,
AudioDataListener* aListener) {
MOZ_ASSERT(mInputListener == aListener);
// Destroy() may have run already and cleared this
if (GraphImpl() && mInputListener) {
GraphImpl()->CloseAudioInput(aID, aListener);
void SourceMediaStream::CloseAudioInput(Maybe<CubebUtils::AudioDeviceID>& aID) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(GraphImpl());
if (!mInputListener) {
return;
}
GraphImpl()->CloseAudioInput(aID, mInputListener);
mInputListener = nullptr;
}
void SourceMediaStream::DestroyImpl() {
void SourceMediaStream::Destroy() {
MOZ_ASSERT(NS_IsMainThread());
Maybe<CubebUtils::AudioDeviceID> id = Nothing();
CloseAudioInput(id, mInputListener);
CloseAudioInput(id);
MediaStream::Destroy();
}
void SourceMediaStream::DestroyImpl() {
GraphImpl()->AssertOnGraphThreadOrNotRunning();
for (int32_t i = mConsumers.Length() - 1; i >= 0; --i) {
// Disconnect before we come under mMutex's lock since it can call back

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

@ -655,14 +655,14 @@ class SourceMediaStream : public MediaStream {
// Users of audio inputs go through the stream so it can track when the
// last stream referencing an input goes away, so it can close the cubeb
// input. Also note: callable on any thread (though it bounces through
// MainThread to set the command if needed).
// input. Main thread only.
nsresult OpenAudioInput(CubebUtils::AudioDeviceID aID,
AudioDataListener* aListener);
// Note: also implied when Destroy() happens
void CloseAudioInput(Maybe<CubebUtils::AudioDeviceID>& aID,
AudioDataListener* aListener);
// Main thread only.
void CloseAudioInput(Maybe<CubebUtils::AudioDeviceID>& aID);
// Main thread only.
void Destroy() override;
// MediaStreamGraph thread only
void DestroyImpl() override;

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

@ -601,7 +601,7 @@ nsresult MediaEngineWebRTCMicrophoneSource::Stop() {
that->mInputProcessing, StartStopMessage::Stop));
CubebUtils::AudioDeviceID deviceID = that->mDeviceInfo->DeviceID();
Maybe<CubebUtils::AudioDeviceID> id = Some(deviceID);
stream->CloseAudioInput(id, that->mInputProcessing);
stream->CloseAudioInput(id);
}));
MOZ_ASSERT(mState == kStarted, "Should be started when stopping");

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

@ -212,7 +212,7 @@ pref("extensions.update.background.url", "https://versioncheck-bg.addons.mozilla
/* preferences for the Get Add-ons pane */
pref("extensions.getAddons.cache.enabled", true);
pref("extensions.getAddons.search.browseURL", "https://addons.mozilla.org/%LOCALE%/android/search?q=%TERMS%&platform=%OS%&appver=%VERSION%");
pref("extensions.getAddons.browseAddons", "https://addons.mozilla.org/%LOCALE%/android/");
pref("extensions.getAddons.browseAddons", "https://addons.mozilla.org/%LOCALE%/firefox/collections/4757633/mob/");
pref("extensions.getAddons.get.url", "https://services.addons.mozilla.org/api/v3/addons/search/?guid=%IDS%&lang=%LOCALE%");
pref("extensions.getAddons.compatOverides.url", "https://services.addons.mozilla.org/api/v3/addons/compat-override/?guid=%IDS%&lang=%LOCALE%");
pref("extensions.getAddons.langpacks.url", "https://services.addons.mozilla.org/api/v3/addons/language-tools/?app=android&type=language&appversion=%VERSION%");

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

@ -9,6 +9,7 @@
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const {AddonManager} = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
const {EventDispatcher} = ChromeUtils.import("resource://gre/modules/Messaging.jsm");
const AMO_ICON = "chrome://browser/skin/images/amo-logo.png";
const UPDATE_INDICATOR = "chrome://browser/skin/images/extension-update.svg";
@ -261,13 +262,34 @@ var Addons = {
let title = document.createElement("div");
title.id = "browse-title";
title.className = "title";
title.textContent = gStringBundle.GetStringFromName("addons.browseAll");
title.textContent = this._getAmoTitle();
inner.appendChild(title);
outer.appendChild(inner);
return outer;
},
// Ensure we get a localized string by using the previous title as a fallback
// if the new one has not yet been translated.
_getAmoTitle: function _getAmoTitle() {
const initialTitleUS = "Browse all Firefox Add-ons";
const updatedTitleUS = "Browse Firefoxs Recommended Extensions";
const initialTitleLocalized = gStringBundle.GetStringFromName("addons.browseAll");
const updatedTitleLocalized = gStringBundle.GetStringFromName("addons.browseRecommended");
let title = initialTitleLocalized;
const titleWasLocalized = updatedTitleLocalized !== updatedTitleUS;
const localeIsDefaultUS = updatedTitleLocalized === updatedTitleUS &&
initialTitleLocalized === initialTitleUS;
if (titleWasLocalized || localeIsDefaultUS) {
title = updatedTitleLocalized;
}
EventDispatcher.instance.dispatch("about:addons", {amoTitle: title} );
return title;
},
_createItemForAddon: function _createItemForAddon(aAddon) {
let opType = this._getOpTypeForOperations(aAddon.pendingOperations);
let hasUpdate = this._addonHasUpdate(aAddon);

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

@ -8,6 +8,8 @@ addonType.locale=Locale
addonStatus.uninstalled=%S will be uninstalled after restart.
# Will keep both strings and at runtime will fallback on the old one if the new one is not yet localized
addons.browseAll=Browse all Firefox Add-ons
addons.browseRecommended=Browse Firefoxs Recommended Extensions
addon.options=Options
addon.options=Options

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

@ -34,6 +34,9 @@ public class StringHelper {
// About pages' titles
public final String ABOUT_HOME_TITLE = "";
// To be kept in sync with 'addons.browseRecommended' from 'aboutAddons.properties'
public final String ABOUT_ADDONS_AMO_TITLE = "Browse Firefoxs Recommended Extensions";
// Context Menu item strings
public final String CONTEXT_MENU_BOOKMARK_LINK = "Bookmark Link";
public final String CONTEXT_MENU_OPEN_LINK_IN_NEW_TAB = "Open Link in New Tab";

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

@ -6,6 +6,7 @@ package org.mozilla.gecko.tests;
import org.json.JSONObject;
import org.mozilla.gecko.Actions;
import org.mozilla.gecko.util.GeckoBundle;
import android.util.DisplayMetrics;
@ -21,7 +22,9 @@ public class testAddonManager extends PixelTest {
public void testAddonManager() {
Actions.EventExpecter tabEventExpecter;
Actions.EventExpecter contentEventExpecter;
Actions.EventExpecter amoTitleExpecter;
final String aboutAddonsURL = mStringHelper.ABOUT_ADDONS_URL;
final String amoTitle = mStringHelper.ABOUT_ADDONS_AMO_TITLE;
blockForGeckoReady();
@ -31,13 +34,20 @@ public class testAddonManager extends PixelTest {
// Set up listeners to catch the page load we're about to do
tabEventExpecter = mActions.expectGlobalEvent(Actions.EventType.UI, "Tab:Added");
contentEventExpecter = mActions.expectGlobalEvent(Actions.EventType.UI, "Content:DOMContentLoaded");
amoTitleExpecter = mActions.expectGlobalEvent(Actions.EventType.UI, "about:addons");
// Wait for the new tab and page to load
tabEventExpecter.blockForEvent();
contentEventExpecter.blockForEvent();
GeckoBundle addonsPageBundle = amoTitleExpecter.blockForBundle();
tabEventExpecter.unregisterListener();
contentEventExpecter.unregisterListener();
amoTitleExpecter.unregisterListener();
// Verify the AMO title
final String actualAmoTitle = addonsPageBundle.getString("amoTitle");
mAsserter.is(actualAmoTitle, amoTitle, "Incorrect AMO title");
// Verify the url
verifyUrlBarTitle(aboutAddonsURL);

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

@ -120,6 +120,8 @@ nsHttpConnection::nsHttpConnection()
mIdleTimeout = (k5Sec < gHttpHandler->IdleTimeout())
? k5Sec
: gHttpHandler->IdleTimeout();
mThroughCaptivePortal = gHttpHandler->GetThroughCaptivePortal();
}
nsHttpConnection::~nsHttpConnection() {
@ -153,6 +155,20 @@ nsHttpConnection::~nsHttpConnection() {
: Telemetry::HTTP_KBREAD_PER_CONN2,
totalKBRead);
}
if (mThroughCaptivePortal) {
if (mTotalBytesRead || mTotalBytesWritten) {
auto total = Clamp<uint32_t>(
(mTotalBytesRead >> 10) + (mTotalBytesWritten >> 10), 0,
std::numeric_limits<uint32_t>::max());
Telemetry::ScalarAdd(
Telemetry::ScalarID::NETWORKING_DATA_TRANSFERRED_CAPTIVE_PORTAL, total);
}
Telemetry::ScalarAdd(
Telemetry::ScalarID::NETWORKING_HTTP_CONNECTIONS_CAPTIVE_PORTAL, 1);
}
if (mForceSendTimer) {
mForceSendTimer->Cancel();
mForceSendTimer = nullptr;

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

@ -441,6 +441,7 @@ class nsHttpConnection final : public nsAHttpSegmentReader,
bool mBootstrappedTimingsSet;
nsTArray<HttpTrafficCategory> mTrafficCategory;
bool mThroughCaptivePortal;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsHttpConnection, NS_HTTPCONNECTION_IID)

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

@ -307,7 +307,8 @@ nsHttpHandler::nsHttpHandler()
mProcessId(0),
mNextChannelId(1),
mLastActiveTabLoadOptimizationLock(
"nsHttpConnectionMgr::LastActiveTabLoadOptimization") {
"nsHttpConnectionMgr::LastActiveTabLoadOptimization"),
mThroughCaptivePortal(false) {
LOG(("Creating nsHttpHandler [this=%p].\n", this));
mUserAgentOverride.SetIsVoid(true);
@ -567,6 +568,7 @@ nsresult nsHttpHandler::Init() {
obsService->AddObserver(this, "psm:user-certificate-deleted", true);
obsService->AddObserver(this, "intl:app-locales-changed", true);
obsService->AddObserver(this, "browser-delayed-startup-finished", true);
obsService->AddObserver(this, "network:captive-portal-connectivity", true);
if (!IsNeckoChild()) {
obsService->AddObserver(
@ -2338,6 +2340,9 @@ nsHttpHandler::Observe(nsISupports *subject, const char *topic,
mAcceptLanguagesIsDirty = true;
} else if (!strcmp(topic, "browser-delayed-startup-finished")) {
MaybeEnableSpeculativeConnect();
} else if (!strcmp(topic, "network:captive-portal-connectivity")) {
nsAutoCString data8 = NS_ConvertUTF16toUTF8(data);
mThroughCaptivePortal = data8.EqualsLiteral("captive");
}
return NS_OK;

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

@ -422,6 +422,7 @@ class nsHttpHandler final : public nsIHttpProtocolHandler,
HttpTrafficAnalyzer *GetHttpTrafficAnalyzer();
bool GetThroughCaptivePortal() { return mThroughCaptivePortal; }
private:
nsHttpHandler();
@ -737,6 +738,8 @@ class nsHttpHandler final : public nsIHttpProtocolHandler,
private:
nsTHashtable<nsCStringHashKey> mBlacklistedSpdyOrigins;
bool mThroughCaptivePortal;
};
extern StaticRefPtr<nsHttpHandler> gHttpHandler;

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

@ -158,6 +158,8 @@ nsHttpTransaction::nsHttpTransaction()
#endif
mSelfAddr.raw.family = PR_AF_UNSPEC;
mPeerAddr.raw.family = PR_AF_UNSPEC;
mThroughCaptivePortal = gHttpHandler->GetThroughCaptivePortal();
}
void nsHttpTransaction::ResumeReading() {
@ -1196,6 +1198,11 @@ void nsHttpTransaction::Close(nsresult reason) {
}
}
if (mThroughCaptivePortal) {
Telemetry::ScalarAdd(
Telemetry::ScalarID::NETWORKING_HTTP_TRANSACTIONS_CAPTIVE_PORTAL, 1);
}
if (relConn && mConnection) {
MutexAutoLock lock(mLock);
mConnection = nullptr;

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

@ -484,6 +484,7 @@ class nsHttpTransaction final : public nsAHttpTransaction,
RefPtr<SpdyConnectTransaction> mH2WSTransaction;
HttpTrafficCategory mTrafficCategory;
bool mThroughCaptivePortal;
};
} // namespace net

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

@ -1,6 +1,8 @@
[sub-sample-buffer-stitching.html]
disabled:
if (os == 'win' and processor == 'aarch64'): https://bugzilla.mozilla.org/show_bug.cgi?id=1533911
if (os == 'win' and version == '6.1.7601'): https://bugzilla.mozilla.org/show_bug.cgi?id=1533762
if (os == 'linux' and bits == 32): https://bugzilla.mozilla.org/show_bug.cgi?id=1533762
[# AUDIT TASK RUNNER FINISHED: 2 out of 2 tasks were failed.]
expected: FAIL

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

@ -56,19 +56,11 @@ add_task(async function test_support_separator_properties() {
);
let toolbox = document.querySelector("#navigator-toolbox");
if (AppConstants.platform == "macosx") {
Assert.ok(
window.getComputedStyle(toolbox, "::after").boxShadow
.includes(`rgb(${hexToRGB(SEPARATOR_BOTTOM_COLOR).join(", ")})`),
"Bottom separator color properly set"
);
} else {
Assert.equal(
window.getComputedStyle(toolbox, "::after").borderBottomColor,
`rgb(${hexToRGB(SEPARATOR_BOTTOM_COLOR).join(", ")})`,
"Bottom separator color properly set"
);
}
Assert.equal(
window.getComputedStyle(toolbox).borderBottomColor,
`rgb(${hexToRGB(SEPARATOR_BOTTOM_COLOR).join(", ")})`,
"Bottom separator color properly set"
);
await extension.unload();
});

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

@ -2862,6 +2862,8 @@ SearchService.prototype = {
return val;
},
_listJSONURL: ((AppConstants.platform == "android") ? APP_SEARCH_PREFIX : EXT_SEARCH_PREFIX) + "list.json",
_engines: { },
__sortedEngines: null,
_visibleDefaultEngines: [],
@ -3467,11 +3469,9 @@ SearchService.prototype = {
async _findEngines() {
LOG("_findEngines: looking for engines in JARs");
let prefix = AppConstants.platform == "android" ? APP_SEARCH_PREFIX : EXT_SEARCH_PREFIX;
let listURL = prefix + "list.json";
let chan = makeChannel(listURL);
let chan = makeChannel(this._listJSONURL);
if (!chan) {
LOG("_findEngines: " + prefix + " isn't registered");
LOG("_findEngines: " + this._listJSONURL + " isn't registered");
return [];
}
@ -3485,10 +3485,10 @@ SearchService.prototype = {
resolve(event.target.responseText);
};
request.onerror = function(event) {
LOG("_findEngines: failed to read " + listURL);
LOG("_findEngines: failed to read " + this._listJSONURL);
resolve();
};
request.open("GET", Services.io.newURI(listURL).spec, true);
request.open("GET", Services.io.newURI(this._listJSONURL).spec, true);
request.send();
});

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

@ -0,0 +1,43 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Ensure all the engines defined in list.json are valid by
// creating a new list.json that contains every engine and
// loading them all.
"use strict";
Cu.importGlobalProperties(["fetch"]);
const {SearchService} = ChromeUtils.import("resource://gre/modules/SearchService.jsm");
const LIST_JSON_URL = "resource://search-extensions/list.json";
function traverse(obj, fun) {
for (var i in obj) {
fun.apply(this, [i, obj[i]]);
if (obj[i] !== null && typeof(obj[i]) == "object") {
traverse(obj[i], fun);
}
}
}
const ss = new SearchService();
add_task(async function test_validate_engines() {
let engines = await fetch(LIST_JSON_URL).then(req => req.json());
let visibleDefaultEngines = new Set();
traverse(engines, (key, val) => {
if (key === "visibleDefaultEngines") {
val.forEach(engine => visibleDefaultEngines.add(engine));
}
});
let listjson = {default: {
visibleDefaultEngines: Array.from(visibleDefaultEngines),
}};
ss._listJSONURL = "data:application/json," + JSON.stringify(listjson);
await AddonTestUtils.promiseStartupManager();
await ss.init();
});

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

@ -107,6 +107,7 @@ skip-if = (verify && !debug && (os == 'linux'))
[test_paramSubstitution.js]
[test_migrateWebExtensionEngine.js]
[test_sendSubmissionURL.js]
[test_validate_engines.js]
[test_validate_manifests.js]
[test_webextensions_install.js]
[test_purpose.js]

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

@ -2692,6 +2692,772 @@ update:
operating_systems:
- windows
update.startup:
from_app_version:
bug_numbers:
- 1539154
description: >
Records the previous application version that the update was applied to
when the update makes it to the last phase where the application has
exited and started.
expires: "72"
kind: string
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- 'main'
mar_partial_size_bytes:
bug_numbers:
- 1539154
description: >
Records the total number of bytes of a partial update MAR file when
the update makes it to the last phase where the application has exited and
started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
mar_complete_size_bytes:
bug_numbers:
- 1539154
description: >
Records the total number of bytes of a complete update MAR file when
the update makes it to the last phase where the application has exited and
started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
update.startup.intervals:
check:
bug_numbers:
- 1539154
description: >
Records the interval in seconds of the check phase of the update process
when an update makes it to the last phase where the application has exited
and started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
download_bits_partial:
bug_numbers:
- 1539154
description: >
Records the interval in seconds of the download phase of the update
process using the BITS downloader for a partial update MAR file when the
update makes it to the last phase where the application has exited and
and started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
operating_systems:
- "windows"
download_bits_complete:
bug_numbers:
- 1539154
description: >
Records the interval in seconds of the download phase of the update
process using the BITS downloader for a complete update MAR file when the
update makes it to the last phase where the application has exited and
started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
operating_systems:
- "windows"
download_internal_partial:
bug_numbers:
- 1539154
description: >
Records the interval in seconds of the download phase of the update
process using the internal application downloader for a partial update MAR
file when the update makes it to the last phase where the application has
exited and and started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
download_internal_complete:
bug_numbers:
- 1539154
description: >
Records the interval in seconds of the download phase of the update
process using the internal application downloader for a complete update
MAR file when the update makes it to the last phase where the application
has exited and and started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
stage_partial:
bug_numbers:
- 1539154
description: >
Records the interval in seconds of the stage phase of the update process
for a partial update MAR file when the update makes it to the last phase
where the application has exited and started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
stage_complete:
bug_numbers:
- 1539154
description: >
Records the interval in seconds of the stage phase of the update process
for a complete update MAR file when the update makes it to the last phase
where the application has exited and started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
apply_partial:
bug_numbers:
- 1539154
description: >
Records the interval in seconds of the apply phase of the update process
for a partial update MAR file when the update makes it to the last phase
where the application has exited and started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
apply_complete:
bug_numbers:
- 1539154
description: >
Records the interval in seconds of the apply phase of the update process
for a complete update MAR file when the update makes it to the last phase
where the application has exited and started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
update.startup.downloads:
bits_partial_bytes:
bug_numbers:
- 1539154
description: >
Records the total number of bytes downloaded using the BITS downloader for
a partial update MAR file when the update makes it to the last phase where
the application has exited and started. This value can be different than
the size of the update MAR file because the value is only monitored
during the initial download while the application is running and not if
the download is resumed.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
operating_systems:
- "windows"
bits_partial_seconds:
bug_numbers:
- 1539154
description: >
Records the total number of seconds spent downloading during the initial
download without exiting the application using the BITS downloader for a
partial update MAR file when the update makes it to the last phase where
the application has exited and started. This value can be used with the
value of update.startup.downloads.bits_partial_bytes to estimate the bytes
per second for the download.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
operating_systems:
- "windows"
bits_complete_bytes:
bug_numbers:
- 1539154
description: >
Records the total number of bytes downloaded using the BITS downloader for
a complete update MAR file when the update makes it to the last phase
where the application has exited and started. This value can be different
than the size of the update MAR file because the value is only monitored
during the initial download while the application is running and not if
the download is resumed.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
operating_systems:
- "windows"
bits_complete_seconds:
bug_numbers:
- 1539154
description: >
Records the total number of seconds spent downloading during the initial
download without exiting the application using the BITS downloader for a
complete update MAR file when the update makes it to the last phase where
the application has exited and started. This value can be used with the
value of update.startup.downloads.bits_complete_bytes to estimate the
bytes per second for the download.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
operating_systems:
- "windows"
internal_partial_bytes:
bug_numbers:
- 1539154
description: >
Records the total number of bytes downloaded using the internal application
downloader for a partial update MAR file when the update makes it to the
last phase where the application has exited and started. This value can be
different than the size of the update MAR file because the value is only
monitored during the initial download while the application is running and
not if the download is resumed.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
internal_partial_seconds:
bug_numbers:
- 1539154
description: >
Records the total number of seconds spent downloading during the initial
download without exiting the application using the internal application
downloader for a partial update MAR file when the update makes it to the
last phase where the application has exited and started. This value can be
used with the value of update.startup.downloads.internal_partial_bytes to
estimate the bytes per second for the download.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
internal_complete_bytes:
bug_numbers:
- 1539154
description: >
Records the total number of bytes downloaded by the internal
application downloader for a complete update MAR file when an update makes
it to the last phase where the application has exited and started. This
value can be different than the size of the update MAR file because the
value is only monitored during the initial download while the
application is running and not if the download is resumed.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
internal_complete_seconds:
bug_numbers:
- 1539154
description: >
Records the total number of seconds spent downloading during the initial
download without exiting the application using the internal application
downloader for a complete update MAR file when the update makes it to the
last phase where the application has exited and started. This value can be
used with the value of update.startup.downloads.internal_complete_bytes to
estimate the bytes per second for the download.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
update.session:
from_app_version:
bug_numbers:
- 1539154
description: >
Records the previous application version that the update was applied to
when the update has finished due to a failure before the application has
exited and started.
expires: "72"
kind: string
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- 'main'
mar_partial_size_bytes:
bug_numbers:
- 1539154
description: >
Records the total number of bytes of a partial update MAR file when
the update has finished due to a failure before the application has exited
and started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
mar_complete_size_bytes:
bug_numbers:
- 1539154
description: >
Records the total number of bytes of a complete update MAR file when
the update has finished due to a failure before the application has exited
and started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
update.session.intervals:
check:
bug_numbers:
- 1539154
description: >
Records the interval in seconds of the check phase of the update process
when an update has finished due to a failure before the application has
exited and started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
download_bits_partial:
bug_numbers:
- 1539154
description: >
Records the interval in seconds of the download phase of the update
process using the BITS downloader for a partial update MAR file when the
update has finished due to a failure before the application has exited
and started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
operating_systems:
- "windows"
download_bits_complete:
bug_numbers:
- 1539154
description: >
Records the interval in seconds of the download phase of the update
process using the BITS downloader for a complete update MAR file when the
update has finished due to a failure before the application has exited and
started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
operating_systems:
- "windows"
download_internal_partial:
bug_numbers:
- 1539154
description: >
Records the interval in seconds of the download phase of the update
process using the internal application downloader for a partial update MAR
file when the update has finished due to a failure before the application
has exited and and started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
download_internal_complete:
bug_numbers:
- 1539154
description: >
Records the interval in seconds of the download phase of the update
process using the internal application downloader for a complete update
MAR file when the update has finished due to a failure before the
application has exited and and started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
stage_partial:
bug_numbers:
- 1539154
description: >
Records the interval in seconds of the stage phase of the update process
for a partial update MAR file when the update has finished due to a
failure before the application has exited and started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
stage_complete:
bug_numbers:
- 1539154
description: >
Records the interval in seconds of the stage phase of the update process
for a complete update MAR file when the update has finished due to a
failure before the application has exited and started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
apply_partial:
bug_numbers:
- 1539154
description: >
Records the interval in seconds of the apply phase of the update process
for a partial update MAR file when the update has finished due to a
failure before the application has exited and started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
apply_complete:
bug_numbers:
- 1539154
description: >
Records the interval in seconds of the apply phase of the update process
for a complete update MAR file when the update has finished due to a
failure before the application has exited and started.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
update.session.downloads:
bits_partial_bytes:
bug_numbers:
- 1539154
description: >
Records the total number of bytes downloaded using the BITS downloader for
a partial update MAR file when the update has finished due to a failure
before the application has exited and started. This value can be
different than the size of the update MAR file because the value is only
monitored during the initial download while the application is running and
not if the download is resumed.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
operating_systems:
- "windows"
bits_partial_seconds:
bug_numbers:
- 1539154
description: >
Records the total number of seconds spent downloading during the initial
download without exiting the application using the BITS downloader for a
partial update MAR file when the update has finished due to a failure
before the application has exited and started. This value can be used with
the value of update.session.downloads.bits_partial_bytes to estimate the
bytes per second for the download.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
operating_systems:
- "windows"
bits_complete_bytes:
bug_numbers:
- 1539154
description: >
Records the total number of bytes downloaded using the BITS downloader for
a complete update MAR file when the update has finished due to a failure
before the application has exited and started. This value can be different
than the size of the update MAR file because the value is only monitored
during the initial download while the application is running and not if
the download is resumed.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
operating_systems:
- "windows"
bits_complete_seconds:
bug_numbers:
- 1539154
description: >
Records the total number of seconds spent downloading during the initial
download without exiting the application using the BITS downloader for a
complete update MAR file when the update has finished due to a failure
before the application has exited and started. This value can be used with
the value of update.session.downloads.bits_complete_bytes to estimate the
bytes per second for the download.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
operating_systems:
- "windows"
internal_partial_bytes:
bug_numbers:
- 1539154
description: >
Records the total number of bytes downloaded using the internal
application downloader for a partial update MAR file when the update has
finished due to a failure before the application has exited and started.
This value can be different than the size of the update MAR file because
the value is only monitored during the initial download while the
application is running and not if the download is resumed.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
internal_partial_seconds:
bug_numbers:
- 1539154
description: >
Records the total number of seconds spent downloading during the initial
download without exiting the application using the internal application
downloader for a partial update MAR file when the update has finished due
to a failure before the application has exited and started. This value can
be used with the value of update.session.downloads.internal_partial_bytes
to estimate the bytes per second for the download.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
internal_complete_bytes:
bug_numbers:
- 1539154
description: >
Records the total number of bytes downloaded by the internal
application downloader for a complete update MAR file when an update has
finished due to a failure before the application has exited and started.
This value can be different than the size of the update MAR file because
the value is only monitored during the initial download while the
application is running and not if the download is resumed.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
internal_complete_seconds:
bug_numbers:
- 1539154
description: >
Records the total number of seconds spent downloading during the initial
download without exiting the application using the internal application
downloader for a complete update MAR file when the update has finished due
to a failure before the application has exited and started. This value can
be used with the value of update.session.downloads.internal_complete_bytes
to estimate the bytes per second for the download.
expires: "72"
kind: uint
keyed: false
notification_emails:
- application-update-telemetry-alerts@mozilla.com
- rstrong@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- main
# The following section contains search counters.
browser.search:
with_ads:
@ -2848,6 +3614,45 @@ networking:
record_in_processes:
- 'main'
data_transferred_captive_portal:
bug_numbers:
- 1543005
description: >
Hom many KB has been transfer over a captive portal during a subsession.
expires: "73"
keyed: false
kind: uint
notification_emails:
- ddamjanovic@mozilla.com
record_in_processes:
- 'main'
http_transactions_captive_portal:
bug_numbers:
- 1543005
description: >
Number of http transactions transfer over a captive portal during a subsession.
expires: "73"
keyed: false
kind: uint
notification_emails:
- ddamjanovic@mozilla.com
record_in_processes:
- 'main'
http_connections_captive_portal:
bug_numbers:
- 1543005
description: >
Number of http connections transfer over a captive portal during a subsession.
expires: "73"
keyed: false
kind: uint
notification_emails:
- ddamjanovic@mozilla.com
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:

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

@ -62,8 +62,6 @@ skip-if = (verify && (os == 'win'))
[test_autocomplete3.xul]
[test_autocomplete4.xul]
[test_autocomplete5.xul]
[test_autocomplete_delayOnPaste.xul]
subsuite = clipboard
[test_autocomplete_emphasis.xul]
[test_autocomplete_with_composition_on_input.html]
[test_autocomplete_with_composition_on_textbox.xul]

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

@ -1,126 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<window title="Autocomplete Widget Test 4"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="runTest();">
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
<script type="application/javascript"
src="chrome://global/content/globalOverlay.js"/>
<textbox id="autocomplete"
type="autocomplete"
completedefaultindex="true"
onsearchcomplete="searchComplete();"
timeout="0"
autocompletesearch="simple"/>
<script class="testbody" type="application/javascript">
<![CDATA[
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
function autoCompleteSimpleResult(aString) {
this.searchString = aString;
this.searchResult = Ci.nsIAutoCompleteResult.RESULT_SUCCESS;
this.matchCount = 1;
this._param = "Result";
}
autoCompleteSimpleResult.prototype = {
_param: "",
searchString: null,
searchResult: Ci.nsIAutoCompleteResult.RESULT_FAILURE,
defaultIndex: 0,
errorDescription: null,
matchCount: 0,
getValueAt: function() { return this._param; },
getCommentAt: function() { return null; },
getStyleAt: function() { return null; },
getImageAt: function() { return null; },
getFinalCompleteValueAt: function() { return this.getValueAt(); },
getLabelAt: function() { return null; },
removeValueAt: function() {}
};
// A basic autocomplete implementation that returns one result.
let autoCompleteSimple = {
classID: Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca"),
contractID: "@mozilla.org/autocomplete/search;1?name=simple",
QueryInterface: ChromeUtils.generateQI([
Ci.nsIFactory,
Ci.nsIAutoCompleteSearch
]),
createInstance: function (outer, iid) {
return this.QueryInterface(iid);
},
registerFactory: function () {
let registrar =
Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
registrar.registerFactory(this.classID, "Test Simple Autocomplete",
this.contractID, this);
},
unregisterFactory: function () {
let registrar =
Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
registrar.unregisterFactory(this.classID, this);
},
startSearch: function (aString, aParam, aResult, aListener) {
let result = new autoCompleteSimpleResult(aString);
aListener.onSearchResult(this, result);
},
stopSearch: function () {}
};
SimpleTest.waitForExplicitFinish();
let gACTimer;
let gAutoComplete;
function searchComplete() {
is(gAutoComplete.value, "result", "Value should be autocompleted now");
ok(Date.now() - gACTimer > 500, "There should be a delay before autocomplete");
// Unregister the factory so that we don't get in the way of other tests
autoCompleteSimple.unregisterFactory();
SimpleTest.finish();
}
function runTest() {
autoCompleteSimple.registerFactory();
gAutoComplete = $("autocomplete");
const SEARCH_STRING = "res";
function cbCallback() {
gAutoComplete.focus();
synthesizeKey("v", { accelKey: true });
is(gAutoComplete.value, SEARCH_STRING, "Value should not be autocompleted immediately");
}
SimpleTest.waitForClipboard(SEARCH_STRING, function () {
gACTimer = Date.now();
Cc["@mozilla.org/widget/clipboardhelper;1"]
.getService(Ci.nsIClipboardHelper)
.copyStringToClipboard(SEARCH_STRING, Ci.nsIClipboard.kGlobalClipboard);
}, cbCallback, cbCallback);
}
]]>
</script>
<body xmlns="http://www.w3.org/1999/xhtml">
<p id="display">
</p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</window>

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

@ -45,15 +45,8 @@
this._searchCompleteHandler = this.initEventHandler("searchcomplete");
this._textEnteredHandler = this.initEventHandler("textentered");
this._textRevertedHandler = this.initEventHandler("textreverted");
// For security reasons delay searches on pasted values.
this.inputField.controllers.insertControllerAt(0, this._pasteController);
]]></constructor>
<destructor><![CDATA[
this.inputField.controllers.removeController(this._pasteController);
]]></destructor>
<!-- =================== nsIAutoCompleteInput =================== -->
<field name="_popup">null</field>
@ -113,18 +106,8 @@
onget="var m = parseInt(this.getAttribute('minresultsforpopup')); return isNaN(m) ? 1 : m;"/>
<property name="timeout"
onset="this.setAttribute('timeout', val); return val;">
<getter><![CDATA[
// For security reasons delay searches on pasted values.
if (this._valueIsPasted) {
let t = parseInt(this.getAttribute("pastetimeout"));
return isNaN(t) ? 1000 : t;
}
let t = parseInt(this.getAttribute("timeout"));
return isNaN(t) ? 50 : t;
]]></getter>
</property>
onset="this.setAttribute('timeout', val); return val;"
onget="var t = parseInt(this.getAttribute('timeout')); return isNaN(t) ? 50 : t;"/>
<property name="searchParam"
onget="return this.getAttribute('autocompletesearchparam') || '';"
@ -554,25 +537,6 @@
]]></body>
</method>
<field name="_valueIsPasted">false</field>
<field name="_pasteController"><![CDATA[
({
_autocomplete: this,
_kGlobalClipboard: Ci.nsIClipboard.kGlobalClipboard,
supportsCommand: aCommand => aCommand == "cmd_paste",
doCommand(aCommand) {
this._autocomplete._valueIsPasted = true;
this._autocomplete.editor.paste(this._kGlobalClipboard);
this._autocomplete._valueIsPasted = false;
},
isCommandEnabled(aCommand) {
return this._autocomplete.editor.isSelectionEditable &&
this._autocomplete.editor.canPaste(this._kGlobalClipboard);
},
onEvent() {},
})
]]></field>
<method name="_setValueInternal">
<parameter name="aValue"/>
<parameter name="aIsUserInput"/>

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

@ -233,6 +233,8 @@ var gLogfileWritePromise;
// at once. Computers with many users (ex: a school computer), should not end
// up with dozens of BITS jobs.
var gBITSInUseByAnotherUser = false;
// The start time in milliseconds of the update check.
var gCheckStartMs;
XPCOMUtils.defineLazyGetter(this, "gLogEnabled", function aus_gLogEnabled() {
return Services.prefs.getBoolPref(PREF_APP_UPDATE_LOG, false) ||
@ -1933,8 +1935,16 @@ UpdateService.prototype = {
// be resumed the next time the application starts. Downloads using
// Windows BITS are not stopped since they don't require Firefox to be
// running to perform the download.
if (this._downloader && !this._downloader.usingBits) {
this.stopDownload();
if (this._downloader) {
if (!this._downloader.usingBits) {
this.stopDownload();
} else {
// The BITS downloader isn't stopped on exit so the
// active-update.xml needs to be saved for the values sent to
// telemetry to be saved to disk.
Cc["@mozilla.org/updates/update-manager;1"].
getService(Ci.nsIUpdateManager).saveUpdates();
}
}
// Prevent leaking the downloader (bug 454964)
this._downloader = null;
@ -2127,6 +2137,10 @@ UpdateService.prototype = {
update.errorCode = parseInt(parts[1]);
}
if (update.state == STATE_SUCCEEDED || update.patchCount == 1 ||
(update.selectedPatch && update.selectedPatch.type == "complete")) {
AUSTLMY.pingUpdatePhases(update, true);
}
if (status != STATE_SUCCEEDED) {
// Rotate the update logs so the update log isn't removed. By passing
@ -3175,6 +3189,10 @@ UpdateManager.prototype = {
if (!update) {
return;
}
let patch = update.selectedPatch.QueryInterface(Ci.nsIWritablePropertyBag);
patch.setProperty("stageFinished", Math.ceil(Date.now() / 1000));
var status = readStatusFile(getUpdatesDir());
pingStateAndStatusCodes(update, false, status);
var parts = status.split(":");
@ -3200,6 +3218,10 @@ UpdateManager.prototype = {
writeStatusFile(getUpdatesDir(), update.state = STATE_APPLIED_SERVICE);
}
if (update.state == STATE_FAILED) {
AUSTLMY.pingUpdatePhases(update, false);
}
// Now that the active update's properties have been updated write the
// active-update.xml to disk. Since there have been no changes to the update
// history the updates.xml will not be written to disk.
@ -3223,6 +3245,7 @@ UpdateManager.prototype = {
update.state == STATE_PENDING ||
update.state == STATE_PENDING_SERVICE ||
update.state == STATE_PENDING_ELEVATE) {
patch.setProperty("applyStart", Math.floor(Date.now() / 1000));
// Notify the user that an update has been staged and is ready for
// installation (i.e. that they should restart the application).
let prompter = Cc["@mozilla.org/updates/update-prompt;1"].
@ -3378,6 +3401,7 @@ Checker.prototype = {
throw Cr.NS_ERROR_NULL_POINTER;
}
gCheckStartMs = Date.now();
let UpdateServiceInstance = UpdateServiceFactory.createInstance();
// |force| can override |canCheckForUpdates| since |force| indicates a
// manual update check. But nothing should override enterprise policies.
@ -3650,6 +3674,17 @@ Downloader.prototype = {
*/
_bitsActiveNotifications: false,
/**
* The start time of the first download attempt in milliseconds for telemetry.
*/
_startDownloadMs: null,
/**
* The name of the downloader being used to download the update. This is used
* when setting property names on the update patch for telemetry.
*/
_downloaderName: "bits",
/**
* Cancels the active download.
*
@ -3878,13 +3913,28 @@ Downloader.prototype = {
AUSTLMY.pingDownloadCode(undefined, AUSTLMY.DWNLD_ERR_NO_UPDATE_PATCH);
return readStatusFile(updateDir);
}
// QI the update and the patch to nsIWritablePropertyBag so it isn't
// necessary later in the download code.
this._update.QueryInterface(Ci.nsIWritablePropertyBag);
if (gCheckStartMs && !this._update.getProperty("checkInterval")) {
let interval = Math.max(Math.ceil((Date.now() - gCheckStartMs) / 1000), 1);
this._update.setProperty("checkInterval", interval);
}
// this._patch implements nsIWritablePropertyBag. Expose that interface
// immediately after a patch is assigned so that this._patch.getProperty
// and this._patch.setProperty can always safely be called.
this._patch.QueryInterface(Ci.nsIWritablePropertyBag);
this.isCompleteUpdate = this._patch.type == "complete";
if (!this._canUseBits(this._patch)) {
let canUseBits = this._canUseBits(this._patch);
if (!canUseBits) {
this._downloaderName = "internal";
}
if (!this._patch.getProperty(this._downloaderName + "DownloadStart")) {
this._patch.setProperty(this._downloaderName + "DownloadStart", Math.floor(Date.now() / 1000));
}
if (!canUseBits) {
let patchFile = getUpdatesDir().clone();
patchFile.append(FILE_UPDATE_MAR);
@ -4108,6 +4158,17 @@ Downloader.prototype = {
getService(Ci.nsIUpdateManager).saveUpdates();
}
}
// Only record the download bytes per second when there isn't already a
// value for the bytes per second so downloads that are already in progess
// don't have their records overwritten. When the Update Agent is
// implemented this should be reworked so that telemetry receives the bytes
// and seconds it took to complete for the entire update download instead of
// just the sample that is currently recorded. Note: this._patch has already
// been QI'd to nsIWritablePropertyBag.
if (!this._patch.getProperty("internalBytes") &&
!this._patch.getProperty("bitsBytes")) {
this._startDownloadMs = Date.now();
}
// Make shallow copy in case listeners remove themselves when called.
let listeners = this._listeners.concat();
@ -4131,6 +4192,11 @@ Downloader.prototype = {
onProgress: function Downloader_onProgress(request, context, progress,
maxProgress) {
LOG("Downloader:onProgress - progress: " + progress + "/" + maxProgress);
if (this._startDownloadMs) {
let seconds = Math.round((Date.now() - this._startDownloadMs) / 1000);
this._patch.setProperty(this._downloaderName + "Seconds", seconds);
this._patch.setProperty(this._downloaderName + "Bytes", progress);
}
if (progress > this._patch.size) {
LOG("Downloader:onProgress - progress: " + progress +
@ -4253,6 +4319,8 @@ Downloader.prototype = {
"current fail: " + this.updateService._consecutiveSocketErrors + ", " +
"max fail: " + maxFail + ", " +
"retryTimeout: " + retryTimeout);
this._patch.setProperty(this._downloaderName + "DownloadFinished",
Math.floor(Date.now() / 1000));
if (Components.isSuccessCode(status)) {
if (this._verifyDownload()) {
if (shouldUseService()) {
@ -4456,6 +4524,7 @@ Downloader.prototype = {
Services.prefs.setIntPref(PREF_APP_UPDATE_DOWNLOAD_ATTEMPTS, downloadAttempts);
let maxAttempts = Math.min(Services.prefs.getIntPref(PREF_APP_UPDATE_DOWNLOAD_MAXATTEMPTS, 2), 10);
AUSTLMY.pingUpdatePhases(this._update, false);
if (downloadAttempts > maxAttempts) {
LOG("Downloader:onStopRequest - notifying observers of error. " +
"topic: update-error, status: download-attempts-exceeded, " +
@ -4496,6 +4565,7 @@ Downloader.prototype = {
LOG("Downloader:onStopRequest - attempting to stage update: " +
this._update.name);
gUpdateFileWriteInfo = {phase: "stage", failure: false};
this._patch.setProperty("stageStart", Math.floor(Date.now() / 1000));
// Stage the update
try {
Cc["@mozilla.org/updates/update-processor;1"].
@ -4509,6 +4579,8 @@ Downloader.prototype = {
shouldShowPrompt = true;
}
}
} else {
this._patch.setProperty("applyStart", Math.floor(Date.now() / 1000));
}
}

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

@ -13,6 +13,14 @@ const {BitsError, BitsUnknownError} =
ChromeUtils.import("resource://gre/modules/Bits.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm", this);
// It is possible for the update.session telemetry to be set more than once
// which must be prevented since they are scalars and setting them more than
// once could lead to values set in the first ping not being present in the
// next ping which would make the values incomprehensible in relation to the
// other values. This isn't needed for update.startup since this will only be
// set once during startup.
var gUpdatePhasesSetForSession = false;
var AUSTLMY = {
// Telemetry for the application update background update check occurs when
// the background update timer fires after the update interval which is
@ -432,6 +440,111 @@ var AUSTLMY = {
}
},
/**
* Submit the update phase telemetry. These are scalars and must only be
* submitted once per sesssion. The update.startup is only submitted once
* once per session due to it only being submitted during startup and only the
* first call to pingUpdatePhases for update.session will be submitted.
*
* @param aUpdate
* The update object which contains the values to submit to telemetry.
* @param aIsStartup
* If true the telemetry will be set under update.startup and if false
* the telemetry will be set under update.session. When false
* subsequent calls will return early and not submit telemetry.
*/
pingUpdatePhases: function UT_pingUpdatePhases(aUpdate, aIsStartup) {
if (!aIsStartup && !Cu.isInAutomation) {
if (gUpdatePhasesSetForSession) {
return;
}
gUpdatePhasesSetForSession = true;
}
let basePrefix = aIsStartup ? "update.startup." : "update.session.";
// None of the calls to getProperty should fail.
try {
let update = aUpdate.QueryInterface(Ci.nsIWritablePropertyBag);
let scalarSet = Services.telemetry.scalarSet;
// Though it is possible that the previous app version that was updated
// from could change the record is for the app version that initiated the
// update.
scalarSet(basePrefix + "from_app_version", aUpdate.previousAppVersion);
// The check interval only happens once even if the partial patch fails
// to apply on restart and the complete patch is downloaded.
scalarSet(basePrefix + "intervals.check",
update.getProperty("checkInterval"));
for (let i = 0; i < aUpdate.patchCount; ++i) {
let patch =
aUpdate.getPatchAt(i).QueryInterface(Ci.nsIWritablePropertyBag);
let type = patch.type;
scalarSet(basePrefix + "mar_" + type + "_size_bytes", patch.size);
let prefix = basePrefix + "intervals.";
let internalDownloadStart = patch.getProperty("internalDownloadStart");
let internalDownloadFinished =
patch.getProperty("internalDownloadFinished");
if (internalDownloadStart !== null && internalDownloadFinished !== null) {
scalarSet(prefix + "download_internal_" + type,
Math.max((internalDownloadFinished - internalDownloadStart), 1));
}
let bitsDownloadStart = patch.getProperty("bitsDownloadStart");
let bitsDownloadFinished = patch.getProperty("bitsDownloadFinished");
if (bitsDownloadStart !== null && bitsDownloadFinished !== null) {
scalarSet(prefix + "download_bits_" + type,
Math.max((bitsDownloadFinished - bitsDownloadStart), 1));
}
let stageStart = patch.getProperty("stageStart");
let stageFinished = patch.getProperty("stageFinished");
if (stageStart !== null && stageFinished !== null) {
scalarSet(prefix + "stage_" + type,
Math.max((stageFinished - stageStart), 1));
}
// Both the partial and the complete patch are recorded for the apply
// interval because it is possible for a partial patch to fail when it
// is applied during a restart and then to try the complete patch.
let applyStart = patch.getProperty("applyStart");
if (applyStart !== null) {
let applyFinished = Date.now() / 1000;
scalarSet(prefix + "apply_" + type,
Math.max((applyFinished - applyStart), 1));
}
prefix = basePrefix + "downloads.";
let internalBytes = patch.getProperty("internalBytes");
if (internalBytes !== null) {
scalarSet(prefix + "internal_" + type + "_bytes",
Math.max(internalBytes, 1));
}
let internalSeconds = patch.getProperty("internalSeconds");
if (internalSeconds !== null) {
scalarSet(prefix + "internal_" + type + "_seconds",
Math.max(internalSeconds, 1));
}
let bitsBytes = patch.getProperty("bitsBytes");
if (bitsBytes !== null) {
scalarSet(prefix + "bits_" + type + "_bytes",
Math.max(bitsBytes, 1));
}
let bitsSeconds = patch.getProperty("bitsSeconds");
if (bitsSeconds !== null) {
scalarSet(prefix + "bits_" + type + "_seconds",
Math.max(bitsSeconds, 1));
}
}
} catch (e) {
Cu.reportError(e);
}
},
/**
* Submit a telemetry ping for the last page displayed by the update wizard.
*

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

@ -74,4 +74,26 @@ reason = test must be able to prevent file deletion.
[browser_doorhanger_sp_patch_partialApplyFailure_complete.js]
[browser_doorhanger_sp_patch_partialApplyFailure_complete_staging.js]
[browser_doorhanger_sp_patch_partialApplyFailure_completeBadSize.js]
# Telemetry Application Update Tests
[browser_telemetry_completeBadSize.js]
[browser_telemetry_partialBadSize_completeBadSize.js]
[browser_telemetry_complete_stageFailure.js]
skip-if = asan
reason = Bug 1545712
[browser_telemetry_partial_stageFailure_complete_stageFailure.js]
skip-if = asan
reason = Bug 1545712
[browser_telemetry_complete_applyFailure.js]
[browser_telemetry_partial_applyFailure_complete_applyFailure.js]
[browser_telemetry_partial_applyFailure_complete_stageFailure.js]
skip-if = asan
reason = Bug 1545712
[browser_telemetry_partial_applyFailure_complete_applied.js]
[browser_telemetry_partial_applyFailure_complete_staged_applied.js]
[browser_telemetry_partialBadSize_complete_staged_applied.js]
[browser_telemetry_complete_applied.js]
[browser_telemetry_partial_applied.js]
[browser_telemetry_partial_staged_applied.js]
[browser_telemetry_complete_staged_applied.js]
[browser_TelemetryUpdatePing.js]

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

@ -2,7 +2,6 @@ add_task(async function testDownloadFailures() {
const maxBackgroundErrors = 5;
SpecialPowers.pushPrefEnv({set: [
[PREF_APP_UPDATE_BACKGROUNDMAXERRORS, maxBackgroundErrors],
[PREF_APP_UPDATE_DOWNLOADPROMPT_MAXATTEMPTS, 2],
]});
let updateParams = "badURL=1";

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

@ -2,7 +2,6 @@ add_task(async function testBackgroundWindowFailures() {
const maxBackgroundErrors = 5;
SpecialPowers.pushPrefEnv({set: [
[PREF_APP_UPDATE_BACKGROUNDMAXERRORS, maxBackgroundErrors],
[PREF_APP_UPDATE_DOWNLOADPROMPT_MAXATTEMPTS, 2],
]});
let updateParams = "badURL=1";

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

@ -4,7 +4,6 @@ add_task(async function testCompleteAndPartialPatchesWithBadCompleteSize() {
]});
let updateParams = "invalidCompleteSize=1&promptWaitTime=0";
await runUpdateTest(updateParams, 1, [
{
notificationId: "update-restart",

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

@ -1,10 +1,5 @@
add_task(async function testCompletePatchWithBadCompleteSize() {
SpecialPowers.pushPrefEnv({set: [
[PREF_APP_UPDATE_DOWNLOADPROMPT_MAXATTEMPTS, 2],
]});
let updateParams = "completePatchOnly=1&invalidCompleteSize=1";
await runUpdateTest(updateParams, 1, [
{
// if we fail maxBackgroundErrors download attempts, then we want to

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

@ -1,9 +1,5 @@
add_task(async function testPartialPatchWithBadPartialSize() {
SpecialPowers.pushPrefEnv({set: [
[PREF_APP_UPDATE_DOWNLOADPROMPT_MAXATTEMPTS, 2],
]});
let updateParams = "partialPatchOnly=1&invalidPartialSize=1";
await runUpdateTest(updateParams, 1, [
{
// if we fail maxBackgroundErrors download attempts, then we want to

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

@ -1,9 +1,5 @@
add_task(async function testCompleteAndPartialPatchesWithBadSizes() {
SpecialPowers.pushPrefEnv({set: [
[PREF_APP_UPDATE_DOWNLOADPROMPT_MAXATTEMPTS, 2],
]});
let updateParams = "invalidPartialSize=1&invalidCompleteSize=1";
await runUpdateTest(updateParams, 1, [
{
// if we fail maxBackgroundErrors download attempts, then we want to

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

@ -1,9 +1,11 @@
add_task(async function testPartialPatchApplyFailureWithCompleteValidationFailure() {
// because of the way we're simulating failure, we have to just pretend we've already
// retried.
SpecialPowers.pushPrefEnv({set: [
[PREF_APP_UPDATE_DOWNLOADPROMPT_MAXATTEMPTS, 0],
]});
await SpecialPowers.pushPrefEnv({
set: [
[PREF_APP_UPDATE_DOWNLOAD_MAXATTEMPTS, 0],
],
});
let patchProps = {type: "partial",
state: STATE_PENDING};

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

@ -0,0 +1,24 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Telemetry test for Application Update phases.
// Telemetry update.session
// Complete patch only
// Complete patch download failure
add_task(async function telemetry_completeBadSize() {
let updateParams = "&completePatchOnly=1&invalidCompleteSize=1";
await runTelemetryUpdateTest(updateParams, "update-error");
let expected = getTelemetryUpdatePhaseValues({
forSession: true,
noPartialPatch: true,
completeBadSize: true,
});
checkTelemetryUpdatePhases(expected);
testPostUpdateProcessing();
// Verify that update phase startup telemetry is empty.
checkTelemetryUpdatePhaseEmpty(true);
});

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

@ -0,0 +1,25 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Telemetry test for Application Update phases.
// Telemetry update.startup
// Complete patch only
// Complete patch download
// Complete patch applied
add_task(async function telemetry_complete_applied() {
let updateParams = "&completePatchOnly=1";
await runTelemetryUpdateTest(updateParams, "update-downloaded");
writeStatusFile(STATE_SUCCEEDED);
testPostUpdateProcessing();
let expected = getTelemetryUpdatePhaseValues({
noPartialPatch: true,
});
checkTelemetryUpdatePhases(expected);
// Verify that update phase session telemetry is empty.
checkTelemetryUpdatePhaseEmpty(false);
});

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

@ -0,0 +1,25 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Telemetry test for Application Update phases.
// Telemetry update.startup
// Complete patch only
// Complete patch download
// Complete patch apply failure
add_task(async function telemetry_complete_applyFailure() {
let updateParams = "&completePatchOnly=1";
await runTelemetryUpdateTest(updateParams, "update-downloaded");
writeStatusFile(STATE_FAILED_CRC_ERROR);
testPostUpdateProcessing();
let expected = getTelemetryUpdatePhaseValues({
noPartialPatch: true,
});
checkTelemetryUpdatePhases(expected);
// Verify that update phase session telemetry is empty.
checkTelemetryUpdatePhaseEmpty(false);
});

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

@ -0,0 +1,31 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Telemetry test for Application Update phases.
// Telemetry update.session
// Complete patch only
// Complete patch download
// Complete patch stage failure
add_task(async function telemetry_complete_stageFailure() {
await SpecialPowers.pushPrefEnv({
set: [
[PREF_APP_UPDATE_STAGING_ENABLED, true],
],
});
let updateParams = "&completePatchOnly=1";
await runTelemetryUpdateTest(updateParams, "update-staged", true);
let expected = getTelemetryUpdatePhaseValues({
forSession: true,
noPartialPatch: true,
noApplyComplete: true,
});
checkTelemetryUpdatePhases(expected);
testPostUpdateProcessing();
// Verify that update phase startup telemetry is empty.
checkTelemetryUpdatePhaseEmpty(true);
});

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

@ -0,0 +1,32 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Telemetry test for Application Update phases.
// Telemetry update.startup
// Complete patch only
// Complete patch download
// Complete patch staged
// Complete patch applied
add_task(async function telemetry_complete_staged_applied() {
await SpecialPowers.pushPrefEnv({
set: [
[PREF_APP_UPDATE_STAGING_ENABLED, true],
],
});
let updateParams = "&completePatchOnly=1";
await runTelemetryUpdateTest(updateParams, "update-staged");
writeStatusFile(STATE_SUCCEEDED);
testPostUpdateProcessing();
let expected = getTelemetryUpdatePhaseValues({
noPartialPatch: true,
});
checkTelemetryUpdatePhases(expected);
// Verify that update phase session telemetry is empty.
checkTelemetryUpdatePhaseEmpty(false);
});

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

@ -0,0 +1,25 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Telemetry test for Application Update phases.
// Telemetry update.session
// Partial and complete patches
// Partial patch download failure
// Complete patch download failure
add_task(async function telemetry_partialBadSize_completeBadSize() {
let updateParams = "&invalidPartialSize=1&invalidCompleteSize=1";
await runTelemetryUpdateTest(updateParams, "update-error");
let expected = getTelemetryUpdatePhaseValues({
forSession: true,
partialBadSize: true,
completeBadSize: true,
});
checkTelemetryUpdatePhases(expected);
testPostUpdateProcessing();
// Verify that update phase startup telemetry is empty.
checkTelemetryUpdatePhaseEmpty(true);
});

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

@ -0,0 +1,33 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Telemetry test for Application Update phases.
// Telemetry update.startup
// Partial and complete patches
// Partial patch download failure
// Complete patch download
// Complete patch staged
// Complete patch applied
add_task(async function telemetry_partialBadSize_complete_staged_applied() {
await SpecialPowers.pushPrefEnv({
set: [
[PREF_APP_UPDATE_STAGING_ENABLED, true],
],
});
let updateParams = "&invalidPartialSize=1";
await runTelemetryUpdateTest(updateParams, "update-staged");
writeStatusFile(STATE_SUCCEEDED);
testPostUpdateProcessing();
let expected = getTelemetryUpdatePhaseValues({
partialBadSize: true,
});
checkTelemetryUpdatePhases(expected);
// Verify that update phase session telemetry is empty.
checkTelemetryUpdatePhaseEmpty(false);
});

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

@ -0,0 +1,25 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Telemetry test for Application Update phases.
// Telemetry update.startup
// Partial and complete patches
// Partial patch download
// Partial patch applied
add_task(async function telemetry_partial_applied() {
let updateParams = "";
await runTelemetryUpdateTest(updateParams, "update-downloaded");
writeStatusFile(STATE_SUCCEEDED);
testPostUpdateProcessing();
let expected = getTelemetryUpdatePhaseValues({
noInternalComplete: true,
});
checkTelemetryUpdatePhases(expected);
// Verify that update phase session telemetry is empty.
checkTelemetryUpdatePhaseEmpty(false);
});

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

@ -0,0 +1,32 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Telemetry test for Application Update phases.
// Telemetry update.startup
// Partial and complete patches
// Partial patch download
// Partial patch apply failure
// Complete patch download
// Complete patch applied
add_task(async function telemetry_sp_partialBadSize_complete_staged_applied() {
let updateParams = "";
await runTelemetryUpdateTest(updateParams, "update-downloaded");
writeStatusFile(STATE_FAILED_CRC_ERROR);
testPostUpdateProcessing();
// Verify that update phase startup telemetry is empty.
checkTelemetryUpdatePhaseEmpty(true);
// The download of the complete patch will happen automatically.
await waitForEvent("update-downloaded");
writeStatusFile(STATE_SUCCEEDED);
testPostUpdateProcessing();
let expected = getTelemetryUpdatePhaseValues({});
checkTelemetryUpdatePhases(expected);
// Verify that update phase session telemetry is empty.
checkTelemetryUpdatePhaseEmpty(false);
});

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

@ -0,0 +1,32 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Telemetry test for Application Update phases.
// Telemetry update.startup
// Partial and complete patches
// Partial patch download
// Partial patch apply failure
// Complete patch download
// Complete patch apply failure
add_task(async function telemetry_partial_applyFailure_complete_applyFailure() {
let updateParams = "";
await runTelemetryUpdateTest(updateParams, "update-downloaded");
writeStatusFile(STATE_FAILED_CRC_ERROR);
testPostUpdateProcessing();
// Verify that update phase startup telemetry is empty.
checkTelemetryUpdatePhaseEmpty(true);
// The download of the complete patch will happen automatically.
await waitForEvent("update-downloaded");
writeStatusFile(STATE_FAILED_CRC_ERROR);
testPostUpdateProcessing();
let expected = getTelemetryUpdatePhaseValues({});
checkTelemetryUpdatePhases(expected);
// Verify that update phase session telemetry is empty.
checkTelemetryUpdatePhaseEmpty(false);
});

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

@ -0,0 +1,45 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Telemetry test for Application Update phases.
// Telemetry update.session
// Partial and complete patches
// Partial patch download
// Partial patch apply failure
// Complete patch download
// Complete patch stage failure
add_task(async function telemetry_partial_applyFailure_complete_stageFailure() {
let updateParams = "";
await runTelemetryUpdateTest(updateParams, "update-downloaded");
await SpecialPowers.pushPrefEnv({
set: [
[PREF_APP_UPDATE_STAGING_ENABLED, true],
],
});
// Now that staging is enabled setup the test updater.
await setupTestUpdater();
// Remove the update-settings.ini file so staging fails.
removeUpdateSettingsIni();
// Fail applying the partial.
writeStatusFile(STATE_FAILED_CRC_ERROR);
testPostUpdateProcessing();
// Verify that update phase startup telemetry wasn't set.
checkTelemetryUpdatePhaseEmpty(true);
// The download and staging of the complete patch will happen automatically.
await waitForEvent("update-staged");
let expected = getTelemetryUpdatePhaseValues({
forSession: true,
noStagePartial: true,
noApplyComplete: true,
});
checkTelemetryUpdatePhases(expected);
testPostUpdateProcessing();
// Verify that update phase startup telemetry is empty.
checkTelemetryUpdatePhaseEmpty(true);
});

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

@ -0,0 +1,44 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Telemetry test for Application Update phases.
// Telemetry update.startup
// Partial and complete patches
// Partial patch download
// Partial patch apply failure
// Complete patch download
// Complete patch staged
// Complete patch applied
add_task(async function telemetry_partial_applyFailure_complete_staged_applied() {
let updateParams = "";
await runTelemetryUpdateTest(updateParams, "update-downloaded");
await SpecialPowers.pushPrefEnv({
set: [
[PREF_APP_UPDATE_STAGING_ENABLED, true],
],
});
// Now that staging is enabled setup the test updater.
await setupTestUpdater();
// Fail applying the partial.
writeStatusFile(STATE_FAILED_CRC_ERROR);
testPostUpdateProcessing();
// Verify that update phase startup telemetry is empty.
checkTelemetryUpdatePhaseEmpty(true);
// The download and staging of the complete will happen automatically.
await waitForEvent("update-staged");
// Succeed applying the complete patch.
writeStatusFile(STATE_SUCCEEDED);
testPostUpdateProcessing();
let expected = getTelemetryUpdatePhaseValues({
noStagePartial: true,
});
checkTelemetryUpdatePhases(expected);
// Verify that update phase session telemetry is empty.
checkTelemetryUpdatePhaseEmpty(false);
});

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

@ -0,0 +1,35 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Telemetry test for Application Update phases.
// Telemetry update.session
// Partial and complete patches
// Partial patch download
// Partial patch stage failure
// Complete patch download
// Complete patch stage failure
add_task(async function telemetry_partial_stageFailure_complete_stageFailure() {
await SpecialPowers.pushPrefEnv({
set: [
[PREF_APP_UPDATE_STAGING_ENABLED, true],
],
});
let updateParams = "";
await runTelemetryUpdateTest(updateParams, "update-staged", true);
await waitForEvent("update-staged");
let expected = getTelemetryUpdatePhaseValues({
forSession: true,
noApplyPartial: true,
noApplyComplete: true,
});
checkTelemetryUpdatePhases(expected);
testPostUpdateProcessing();
// Verify that update phase startup telemetry is empty.
checkTelemetryUpdatePhaseEmpty(true);
});

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

@ -0,0 +1,32 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Telemetry test for Application Update phases.
// Telemetry update.startup
// Partial and complete patches
// Partial patch download
// Partial patch staged
// Partial patch applied
add_task(async function telemetry_partial_staged_applied() {
await SpecialPowers.pushPrefEnv({
set: [
[PREF_APP_UPDATE_STAGING_ENABLED, true],
],
});
let updateParams = "";
await runTelemetryUpdateTest(updateParams, "update-staged");
writeStatusFile(STATE_SUCCEEDED);
testPostUpdateProcessing();
let expected = getTelemetryUpdatePhaseValues({
noInternalComplete: true,
});
checkTelemetryUpdatePhases(expected);
// Verify that update phase session telemetry is empty.
checkTelemetryUpdatePhaseEmpty(false);
});

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

@ -46,12 +46,16 @@ requestLongerTimeout(10);
add_task(async function setupTestCommon() {
await SpecialPowers.pushPrefEnv({
set: [
[PREF_APP_UPDATE_DOWNLOAD_ATTEMPTS, 0],
[PREF_APP_UPDATE_DOWNLOAD_MAXATTEMPTS, 2],
[PREF_APP_UPDATE_LOG, gDebugTest],
[PREF_APP_UPDATE_SERVICE_ENABLED, false],
],
});
setUpdateTimerPrefs();
removeUpdateFiles(true);
AppMenuNotifications.removeNotification(/.*/);
// Most app update mochitest-browser-chrome tests expect auto update to be
// enabled. Those that don't will explicitly change this.
await setAppUpdateAutoEnabledHelper(true);
@ -61,6 +65,7 @@ add_task(async function setupTestCommon() {
* Common tasks to perform for all tests after each one has finished.
*/
registerCleanupFunction(async () => {
AppMenuNotifications.removeNotification(/.*/);
gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "");
gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "");
UpdateListener.reset();
@ -120,8 +125,9 @@ async function continueFileHandler(leafName) {
}
}
if (continueFile.exists()) {
throw new Error("The continue file should not exist, path: " +
continueFile.path);
logTestInfo("The continue file should not exist, path: " +
continueFile.path);
continueFile.remove(false);
}
debugDump("Creating continue file, path: " + continueFile.path);
continueFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE);
@ -258,7 +264,6 @@ function runUpdateTest(updateParams, checkAttempts, steps) {
gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
await SpecialPowers.pushPrefEnv({
set: [
[PREF_APP_UPDATE_DOWNLOADPROMPTATTEMPTS, 0],
[PREF_APP_UPDATE_DISABLEDFORTESTING, false],
[PREF_APP_UPDATE_IDLETIME, 0],
[PREF_APP_UPDATE_URL_MANUAL, URL_MANUAL_UPDATE],
@ -305,7 +310,6 @@ function runUpdateProcessingTest(updates, steps) {
gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
await SpecialPowers.pushPrefEnv({
set: [
[PREF_APP_UPDATE_DOWNLOADPROMPTATTEMPTS, 0],
[PREF_APP_UPDATE_DISABLEDFORTESTING, false],
[PREF_APP_UPDATE_IDLETIME, 0],
[PREF_APP_UPDATE_URL_MANUAL, URL_MANUAL_UPDATE],
@ -676,7 +680,6 @@ function runAboutDialogUpdateTest(updateParams, backgroundUpdate, steps) {
gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "1");
await SpecialPowers.pushPrefEnv({
set: [
[PREF_APP_UPDATE_SERVICE_ENABLED, false],
[PREF_APP_UPDATE_DISABLEDFORTESTING, false],
[PREF_APP_UPDATE_URL_MANUAL, detailsURL],
],
@ -805,7 +808,6 @@ function runAboutPrefsUpdateTest(updateParams, backgroundUpdate, steps) {
gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "1");
await SpecialPowers.pushPrefEnv({
set: [
[PREF_APP_UPDATE_SERVICE_ENABLED, false],
[PREF_APP_UPDATE_DISABLEDFORTESTING, false],
[PREF_APP_UPDATE_URL_MANUAL, detailsURL],
],
@ -841,3 +843,274 @@ function runAboutPrefsUpdateTest(updateParams, backgroundUpdate, steps) {
}
})();
}
/**
* Removes the modified update-settings.ini file so the updater will fail to
* stage an update.
*/
function removeUpdateSettingsIni() {
if (Services.prefs.getBoolPref(PREF_APP_UPDATE_STAGING_ENABLED)) {
let greDir = getGREDir();
let updateSettingsIniBak = greDir.clone();
updateSettingsIniBak.append(FILE_UPDATE_SETTINGS_INI_BAK);
if (updateSettingsIniBak.exists()) {
let updateSettingsIni = greDir.clone();
updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
updateSettingsIni.remove(false);
}
}
}
/**
* Runs a telemetry update test. This will set various common prefs for
* updating, checks for an update, and waits for the specified observer
* notification.
*
* @param updateParams
* Params which will be sent to app_update.sjs.
* @param event
* The observer notification to wait for before proceeding.
* @param stageFailure (optional)
* Whether to force a staging failure by removing the modified
* update-settings.ini file.
* @return A promise which will resolve after the .
*/
function runTelemetryUpdateTest(updateParams, event, stageFailure = false) {
// Some elements append a trailing /. After the chrome tests are removed this
// code can be changed so URL_HOST already has a trailing /.
let detailsURL = URL_HOST + "/";
return (async function() {
Services.telemetry.clearScalars();
gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "1");
await SpecialPowers.pushPrefEnv({
set: [
[PREF_APP_UPDATE_DISABLEDFORTESTING, false],
],
});
await setupTestUpdater();
if (stageFailure) {
removeUpdateSettingsIni();
}
let updateURL = URL_HTTP_UPDATE_SJS + "?detailsURL=" + detailsURL +
updateParams + getVersionParams();
setUpdateURL(updateURL);
if (Services.prefs.getBoolPref(PREF_APP_UPDATE_STAGING_ENABLED)) {
// Since MOZ_TEST_SKIP_UPDATE_STAGE is checked before
// MOZ_TEST_SLOW_SKIP_UPDATE_STAGE in updater.cpp this removes the need
// for the continue file to continue staging the update.
gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
}
gAUS.checkForBackgroundUpdates();
await waitForEvent(event);
})();
}
/**
* Gets an object with the expected update phase values that can be passed to
* checkTelemetryUpdatePhases for update phase telemetry tests.
*
* @param overrides
* Params which can override the default values.
* @return An object that can be passed to checkTelemetryUpdatePhases for update
* phase telemetry tests.
*/
function getTelemetryUpdatePhaseValues(overrides) {
// Set values that could never be recorded due to values that would prevent
// them from occurring. This makes it so callers only have to specify a couple
// of values.
if (overrides.noPartialPatch) {
if (!overrides.noInternalPartial) {
overrides.noInternalPartial = true;
}
}
if (overrides.noCompletePatch) {
if (!overrides.noInternalComplete) {
overrides.noInternalComplete = true;
}
}
if (overrides.noPartialPatch || overrides.partialBadSize ||
overrides.noInternalPartial) {
if (!overrides.noStagePartial) {
overrides.noStagePartial = true;
}
if (!overrides.noApplyPartial) {
overrides.noApplyPartial = true;
}
}
if (overrides.noCompletePatch || overrides.completeBadSize ||
overrides.noInternalComplete) {
if (!overrides.noStageComplete) {
overrides.noStageComplete = true;
}
if (!overrides.noApplyComplete) {
overrides.noApplyComplete = true;
}
}
if (!Services.prefs.getBoolPref(PREF_APP_UPDATE_STAGING_ENABLED)) {
if (!overrides.noStagePartial) {
overrides.noStagePartial = true;
}
if (!overrides.noStageComplete) {
overrides.noStageComplete = true;
}
}
let marSize = parseInt(SIZE_SIMPLE_MAR);
let partialSize =
overrides.partialBadSize ? parseInt(SIZE_SIMPLE_MAR + "1") : marSize;
let completeSize =
overrides.completeBadSize ? parseInt(SIZE_SIMPLE_MAR + "1") : marSize;
let partialDownloadBytes = overrides.partialBadSize ? 1 : marSize;
let completeDownloadBytes = overrides.completeBadSize ? 1 : marSize;
let obj = {};
obj.basePrefix =
overrides.forSession ? "update.session." : "update.startup.";
obj.from_app_version = Services.appinfo.version;
obj.mars = {};
obj.mars.mar_partial_size_bytes =
overrides.noPartialPatch ? null : partialSize;
obj.mars.mar_complete_size_bytes =
overrides.noCompletePatch ? null : completeSize;
obj.intervals = {};
obj.intervals.check = 1;
obj.intervals.download_bits_partial = null;
obj.intervals.download_bits_complete = null;
obj.intervals.download_internal_partial =
overrides.noInternalPartial ? null : 1;
obj.intervals.download_internal_complete =
overrides.noInternalComplete ? null : 1;
obj.intervals.stage_partial = overrides.noStagePartial ? null : 1;
obj.intervals.stage_complete = overrides.noStageComplete ? null : 1;
obj.intervals.apply_partial = overrides.noApplyPartial ? null : 1;
obj.intervals.apply_complete = overrides.noApplyComplete ? null : 1;
obj.downloads = {};
obj.downloads.bits_partial_ = {};
obj.downloads.bits_partial_.bytes = null;
obj.downloads.bits_partial_.seconds = null;
obj.downloads.bits_complete_ = {};
obj.downloads.bits_complete_.bytes = null;
obj.downloads.bits_complete_.seconds = null;
obj.downloads.internal_partial_ = {};
obj.downloads.internal_partial_.bytes =
overrides.noInternalPartial ? null : partialDownloadBytes;
obj.downloads.internal_partial_.seconds =
overrides.noInternalPartial ? null : 1;
obj.downloads.internal_complete_ = {};
obj.downloads.internal_complete_.bytes =
overrides.noInternalComplete ? null : completeDownloadBytes;
obj.downloads.internal_complete_.seconds =
overrides.noInternalComplete ? null : 1;
return obj;
}
/**
* Checks the telemetry values for app update phases under either update.startup
* or update.session based on the object passed to this function.
*
* @param expected
* An object containing the expected results to compare against the
* actual results.
*/
function checkTelemetryUpdatePhases(expected) {
let scalars = TelemetryTestUtils.getProcessScalars("parent");
let basePrefix = expected.basePrefix;
let namePrefix = basePrefix;
{
let name = namePrefix + "from_app_version";
if (expected.from_app_version) {
Assert.ok(!!scalars[name],
"The " + name + " value should exist.");
Assert.equal(scalars[name],
expected.from_app_version,
"The " + name + " value should equal the expected value.");
} else {
Assert.ok(!scalars[name],
"The " + name + " value should not exist.");
}
}
for (let [nameSuffix, value] of Object.entries(expected.mars)) {
let name = namePrefix + nameSuffix;
if (value) {
Assert.ok(!!scalars[name],
"The " + name + " value should exist.");
Assert.equal(scalars[name], value,
"The " + name + " value should equal the expected value.");
} else {
Assert.ok(!scalars[name],
"The " + name + " value should not exist.");
}
}
namePrefix = basePrefix + "intervals.";
for (let [suffix, value] of Object.entries(expected.intervals)) {
let name = namePrefix + suffix;
if (value) {
Assert.ok(!!scalars[name],
"The " + name + " value should exist.");
Assert.greaterOrEqual(scalars[name], value,
"The " + name + " value should be equal to or " +
"greater than " + value + ".");
} else {
Assert.ok(!scalars[name],
"The " + name + " value should not exist.");
}
}
namePrefix = basePrefix + "downloads.";
for (let [nameMid, values] of Object.entries(expected.downloads)) {
let name = namePrefix + nameMid + "bytes";
if (values.bytes) {
Assert.ok(!!scalars[name],
"The " + name + " value should exist.");
Assert.greaterOrEqual(scalars[name], values.bytes,
"The " + name + " value should be equal to or " +
"greater than " + values.bytes + ".");
} else {
Assert.ok(!scalars[name],
"The " + name + " value should not exist.");
}
name = namePrefix + nameMid + "seconds";
if (values.seconds) {
Assert.ok(!!scalars[name],
"The " + name + " value should exist.");
Assert.greaterOrEqual(scalars[name], values.seconds,
"The " + name + " value should be equal to or " +
"greater than " + values.seconds + ".");
} else {
Assert.ok(!scalars[name],
"The " + name + " value should not exist.");
}
}
}
/**
* Checks whether telemetry for update.startup or update.session is set by
* checking if there is a value for the from_app_version scalar.
*
* @param isStartup
* When true update.startup.from_app_version will be checked and when
* false update.session.from_app_version will be checked.
*/
function checkTelemetryUpdatePhaseEmpty(isStartup) {
let scalars = TelemetryTestUtils.getProcessScalars("parent");
let name =
"update." + (isStartup ? "startup" : "session") + ".from_app_version";
Assert.ok(!scalars[name],
"The " + name + " value should not exist.");
}

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

@ -10,36 +10,38 @@
const {FileUtils} = ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
const {TelemetryTestUtils} =
ChromeUtils.import("resource://testing-common/TelemetryTestUtils.jsm");
ChromeUtils.defineModuleGetter(this, "ctypes",
"resource://gre/modules/ctypes.jsm");
ChromeUtils.defineModuleGetter(this, "UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm");
const PREF_APP_UPDATE_AUTO = "app.update.auto";
const PREF_APP_UPDATE_BACKGROUNDERRORS = "app.update.backgroundErrors";
const PREF_APP_UPDATE_BACKGROUNDMAXERRORS = "app.update.backgroundMaxErrors";
const PREF_APP_UPDATE_BITS_ENABLED = "app.update.BITS.enabled";
const PREF_APP_UPDATE_CANCELATIONS = "app.update.cancelations";
const PREF_APP_UPDATE_CHANNEL = "app.update.channel";
const PREF_APP_UPDATE_DOORHANGER = "app.update.doorhanger";
const PREF_APP_UPDATE_DOWNLOADPROMPTATTEMPTS = "app.update.download.attempts";
const PREF_APP_UPDATE_DOWNLOADPROMPT_MAXATTEMPTS = "app.update.download.maxAttempts";
const PREF_APP_UPDATE_DISABLEDFORTESTING = "app.update.disabledForTesting";
const PREF_APP_UPDATE_IDLETIME = "app.update.idletime";
const PREF_APP_UPDATE_INTERVAL = "app.update.interval";
const PREF_APP_UPDATE_LASTUPDATETIME = "app.update.lastUpdateTime.background-update-timer";
const PREF_APP_UPDATE_LOG = "app.update.log";
const PREF_APP_UPDATE_NOTIFIEDUNSUPPORTED = "app.update.notifiedUnsupported";
const PREF_APP_UPDATE_PROMPTWAITTIME = "app.update.promptWaitTime";
const PREF_APP_UPDATE_RETRYTIMEOUT = "app.update.socket.retryTimeout";
const PREF_APP_UPDATE_SERVICE_ENABLED = "app.update.service.enabled";
const PREF_APP_UPDATE_SILENT = "app.update.silent";
const PREF_APP_UPDATE_SOCKET_MAXERRORS = "app.update.socket.maxErrors";
const PREF_APP_UPDATE_STAGING_ENABLED = "app.update.staging.enabled";
const PREF_APP_UPDATE_URL = "app.update.url";
const PREF_APP_UPDATE_URL_DETAILS = "app.update.url.details";
const PREF_APP_UPDATE_URL_MANUAL = "app.update.url.manual";
const PREF_APP_UPDATE_AUTO = "app.update.auto";
const PREF_APP_UPDATE_BACKGROUNDERRORS = "app.update.backgroundErrors";
const PREF_APP_UPDATE_BACKGROUNDMAXERRORS = "app.update.backgroundMaxErrors";
const PREF_APP_UPDATE_BITS_ENABLED = "app.update.BITS.enabled";
const PREF_APP_UPDATE_CANCELATIONS = "app.update.cancelations";
const PREF_APP_UPDATE_CHANNEL = "app.update.channel";
const PREF_APP_UPDATE_DOORHANGER = "app.update.doorhanger";
const PREF_APP_UPDATE_DOWNLOAD_MAXATTEMPTS = "app.update.download.maxAttempts";
const PREF_APP_UPDATE_DOWNLOAD_ATTEMPTS = "app.update.download.attempts";
const PREF_APP_UPDATE_DISABLEDFORTESTING = "app.update.disabledForTesting";
const PREF_APP_UPDATE_IDLETIME = "app.update.idletime";
const PREF_APP_UPDATE_INTERVAL = "app.update.interval";
const PREF_APP_UPDATE_LASTUPDATETIME = "app.update.lastUpdateTime.background-update-timer";
const PREF_APP_UPDATE_LOG = "app.update.log";
const PREF_APP_UPDATE_NOTIFIEDUNSUPPORTED = "app.update.notifiedUnsupported";
const PREF_APP_UPDATE_PROMPTWAITTIME = "app.update.promptWaitTime";
const PREF_APP_UPDATE_RETRYTIMEOUT = "app.update.socket.retryTimeout";
const PREF_APP_UPDATE_SERVICE_ENABLED = "app.update.service.enabled";
const PREF_APP_UPDATE_SILENT = "app.update.silent";
const PREF_APP_UPDATE_SOCKET_MAXERRORS = "app.update.socket.maxErrors";
const PREF_APP_UPDATE_STAGING_ENABLED = "app.update.staging.enabled";
const PREF_APP_UPDATE_URL = "app.update.url";
const PREF_APP_UPDATE_URL_DETAILS = "app.update.url.details";
const PREF_APP_UPDATE_URL_MANUAL = "app.update.url.manual";
const PREFBRANCH_APP_PARTNER = "app.partner.";
const PREF_DISTRIBUTION_ID = "distribution.id";