1:mod:`mozrunner` --- Manage remote and local gecko processes
2============================================================
3
4Mozrunner provides an API to manage a gecko-based application with an
5arbitrary configuration profile. It currently supports local desktop
6binaries such as Firefox and Thunderbird, as well as Firefox OS on
7mobile devices and emulators.
8
9
10Basic usage
11-----------
12
13The simplest way to use mozrunner, is to instantiate a runner, start it
14and then wait for it to finish:
15
16.. code-block:: python
17
18    from mozrunner import FirefoxRunner
19    binary = 'path/to/firefox/binary'
20    runner = FirefoxRunner(binary=binary)
21    runner.start()
22    runner.wait()
23
24This automatically creates and uses a default mozprofile object. If you
25wish to use a specialized or pre-existing profile, you can create a
26:doc:`mozprofile <mozprofile>` object and pass it in:
27
28.. code-block:: python
29
30    from mozprofile import FirefoxProfile
31    from mozrunner import FirefoxRunner
32    import os
33
34    binary = 'path/to/firefox/binary'
35    profile_path = 'path/to/profile'
36    if os.path.exists(profile_path):
37        profile = FirefoxProfile.clone(path_from=profile_path)
38    else:
39        profile = FirefoxProfile(profile=profile_path)
40    runner = FirefoxRunner(binary=binary, profile=profile)
41    runner.start()
42    runner.wait()
43
44
45Handling output
46---------------
47
48By default, mozrunner dumps the output of the gecko process to standard output.
49It is possible to add arbitrary output handlers by passing them in via the
50`process_args` argument. Be careful, passing in a handler overrides the default
51behaviour. So if you want to use a handler in addition to dumping to stdout, you
52need to specify that explicitly. For example:
53
54.. code-block:: python
55
56    from mozrunner import FirefoxRunner
57
58    def handle_output_line(line):
59        do_something(line)
60
61    binary = 'path/to/firefox/binary'
62    process_args = { 'stream': sys.stdout,
63                     'processOutputLine': [handle_output_line] }
64    runner = FirefoxRunner(binary=binary, process_args=process_args)
65
66Mozrunner uses :doc:`mozprocess <mozprocess>` to manage the underlying gecko
67process and handle output. See the :doc:`mozprocess documentation <mozprocess>`
68for all available arguments accepted by `process_args`.
69
70
71Handling timeouts
72-----------------
73
74Sometimes gecko can hang, or maybe it is just taking too long. To handle this case you
75may want to set a timeout. Mozrunner has two kinds of timeouts, the
76traditional `timeout`, and the `outputTimeout`. These get passed into the
77`runner.start()` method. Setting `timeout` will cause gecko to be killed after
78the specified number of seconds, no matter what. Setting `outputTimeout` will cause
79gecko to be killed after the specified number of seconds with no output. In both
80cases the process handler's `onTimeout` callbacks will be triggered.
81
82.. code-block:: python
83
84    from mozrunner import FirefoxRunner
85
86    def on_timeout():
87        print('timed out after 10 seconds with no output!')
88
89    binary = 'path/to/firefox/binary'
90    process_args = { 'onTimeout': on_timeout }
91    runner = FirefoxRunner(binary=binary, process_args=process_args)
92    runner.start(outputTimeout=10)
93    runner.wait()
94
95The `runner.wait()` method also accepts a timeout argument. But unlike the arguments
96to `runner.start()`, this one simply returns from the wait call and does not kill the
97gecko process.
98
99.. code-block:: python
100
101    runner.start(timeout=100)
102
103    waiting = 0
104    while runner.wait(timeout=1) is None:
105        waiting += 1
106        print("Been waiting for %d seconds so far.." % waiting)
107    assert waiting <= 100
108
109
110Using a device runner
111---------------------
112
113The previous examples used a GeckoRuntimeRunner. If you want to control a
114gecko process on a remote device, you need to use a DeviceRunner. The api is
115nearly identical except you don't pass in a binary, instead you create a device
116object. For example to run Firefox for Android on the emulator, you might do:
117
118.. code-block:: python
119
120    from mozrunner import FennecEmulatorRunner
121
122    avd_home = 'path/to/avd'
123    runner = FennecEmulatorRunner(app='org.mozilla.fennec', avd_home=avd_home)
124    runner.start()
125    runner.wait()
126
127Device runners have a `device` object. Remember that the gecko process runs on
128the device. In the case of the emulator, it is possible to start the
129device independently of the gecko process.
130
131.. code-block:: python
132
133    runner.device.start() # launches the emulator
134    runner.start()        # stops the gecko process (if started), installs the profile, (re)starts the gecko process
135
136
137Runner API Documentation
138------------------------
139
140Application Runners
141~~~~~~~~~~~~~~~~~~~
142.. automodule:: mozrunner.runners
143   :members:
144
145BaseRunner
146~~~~~~~~~~
147.. autoclass:: mozrunner.base.BaseRunner
148   :members:
149
150GeckoRuntimeRunner
151~~~~~~~~~~~~~~~~~~
152.. autoclass:: mozrunner.base.GeckoRuntimeRunner
153   :show-inheritance:
154   :members:
155
156BlinkRuntimeRunner
157~~~~~~~~~~~~~~~~~~
158.. autoclass:: mozrunner.base.BlinkRuntimeRunner
159   :show-inheritance:
160   :members:
161
162DeviceRunner
163~~~~~~~~~~~~
164.. autoclass:: mozrunner.base.DeviceRunner
165   :show-inheritance:
166   :members:
167
168Device API Documentation
169------------------------
170
171Generally using the device classes directly shouldn't be required, but in some
172cases it may be desirable.
173
174Device
175~~~~~~
176.. autoclass:: mozrunner.devices.Device
177   :members:
178
179EmulatorAVD
180~~~~~~~~~~~
181.. autoclass:: mozrunner.devices.EmulatorAVD
182   :show-inheritance:
183   :members:
184