This commit is contained in:
Wes Kocher 2016-08-03 16:47:07 -07:00
Родитель 9605851be0 429b4cc773
Коммит ae855cdb28
53 изменённых файлов: 320 добавлений и 206 удалений

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

@ -128,6 +128,7 @@ devtools/shared/*.js
!devtools/shared/css-lexer.js
!devtools/shared/defer.js
!devtools/shared/event-emitter.js
!devtools/shared/loader-plugin-raw.jsm
!devtools/shared/task.js
devtools/shared/*.jsm
!devtools/shared/Loader.jsm

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

@ -13,6 +13,7 @@
<em:version>1.0</em:version>
<em:type>2</em:type>
<em:bootstrap>true</em:bootstrap>
<em:multiprocessCompatible>true</em:multiprocessCompatible>
<!-- Target Application this theme can install into,
with minimum and maximum supported versions. -->

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

@ -13,6 +13,7 @@
<em:version>1.0</em:version>
<em:type>2</em:type>
<em:bootstrap>true</em:bootstrap>
<em:multiprocessCompatible>true</em:multiprocessCompatible>
<!-- Target Application this theme can install into,
with minimum and maximum supported versions. -->

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

@ -101,6 +101,12 @@ function BrowserLoaderBuilder({ baseURI, window, useOnlyShared }) {
paths: Object.assign({}, dynamicPaths, loaderOptions.paths),
invisibleToDebugger: loaderOptions.invisibleToDebugger,
requireHook: (id, require) => {
// If |id| requires special handling, simply defer to devtools
// immediately.
if (devtools.isLoaderPluginId(id)) {
return devtools.require(id);
}
const uri = require.resolve(id);
let isBrowserDir = BROWSER_BASED_DIRS.filter(dir => {
return uri.startsWith(dir);

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

@ -147,6 +147,7 @@ skip-if = e10s # Test intermittently fails with e10s. Bug 1124162.
[browser_poller.js]
[browser_prefs-01.js]
[browser_prefs-02.js]
[browser_require_raw.js]
[browser_spectrum.js]
[browser_theme.js]
[browser_tableWidget_basic.js]

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

@ -0,0 +1,20 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { BrowserLoader } = Cu.import("resource://devtools/client/shared/browser-loader.js", {});
const { require: browserRequire } = BrowserLoader({
baseURI: "resource://devtools/client/shared/",
window: this
});
const variableFileContents = browserRequire("raw!devtools/client/themes/variables.css");
function test() {
ok(variableFileContents.length > 0, "raw browserRequire worked");
finish();
}

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

@ -9,45 +9,21 @@
* https://developer.mozilla.org/en-US/docs/Tools/DevToolsColors
*/
const { Cu } = require("chrome");
const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
const Services = require("Services");
const { gDevTools } = require("devtools/client/framework/devtools");
const VARIABLES_URI = "chrome://devtools/skin/variables.css";
const variableFileContents = require("raw!devtools/client/themes/variables.css");
const THEME_SELECTOR_STRINGS = {
light: ":root.theme-light {",
dark: ":root.theme-dark {"
};
let variableFileContents;
/**
* Returns a string of the file found at URI
*/
function readURI(uri) {
let stream = NetUtil.newChannel({
uri: NetUtil.newURI(uri, "UTF-8"),
loadUsingSystemPrincipal: true}
).open2();
let count = stream.available();
let data = NetUtil.readInputStreamToString(stream, count, {
charset: "UTF-8"
});
stream.close();
return data;
}
/**
* Takes a theme name and returns the contents of its variable rule block.
* The first time this runs fetches the variables CSS file and caches it.
*/
function getThemeFile(name) {
if (!variableFileContents) {
variableFileContents = readURI(VARIABLES_URI);
}
// If there's no theme expected for this name, use `light` as default.
let selector = THEME_SELECTOR_STRINGS[name] ||
THEME_SELECTOR_STRINGS.light;

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

@ -11,6 +11,7 @@
var { utils: Cu } = Components;
var { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
var { Loader, descriptor, resolveURI } = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {});
var { requireRawId } = Cu.import("resource://devtools/shared/loader-plugin-raw.jsm", {});
this.EXPORTED_SYMBOLS = ["DevToolsLoader", "devtools", "BuiltinProvider",
"require", "loader"];
@ -59,6 +60,12 @@ BuiltinProvider.prototype = {
invisibleToDebugger: this.invisibleToDebugger,
sharedGlobal: true,
sharedGlobalBlocklist,
requireHook: (id, require) => {
if (id.startsWith("raw!")) {
return requireRawId(id, require);
}
return require(id);
},
});
},
@ -120,6 +127,14 @@ DevToolsLoader.prototype = {
return this.require.apply(this, arguments);
},
/**
* Return true if |id| refers to something requiring help from a
* loader plugin.
*/
isLoaderPluginId: function (id) {
return id.startsWith("raw!");
},
/**
* Override the provider used to load the tools.
*/

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

@ -0,0 +1,41 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { utils: Cu } = Components;
const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
/**
* A function that can be used as part of a require hook for a
* loader.js Loader. This function only handles webpack-style "raw!"
* requires; other requires should not be passed to this. See
* https://github.com/webpack/raw-loader.
*/
function requireRawId(id, require) {
let uri = require.resolve(id.slice(4));
// If the original string did not end with ".js", then
// require.resolve might have added the suffix. We don't want to
// add a suffix for a raw load (if needed the caller can specify it
// manually), so remove it here.
if (!id.endsWith(".js") && uri.endsWith(".js")) {
uri = uri.slice(0, -3);
}
let stream = NetUtil.newChannel({
uri: NetUtil.newURI(uri, "UTF-8"),
loadUsingSystemPrincipal: true
}).open2();
let count = stream.available();
let data = NetUtil.readInputStreamToString(stream, count, {
charset: "UTF-8"
});
stream.close();
// For the time being it doesn't seem worthwhile to cache the
// result here.
return data;
}
this.EXPORTED_SYMBOLS = ["requireRawId"];

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

