зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central and b2g-inbound
This commit is contained in:
Коммит
aa9cf18b40
|
@ -326,12 +326,13 @@ let FormAssistant = {
|
|||
break;
|
||||
}
|
||||
|
||||
if (target instanceof HTMLDocument ||
|
||||
// Bug 811177, we don't support editing the entire document.
|
||||
target instanceof HTMLBodyElement ||
|
||||
target == content) {
|
||||
break;
|
||||
}
|
||||
// Focusing on Window, Document or iFrame should focus body
|
||||
if (target instanceof HTMLHtmlElement)
|
||||
target = target.document.body;
|
||||
else if (target instanceof HTMLDocument)
|
||||
target = target.body;
|
||||
else if (target instanceof HTMLIFrameElement)
|
||||
target = target.contentDocument.body;
|
||||
|
||||
if (isContentEditable(target)) {
|
||||
this.showKeyboard(this.getTopLevelEditable(target));
|
||||
|
@ -628,24 +629,11 @@ let FormAssistant = {
|
|||
|
||||
getTopLevelEditable: function fa_getTopLevelEditable(element) {
|
||||
function retrieveTopLevelEditable(element) {
|
||||
// Retrieve the top element that is editable
|
||||
if (element instanceof HTMLHtmlElement)
|
||||
element = element.ownerDocument.body;
|
||||
else if (element instanceof HTMLDocument)
|
||||
element = element.body;
|
||||
|
||||
while (element && !isContentEditable(element))
|
||||
element = element.parentNode;
|
||||
|
||||
// Return the container frame if we are into a nested editable frame
|
||||
if (element &&
|
||||
element instanceof HTMLBodyElement &&
|
||||
element.ownerDocument.defaultView != content.document.defaultView)
|
||||
return element.ownerDocument.defaultView.frameElement;
|
||||
}
|
||||
|
||||
if (element instanceof HTMLIFrameElement)
|
||||
return element;
|
||||
}
|
||||
|
||||
return retrieveTopLevelEditable(element) || element;
|
||||
},
|
||||
|
@ -712,14 +700,6 @@ function isContentEditable(element) {
|
|||
if (element.isContentEditable || element.designMode == "on")
|
||||
return true;
|
||||
|
||||
// If a body element is editable and the body is the child of an
|
||||
// iframe we can assume this is an advanced HTML editor
|
||||
if (element instanceof HTMLIFrameElement &&
|
||||
element.contentDocument &&
|
||||
(element.contentDocument.body.isContentEditable ||
|
||||
element.contentDocument.designMode == "on"))
|
||||
return true;
|
||||
|
||||
return element.ownerDocument && element.ownerDocument.designMode == "on";
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"revision": "7db3c28d7056b880b3be261f7784b5cc3e96702b",
|
||||
"revision": "2cfd8ac379712647d8b584714c1abc6a3bca380e",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ this.webappsUI = {
|
|||
localDir = app.appProfile.localDir;
|
||||
}
|
||||
|
||||
DOMApplicationRegistry.confirmInstall(aData, localDir, null,
|
||||
DOMApplicationRegistry.confirmInstall(aData, localDir,
|
||||
(aManifest) => {
|
||||
Task.spawn(function() {
|
||||
try {
|
||||
|
|
|
@ -117,6 +117,7 @@ MOCHITEST_FILES = \
|
|||
test_audiowrite.html \
|
||||
test_mediarecorder_creation.html \
|
||||
test_mediarecorder_avoid_recursion.html \
|
||||
test_mediarecorder_record_timeslice.html \
|
||||
test_mediarecorder_record_audiocontext.html \
|
||||
test_mediarecorder_record_stopms.html \
|
||||
test_mozHasAudio.html \
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test MediaRecorder Record Timeslice</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
var manager = new MediaTestManager;
|
||||
|
||||
/**
|
||||
* Starts a test on every media recorder file included to check that a stream
|
||||
* derived from the file can be recorded with a timeslice provided
|
||||
*/
|
||||
function startTest(test, token) {
|
||||
var element = document.createElement('audio');
|
||||
var expectedMimeType = test.type.substring(0, test.type.indexOf(';'));
|
||||
|
||||
element.token = token;
|
||||
manager.started(token);
|
||||
|
||||
element.src = test.name;
|
||||
element.test = test;
|
||||
element.stream = element.mozCaptureStream();
|
||||
|
||||
var mediaRecorder = new MediaRecorder(element.stream);
|
||||
|
||||
mediaRecorder.onerror = function () {
|
||||
ok(false, 'Unexpected onerror callback fired');
|
||||
};
|
||||
|
||||
mediaRecorder.onwarning = function () {
|
||||
ok(false, 'Unexpected onwarning callback fired');
|
||||
};
|
||||
|
||||
mediaRecorder.onstop = function () {
|
||||
ok(false, 'Unexpected onstop callback fired');
|
||||
};
|
||||
|
||||
var dataAvailableCount = 0;
|
||||
var onDataAvailableFirst = false;
|
||||
|
||||
// This handler fires every second to generate a blob.
|
||||
mediaRecorder.ondataavailable = function (evt) {
|
||||
info('ondataavailable fired');
|
||||
dataAvailableCount++;
|
||||
|
||||
ok(evt instanceof BlobEvent,
|
||||
'Events fired from ondataavailable should be BlobEvent');
|
||||
is(evt.type, 'dataavailable',
|
||||
'Event type should dataavailable');
|
||||
ok(evt.data.size >= 0,
|
||||
'Blob data size received is greater than or equal to zero');
|
||||
|
||||
is(evt.data.type, expectedMimeType,
|
||||
'Blob data received should have type = ' + expectedMimeType);
|
||||
is(mediaRecorder.mimeType, expectedMimeType,
|
||||
'Mime type in ondataavailable = ' + expectedMimeType);
|
||||
|
||||
// We'll stop recording upon the 1st blob being received
|
||||
if (dataAvailableCount === 1) {
|
||||
mediaRecorder.onstop = function (evt) {
|
||||
info('onstop fired');
|
||||
|
||||
if (!onDataAvailableFirst) {
|
||||
ok(false, 'onstop unexpectedly fired before ondataavailable');
|
||||
}
|
||||
|
||||
manager.finished(token);
|
||||
};
|
||||
|
||||
mediaRecorder.stop();
|
||||
is(mediaRecorder.state, 'inactive',
|
||||
'Media recorder is inactive after being stopped');
|
||||
is(mediaRecorder.stream, element.stream,
|
||||
'Media recorder stream = element stream post recording');
|
||||
|
||||
} else if (dataAvailableCount === 2) {
|
||||
// On the last blob, we ensure ondataavailable fires before onstop
|
||||
onDataAvailableFirst = true;
|
||||
|
||||
} else if (dataAvailableCount > 2) {
|
||||
// We should never receive more than three ondataavailable events
|
||||
ok(false, 'Too many ondataavailable events');
|
||||
}
|
||||
};
|
||||
|
||||
// Start recording once canplaythrough fires
|
||||
element.oncanplaythrough = function() {
|
||||
mediaRecorder.start(250);
|
||||
is(mediaRecorder.state, 'recording', 'Media recorder should be recording');
|
||||
is(mediaRecorder.stream, element.stream,
|
||||
'Media recorder stream = element stream at the start of recording');
|
||||
};
|
||||
|
||||
element.play();
|
||||
}
|
||||
|
||||
manager.runTests(gMediaRecorderTests, startTest);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1130,7 +1130,7 @@ this.DOMApplicationRegistry = {
|
|||
|
||||
if (manifest.appcache_path) {
|
||||
debug("appcache found");
|
||||
this.startOfflineCacheDownload(manifest, app, null, null, isUpdate);
|
||||
this.startOfflineCacheDownload(manifest, app, null, isUpdate);
|
||||
} else {
|
||||
// hosted app with no appcache, nothing to do, but we fire a
|
||||
// downloaded event
|
||||
|
@ -1280,10 +1280,7 @@ this.DOMApplicationRegistry = {
|
|||
}).bind(this));
|
||||
},
|
||||
|
||||
startOfflineCacheDownload: function startOfflineCacheDownload(aManifest, aApp,
|
||||
aProfileDir,
|
||||
aOfflineCacheObserver,
|
||||
aIsUpdate) {
|
||||
startOfflineCacheDownload: function(aManifest, aApp, aProfileDir, aIsUpdate) {
|
||||
if (!aManifest.appcache_path) {
|
||||
return;
|
||||
}
|
||||
|
@ -1320,9 +1317,6 @@ this.DOMApplicationRegistry = {
|
|||
AppDownloadManager.add(aApp.manifestURL, download);
|
||||
|
||||
cacheUpdate.addObserver(new AppcacheObserver(aApp), false);
|
||||
if (aOfflineCacheObserver) {
|
||||
cacheUpdate.addObserver(aOfflineCacheObserver, false);
|
||||
}
|
||||
}).bind(this));
|
||||
},
|
||||
|
||||
|
@ -1928,8 +1922,7 @@ this.DOMApplicationRegistry = {
|
|||
if (cacheDownload) {
|
||||
this.startOfflineCacheDownload(cacheDownload.manifest,
|
||||
cacheDownload.app,
|
||||
cacheDownload.profileDir,
|
||||
cacheDownload.offlineCacheObserver);
|
||||
cacheDownload.profileDir);
|
||||
delete this.queuedDownload[aManifestURL];
|
||||
|
||||
return;
|
||||
|
@ -1987,8 +1980,7 @@ this.DOMApplicationRegistry = {
|
|||
}
|
||||
},
|
||||
|
||||
confirmInstall: function(aData, aProfileDir, aOfflineCacheObserver,
|
||||
aInstallSuccessCallback) {
|
||||
confirmInstall: function(aData, aProfileDir, aInstallSuccessCallback) {
|
||||
let isReinstall = false;
|
||||
let app = aData.app;
|
||||
app.removable = true;
|
||||
|
@ -2025,8 +2017,6 @@ this.DOMApplicationRegistry = {
|
|||
|
||||
appObject.installTime = app.installTime = Date.now();
|
||||
appObject.lastUpdateCheck = app.lastUpdateCheck = Date.now();
|
||||
let appNote = JSON.stringify(appObject);
|
||||
appNote.id = id;
|
||||
|
||||
appObject.id = id;
|
||||
appObject.localId = localId;
|
||||
|
@ -2088,8 +2078,7 @@ this.DOMApplicationRegistry = {
|
|||
this.queuedDownload[app.manifestURL] = {
|
||||
manifest: manifest,
|
||||
app: appObject,
|
||||
profileDir: aProfileDir,
|
||||
offlineCacheObserver: aOfflineCacheObserver
|
||||
profileDir: aProfileDir
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2099,7 +2088,6 @@ this.DOMApplicationRegistry = {
|
|||
this._saveApps((function() {
|
||||
this.broadcastMessage("Webapps:AddApp", { id: id, app: appObject });
|
||||
this.broadcastMessage("Webapps:Install:Return:OK", aData);
|
||||
Services.obs.notifyObservers(this, "webapps-sync-install", appNote);
|
||||
}).bind(this));
|
||||
|
||||
if (!aData.isPackage) {
|
||||
|
@ -2795,7 +2783,6 @@ this.DOMApplicationRegistry = {
|
|||
Cu.reportError("DOMApplicationRegistry: Exception on app uninstall: " +
|
||||
ex + "\n" + ex.stack);
|
||||
}
|
||||
Services.obs.notifyObservers(this, "webapps-sync-uninstall", JSON.stringify(appClone));
|
||||
this.broadcastMessage("Webapps:RemoveApp", { id: id });
|
||||
}).bind(this));
|
||||
},
|
||||
|
|
|
@ -63,6 +63,7 @@ nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId, nsIThread* aCameraThr
|
|||
mWindow(aWindow)
|
||||
{
|
||||
MOZ_ASSERT(aWindow, "shouldn't be created with null window!");
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -148,6 +148,7 @@ nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId, nsIThread* aCameraThr
|
|||
{
|
||||
MOZ_ASSERT(aWindow, "shouldn't be created with null window!");
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
SetIsDOMBinding();
|
||||
|
||||
/**
|
||||
* nsDOMCameraControl is a cycle-collection participant, which means it is
|
||||
|
|
|
@ -74,6 +74,7 @@ const DOM_MOBILE_MESSAGE_DELIVERY_SENT = "sent";
|
|||
const DOM_MOBILE_MESSAGE_DELIVERY_ERROR = "error";
|
||||
|
||||
const CALL_WAKELOCK_TIMEOUT = 5000;
|
||||
const RADIO_POWER_OFF_TIMEOUT = 30000;
|
||||
|
||||
const RIL_IPC_TELEPHONY_MSG_NAMES = [
|
||||
"RIL:EnumerateCalls",
|
||||
|
@ -1516,14 +1517,52 @@ RadioInterface.prototype = {
|
|||
|
||||
if (this.rilContext.radioState == RIL.GECKO_RADIOSTATE_OFF &&
|
||||
this._radioEnabled) {
|
||||
this._changingRadioPower = true;
|
||||
this.setRadioEnabled(true);
|
||||
}
|
||||
if (this.rilContext.radioState == RIL.GECKO_RADIOSTATE_READY &&
|
||||
!this._radioEnabled) {
|
||||
this.setRadioEnabled(false);
|
||||
this._changingRadioPower = true;
|
||||
this.powerOffRadioSafely();
|
||||
}
|
||||
},
|
||||
|
||||
_radioOffTimer: null,
|
||||
_cancelRadioOffTimer: function _cancelRadioOffTimer() {
|
||||
if (this._radioOffTimer) {
|
||||
this._radioOffTimer.cancel();
|
||||
}
|
||||
},
|
||||
_fireRadioOffTimer: function _fireRadioOffTimer() {
|
||||
if (DEBUG) this.debug("Radio off timer expired, set radio power off right away.");
|
||||
this.setRadioEnabled(false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Clean up all existing data calls before turning radio off.
|
||||
*/
|
||||
powerOffRadioSafely: function powerOffRadioSafely() {
|
||||
let dataDisconnecting = false;
|
||||
for each (let apnSetting in this.apnSettings.byAPN) {
|
||||
for each (let type in apnSetting.types) {
|
||||
if (this.getDataCallStateByType(type) ==
|
||||
RIL.GECKO_NETWORK_STATE_CONNECTED) {
|
||||
this.deactivateDataCallByType(type);
|
||||
dataDisconnecting = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dataDisconnecting) {
|
||||
if (this._radioOffTimer == null) {
|
||||
this._radioOffTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
}
|
||||
this._radioOffTimer.initWithCallback(this._fireRadioOffTimer.bind(this),
|
||||
RADIO_POWER_OFF_TIMEOUT, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
return;
|
||||
}
|
||||
this.setRadioEnabled(false);
|
||||
},
|
||||
|
||||
/**
|
||||
* This function will do the following steps:
|
||||
* 1. Clear the old APN settings.
|
||||
|
@ -2086,6 +2125,29 @@ RadioInterface.prototype = {
|
|||
|
||||
this._deliverDataCallCallback("dataCallStateChanged",
|
||||
[datacall]);
|
||||
|
||||
// Process pending radio power off request after all data calls
|
||||
// are disconnected.
|
||||
if (datacall.state == RIL.GECKO_NETWORK_STATE_UNKNOWN &&
|
||||
this._changingRadioPower) {
|
||||
let anyDataConnected = false;
|
||||
for each (let apnSetting in this.apnSettings.byAPN) {
|
||||
for each (let type in apnSetting.types) {
|
||||
if (this.getDataCallStateByType(type) == RIL.GECKO_NETWORK_STATE_CONNECTED) {
|
||||
anyDataConnected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (anyDataConnected) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!anyDataConnected) {
|
||||
if (DEBUG) this.debug("All data connections are disconnected, set radio off.");
|
||||
this._cancelRadioOffTimer();
|
||||
this.setRadioEnabled(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -2398,7 +2460,6 @@ RadioInterface.prototype = {
|
|||
|
||||
setRadioEnabled: function setRadioEnabled(value) {
|
||||
if (DEBUG) this.debug("Setting radio power to " + value);
|
||||
this._changingRadioPower = true;
|
||||
this.workerMessenger.send("setRadioPower", { on: value });
|
||||
},
|
||||
|
||||
|
|
|
@ -6703,16 +6703,14 @@ var WebappsUI = {
|
|||
|
||||
Services.obs.addObserver(this, "webapps-ask-install", false);
|
||||
Services.obs.addObserver(this, "webapps-launch", false);
|
||||
Services.obs.addObserver(this, "webapps-sync-install", false);
|
||||
Services.obs.addObserver(this, "webapps-sync-uninstall", false);
|
||||
Services.obs.addObserver(this, "webapps-uninstall", false);
|
||||
Services.obs.addObserver(this, "webapps-install-error", false);
|
||||
},
|
||||
|
||||
uninit: function unint() {
|
||||
Services.obs.removeObserver(this, "webapps-ask-install");
|
||||
Services.obs.removeObserver(this, "webapps-launch");
|
||||
Services.obs.removeObserver(this, "webapps-sync-install");
|
||||
Services.obs.removeObserver(this, "webapps-sync-uninstall");
|
||||
Services.obs.removeObserver(this, "webapps-uninstall");
|
||||
Services.obs.removeObserver(this, "webapps-install-error");
|
||||
},
|
||||
|
||||
|
@ -6748,27 +6746,7 @@ var WebappsUI = {
|
|||
case "webapps-launch":
|
||||
this.openURL(data.manifestURL, data.origin);
|
||||
break;
|
||||
case "webapps-sync-install":
|
||||
// Create a system notification allowing the user to launch the app
|
||||
DOMApplicationRegistry.getManifestFor(data.manifestURL, (function(aManifest) {
|
||||
if (!aManifest)
|
||||
return;
|
||||
let manifest = new ManifestHelper(aManifest, data.origin);
|
||||
|
||||
let observer = {
|
||||
observe: function (aSubject, aTopic) {
|
||||
if (aTopic == "alertclickcallback") {
|
||||
WebappsUI.openURL(data.manifestURL, data.origin);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let message = Strings.browser.GetStringFromName("webapps.alertSuccess");
|
||||
let alerts = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
|
||||
alerts.showAlertNotification("drawable://alert_app", manifest.name, message, true, "", observer, "webapp");
|
||||
}).bind(this));
|
||||
break;
|
||||
case "webapps-sync-uninstall":
|
||||
case "webapps-uninstall":
|
||||
sendMessageToJava({
|
||||
type: "WebApps:Uninstall",
|
||||
origin: data.origin
|
||||
|
@ -6829,7 +6807,7 @@ var WebappsUI = {
|
|||
file.initWithPath(profilePath);
|
||||
|
||||
let self = this;
|
||||
DOMApplicationRegistry.confirmInstall(aData, file, null,
|
||||
DOMApplicationRegistry.confirmInstall(aData, file,
|
||||
function (aManifest) {
|
||||
let localeManifest = new ManifestHelper(aManifest, aData.app.origin);
|
||||
|
||||
|
@ -6868,6 +6846,19 @@ var WebappsUI = {
|
|||
}
|
||||
}, "webapp");
|
||||
}
|
||||
|
||||
// Create a system notification allowing the user to launch the app
|
||||
let observer = {
|
||||
observe: function (aSubject, aTopic) {
|
||||
if (aTopic == "alertclickcallback") {
|
||||
WebappsUI.openURL(aData.app.manifestURL, origin);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let message = Strings.browser.GetStringFromName("webapps.alertSuccess");
|
||||
let alerts = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
|
||||
alerts.showAlertNotification("drawable://alert_app", localeManifest.name, message, true, "", observer, "webapp");
|
||||
} catch(ex) {
|
||||
console.log(ex);
|
||||
}
|
||||
|
|
|
@ -913,7 +913,10 @@ class Marionette(object):
|
|||
|
||||
return unwrapped
|
||||
|
||||
def execute_js_script(self, script, script_args=None, async=True, new_sandbox=True, special_powers=False, script_timeout=None, filename=None):
|
||||
def execute_js_script(self, script, script_args=None, async=True,
|
||||
new_sandbox=True, special_powers=False,
|
||||
script_timeout=None, inactivity_timeout=None,
|
||||
filename=None):
|
||||
if script_args is None:
|
||||
script_args = []
|
||||
args = self.wrapArguments(script_args)
|
||||
|
@ -925,11 +928,13 @@ class Marionette(object):
|
|||
newSandbox=new_sandbox,
|
||||
specialPowers=special_powers,
|
||||
scriptTimeout=script_timeout,
|
||||
inactivityTimeout=inactivity_timeout,
|
||||
filename=filename,
|
||||
line=None)
|
||||
return self.unwrapValue(response)
|
||||
|
||||
def execute_script(self, script, script_args=None, new_sandbox=True, special_powers=False, script_timeout=None):
|
||||
def execute_script(self, script, script_args=None, new_sandbox=True,
|
||||
special_powers=False, script_timeout=None):
|
||||
'''
|
||||
Executes a synchronous JavaScript script, and returns the result (or None if the script does return a value).
|
||||
|
||||
|
|
|
@ -339,6 +339,7 @@ class MarionetteJSTestCase(CommonTestCase):
|
|||
|
||||
context_re = re.compile(r"MARIONETTE_CONTEXT(\s*)=(\s*)['|\"](.*?)['|\"];")
|
||||
timeout_re = re.compile(r"MARIONETTE_TIMEOUT(\s*)=(\s*)(\d+);")
|
||||
inactivity_timeout_re = re.compile(r"MARIONETTE_INACTIVITY_TIMEOUT(\s*)=(\s*)(\d+);")
|
||||
match_re = re.compile(r"test_(.*)\.js$")
|
||||
|
||||
def __init__(self, marionette_weakref, methodName='runTest', jsFile=None):
|
||||
|
@ -388,10 +389,15 @@ class MarionetteJSTestCase(CommonTestCase):
|
|||
timeout = timeout.group(3)
|
||||
self.marionette.set_script_timeout(timeout)
|
||||
|
||||
inactivity_timeout = self.inactivity_timeout_re.search(js)
|
||||
if inactivity_timeout:
|
||||
inactivity_timeout = inactivity_timeout.group(3)
|
||||
|
||||
try:
|
||||
results = self.marionette.execute_js_script(js,
|
||||
args,
|
||||
special_powers=True,
|
||||
inactivity_timeout=inactivity_timeout,
|
||||
filename=os.path.basename(self.jsFile))
|
||||
|
||||
self.assertTrue(not 'timeout' in self.jsFile,
|
||||
|
|
|
@ -52,6 +52,10 @@ let onunload;
|
|||
let asyncTestRunning = false;
|
||||
let asyncTestCommandId;
|
||||
let asyncTestTimeoutId;
|
||||
|
||||
let inactivityTimeoutId = null;
|
||||
let heartbeatCallback = function () {}; // Called by the simpletest methods.
|
||||
|
||||
let originalOnError;
|
||||
//timer for doc changes
|
||||
let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
|
@ -297,8 +301,9 @@ function createExecuteContentSandbox(aWindow, timeout) {
|
|||
sandbox.asyncTestCommandId = asyncTestCommandId;
|
||||
|
||||
let marionette = new Marionette(this, aWindow, "content",
|
||||
marionetteLogObj,
|
||||
timeout, marionetteTestName);
|
||||
marionetteLogObj, timeout,
|
||||
heartbeatCallback,
|
||||
marionetteTestName);
|
||||
sandbox.marionette = marionette;
|
||||
marionette.exports.forEach(function(fn) {
|
||||
try {
|
||||
|
@ -318,6 +323,11 @@ function createExecuteContentSandbox(aWindow, timeout) {
|
|||
curWindow.removeEventListener("unload", onunload, false);
|
||||
curWindow.clearTimeout(asyncTestTimeoutId);
|
||||
|
||||
if (inactivityTimeoutId != null) {
|
||||
curWindow.clearTimeout(inactivityTimeoutId);
|
||||
}
|
||||
|
||||
|
||||
sendSyncMessage("Marionette:shareData",
|
||||
{log: elementManager.wrapValue(marionetteLogObj.getLogs())});
|
||||
marionetteLogObj.clearLogs();
|
||||
|
@ -340,6 +350,7 @@ function createExecuteContentSandbox(aWindow, timeout) {
|
|||
asyncTestRunning = false;
|
||||
asyncTestTimeoutId = undefined;
|
||||
asyncTestCommandId = undefined;
|
||||
inactivityTimeoutId = null;
|
||||
}
|
||||
};
|
||||
sandbox.finish = function sandbox_finish() {
|
||||
|
@ -361,6 +372,21 @@ function createExecuteContentSandbox(aWindow, timeout) {
|
|||
* or directly (for 'mochitest' like JS Marionette tests)
|
||||
*/
|
||||
function executeScript(msg, directInject) {
|
||||
// Set up inactivity timeout.
|
||||
if (msg.json.inactivityTimeout) {
|
||||
let setTimer = function() {
|
||||
inactivityTimeoutId = curWindow.setTimeout(function() {
|
||||
sendError('timed out due to inactivity', 28, null, asyncTestCommandId);
|
||||
}, msg.json.inactivityTimeout);
|
||||
};
|
||||
|
||||
setTimer();
|
||||
heartbeatCallback = function resetInactivityTimeout() {
|
||||
curWindow.clearTimeout(inactivityTimeoutId);
|
||||
setTimer();
|
||||
};
|
||||
}
|
||||
|
||||
asyncTestCommandId = msg.json.command_id;
|
||||
let script = msg.json.value;
|
||||
|
||||
|
@ -470,6 +496,21 @@ function executeJSScript(msg) {
|
|||
* method is called, or if it times out.
|
||||
*/
|
||||
function executeWithCallback(msg, useFinish) {
|
||||
// Set up inactivity timeout.
|
||||
if (msg.json.inactivityTimeout) {
|
||||
let setTimer = function() {
|
||||
inactivityTimeoutId = curWindow.setTimeout(function() {
|
||||
sandbox.asyncComplete('timed out due to inactivity', 28, null, asyncTestCommandId);
|
||||
}, msg.json.inactivityTimeout);
|
||||
};
|
||||
|
||||
setTimer();
|
||||
heartbeatCallback = function resetInactivityTimeout() {
|
||||
curWindow.clearTimeout(inactivityTimeoutId);
|
||||
setTimer();
|
||||
};
|
||||
}
|
||||
|
||||
let script = msg.json.value;
|
||||
asyncTestCommandId = msg.json.command_id;
|
||||
|
||||
|
|
|
@ -141,6 +141,8 @@ function MarionetteServerConnection(aPrefix, aTransport, aServer)
|
|||
this.searchTimeout = null;
|
||||
this.pageTimeout = null;
|
||||
this.timer = null;
|
||||
this.inactivityTimer = null;
|
||||
this.heartbeatCallback = function () {}; // called by simpletest methods
|
||||
this.marionetteLog = new MarionetteLogObj();
|
||||
this.command_id = null;
|
||||
this.mainFrame = null; //topmost chrome frame
|
||||
|
@ -766,6 +768,7 @@ MarionetteServerConnection.prototype = {
|
|||
* function body
|
||||
*/
|
||||
execute: function MDA_execute(aRequest, directInject) {
|
||||
let inactivityTimeout = aRequest.inactivityTimeout;
|
||||
let timeout = aRequest.scriptTimeout ? aRequest.scriptTimeout : this.scriptTimeout;
|
||||
let command_id = this.command_id = this.getCommandId();
|
||||
let script;
|
||||
|
@ -790,10 +793,33 @@ MarionetteServerConnection.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
// handle the inactivity timeout
|
||||
let that = this;
|
||||
if (inactivityTimeout) {
|
||||
let inactivityTimeoutHandler = function(message, status) {
|
||||
let error_msg = {message: value, status: status};
|
||||
that.sendToClient({from: that.actorID, error: error_msg},
|
||||
marionette.command_id);
|
||||
};
|
||||
let setTimer = function() {
|
||||
that.inactivityTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
if (that.inactivityTimer != null) {
|
||||
that.inactivityTimer.initWithCallback(function() {
|
||||
inactivityTimeoutHandler("timed out due to inactivity", 28);
|
||||
}, inactivityTimeout, Ci.nsITimer.TYPE_ONESHOT);
|
||||
}
|
||||
}
|
||||
setTimer();
|
||||
this.heartbeatCallback = function resetInactivityTimer() {
|
||||
that.inactivityTimer.cancel();
|
||||
setTimer();
|
||||
}
|
||||
}
|
||||
|
||||
let curWindow = this.getCurrentWindow();
|
||||
let marionette = new Marionette(this, curWindow, "chrome",
|
||||
this.marionetteLog,
|
||||
timeout, this.testName);
|
||||
timeout, this.heartbeatCallback, this.testName);
|
||||
let _chromeSandbox = this.createExecuteSandbox(curWindow,
|
||||
marionette,
|
||||
aRequest.args,
|
||||
|
@ -804,6 +830,9 @@ MarionetteServerConnection.prototype = {
|
|||
|
||||
try {
|
||||
_chromeSandbox.finish = function chromeSandbox_finish() {
|
||||
if (that.inactivityTimer != null) {
|
||||
that.inactivityTimer.cancel();
|
||||
}
|
||||
return marionette.generate_results();
|
||||
};
|
||||
|
||||
|
@ -858,6 +887,7 @@ MarionetteServerConnection.prototype = {
|
|||
executeJSScript: function MDA_executeJSScript(aRequest) {
|
||||
let timeout = aRequest.scriptTimeout ? aRequest.scriptTimeout : this.scriptTimeout;
|
||||
let command_id = this.command_id = this.getCommandId();
|
||||
|
||||
//all pure JS scripts will need to call Marionette.finish() to complete the test.
|
||||
if (aRequest.newSandbox == undefined) {
|
||||
//if client does not send a value in newSandbox,
|
||||
|
@ -880,6 +910,7 @@ MarionetteServerConnection.prototype = {
|
|||
newSandbox: aRequest.newSandbox,
|
||||
async: aRequest.async,
|
||||
timeout: timeout,
|
||||
inactivityTimeout: aRequest.inactivityTimeout,
|
||||
specialPowers: aRequest.specialPowers,
|
||||
filename: aRequest.filename,
|
||||
line: aRequest.line,
|
||||
|
@ -904,6 +935,7 @@ MarionetteServerConnection.prototype = {
|
|||
* function body
|
||||
*/
|
||||
executeWithCallback: function MDA_executeWithCallback(aRequest, directInject) {
|
||||
let inactivityTimeout = aRequest.inactivityTimeout;
|
||||
let timeout = aRequest.scriptTimeout ? aRequest.scriptTimeout : this.scriptTimeout;
|
||||
let command_id = this.command_id = this.getCommandId();
|
||||
let script;
|
||||
|
@ -922,6 +954,7 @@ MarionetteServerConnection.prototype = {
|
|||
id: this.command_id,
|
||||
newSandbox: aRequest.newSandbox,
|
||||
timeout: timeout,
|
||||
inactivityTimeout: inactivityTimeout,
|
||||
specialPowers: aRequest.specialPowers,
|
||||
filename: aRequest.filename,
|
||||
line: aRequest.line
|
||||
|
@ -930,13 +963,33 @@ MarionetteServerConnection.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
// handle the inactivity timeout
|
||||
let that = this;
|
||||
if (inactivityTimeout) {
|
||||
this.inactivityTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
if (this.inactivityTimer != null) {
|
||||
this.inactivityTimer.initWithCallback(function() {
|
||||
chromeAsyncReturnFunc("timed out due to inactivity", 28);
|
||||
}, inactivityTimeout, Ci.nsITimer.TYPE_ONESHOT);
|
||||
}
|
||||
this.heartbeatCallback = function resetInactivityTimer() {
|
||||
that.inactivityTimer.cancel();
|
||||
that.inactivityTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
if (that.inactivityTimer != null) {
|
||||
that.inactivityTimer.initWithCallback(function() {
|
||||
chromeAsyncReturnFunc("timed out due to inactivity", 28);
|
||||
}, inactivityTimeout, Ci.nsITimer.TYPE_ONESHOT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let curWindow = this.getCurrentWindow();
|
||||
let original_onerror = curWindow.onerror;
|
||||
let that = this;
|
||||
that.timeout = timeout;
|
||||
let marionette = new Marionette(this, curWindow, "chrome",
|
||||
this.marionetteLog,
|
||||
timeout, this.testName);
|
||||
timeout, this.heartbeatCallback, this.testName);
|
||||
marionette.command_id = this.command_id;
|
||||
|
||||
function chromeAsyncReturnFunc(value, status, stacktrace) {
|
||||
|
@ -966,6 +1019,9 @@ MarionetteServerConnection.prototype = {
|
|||
marionette.command_id);
|
||||
}
|
||||
}
|
||||
if (that.inactivityTimer != null) {
|
||||
that.inactivityTimer.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
curWindow.onerror = function (errorMsg, url, lineNumber) {
|
||||
|
|
|
@ -5,13 +5,15 @@
|
|||
* The Marionette object, passed to the script context.
|
||||
*/
|
||||
|
||||
this.Marionette = function Marionette(scope, window, context, logObj, timeout, testName) {
|
||||
this.Marionette = function Marionette(scope, window, context, logObj, timeout,
|
||||
heartbeatCallback, testName) {
|
||||
this.scope = scope;
|
||||
this.window = window;
|
||||
this.tests = [];
|
||||
this.logObj = logObj;
|
||||
this.context = context;
|
||||
this.timeout = timeout;
|
||||
this.heartbeatCallback = heartbeatCallback;
|
||||
this.testName = testName;
|
||||
this.TEST_UNEXPECTED_FAIL = "TEST-UNEXPECTED-FAIL";
|
||||
this.TEST_PASS = "TEST-PASS";
|
||||
|
@ -24,6 +26,7 @@ Marionette.prototype = {
|
|||
'TEST_UNEXPECTED_FAIL'],
|
||||
|
||||
ok: function Marionette__ok(condition, name, passString, failString, diag) {
|
||||
this.heartbeatCallback();
|
||||
if (typeof(diag) == "undefined") {
|
||||
diag = this.repr(condition) + " was " + !!condition + ", expected true";
|
||||
}
|
||||
|
@ -35,6 +38,7 @@ Marionette.prototype = {
|
|||
},
|
||||
|
||||
is: function Marionette__is(a, b, name, passString, failString) {
|
||||
this.heartbeatCallback();
|
||||
let pass = (a == b);
|
||||
let diag = pass ? this.repr(a) + " should equal " + this.repr(b)
|
||||
: "got " + this.repr(a) + ", expected " + this.repr(b);
|
||||
|
@ -42,6 +46,7 @@ Marionette.prototype = {
|
|||
},
|
||||
|
||||
isnot: function Marionette__isnot (a, b, name, passString, failString) {
|
||||
this.heartbeatCallback();
|
||||
let pass = (a != b);
|
||||
let diag = pass ? this.repr(a) + " should not equal " + this.repr(b)
|
||||
: "didn't expect " + this.repr(a) + ", but got it";
|
||||
|
@ -49,6 +54,7 @@ Marionette.prototype = {
|
|||
},
|
||||
|
||||
log: function Marionette__log(msg, level) {
|
||||
this.heartbeatCallback();
|
||||
dump("MARIONETTE LOG: " + (level ? level : "INFO") + ": " + msg + "\n");
|
||||
if (this.logObj != null) {
|
||||
this.logObj.log(msg, level);
|
||||
|
@ -56,12 +62,14 @@ Marionette.prototype = {
|
|||
},
|
||||
|
||||
getLogs: function Marionette__getLogs() {
|
||||
this.heartbeatCallback();
|
||||
if (this.logObj != null) {
|
||||
this.logObj.getLogs();
|
||||
}
|
||||
},
|
||||
|
||||
generate_results: function Marionette__generate_results() {
|
||||
this.heartbeatCallback();
|
||||
let passed = 0;
|
||||
let failed = 0;
|
||||
let failures = [];
|
||||
|
@ -81,10 +89,12 @@ Marionette.prototype = {
|
|||
},
|
||||
|
||||
logToFile: function Marionette__logToFile(file) {
|
||||
this.heartbeatCallback();
|
||||
//TODO
|
||||
},
|
||||
|
||||
logResult: function Marionette__logResult(test, passString, failString) {
|
||||
this.heartbeatCallback();
|
||||
//TODO: dump to file
|
||||
let resultString = test.result ? passString : failString;
|
||||
let diagnostic = test.name + (test.diag ? " - " + test.diag : "");
|
||||
|
@ -132,6 +142,7 @@ Marionette.prototype = {
|
|||
},
|
||||
|
||||
waitFor: function test_waitFor(callback, test, timeout) {
|
||||
this.heartbeatCallback();
|
||||
if (test()) {
|
||||
callback();
|
||||
return;
|
||||
|
@ -148,6 +159,7 @@ Marionette.prototype = {
|
|||
},
|
||||
|
||||
runEmulatorCmd: function runEmulatorCmd(cmd, callback) {
|
||||
this.heartbeatCallback();
|
||||
this.scope.runEmulatorCmd(cmd, callback);
|
||||
},
|
||||
|
||||
|
|
|
@ -158,24 +158,14 @@ add_test(function testUninstall() {
|
|||
manifestURL: manifestURL
|
||||
};
|
||||
|
||||
let gotFirstUninstallEvent = false;
|
||||
Services.obs.addObserver(function observer(subject, topic, data) {
|
||||
Services.obs.removeObserver(observer, topic);
|
||||
let json = JSON.parse(data);
|
||||
do_check_eq(json.manifestURL, manifestURL);
|
||||
do_check_eq(json.origin, origin);
|
||||
gotFirstUninstallEvent = true;
|
||||
}, "webapps-uninstall", false);
|
||||
|
||||
Services.obs.addObserver(function observer(subject, topic, data) {
|
||||
Services.obs.removeObserver(observer, topic);
|
||||
let json = JSON.parse(data);
|
||||
do_check_eq(json.manifestURL, manifestURL);
|
||||
do_check_eq(json.origin, origin);
|
||||
do_check_eq(json.id, gAppId);
|
||||
do_check_true(gotFirstUninstallEvent);
|
||||
run_next_test();
|
||||
}, "webapps-sync-uninstall", false);
|
||||
}, "webapps-uninstall", false);
|
||||
|
||||
webappActorRequest(request, function (aResponse) {
|
||||
do_check_false("error" in aResponse);
|
||||
|
|
|
@ -67,7 +67,7 @@ this.WebappsHandler = {
|
|||
localDir = shell.appProfile.localDir;
|
||||
}
|
||||
|
||||
DOMApplicationRegistry.confirmInstall(data, localDir, null,
|
||||
DOMApplicationRegistry.confirmInstall(data, localDir,
|
||||
function (aManifest) {
|
||||
WebappsInstaller.install(data, aManifest);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче