(tidlong);
+ // Do not set the priority of threads running with a real-time policy
+ // as part of the bulk process adjustment. These threads need to run
+ // at their specified priority in order to meet timing guarantees.
+ int schedPolicy = sched_getscheduler(tid);
+ if (schedPolicy == SCHED_FIFO || schedPolicy == SCHED_RR) {
+ continue;
+ }
+
errno = 0;
// Get and set the task's new priority.
int origtaskpriority = getpriority(PRIO_PROCESS, tid);
@@ -1360,6 +1370,15 @@ SetNiceForPid(int aPid, int aNice)
int newtaskpriority =
std::max(origtaskpriority - origProcPriority + aNice, aNice);
+
+ // Do not reduce priority of threads already running at priorities greater
+ // than normal. These threads are likely special service threads that need
+ // elevated priorities to process audio, display composition, etc.
+ if (newtaskpriority > origtaskpriority &&
+ origtaskpriority < ANDROID_PRIORITY_NORMAL) {
+ continue;
+ }
+
rv = setpriority(PRIO_PROCESS, tid, newtaskpriority);
if (rv) {
@@ -1454,6 +1473,54 @@ SetProcessPriority(int aPid,
}
}
+void
+SetCurrentThreadPriority(ThreadPriority aPriority)
+{
+ int policy = SCHED_OTHER;
+ int priorityOrNice = ANDROID_PRIORITY_NORMAL;
+
+ switch(aPriority) {
+ case THREAD_PRIORITY_COMPOSITOR:
+ priorityOrNice = Preferences::GetInt("hal.gonk.compositor.rt_priority", 0);
+ if (priorityOrNice >= sched_get_priority_min(SCHED_FIFO) &&
+ priorityOrNice <= sched_get_priority_max(SCHED_FIFO)) {
+ policy = SCHED_FIFO;
+ } else {
+ priorityOrNice = Preferences::GetInt("hal.gonk.compositor.nice",
+ ANDROID_PRIORITY_URGENT_DISPLAY);
+ }
+ break;
+ default:
+ LOG("Unrecognized thread priority %d; Doing nothing", aPriority);
+ return;
+ }
+
+ int tid = gettid();
+ int rv = 0;
+
+ // If a RT scheduler policy is used, then we must set the priority using
+ // sched_setscheduler() and the sched_param.sched_priority value.
+ if (policy == SCHED_FIFO || policy == SCHED_RR) {
+ LOG("Setting thread %d to priority level %s; RT priority %d",
+ tid, ThreadPriorityToString(aPriority), priorityOrNice);
+ sched_param schedParam;
+ schedParam.sched_priority = priorityOrNice;
+ rv = sched_setscheduler(tid, policy, &schedParam);
+
+ // Otherwise priority is solely defined by the nice level, so use the
+ // setpriority() function.
+ } else {
+ LOG("Setting thread %d to priority level %s; nice level %d",
+ tid, ThreadPriorityToString(aPriority), priorityOrNice);
+ rv = setpriority(PRIO_PROCESS, tid, priorityOrNice);
+ }
+
+ if (rv) {
+ LOG("Failed to set thread %d to priority level %s; error code %d",
+ tid, ThreadPriorityToString(aPriority), rv);
+ }
+}
+
void
FactoryReset()
{
diff --git a/hal/moz.build b/hal/moz.build
index 9cf12a10832..e01626ec65c 100644
--- a/hal/moz.build
+++ b/hal/moz.build
@@ -151,6 +151,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
'fallback/FallbackProcessPriority.cpp',
'fallback/FallbackScreenPower.cpp',
'fallback/FallbackSwitch.cpp',
+ 'fallback/FallbackThreadPriority.cpp',
'fallback/FallbackTime.cpp',
'fallback/FallbackWakeLocks.cpp',
]
diff --git a/hal/sandbox/SandboxHal.cpp b/hal/sandbox/SandboxHal.cpp
index bd489d26ce6..1820c8b4dbe 100644
--- a/hal/sandbox/SandboxHal.cpp
+++ b/hal/sandbox/SandboxHal.cpp
@@ -362,6 +362,12 @@ SetProcessPriority(int aPid,
NS_RUNTIMEABORT("Only the main process may set processes' priorities.");
}
+void
+SetCurrentThreadPriority(ThreadPriority aPriority)
+{
+ NS_RUNTIMEABORT("Only the main process may set thread priorities.");
+}
+
void
EnableFMRadio(const hal::FMRadioSettings& aSettings)
{
diff --git a/mobile/android/base/toolbar/BrowserToolbar.java b/mobile/android/base/toolbar/BrowserToolbar.java
index 5d57a599bb1..7f6836dfadd 100644
--- a/mobile/android/base/toolbar/BrowserToolbar.java
+++ b/mobile/android/base/toolbar/BrowserToolbar.java
@@ -503,6 +503,9 @@ public class BrowserToolbar extends GeckoRelativeLayout
break;
case SELECTED:
+ flags.add(UpdateFlags.PRIVATE_MODE);
+ setPrivateMode(tab.isPrivate());
+ // Fall through.
case LOAD_ERROR:
flags.add(UpdateFlags.TITLE);
// Fall through.
@@ -511,12 +514,9 @@ public class BrowserToolbar extends GeckoRelativeLayout
// us of a title change, so we don't update the title here.
flags.add(UpdateFlags.FAVICON);
flags.add(UpdateFlags.SITE_IDENTITY);
- flags.add(UpdateFlags.PRIVATE_MODE);
updateBackButton(tab);
updateForwardButton(tab);
-
- setPrivateMode(tab.isPrivate());
break;
case TITLE:
diff --git a/mobile/android/confvars.sh b/mobile/android/confvars.sh
index adcb3c759d0..ddd52f4e8d0 100644
--- a/mobile/android/confvars.sh
+++ b/mobile/android/confvars.sh
@@ -5,7 +5,7 @@
MOZ_APP_BASENAME=Fennec
MOZ_APP_VENDOR=Mozilla
-MOZ_APP_VERSION=30.0a1
+MOZ_APP_VERSION=31.0a1
MOZ_APP_UA_NAME=Firefox
MOZ_BRANDING_DIRECTORY=mobile/android/branding/unofficial
diff --git a/services/sync/Makefile.in b/services/sync/Makefile.in
index 634a402cfb9..31948f76697 100644
--- a/services/sync/Makefile.in
+++ b/services/sync/Makefile.in
@@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# Definitions used by constants.js.
-weave_version := 1.32.0
+weave_version := 1.33.0
weave_id := {340c2bbc-ce74-4362-90b5-7c26312808ef}
# Preprocess files.
diff --git a/toolkit/components/jsdownloads/src/DownloadCore.jsm b/toolkit/components/jsdownloads/src/DownloadCore.jsm
index 04aa304f005..a82880410b5 100644
--- a/toolkit/components/jsdownloads/src/DownloadCore.jsm
+++ b/toolkit/components/jsdownloads/src/DownloadCore.jsm
@@ -63,7 +63,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
XPCOMUtils.defineLazyModuleGetter(this, "OS",
"resource://gre/modules/osfile.jsm")
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
- "resource://gre/modules/commonjs/sdk/core/promise.js");
+ "resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
@@ -411,27 +411,48 @@ this.Download.prototype = {
}
}
+ // In case the download was restarted while cancellation was in progress,
+ // but the previous attempt actually succeeded before cancellation could
+ // be processed, it is possible that the download has already finished.
+ if (this.succeeded) {
+ return;
+ }
+
try {
// Disallow download if parental controls service restricts it.
if (yield DownloadIntegration.shouldBlockForParentalControls(this)) {
throw new DownloadError({ becauseBlockedByParentalControls: true });
}
+ // We should check if we have been canceled in the meantime, after all
+ // the previous asynchronous operations have been executed and just
+ // before we call the "execute" method of the saver.
+ if (this._promiseCanceled) {
+ // The exception will become a cancellation in the "catch" block.
+ throw undefined;
+ }
+
// Execute the actual download through the saver object.
+ this._saverExecuting = true;
yield this.saver.execute(DS_setProgressBytes.bind(this),
DS_setProperties.bind(this));
+
// Check for application reputation, which requires the entire file to
- // be downloaded.
- if (yield DownloadIntegration.shouldBlockForReputationCheck(this)) {
- // Delete the target file that BackgroundFileSaver already moved
- // into place.
+ // be downloaded. After that, check for the last time if the download
+ // has been canceled. Both cases require the target file to be deleted,
+ // thus we process both in the same block of code.
+ if ((yield DownloadIntegration.shouldBlockForReputationCheck(this)) ||
+ this._promiseCanceled) {
try {
yield OS.File.remove(this.target.path);
} catch (ex) {
Cu.reportError(ex);
}
+ // If this is actually a cancellation, this exception will be changed
+ // in the catch block below.
throw new DownloadError({ becauseBlockedByReputationCheck: true });
}
+
// Update the status properties for a successful download.
this.progress = 100;
this.succeeded = true;
@@ -461,6 +482,7 @@ this.Download.prototype = {
throw ex;
} finally {
// Any cancellation request has now been processed.
+ this._saverExecuting = false;
this._promiseCanceled = null;
// Update the status properties, unless a new attempt already started.
@@ -546,6 +568,12 @@ this.Download.prototype = {
*/
_promiseCanceled: null,
+ /**
+ * True between the call to the "execute" method of the saver and the
+ * completion of the current download attempt.
+ */
+ _saverExecuting: false,
+
/**
* Cancels the download.
*
@@ -589,8 +617,12 @@ this.Download.prototype = {
this.canceled = true;
this._notifyChange();
- // Execute the actual cancellation through the saver object.
- this.saver.cancel();
+ // Execute the actual cancellation through the saver object, in case it
+ // has already started. Otherwise, the cancellation will be handled just
+ // before the saver is started.
+ if (this._saverExecuting) {
+ this.saver.cancel();
+ }
}
return this._promiseCanceled;
@@ -1363,31 +1395,6 @@ this.DownloadSaver.prototype = {
targetUri);
},
- /**
- * Return true if the request's response has been blocked by Windows parental
- * controls with an HTTP 450 error code.
- *
- * @param aRequest
- * nsIRequest object
- * @return True if the response is blocked.
- */
- isResponseParentalBlocked: function(aRequest)
- {
- // If the HTTP status is 450, then Windows Parental Controls have
- // blocked this download.
- if (aRequest instanceof Ci.nsIHttpChannel &&
- aRequest.responseStatus == 450) {
- // Cancel the request, but set a flag on the download that can be
- // retrieved later when handling the cancellation so that the proper
- // blocked by parental controls error can be thrown.
- this.download._blockedByParentalControls = true;
- aRequest.cancel(Cr.NS_BINDING_ABORTED);
- return true;
- }
-
- return false;
- },
-
/**
* Returns a static representation of the current object state.
*
@@ -1612,7 +1619,14 @@ this.DownloadCopySaver.prototype = {
onStartRequest: function (aRequest, aContext) {
backgroundFileSaver.onStartRequest(aRequest, aContext);
- if (this.isResponseParentalBlocked(aRequest)) {
+ // Check if the request's response has been blocked by Windows
+ // Parental Controls with an HTTP 450 error code.
+ if (aRequest instanceof Ci.nsIHttpChannel &&
+ aRequest.responseStatus == 450) {
+ // Set a flag that can be retrieved later when handling the
+ // cancellation so that the proper error can be thrown.
+ this.download._blockedByParentalControls = true;
+ aRequest.cancel(Cr.NS_BINDING_ABORTED);
return;
}
@@ -1707,6 +1721,13 @@ this.DownloadCopySaver.prototype = {
}.bind(copySaver),
}, null);
+ // We should check if we have been canceled in the meantime, after
+ // all the previous asynchronous operations have been executed and
+ // just before we set the _backgroundFileSaver property.
+ if (this._canceled) {
+ throw new DownloadError({ message: "Saver canceled." });
+ }
+
// If the operation succeeded, store the object to allow cancellation.
this._backgroundFileSaver = backgroundFileSaver;
} catch (ex) {
@@ -1930,10 +1951,6 @@ this.DownloadLegacySaver.prototype = {
ex.result == Cr.NS_ERROR_NOT_RESUMABLE) { }
}
- if (this.isResponseParentalBlocked(aRequest)) {
- return;
- }
-
// For legacy downloads, we must update the referrer at this time.
if (aRequest instanceof Ci.nsIHttpChannel && aRequest.referrer) {
this.download.source.referrer = aRequest.referrer.spec;
diff --git a/toolkit/components/jsdownloads/src/DownloadIntegration.jsm b/toolkit/components/jsdownloads/src/DownloadIntegration.jsm
index 209a158bb3f..34be122de83 100644
--- a/toolkit/components/jsdownloads/src/DownloadIntegration.jsm
+++ b/toolkit/components/jsdownloads/src/DownloadIntegration.jsm
@@ -46,7 +46,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
#endif
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
- "resource://gre/modules/commonjs/sdk/core/promise.js");
+ "resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
diff --git a/toolkit/components/jsdownloads/src/DownloadLegacy.js b/toolkit/components/jsdownloads/src/DownloadLegacy.js
index 1a3ba9bf82b..ea4a78afb84 100644
--- a/toolkit/components/jsdownloads/src/DownloadLegacy.js
+++ b/toolkit/components/jsdownloads/src/DownloadLegacy.js
@@ -29,7 +29,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
"resource://gre/modules/Downloads.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
- "resource://gre/modules/commonjs/sdk/core/promise.js");
+ "resource://gre/modules/Promise.jsm");
////////////////////////////////////////////////////////////////////////////////
//// DownloadLegacyTransfer
@@ -89,9 +89,25 @@ DownloadLegacyTransfer.prototype = {
if ((aStateFlags & Ci.nsIWebProgressListener.STATE_START) &&
(aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK)) {
+
+ // If the request's response has been blocked by Windows Parental Controls
+ // with an HTTP 450 error code, we must cancel the request synchronously.
+ let blockedByParentalControls = aRequest instanceof Ci.nsIHttpChannel &&
+ aRequest.responseStatus == 450;
+ if (blockedByParentalControls) {
+ aRequest.cancel(Cr.NS_BINDING_ABORTED);
+ }
+
// The main request has just started. Wait for the associated Download
// object to be available before notifying.
this._deferDownload.promise.then(download => {
+ // If the request was blocked, now that we have the download object we
+ // should set a flag that can be retrieved later when handling the
+ // cancellation so that the proper error can be thrown.
+ if (blockedByParentalControls) {
+ download._blockedByParentalControls = true;
+ }
+
download.saver.onTransferStarted(
aRequest,
this._cancelable instanceof Ci.nsIHelperAppLauncher);
diff --git a/toolkit/components/jsdownloads/src/DownloadList.jsm b/toolkit/components/jsdownloads/src/DownloadList.jsm
index 732870e48a0..e976621b662 100644
--- a/toolkit/components/jsdownloads/src/DownloadList.jsm
+++ b/toolkit/components/jsdownloads/src/DownloadList.jsm
@@ -37,7 +37,7 @@ const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
- "resource://gre/modules/commonjs/sdk/core/promise.js");
+ "resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
diff --git a/toolkit/components/jsdownloads/src/DownloadUIHelper.jsm b/toolkit/components/jsdownloads/src/DownloadUIHelper.jsm
index e6f26891058..ae10cf9c6ce 100644
--- a/toolkit/components/jsdownloads/src/DownloadUIHelper.jsm
+++ b/toolkit/components/jsdownloads/src/DownloadUIHelper.jsm
@@ -27,7 +27,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "OS",
"resource://gre/modules/osfile.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
- "resource://gre/modules/commonjs/sdk/core/promise.js");
+ "resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
diff --git a/toolkit/components/jsdownloads/src/Downloads.jsm b/toolkit/components/jsdownloads/src/Downloads.jsm
index 6500f7ed1ac..bc381387859 100644
--- a/toolkit/components/jsdownloads/src/Downloads.jsm
+++ b/toolkit/components/jsdownloads/src/Downloads.jsm
@@ -36,7 +36,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "DownloadSummary",
XPCOMUtils.defineLazyModuleGetter(this, "DownloadUIHelper",
"resource://gre/modules/DownloadUIHelper.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
- "resource://gre/modules/commonjs/sdk/core/promise.js");
+ "resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
diff --git a/toolkit/components/jsdownloads/test/unit/common_test_Download.js b/toolkit/components/jsdownloads/test/unit/common_test_Download.js
index a9a4e782c97..31e6a0daea0 100644
--- a/toolkit/components/jsdownloads/test/unit/common_test_Download.js
+++ b/toolkit/components/jsdownloads/test/unit/common_test_Download.js
@@ -806,7 +806,10 @@ add_task(function test_cancel_immediately_restart_immediately()
continueResponses();
try {
yield promiseAttempt;
- do_throw("The download should have been canceled.");
+ // If we get here, it means that the first attempt actually succeeded. In
+ // fact, this could be a valid outcome, because the cancellation request may
+ // not have been processed in time before the download finished.
+ do_print("The download should have been canceled.");
} catch (ex if ex instanceof Downloads.Error) {
do_check_false(ex.becauseSourceFailed);
do_check_false(ex.becauseTargetFailed);
diff --git a/toolkit/components/jsdownloads/test/unit/head.js b/toolkit/components/jsdownloads/test/unit/head.js
index 66529bf1799..0b26d3198ab 100644
--- a/toolkit/components/jsdownloads/test/unit/head.js
+++ b/toolkit/components/jsdownloads/test/unit/head.js
@@ -34,7 +34,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
- "resource://gre/modules/commonjs/sdk/core/promise.js");
+ "resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
@@ -731,6 +731,15 @@ add_task(function test_common_initialize()
gHttpServer.registerDirectory("/", do_get_file("../data"));
gHttpServer.start(-1);
+ // Cache locks might prevent concurrent requests to the same resource, and
+ // this may block tests that use the interruptible handlers.
+ Services.prefs.setBoolPref("browser.cache.disk.enable", false);
+ Services.prefs.setBoolPref("browser.cache.memory.enable", false);
+ do_register_cleanup(function () {
+ Services.prefs.clearUserPref("browser.cache.disk.enable");
+ Services.prefs.clearUserPref("browser.cache.memory.enable");
+ });
+
registerInterruptibleHandler("/interruptible.txt",
function firstPart(aRequest, aResponse) {
aResponse.setHeader("Content-Type", "text/plain", false);
diff --git a/toolkit/locales/en-US/chrome/global/aboutSupport.dtd b/toolkit/locales/en-US/chrome/global/aboutSupport.dtd
index 45cc7effd64..57d8f40da7d 100644
--- a/toolkit/locales/en-US/chrome/global/aboutSupport.dtd
+++ b/toolkit/locales/en-US/chrome/global/aboutSupport.dtd
@@ -25,6 +25,15 @@ This is likely the same like id.heading in crashes.dtd. -->
+
+
+
+
+
+
+
+
+
diff --git a/webapprt/PaymentUIGlue.js b/webapprt/PaymentUIGlue.js
index e4d58770673..c7d62361136 100644
--- a/webapprt/PaymentUIGlue.js
+++ b/webapprt/PaymentUIGlue.js
@@ -14,20 +14,21 @@ XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"nsIMessageSender");
function paymentSuccess(aRequestId) {
- return paymentCallback(aRequestId, "Payment:Success");
+ return function(aResult) {
+ closePaymentWindow(aRequestId, function() {
+ cpmm.sendAsyncMessage("Payment:Success", { requestId: aRequestId,
+ result: aResult });
+ });
+ };
}
function paymentFailed(aRequestId) {
- return paymentCallback(aRequestId, "Payment:Failed");
-}
-
-function paymentCallback(aRequestId, aMsg) {
- return function(aResult) {
- closePaymentWindow(aRequestId, function() {
- cpmm.sendAsyncMessage(aMsg, { result: aResult,
- requestId: aRequestId });
- });
- };
+ return function(aErrorMsg) {
+ closePaymentWindow(aRequestId, function() {
+ cpmm.sendAsyncMessage("Payment:Failed", { requestId: aRequestId,
+ errorMsg: aErrorMsg });
+ });
+ };
}
let payments = {};
diff --git a/webapprt/test/chrome/browser_mozpay.js b/webapprt/test/chrome/browser_mozpay.js
index 066270a1904..9da82455888 100644
--- a/webapprt/test/chrome/browser_mozpay.js
+++ b/webapprt/test/chrome/browser_mozpay.js
@@ -1,11 +1,22 @@
Cu.import("resource://gre/modules/Services.jsm");
let { PaymentManager } = Cu.import("resource://gre/modules/Payment.jsm", {});
+Cu.import("resource://webapprt/modules/WebappRT.jsm");
function test() {
waitForExplicitFinish();
- let providerWindow = null;
- let providerUri = "https://example.com:443/webapprtChrome/webapprt/test/chrome/mozpay-success.html?req=";
+ let curTest = 0;
+
+ let tests = [];
+ tests.push({
+ providerUri: "https://example.com:443/webapprtChrome/webapprt/test/chrome/mozpay-success.html?req=",
+ message: "Success."
+ });
+ tests.push({
+ providerUri: "https://example.com:443/webapprtChrome/webapprt/test/chrome/mozpay-failure.html?req=",
+ message: "Chocolate rejected."
+ });
+
let jwt = "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJhdWQiOiAibW9j" +
"a3BheXByb3ZpZGVyLnBocGZvZ2FwcC5jb20iLCAiaXNzIjogIkVudGVyI" +
"HlvdSBhcHAga2V5IGhlcmUhIiwgInJlcXVlc3QiOiB7Im5hbWUiOiAiUG" +
@@ -21,17 +32,19 @@ function test() {
PaymentManager.registeredProviders["mock/payments/inapp/v1"] = {
name: "mockprovider",
description: "Mock Payment Provider",
- uri: providerUri,
+ uri: tests[curTest].providerUri,
requestMethod: "GET"
};
+ let providerWindow;
+
let winObserver = function(win, topic) {
if (topic == "domwindowopened") {
win.addEventListener("load", function onLoadWindow() {
win.removeEventListener("load", onLoadWindow, false);
if (win.document.getElementById("content").getAttribute("src") ==
- (providerUri + jwt)) {
+ (tests[curTest].providerUri + jwt)) {
ok(true, "Payment provider window shown.");
providerWindow = win;
}
@@ -43,25 +56,45 @@ function test() {
let mutObserver = null;
- loadWebapp("mozpay.webapp", undefined, function onLoad() {
+ function onLoad() {
let msg = gAppBrowser.contentDocument.getElementById("msg");
mutObserver = new MutationObserver(function(mutations) {
- if (msg.textContent == "Success.") {
- ok(true, "Payment success.");
- } else {
- ok(false, "Payment success.");
- }
+ is(msg.textContent, tests[curTest].message, "Got: " + tests[curTest].message);
- if (providerWindow == null) {
+ if (!providerWindow) {
ok(false, "Payment provider window shown.");
} else {
providerWindow.close();
+ providerWindow = null;
}
- finish();
+ runNextTest();
});
mutObserver.observe(msg, { childList: true });
- });
+ }
+
+ loadWebapp("mozpay.webapp", undefined, onLoad);
+
+ function runNextTest() {
+ providerWindow = null;
+ if (mutObserver) {
+ mutObserver.disconnect();
+ }
+
+ curTest++;
+
+ if (curTest < tests.length) {
+ PaymentManager.registeredProviders["mock/payments/inapp/v1"].uri = tests[curTest].providerUri;
+
+ gAppBrowser.addEventListener("load", function onLoadH() {
+ gAppBrowser.removeEventListener("load", onLoadH, true);
+ onLoad();
+ }, true);
+ gAppBrowser.reload();
+ } else {
+ finish();
+ }
+ }
registerCleanupFunction(function() {
Services.ww.unregisterNotification(winObserver);
diff --git a/webapprt/test/chrome/mozpay-failure.html b/webapprt/test/chrome/mozpay-failure.html
new file mode 100644
index 00000000000..baaba42e961
--- /dev/null
+++ b/webapprt/test/chrome/mozpay-failure.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+ Webapp waiting to pay...
+
+
diff --git a/webapprt/test/chrome/mozpay.html b/webapprt/test/chrome/mozpay.html
index 3973791a34c..8997bc6c7de 100644
--- a/webapprt/test/chrome/mozpay.html
+++ b/webapprt/test/chrome/mozpay.html
@@ -37,7 +37,7 @@
document.getElementById("msg").textContent = "Success.";
};
request.onerror = function onerror() {
- document.getElementById("msg").textContent = "Failure.";
+ document.getElementById("msg").textContent = request.error.name;
};
Webapp waiting to be paid...
diff --git a/webapprt/test/chrome/webapprt.ini b/webapprt/test/chrome/webapprt.ini
index 715f8e4041f..026742fc299 100644
--- a/webapprt/test/chrome/webapprt.ini
+++ b/webapprt/test/chrome/webapprt.ini
@@ -26,6 +26,7 @@ support-files =
mozpay.webapp^headers^
mozpay.html
mozpay-success.html
+ mozpay-failure.html
getUserMedia.webapp
getUserMedia.webapp^headers^
getUserMedia.html
diff --git a/xpcom/components/Module.h b/xpcom/components/Module.h
index 210cfb30afa..53b04e7ced4 100644
--- a/xpcom/components/Module.h
+++ b/xpcom/components/Module.h
@@ -21,7 +21,7 @@ namespace mozilla {
*/
struct Module
{
- static const unsigned int kVersion = 30;
+ static const unsigned int kVersion = 31;
struct CIDEntry;