@ -54,6 +54,7 @@ DevToolsModules(
'dom-node-filter-constants.js',
'event-emitter.js',
'indentation.js',
'loader-plugin-raw.jsm',
'Loader.jsm',
'Parser.jsm',
'path.js',

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

@ -0,0 +1,12 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test require using "raw!".
function run_test() {
let loader = new DevToolsLoader();
let require = loader.require;
let variableFileContents = require("raw!devtools/client/themes/variables.css");
ok(variableFileContents.length > 0, "raw browserRequire worked");
}

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

@ -25,6 +25,7 @@ support-files =
[test_console_filtering.js]
[test_prettifyCSS.js]
[test_require_lazy.js]
[test_require_raw.js]
[test_require.js]
[test_stack.js]
[test_defer.js]

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

@ -764,11 +764,12 @@ nsDOMWindowUtils::SendPointerEventCommon(const nsAString& aType,
event.pressure = aPressure;
event.inputSource = aInputSourceArg;
event.pointerId = aPointerId;
event.width = aWidth;
event.height = aHeight;
event.mWidth = aWidth;
event.mHeight = aHeight;
event.tiltX = aTiltX;
event.tiltY = aTiltY;
event.isPrimary = (nsIDOMMouseEvent::MOZ_SOURCE_MOUSE == aInputSourceArg) ? true : aIsPrimary;
event.mIsPrimary =
(nsIDOMMouseEvent::MOZ_SOURCE_MOUSE == aInputSourceArg) ? true : aIsPrimary;
event.mClickCount = aClickCount;
event.mTime = PR_IntervalNow();
event.mFlags.mIsSynthesizedForTests = aOptionalArgCount >= 10 ? aIsSynthesized : true;

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

@ -3834,10 +3834,10 @@ CreateMouseOrPointerWidgetEvent(WidgetMouseEvent* aMouseEvent,
newPointerEvent =
new WidgetPointerEvent(aMouseEvent->IsTrusted(), aMessage,
aMouseEvent->mWidget);
newPointerEvent->isPrimary = sourcePointer->isPrimary;
newPointerEvent->mIsPrimary = sourcePointer->mIsPrimary;
newPointerEvent->pointerId = sourcePointer->pointerId;
newPointerEvent->width = sourcePointer->width;
newPointerEvent->height = sourcePointer->height;
newPointerEvent->mWidth = sourcePointer->mWidth;
newPointerEvent->mHeight = sourcePointer->mHeight;
newPointerEvent->inputSource = sourcePointer->inputSource;
newPointerEvent->relatedTarget =
nsIPresShell::GetPointerCapturingContent(sourcePointer->pointerId)

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

@ -87,13 +87,13 @@ PointerEvent::Constructor(EventTarget* aOwner,
WidgetPointerEvent* widgetEvent = e->mEvent->AsPointerEvent();
widgetEvent->pointerId = aParam.mPointerId;
widgetEvent->width = aParam.mWidth;
widgetEvent->height = aParam.mHeight;
widgetEvent->mWidth = aParam.mWidth;
widgetEvent->mHeight = aParam.mHeight;
widgetEvent->pressure = aParam.mPressure;
widgetEvent->tiltX = aParam.mTiltX;
widgetEvent->tiltY = aParam.mTiltY;
widgetEvent->inputSource = ConvertStringToPointerType(aParam.mPointerType);
widgetEvent->isPrimary = aParam.mIsPrimary;
widgetEvent->mIsPrimary = aParam.mIsPrimary;
widgetEvent->buttons = aParam.mButtons;
e->SetTrusted(trusted);
@ -126,13 +126,13 @@ PointerEvent::PointerId()
int32_t
PointerEvent::Width()
{
return mEvent->AsPointerEvent()->width;
return mEvent->AsPointerEvent()->mWidth;
}
int32_t
PointerEvent::Height()
{
return mEvent->AsPointerEvent()->height;
return mEvent->AsPointerEvent()->mHeight;
}
float
@ -156,7 +156,7 @@ PointerEvent::TiltY()
bool
PointerEvent::IsPrimary()
{
return mEvent->AsPointerEvent()->isPrimary;
return mEvent->AsPointerEvent()->mIsPrimary;
}
} // namespace dom

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

@ -369,7 +369,7 @@ HTMLButtonElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
mType == NS_FORM_BUTTON_RESET)) {
InternalFormEvent event(true,
(mType == NS_FORM_BUTTON_RESET) ? eFormReset : eFormSubmit);
event.originator = this;
event.mOriginator = this;
nsEventStatus status = nsEventStatus_eIgnore;
nsCOMPtr<nsIPresShell> presShell =

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

@ -687,7 +687,7 @@ HTMLFormElement::BuildSubmission(HTMLFormSubmission** aFormSubmission,
if (aEvent) {
InternalFormEvent* formEvent = aEvent->AsFormEvent();
if (formEvent) {
nsIContent* originator = formEvent->originator;
nsIContent* originator = formEvent->mOriginator;
if (originator) {
if (!originator->IsHTMLElement()) {
return NS_ERROR_UNEXPECTED;

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

@ -4556,7 +4556,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
if (mForm) {
InternalFormEvent event(true,
(mType == NS_FORM_INPUT_RESET) ? eFormReset : eFormSubmit);
event.originator = this;
event.mOriginator = this;
nsEventStatus status = nsEventStatus_eIgnore;
nsCOMPtr<nsIPresShell> presShell =

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

@ -114,13 +114,10 @@ ProcessHandle GetCurrentProcessHandle();
bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle);
// Converts a PID to a process handle. On Windows the handle is opened
// with more access rights and must only be used by trusted code. Parameter
// error can be used to get the error code in opening the process handle.
// with more access rights and must only be used by trusted code.
// You have to close returned handle using CloseProcessHandle. Returns true
// on success.
bool OpenPrivilegedProcessHandle(ProcessId pid,
ProcessHandle* handle,
int64_t* error = nullptr);
bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle);
// Closes the process handle opened by OpenProcessHandle.
void CloseProcessHandle(ProcessHandle process);

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

@ -49,14 +49,9 @@ bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) {
return true;
}
bool OpenPrivilegedProcessHandle(ProcessId pid,
ProcessHandle* handle,
int64_t* error) {
bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
// On POSIX permissions are checked for each operation on process,
// not when opening a "handle".
if (error) {
*error = 0;
}
return OpenProcessHandle(pid, handle);
}

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

@ -86,9 +86,7 @@ bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) {
return true;
}
bool OpenPrivilegedProcessHandle(ProcessId pid,
ProcessHandle* handle,
int64_t* error) {
bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
ProcessHandle result = OpenProcess(PROCESS_DUP_HANDLE |
PROCESS_TERMINATE |
PROCESS_QUERY_INFORMATION |
@ -97,9 +95,6 @@ bool OpenPrivilegedProcessHandle(ProcessId pid,
FALSE, pid);
if (result == NULL) {
if (error) {
*error = GetLastError();
}
return false;
}

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

@ -1151,43 +1151,47 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExt
mChildTask = child_task;
#endif
OpenPrivilegedHandle(base::GetProcId(process));
{
MonitorAutoLock lock(mMonitor);
mProcessState = PROCESS_CREATED;
lock.Notify();
if (!OpenPrivilegedHandle(base::GetProcId(process))
#ifdef XP_WIN
// If we failed in opening the process handle, try harder by duplicating
// one.
&& !::DuplicateHandle(::GetCurrentProcess(), process,
::GetCurrentProcess(), &mChildProcessHandle,
PROCESS_DUP_HANDLE | PROCESS_TERMINATE |
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ |
SYNCHRONIZE,
FALSE, 0)
#endif
) {
NS_RUNTIMEABORT("cannot open handle to child process");
}
MonitorAutoLock lock(mMonitor);
mProcessState = PROCESS_CREATED;
lock.Notify();
return true;
}
void
bool
GeckoChildProcessHost::OpenPrivilegedHandle(base::ProcessId aPid)
{
if (mChildProcessHandle) {
MOZ_ASSERT(aPid == base::GetProcId(mChildProcessHandle));
return;
}
int64_t error = 0;
if (!base::OpenPrivilegedProcessHandle(aPid, &mChildProcessHandle, &error)) {
#ifdef MOZ_CRASHREPORTER
CrashReporter::
AnnotateCrashReport(NS_LITERAL_CSTRING("LastError"),
nsPrintfCString ("%lld", error));
#endif
NS_RUNTIMEABORT("can't open handle to child process");
return true;
}
return base::OpenPrivilegedProcessHandle(aPid, &mChildProcessHandle);
}
void
GeckoChildProcessHost::OnChannelConnected(int32_t peer_pid)
{
OpenPrivilegedHandle(peer_pid);
{
MonitorAutoLock lock(mMonitor);
mProcessState = PROCESS_CONNECTED;
lock.Notify();
if (!OpenPrivilegedHandle(peer_pid)) {
NS_RUNTIMEABORT("can't open handle to child process");
}
MonitorAutoLock lock(mMonitor);
mProcessState = PROCESS_CONNECTED;
lock.Notify();
}
void
@ -1254,7 +1258,9 @@ bool
GeckoExistingProcessHost::PerformAsyncLaunch(StringVector aExtraOpts,
base::ProcessArchitecture aArch)
{
OpenPrivilegedHandle(base::GetProcId(mExistingProcessHandle));
if (!OpenPrivilegedHandle(base::GetProcId(mExistingProcessHandle))) {
NS_RUNTIMEABORT("can't open handle to child process");
}
MonitorAutoLock lock(mMonitor);
mProcessState = PROCESS_CREATED;

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

@ -173,7 +173,7 @@ protected:
task_t mChildTask;
#endif
void OpenPrivilegedHandle(base::ProcessId aPid);
bool OpenPrivilegedHandle(base::ProcessId aPid);
private:
DISALLOW_EVIL_CONSTRUCTORS(GeckoChildProcessHost);

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

@ -6839,14 +6839,16 @@ PresShell::UpdateActivePointerState(WidgetGUIEvent* aEvent)
// In this case we have to know information about available mouse pointers
if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
gActivePointersIds->Put(mouseEvent->pointerId,
new PointerInfo(false, mouseEvent->inputSource, true));
new PointerInfo(false, mouseEvent->inputSource,
true));
}
break;
case ePointerDown:
// In this case we switch pointer to active state
if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
gActivePointersIds->Put(pointerEvent->pointerId,
new PointerInfo(true, pointerEvent->inputSource, pointerEvent->isPrimary));
new PointerInfo(true, pointerEvent->inputSource,
pointerEvent->mIsPrimary));
}
break;
case ePointerUp:
@ -6854,14 +6856,17 @@ PresShell::UpdateActivePointerState(WidgetGUIEvent* aEvent)
if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
if(pointerEvent->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
gActivePointersIds->Put(pointerEvent->pointerId,
new PointerInfo(false, pointerEvent->inputSource, pointerEvent->isPrimary));
new PointerInfo(false,
pointerEvent->inputSource,
pointerEvent->mIsPrimary));
} else {
gActivePointersIds->Remove(pointerEvent->pointerId);
}
}
break;
case eMouseExitFromWidget:
// In this case we have to remove information about disappeared mouse pointers
// In this case we have to remove information about disappeared mouse
// pointers
if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
gActivePointersIds->Remove(mouseEvent->pointerId);
}
@ -7205,12 +7210,12 @@ DispatchPointerFromMouseOrTouch(PresShell* aShell,
WidgetPointerEvent event(touchEvent->IsTrusted(), pointerMessage,
touchEvent->mWidget);
event.isPrimary = i == 0;
event.mIsPrimary = i == 0;
event.pointerId = touch->Identifier();
event.mRefPoint = touch->mRefPoint;
event.mModifiers = touchEvent->mModifiers;
event.width = touch->RadiusX();
event.height = touch->RadiusY();
event.mWidth = touch->RadiusX();
event.mHeight = touch->RadiusY();
event.tiltX = touch->tiltX;
event.tiltY = touch->tiltY;
event.mTime = touchEvent->mTime;

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

@ -563,6 +563,9 @@ MediaPipeline::AttachTransport_s()
return res;
}
}
transport_->Attach(this);
return NS_OK;
}

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

