Merge mozilla-central and b2g-inbound

This commit is contained in:
Ed Morley 2013-08-29 15:10:05 +01:00
Родитель c20b13bc75 7a57ab3af2
Коммит aa9cf18b40
17 изменённых файлов: 333 добавлений и 95 удалений

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

@ -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);
}