Bug 1473262 - [marionette] Force client to always use IPv4 to connect to Marionette.
Marionette uses nsIServerSocket which only allows to create a IPv4 listener.
On systems where IPv6 has precedence Marionette client will automatically
use the IPv6 address for `localhost` and will fail to connect to Marionette.
As such we should make sure that Marionette client connects to "127.0.0.1"
by default.
MozReview-Commit-ID: Fwzfa6CwBhX
--- a/testing/marionette/client/docs/basics.rst
+++ b/testing/marionette/client/docs/basics.rst
@@ -51,17 +51,17 @@ Session Management
------------------
A session is a single instance of a Marionette client connected to a Marionette
server. Before you can start executing commands, you need to start a session
with :func:`start_session() <Marionette.start_session>`:
.. parsed-literal::
from marionette_driver.marionette import Marionette
- client = Marionette('localhost', port=2828)
+ client = Marionette('127.0.0.1', port=2828)
client.start_session()
This returns a session id and an object listing the capabilities of the
Marionette server. For example, a server running on Firefox Desktop will
have some features which a server running from Firefox Android won't.
It's also possible to access the capabilities using the
:attr:`~Marionette.session_capabilities` attribute. After finishing with a
session, you can delete it with :func:`~Marionette.delete_session()`. Note that
--- a/testing/marionette/client/docs/interactive.rst
+++ b/testing/marionette/client/docs/interactive.rst
@@ -12,17 +12,17 @@ First, import Marionette:
.. parsed-literal::
from marionette_driver.marionette import Marionette
Now create the client for this session. Assuming you're using the default
port on a Marionette instance running locally:
.. parsed-literal::
- client = Marionette(host='localhost', port=2828)
+ client = Marionette(host='127.0.0.1', port=2828)
client.start_session()
This will return some id representing your session id. Now that you've
established a connection, let's start doing interesting things:
.. parsed-literal::
client.navigate("http://www.mozilla.org")
--- a/testing/marionette/client/marionette_driver/geckoinstance.py
+++ b/testing/marionette/client/marionette_driver/geckoinstance.py
@@ -449,17 +449,17 @@ class FennecInstance(GeckoInstance):
"serial": self.runner.device.app_ctx.device_serial
}
if self.gecko_log == "-":
logcat_args["stream"] = sys.stdout
else:
logcat_args["logfile"] = self.gecko_log
self.runner.device.start_logcat(**logcat_args)
- # forward marionette port (localhost:2828)
+ # forward marionette port
self.runner.device.device.forward(
local="tcp:{}".format(self.marionette_port),
remote="tcp:{}".format(self.marionette_port))
def _get_runner_args(self):
process_args = {
"processOutputLine": [NullOutput()],
}
--- a/testing/marionette/client/marionette_driver/marionette.py
+++ b/testing/marionette/client/marionette_driver/marionette.py
@@ -575,42 +575,42 @@ class Marionette(object):
DEFAULT_SHUTDOWN_TIMEOUT = 120 # Firefox will kill hanging threads after 60s
# Bug 1336953 - Until we can remove the socket timeout parameter it has to be
# set a default value which is larger than the longest timeout as defined by the
# WebDriver spec. In that case its 300s for page load. Also add another minute
# so that slow builds have enough time to send the timeout error to the client.
DEFAULT_SOCKET_TIMEOUT = 360
- def __init__(self, host="localhost", port=2828, app=None, bin=None,
+ def __init__(self, host="127.0.0.1", port=2828, app=None, bin=None,
baseurl=None, socket_timeout=None,
startup_timeout=None, **instance_args):
"""Construct a holder for the Marionette connection.
Remember to call ``start_session`` in order to initiate the
connection and start a Marionette session.
:param host: Host where the Marionette server listens.
- Defaults to localhost.
+ Defaults to 127.0.0.1.
:param port: Port where the Marionette server listens.
Defaults to port 2828.
:param baseurl: Where to look for files served from Marionette's
www directory.
:param socket_timeout: Timeout for Marionette socket operations.
:param startup_timeout: Seconds to wait for a connection with
binary.
:param bin: Path to browser binary. If any truthy value is given
this will attempt to start a Gecko instance with the specified
`app`.
:param app: Type of ``instance_class`` to use for managing app
instance. See ``marionette_driver.geckoinstance``.
:param instance_args: Arguments to pass to ``instance_class``.
"""
- self.host = host
+ self.host = "127.0.0.1" # host
self.port = self.local_port = int(port)
self.bin = bin
self.client = None
self.instance = None
self.session = None
self.session_id = None
self.process_id = None
self.profile = None
--- a/testing/marionette/doc/Taskcluster.md
+++ b/testing/marionette/doc/Taskcluster.md
@@ -57,17 +57,17 @@ Running Marionette tests
### Firefox
To run the Marionette tests execute the `runtests.py` script. For all
the required options as best search in the log file of the failing job
the interactive task has been created from. Then copy the complete
command and run it inside the already sourced virtual environment:
- % /builds/worker/workspace/build/venv/bin/python -u /builds/worker/workspace/build/tests/marionette/harness/marionette_harness/runtests.py --gecko-log=- -vv --binary=/builds/worker/workspace/build/application/firefox/firefox --address=localhost:2828 --symbols-path=https://queue.taskcluster.net/v1/task/GSuwee61Qyibujtxq4UV3A/artifacts/public/build/target.crashreporter-symbols.zip /builds/worker/workspace/build/tests/marionette/tests/testing/marionette/harness/marionette_harness/tests/unit-tests.ini
+ % /builds/worker/workspace/build/venv/bin/python -u /builds/worker/workspace/build/tests/marionette/harness/marionette_harness/runtests.py --gecko-log=- -vv --binary=/builds/worker/workspace/build/application/firefox/firefox --address=127.0.0.1:2828 --symbols-path=https://queue.taskcluster.net/v1/task/GSuwee61Qyibujtxq4UV3A/artifacts/public/build/target.crashreporter-symbols.zip /builds/worker/workspace/build/tests/marionette/tests/testing/marionette/harness/marionette_harness/tests/unit-tests.ini
#### Fennec
The Marionette tests for Fennec are executed by using an Android
emulator which runs on the host platform. As such some extra setup
steps compared to Firefox on desktop are required.
@@ -83,12 +83,12 @@ The actual call to `runtests.py` is diff
those are using chunks on Android. As best search for the command
and its options in the log file of the failing job the interactive
task has been created from. Then copy the complete command and run
it inside the already sourced virtual environment.
Here an example for chunk 1 which runs all the tests in the current
chunk with some options for logs removed:
- % /builds/worker/workspace/build/venv/bin/python -u /builds/worker/workspace/build/tests/marionette/harness/marionette_harness/runtests.py --emulator --app=fennec --package=org.mozilla.fennec_aurora --address=localhost:2828 /builds/worker/workspace/build/tests/marionette/tests/testing/marionette/harness/marionette_harness/tests/unit-tests.ini --disable-e10s --gecko-log=- --symbols-path=/builds/worker/workspace/build/symbols --startup-timeout=300 --this-chunk 1 --total-chunks 10
+ % /builds/worker/workspace/build/venv/bin/python -u /builds/worker/workspace/build/tests/marionette/harness/marionette_harness/runtests.py --emulator --app=fennec --package=org.mozilla.fennec_aurora --address=127.0.0.1:2828 /builds/worker/workspace/build/tests/marionette/tests/testing/marionette/harness/marionette_harness/tests/unit-tests.ini --disable-e10s --gecko-log=- --symbols-path=/builds/worker/workspace/build/symbols --startup-timeout=300 --this-chunk 1 --total-chunks 10
To execute a specific test only simply replace `unit-tests.ini`
with its name.
--- a/testing/marionette/doc/Testing.md
+++ b/testing/marionette/doc/Testing.md
@@ -72,62 +72,62 @@ the dimensions of the no-op virtual disp
using xvfb(1) which you may know from the X windowing system, but
has the additional benefit of also working on macOS and Windows.
### Android
Prerequisites:
-* You have [built Fennec](https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Build_Instructions/Simple_Firefox_for_Android_build) with
+* You have [built Fennec](https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Build_Instructions/Simple_Firefox_for_Android_build) with
`ac_add_options --enable-marionette` in your mozconfig.
-* You can run an Android [emulator](https://wiki.mozilla.org/Mobile/Fennec/Android/Testing#Running_tests_on_the_Android_emulator),
+* You can run an Android [emulator](https://wiki.mozilla.org/Mobile/Fennec/Android/Testing#Running_tests_on_the_Android_emulator),
which means you have the AVD you need.
When running tests on Fennec, you can have Marionette runner take care of
starting Fennec and an emulator, as shown below.
% ./mach marionette test --emulator --app fennec
--avd-home /path/to/.mozbuild/android-device/avd
--emulator-binary /path/to/.mozbuild/android-sdk/emulator/emulator
--avd=mozemulator-x86
For Fennec tests, if the appropriate `emulator` command is in your `PATH`, you may omit the `--emulator-binary` argument. See `./mach marionette test -h`
for additional options.
Alternately, you can start an emulator yourself and have the Marionette runner
start Fennec for you:
- % ./mach marionette test --emulator --app='fennec' --address=localhost:2828 --disable-e10s
+ % ./mach marionette test --emulator --app='fennec' --address=127.0.0.1:2828 --disable-e10s
-To connect to an already-running Fennec in an already running emulator or on a device, you will need to enable Marionette manually by setting the browser preference
+To connect to an already-running Fennec in an already running emulator or on a device, you will need to enable Marionette manually by setting the browser preference
`marionette.enabled` set to true in the Fennec profile.
Make sure port 2828 is forwarded:
% adb forward tcp:2828 tcp:2828
If Fennec is already started:
- % ./mach marionette test --app='fennec' --address=localhost:2828 --disable-e10s
+ % ./mach marionette test --app='fennec' --address=127.0.0.1:2828 --disable-e10s
If Fennec is not already started on the emulator/device, add the `--emulator`
option. Marionette Test Runner will take care of forwarding the port and
starting Fennec with the correct prefs. (You may need to run
`adb forward --remove-all` to allow the runner to start.)
- % ./mach marionette test --emulator --app='fennec' --address=localhost:2828 --disable-e10s
+ % ./mach marionette test --emulator --app='fennec' --address=127.0.0.1:2828 --disable-e10s
--startup-timeout=300
If you need to troubleshoot the Marionette connection, the most basic check is
to start Fennec, make sure the `marionette.enabled` browser preference is
true and port 2828 is forwarded, then see if you get any response from
Marionette when you connect manually:
- % telnet localhost:2828
+ % telnet 127.0.0.1:2828
You should see output like `{"applicationType":"gecko","marionetteProtocol":3}`
[headless mode]: https://developer.mozilla.org/en-US/Firefox/Headless_mode
[geckodriver]: /testing/geckodriver/geckodriver
WPT functional tests
--- a/testing/marionette/harness/marionette_harness/runner/base.py
+++ b/testing/marionette/harness/marionette_harness/runner/base.py
@@ -723,17 +723,17 @@ class BaseMarionetteTestRunner(object):
'socket_timeout': self.socket_timeout,
'prefs': self.prefs,
'startup_timeout': self.startup_timeout,
'verbose': self.verbose,
'symbols_path': self.symbols_path,
}
if self.bin or self.emulator:
kwargs.update({
- 'host': 'localhost',
+ 'host': '127.0.0.1',
'port': 2828,
'app': self.app,
'app_args': self.app_args,
'profile': self.profile,
'addons': self.addons,
'gecko_log': self.gecko_log,
# ensure Marionette class takes care of starting gecko instance
'bin': True,
--- a/testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_runner.py
+++ b/testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_runner.py
@@ -169,17 +169,17 @@ def test_build_kwargs_with_binary_or_add
binary, address):
built_kwargs = build_kwargs_using({'binary': binary, 'address': address, 'emulator': None})
if binary:
expected_driver_args['bin'] = binary
if address:
host, port = address.split(":")
expected_driver_args.update({'host': host, 'port': int(port)})
else:
- expected_driver_args.update({'host': 'localhost', 'port': 2828})
+ expected_driver_args.update({'host': '127.0.0.1', 'port': 2828})
expected_driver_args.assert_matches(built_kwargs)
elif address is None:
expected_driver_args.assert_keys_not_in(built_kwargs)
@pytest.mark.parametrize('address', ['host:123', None])
@pytest.mark.parametrize('emulator', [True, False, None])
def test_build_kwargs_with_emulator_or_address(expected_driver_args, build_kwargs_using,
@@ -192,17 +192,17 @@ def test_build_kwargs_with_emulator_or_a
expected_driver_args.update(emulator_props)
expected_driver_args['emulator_binary'] = expected_driver_args.pop('emulator_bin')
expected_driver_args['bin'] = True
if address:
expected_driver_args['connect_to_running_emulator'] = True
host, port = address.split(":")
expected_driver_args.update({'host': host, 'port': int(port)})
else:
- expected_driver_args.update({'host': 'localhost', 'port': 2828})
+ expected_driver_args.update({'host': '127.0.0.1', 'port': 2828})
assert 'connect_to_running_emulator' not in built_kwargs
expected_driver_args.assert_matches(built_kwargs)
elif not address:
expected_driver_args.assert_keys_not_in(built_kwargs)
def test_parsing_testvars(mach_parsed_kwargs):
mach_parsed_kwargs.pop('tests')