@ -166,6 +166,7 @@ class MediaPipeline : public sigslot::has_slots<> {
: pipeline_(pipeline),
sts_thread_(pipeline->sts_thread_) {}
void Attach(MediaPipeline *pipeline) { pipeline_ = pipeline; }
void Detach() { pipeline_ = nullptr; }
MediaPipeline *pipeline() const { return pipeline_; }

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

@ -53,6 +53,7 @@ firefox-ui-functional-local:
treeherder-symbol: tc-Fxfn-l(en-US)
max-run-time: 5400
tier: 1
docker-image: {"in-tree": "desktop1604-test"}
mozharness:
script: mozharness/scripts/firefox_ui_tests/functional.py
config:
@ -67,6 +68,7 @@ firefox-ui-functional-remote:
treeherder-symbol: tc-Fxfn-r(en-US)
max-run-time: 5400
tier: 2
docker-image: {"in-tree": "desktop1604-test"}
mozharness:
script: mozharness/scripts/firefox_ui_tests/functional.py
config:

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

@ -2,7 +2,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from errors import MarionetteException, TimeoutException
from errors import MarionetteException
from functools import wraps
import socket
import sys
@ -40,13 +40,16 @@ def do_process_check(func, always=False):
try:
return func(*args, **kwargs)
except (MarionetteException, socket.error, IOError) as e:
except (MarionetteException, IOError) as e:
exc, val, tb = sys.exc_info()
# In case of socket failures force a shutdown of the application
if type(e) in (socket.error, socket.timeout):
m.force_shutdown()
if not isinstance(e, MarionetteException) or type(e) is MarionetteException:
if not always:
check_for_crash()
if not isinstance(e, MarionetteException) or type(e) is TimeoutException:
m.force_shutdown()
raise exc, val, tb
finally:
if always:

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

@ -49,7 +49,10 @@ class MarionetteException(Exception):
st = "".join(["\t%s\n" % x for x in self.stacktrace.splitlines()])
msg += "\nstacktrace:\n%s" % st
return "".join(traceback.format_exception(self.__class__, msg, tb)).strip()
if tb:
msg += ': ' + "".join(traceback.format_tb(tb))
return msg
class ElementNotSelectableException(MarionetteException):

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

@ -173,7 +173,7 @@ class GeckoInstance(object):
def restart(self, prefs=None, clean=True):
self.close(restart=True)
if clean:
if clean and self.profile:
self.profile.cleanup()
self.profile = None
@ -221,11 +221,9 @@ class FennecInstance(GeckoInstance):
self.runner.device.connect()
self.runner.start()
except Exception as e:
message = 'Error possibly due to runner or device args.'
e.args += (message,)
if hasattr(e, 'strerror') and e.strerror:
e.strerror = ', '.join([e.strerror, message])
raise e
exc, val, tb = sys.exc_info()
message = 'Error possibly due to runner or device args: {}'
raise exc, message.format(e.message), tb
# gecko_log comes from logcat when running with device/emulator
logcat_args = {
'filterspec': 'Gecko',

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

@ -543,6 +543,7 @@ class Marionette(object):
TIMEOUT_PAGE = 'page load'
DEFAULT_SOCKET_TIMEOUT = 360
DEFAULT_STARTUP_TIMEOUT = 120
DEFAULT_SHUTDOWN_TIMEOUT = 65 # Firefox will kill hanging threads after 60s
def __init__(self, host='localhost', port=2828, app=None, bin=None,
baseurl=None, timeout=None, socket_timeout=DEFAULT_SOCKET_TIMEOUT,
@ -616,7 +617,7 @@ class Marionette(object):
if self.session:
try:
self.delete_session()
except (errors.MarionetteException, socket.error, IOError):
except (errors.MarionetteException, IOError):
# These exceptions get thrown if the Marionette server
# hit an exception/died or the connection died. We can
# do no further server-side cleanup in this case.
@ -648,7 +649,7 @@ class Marionette(object):
@do_process_check
def raise_for_port(self, port_obtained):
if not port_obtained:
raise IOError("Timed out waiting for port!")
raise socket.timeout("Timed out waiting for port {}!".format(self.port))
@do_process_check
def _send_message(self, name, params=None, key=None):
@ -684,7 +685,8 @@ class Marionette(object):
self.session = None
self.window = None
self.client.close()
raise errors.TimeoutException("Connection timed out")
raise
res, err = msg.result, msg.error
if err:
@ -754,17 +756,19 @@ class Marionette(object):
if self.instance:
exc, val, tb = sys.exc_info()
returncode = self.instance.runner.returncode
# Give the application some time to shutdown
returncode = self.instance.runner.wait(timeout=self.DEFAULT_STARTUP_TIMEOUT)
if returncode is None:
self.instance.runner.stop()
message = 'Process killed because the connection was lost'
self.cleanup()
message = ('Process killed because the connection to Marionette server is lost.'
' Check gecko.log for errors')
else:
message = 'Process died with returncode "{returncode}"'
message = 'Process has been closed (Exit code: {returncode})'
if exc:
message += ' (Reason: {reason})'
raise exc, message.format(returncode=returncode, reason=val), tb
raise IOError, message.format(returncode=returncode, reason=val), tb
@staticmethod
def convert_keys(*string):
@ -993,8 +997,8 @@ class Marionette(object):
: param prefs: A dictionary whose keys are preference names.
"""
if not self.instance:
raise errors.MarionetteException("enforce_gecko_prefs can only be called "
"on gecko instances launched by Marionette")
raise errors.MarionetteException("enforce_gecko_prefs() can only be called "
"on Gecko instances launched by Marionette")
pref_exists = True
self.set_context(self.CONTEXT_CHROME)
for pref, value in prefs.iteritems():
@ -1027,13 +1031,14 @@ class Marionette(object):
self.start_session()
self.reset_timeouts()
@do_process_check
def quit_in_app(self):
"""
This will terminate the currently running instance.
"""
if not self.instance:
raise errors.MarionetteException("quit_in_app can only be called "
"on gecko instances launched by Marionette")
raise errors.MarionetteException("quit_in_app() can only be called "
"on Gecko instances launched by Marionette")
# Values here correspond to constants in nsIAppStartup.
# See http://mzl.la/1X0JZsC
restart_flags = [
@ -1042,7 +1047,14 @@ class Marionette(object):
]
self._send_message("quitApplication", {"flags": restart_flags})
self.client.close()
self.raise_for_port(self.wait_for_port())
try:
self.raise_for_port(self.wait_for_port())
except socket.timeout:
if self.instance.runner.returncode is not None:
exc, val, tb = sys.exc_info()
self.cleanup()
raise exc, 'Requested restart of the application was aborted', tb
def restart(self, clean=False, in_app=False):
"""
@ -1057,11 +1069,11 @@ class Marionette(object):
by killing the process.
"""
if not self.instance:
raise errors.MarionetteException("restart can only be called "
"on gecko instances launched by Marionette")
raise errors.MarionetteException("restart() can only be called "
"on Gecko instances launched by Marionette")
if in_app:
if clean:
raise ValueError
raise ValueError("An in_app restart cannot be triggered with the clean flag set")
self.quit_in_app()
else:
self.delete_session()
@ -1463,8 +1475,13 @@ class Marionette(object):
:param ms: A number value specifying the timeout length in
milliseconds (ms)
"""
if timeout_type not in [self.TIMEOUT_SEARCH, self.TIMEOUT_SCRIPT, self.TIMEOUT_PAGE]:
raise ValueError("Unknown timeout type: %s" % timeout_type)
timeout_types = (self.TIMEOUT_PAGE,
self.TIMEOUT_SCRIPT,
self.TIMEOUT_SEARCH,
)
if timeout_type not in timeout_types:
raise ValueError("Unknown timeout type: {0} (should be one "
"of {1})".format(timeout_type, timeout_types))
body = {"type": timeout_type, "ms": ms}
self._send_message("timeouts", body)

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

@ -3,7 +3,6 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import datetime
import errno
import json
import socket
import time
@ -119,7 +118,6 @@ class TcpTransport(object):
Supported protocol levels are 1 and above.
"""
max_packet_length = 4096
connection_lost_msg = "Connection to Marionette server is lost. Check gecko.log for errors."
def __init__(self, addr, port, socket_timeout=360.0):
"""If `socket_timeout` is `0` or `0.0`, non-blocking socket mode
@ -176,7 +174,7 @@ class TcpTransport(object):
pass
else:
if not chunk:
raise IOError(self.connection_lost_msg)
raise socket.error("No data received over socket")
sep = data.find(":")
if sep > -1:
@ -203,7 +201,7 @@ class TcpTransport(object):
bytes_to_recv = int(length) - len(remaining)
raise socket.timeout("connection timed out after %ds" % self.socket_timeout)
raise socket.timeout("Connection timed out after %ds" % self.socket_timeout)
def connect(self):
"""Connect to the server and process the hello message we expect
@ -246,19 +244,12 @@ class TcpTransport(object):
totalsent = 0
while totalsent < len(payload):
try:
sent = self.sock.send(payload[totalsent:])
if sent == 0:
raise IOError("socket error after sending %d of %d bytes" %
(totalsent, len(payload)))
else:
totalsent += sent
except IOError as e:
if e.errno == errno.EPIPE:
raise IOError("%s: %s" % (str(e), self.connection_lost_msg))
else:
raise e
sent = self.sock.send(payload[totalsent:])
if sent == 0:
raise IOError("Socket error after sending %d of %d bytes" %
(totalsent, len(payload)))
else:
totalsent += sent
def respond(self, obj):
"""Send a response to a command. This can be an arbitrary JSON

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

@ -121,9 +121,9 @@ class Wait(object):
while not until(self.clock, self.end):
try:
rv = condition(self.marionette)
except (KeyboardInterrupt, SystemExit) as e:
raise e
except self.exceptions as e:
except (KeyboardInterrupt, SystemExit):
raise
except self.exceptions:
last_exc = sys.exc_info()
if not rv:

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

@ -128,9 +128,9 @@ this.GeckoDriver = function(appName, stopSignal) {
this.sessionCapabilities = {
// mandated capabilities
"browserName": Services.appinfo.name,
"browserName": Services.appinfo.name.toLowerCase(),
"browserVersion": Services.appinfo.version,
"platformName": Services.sysinfo.getProperty("name"),
"platformName": Services.sysinfo.getProperty("name").toLowerCase(),
"platformVersion": Services.sysinfo.getProperty("version"),
"specificationLevel": 0,

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

@ -616,9 +616,9 @@ class BaseMarionetteTestRunner(object):
with open(path) as f:
data.append(json.loads(f.read()))
except ValueError as e:
raise Exception("JSON file (%s) is not properly "
"formatted: %s" % (os.path.abspath(path),
e.message))
exc, val, tb = sys.exc_info()
msg = "JSON file ({0}) is not properly formatted: {1}"
raise exc, msg.format(os.path.abspath(path), e.message), tb
return data
@property
@ -669,11 +669,7 @@ class BaseMarionetteTestRunner(object):
"""
self._bin = path
self.tests = []
if hasattr(self, 'marionette') and self.marionette:
self.marionette.cleanup()
if self.marionette.instance:
self.marionette.instance = None
self.marionette = None
self.cleanup()
def reset_test_stats(self):
self.passed = 0
@ -737,8 +733,10 @@ class BaseMarionetteTestRunner(object):
connection = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
connection.connect((host,int(port)))
connection.close()
except Exception, e:
raise Exception("Connection attempt to %s:%s failed with error: %s" %(host,port,e))
except Exception as e:
exc, val, tb = sys.exc_info()
msg = "Connection attempt to {0}:{1} failed with error: {2}"
raise exc, msg.format(host, port, e), tb
if self.workspace:
kwargs['workspace'] = self.workspace_path
return kwargs
@ -896,16 +894,17 @@ setReq.onerror = function() {
# we want to display current test results.
# so we keep the exception to raise it later.
interrupted = sys.exc_info()
except:
# For any other exception we return immediately and have to
# cleanup running processes
self.cleanup()
raise
try:
self._print_summary(tests)
self.record_crash()
self.elapsedtime = time.time() - start_time
if self.marionette.instance:
self.marionette.instance.close()
self.marionette.instance = None
self.marionette.cleanup()
for run_tests in self.mixin_run_tests:
run_tests(tests)
if self.shuffle:
@ -918,6 +917,8 @@ setReq.onerror = function() {
if not interrupted:
raise
finally:
self.cleanup()
# reraise previous interruption now
if interrupted:
raise interrupted[0], interrupted[1], interrupted[2]
@ -1090,10 +1091,16 @@ setReq.onerror = function() {
self.run_test_set(self.tests)
def cleanup(self):
if self.httpd:
if hasattr(self, 'httpd') and self.httpd:
self.httpd.stop()
self.httpd = None
if hasattr(self, 'marionette') and self.marionette:
if self.marionette.instance:
self.marionette.instance.close()
self.marionette.instance = None
if self.marionette:
self.marionette.cleanup()
self.marionette = None
__del__ = cleanup

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

@ -11,7 +11,7 @@ class FixtureServer(object):
def __init__(self, root, host="127.0.0.1", port=0):
if not os.path.isdir(root):
raise Exception("Server root is not a valid path: %s" % root)
raise IOError("Server root is not a valid path: %s" % root)
self.root = root
self.host = host
self.port = port
@ -44,7 +44,7 @@ class FixtureServer(object):
def get_url(self, path="/"):
if not self.alive:
raise "Server not started"
raise Exception("Server not started")
return self._server.get_url(path)
@property

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

@ -31,8 +31,8 @@ class Server(object):
break
if not os.path.isfile(path) and exec_not_on_path:
raise Exception("Browsermob-Proxy binary couldn't be found in path"
" provided: %s" % path)
raise IOError("Browsermob-Proxy binary couldn't be found in path"
" provided: %s" % path)
self.path = path
self.port = options.get('port', 8080)

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

@ -12,7 +12,7 @@ class TestAboutPages(MarionetteTestCase):
def setUp(self):
MarionetteTestCase.setUp(self)
if self.marionette.session_capabilities['platformName'] == 'Darwin':
if self.marionette.session_capabilities['platformName'] == 'darwin':
self.mod_key = Keys.META
else:
self.mod_key = Keys.CONTROL

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

@ -15,7 +15,7 @@ class TestCapabilities(MarionetteTestCase):
self.appinfo = self.marionette.execute_script(
"return Services.appinfo")
self.os_name = self.marionette.execute_script(
"return Services.sysinfo.getProperty('name')")
"return Services.sysinfo.getProperty('name')").lower()
self.os_version = self.marionette.execute_script(
"return Services.sysinfo.getProperty('version')")
@ -30,7 +30,7 @@ class TestCapabilities(MarionetteTestCase):
self.assertIn("platformVersion", self.caps)
self.assertIn("specificationLevel", self.caps)
self.assertEqual(self.caps["browserName"], self.appinfo["name"])
self.assertEqual(self.caps["browserName"], self.appinfo["name"].lower())
self.assertEqual(self.caps["browserVersion"], self.appinfo["version"])
self.assertEqual(self.caps["platformName"], self.os_name)
self.assertEqual(self.caps["platformVersion"], self.os_version)
@ -78,12 +78,12 @@ class TestCapabilities(MarionetteTestCase):
capabilities = {"desiredCapabilities": {"browserName": "ChocolateCake"}}
self.marionette.start_session(capabilities)
caps = self.marionette.session_capabilities
self.assertEqual(caps["browserName"], self.appinfo["name"],
"This should have appname not ChocolateCake")
self.assertEqual(caps["browserName"], self.appinfo["name"].lower(),
"This should have appname not ChocolateCake.")
def test_we_can_pass_in_required_capabilities_on_session_start(self):
self.marionette.delete_session()
capabilities = {"requiredCapabilities": {"browserName": self.appinfo["name"]}}
capabilities = {"requiredCapabilities": {"browserName": self.appinfo["name"].lower()}}
self.marionette.start_session(capabilities)
caps = self.marionette.session_capabilities
self.assertIn("browserName", caps)

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

@ -38,7 +38,6 @@ class TestErrors(marionette_test.MarionetteTestCase):
self.assertIn(message, r)
self.assertIn(", caused by %r" % cause[0], r)
self.assertIn("\nstacktrace:\n\tfirst\n\tsecond", r)
self.assertIn("MarionetteException:", r)
def test_cause_string(self):
exc = errors.MarionetteException(cause="foo")

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

@ -11,7 +11,7 @@ from marionette_driver.by import By
class TestKeyActions(MarionetteTestCase):
def setUp(self):
MarionetteTestCase.setUp(self)
if self.marionette.session_capabilities["platformName"] == "Darwin":
if self.marionette.session_capabilities["platformName"] == "darwin":
self.mod_key = Keys.META
else:
self.mod_key = Keys.CONTROL

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

@ -11,7 +11,7 @@ from marionette_driver.by import By
class TestMouseAction(MarionetteTestCase):
def setUp(self):
MarionetteTestCase.setUp(self)
if self.marionette.session_capabilities["platformName"] == "Darwin":
if self.marionette.session_capabilities["platformName"] == "darwin":
self.mod_key = Keys.META
else:
self.mod_key = Keys.CONTROL

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

@ -11,6 +11,12 @@ from marionette_driver.by import By
class TestTimeouts(MarionetteTestCase):
def tearDown(self):
self.marionette.reset_timeouts()
MarionetteTestCase.tearDown(self)
def test_pagetimeout_notdefinetimeout_pass(self):
test_html = self.marionette.absolute_url("test.html")
self.marionette.navigate(test_html)
@ -62,3 +68,8 @@ class TestTimeouts(MarionetteTestCase):
var callback = arguments[arguments.length - 1];
setTimeout(function() { callback(true); }, 500);
"""))
def test_invalid_timeout_type(self):
self.assertRaises(ValueError, self.marionette.timeouts, "foobar", 1000)
self.assertRaises(ValueError, self.marionette.timeouts, 42, 1000)
self.assertRaises(MarionetteException, self.marionette.timeouts, "page load", "foobar")

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

@ -58,7 +58,7 @@ class TestTyping(MarionetteTestCase):
def testCutAndPasteShortcuts(self):
# test that modifier keys work via copy/paste shortcuts
if self.marionette.session_capabilities["platformName"] == "Darwin":
if self.marionette.session_capabilities["platformName"] == "darwin":
mod_key = Keys.META
else:
mod_key = Keys.CONTROL

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

@ -12,7 +12,7 @@ class TestWindowHandles(MarionetteTestCase):
def test_new_tab_window_handles(self):
keys = []
if self.marionette.session_capabilities['platformName'] == 'Darwin':
if self.marionette.session_capabilities['platformName'] == 'darwin':
keys.append(Keys.META)
else:
keys.append(Keys.CONTROL)

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

@ -126,7 +126,7 @@ function registerSelf() {
if (register[0]) {
let {id, remotenessChange} = register[0][0];
capabilities = register[0][2];
isB2G = capabilities.platformName == "B2G";
isB2G = capabilities.platformName == "b2g";
listenerId = id;
if (typeof id != "undefined") {
// check if we're the main process

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

@ -66,7 +66,7 @@ class Puppeteer(object):
:returns: Platform name
"""
return self.marionette.session_capabilities['platformName'].lower()
return self.marionette.session_capabilities['platformName']
@use_class_as_property('api.prefs.Preferences')
def prefs(self):

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

@ -13,7 +13,7 @@ class Keys(marionette_driver.keys.Keys):
self.marionette_getter = marionette_getter
caps = self.marionette_getter().session_capabilities
self.isDarwin = caps['platformName'] == 'DARWIN'
self.isDarwin = caps['platformName'] == 'darwin'
@property
def ACCEL(self):

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

@ -398,7 +398,7 @@ class BaseWindow(BaseLib):
Defaults to `False`.
"""
platform = self.marionette.session_capabilities['platformName'].lower()
platform = self.marionette.session_capabilities['platformName']
keymap = {
'accel': Keys.META if platform == 'darwin' else Keys.CONTROL,

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

@ -283,8 +283,14 @@ FinderHighlighter.prototype = {
* Optional, defaults to the finder window.
* @param {nsIDOMRange} skipRange A range that should not be removed from the
* find selection.
* @param {nsIDOMEvent} event When called from an event handler, this will
* be the triggering event.
*/
hide(window = null, skipRange = null) {
hide(window = null, skipRange = null, event = null) {
// Do not hide on anything but a left-click.
if (event && event.type == "click" && event.button !== 0)
return;
window = window || this.finder._getWindow();
let doc = window.document;
@ -836,12 +842,11 @@ FinderHighlighter.prototype = {
this._highlightListeners = [
this._scheduleRepaintOfMask.bind(this, window),
this.hide.bind(this, window)
this.hide.bind(this, window, null)
];
window.addEventListener("DOMContentLoaded", this._highlightListeners[0]);
window.addEventListener("mousedown", this._highlightListeners[1]);
window.addEventListener("click", this._highlightListeners[1]);
window.addEventListener("resize", this._highlightListeners[1]);
window.addEventListener("touchstart", this._highlightListeners[1]);
},
/**
@ -854,9 +859,8 @@ FinderHighlighter.prototype = {
return;
window.removeEventListener("DOMContentLoaded", this._highlightListeners[0]);
window.removeEventListener("mousedown", this._highlightListeners[1]);
window.removeEventListener("click", this._highlightListeners[1]);
window.removeEventListener("resize", this._highlightListeners[1]);
window.removeEventListener("touchstart", this._highlightListeners[1]);
this._highlightListeners = null;
},

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

@ -113,7 +113,7 @@ public:
* mozilla::InternalFormEvent
*
* We hold the originating form control for form submit and reset events.
* originator is a weak pointer (does not hold a strong reference).
* mOriginator is a weak pointer (does not hold a strong reference).
******************************************************************************/
class InternalFormEvent : public WidgetEvent
@ -123,7 +123,7 @@ public:
InternalFormEvent(bool aIsTrusted, EventMessage aMessage)
: WidgetEvent(aIsTrusted, aMessage, eFormEventClass)
, originator(nullptr)
, mOriginator(nullptr)
{
}
@ -137,13 +137,13 @@ public:
return result;
}
nsIContent *originator;
nsIContent* mOriginator;
void AssignFormEventData(const InternalFormEvent& aEvent, bool aCopyTargets)
{
AssignEventData(aEvent, aCopyTargets);
// Don't copy originator due to a weak pointer.
// Don't copy mOriginator due to a weak pointer.
}
};

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

@ -666,9 +666,9 @@ class WidgetPointerEvent : public WidgetMouseEvent
friend class mozilla::dom::PBrowserChild;
WidgetPointerEvent()
: width(0)
, height(0)
, isPrimary(true)
: mWidth(0)
, mHeight(0)
, mIsPrimary(true)
{
}
@ -677,17 +677,17 @@ public:
WidgetPointerEvent(bool aIsTrusted, EventMessage aMsg, nsIWidget* w)
: WidgetMouseEvent(aIsTrusted, aMsg, w, ePointerEventClass, eReal)
, width(0)
, height(0)
, isPrimary(true)
, mWidth(0)
, mHeight(0)
, mIsPrimary(true)
{
}
explicit WidgetPointerEvent(const WidgetMouseEvent& aEvent)
: WidgetMouseEvent(aEvent)
, width(0)
, height(0)
, isPrimary(true)
, mWidth(0)
, mHeight(0)
, mIsPrimary(true)
{
mClass = ePointerEventClass;
}
@ -704,9 +704,9 @@ public:
return result;
}
uint32_t width;
uint32_t height;
bool isPrimary;
uint32_t mWidth;
uint32_t mHeight;
bool mIsPrimary;
// XXX Not tested by test_assign_event_data.html
void AssignPointerEventData(const WidgetPointerEvent& aEvent,
@ -714,9 +714,9 @@ public:
{
AssignMouseEventData(aEvent, aCopyTargets);
width = aEvent.width;
height = aEvent.height;
isPrimary = aEvent.isPrimary;
mWidth = aEvent.mWidth;
mHeight = aEvent.mHeight;
mIsPrimary = aEvent.mIsPrimary;
}
};

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

@ -287,11 +287,11 @@ struct ParamTraits<mozilla::WidgetPointerEvent>
{
WriteParam(aMsg, static_cast<mozilla::WidgetMouseEvent>(aParam));
WriteParam(aMsg, aParam.pointerId);
WriteParam(aMsg, aParam.width);
WriteParam(aMsg, aParam.height);
WriteParam(aMsg, aParam.mWidth);
WriteParam(aMsg, aParam.mHeight);
WriteParam(aMsg, aParam.tiltX);
WriteParam(aMsg, aParam.tiltY);
WriteParam(aMsg, aParam.isPrimary);
WriteParam(aMsg, aParam.mIsPrimary);
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
@ -299,11 +299,11 @@ struct ParamTraits<mozilla::WidgetPointerEvent>
bool rv =
ReadParam(aMsg, aIter, static_cast<mozilla::WidgetMouseEvent*>(aResult)) &&
ReadParam(aMsg, aIter, &aResult->pointerId) &&
ReadParam(aMsg, aIter, &aResult->width) &&
ReadParam(aMsg, aIter, &aResult->height) &&
ReadParam(aMsg, aIter, &aResult->mWidth) &&
ReadParam(aMsg, aIter, &aResult->mHeight) &&
ReadParam(aMsg, aIter, &aResult->tiltX) &&
ReadParam(aMsg, aIter, &aResult->tiltY) &&
ReadParam(aMsg, aIter, &aResult->isPrimary);
ReadParam(aMsg, aIter, &aResult->mIsPrimary);
return rv;
}
};