18
18
from mozprocess import ProcessHandlerMixin
21
class LogcatProc(ProcessHandlerMixin):
22
"""Process handler for logcat which puts all output in a Queue.
21
class StdOutProc(ProcessHandlerMixin):
22
"""Process handler for b2g which puts all output in a Queue.
25
25
def __init__(self, cmd, queue, **kwargs):
35
35
_devicemanager = None
37
37
def __init__(self, deviceManager, appName='', remoteLog=None,
38
marionette=None, context_chrome=True):
39
39
self._devicemanager = deviceManager
40
40
self._appName = appName
41
41
self._remoteProfile = None
42
42
self._remoteLog = remoteLog
43
43
self.marionette = marionette
44
self.context_chrome = context_chrome
44
45
self._is_emulator = False
46
self.test_script = None
47
self.test_script_args = None
46
49
# Default our product to b2g
47
50
self._product = "b2g"
51
self.lastTestSeen = "b2gautomation.py"
52
# Default log finish to mochitest standard
53
self.logFinish = 'INFO SimpleTest FINISHED'
48
54
Automation.__init__(self)
50
56
def setEmulator(self, is_emulator):
76
82
env['MOZ_HIDE_RESULTS_TABLE'] = '1'
88
while not active and time_out < 40:
89
data = self._devicemanager.runCmd(['shell', '/system/bin/netcfg']).stdout.readlines()
92
if (re.search(r'UP\s+(?:[0-9]{1,3}\.){3}[0-9]{1,3}', line)):
79
99
def checkForCrashes(self, directory, symbolsPath):
80
100
# XXX: This will have to be updated after crash reporting on b2g
106
126
return nettools.getLanIp()
108
128
def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime,
109
debuggerInfo, symbolsPath, logger):
110
""" Wait for mochitest to finish (as evidenced by a signature string
129
debuggerInfo, symbolsPath):
130
""" Wait for tests to finish (as evidenced by a signature string
111
131
in logcat), or for a given amount of time to elapse with no
114
134
timeout = timeout or 120
118
done = time.time() + timeout
135
responseDueBy = time.time() + timeout
120
137
currentlog = proc.stdout
122
done = time.time() + timeout
139
responseDueBy = time.time() + timeout
124
if 'INFO SimpleTest FINISHED' in currentlog:
141
# Match the test filepath from the last TEST-START line found in the new
142
# log content. These lines are in the form:
143
# ... INFO TEST-START | /filepath/we/wish/to/capture.html\n
144
testStartFilenames = re.findall(r"TEST-START \| ([^\s]*)", currentlog)
145
if testStartFilenames:
146
self.lastTestSeen = testStartFilenames[-1]
147
if hasattr(self, 'logFinish') and self.logFinish in currentlog:
127
if time.time() > done:
150
if time.time() > responseDueBy:
128
151
self.log.info("TEST-UNEXPECTED-FAIL | %s | application timed "
129
152
"out after %d seconds with no output",
130
153
self.lastTestSeen, int(timeout))
160
185
serial, status = self.getDeviceStatus()
163
self._devicemanager.checkCmd(['reboot'])
188
self._devicemanager.runCmd(['shell', '/system/bin/reboot'])
190
# The above command can return while adb still thinks the device is
191
# connected, so wait a little bit for it to disconnect from adb.
165
194
# wait for device to come back to previous status
166
195
print 'waiting for device to come back online after reboot'
177
206
def Process(self, cmd, stdout=None, stderr=None, env=None, cwd=None):
178
207
# On a desktop or fennec run, the Process method invokes a gecko
179
# process in which to run mochitests. For B2G, we simply
208
# process in which to the tests. For B2G, we simply
180
209
# reboot the device (which was configured with a test profile
181
210
# already), wait for B2G to start up, and then navigate to the
182
211
# test url using Marionette. There doesn't seem to be any way
183
# to pass env variables into the B2G process, but this doesn't
212
# to pass env variables into the B2G process, but this doesn't
184
213
# seem to matter.
186
instance = self.B2GInstance(self._devicemanager)
188
215
# reboot device so it starts up with the mochitest profile
189
216
# XXX: We could potentially use 'stop b2g' + 'start b2g' to achieve
190
217
# a similar effect; will see which is more stable while attempting
191
218
# to bring up the continuous integration.
192
if self._is_emulator:
219
if not self._is_emulator:
195
220
self.rebootDevice()
197
# Infrequently, gecko comes up before networking does, so wait a little
198
# bit to give the network time to become available.
199
# XXX: need a more robust mechanism for this
222
#wait for wlan to come up
223
if not self.waitForNet():
224
raise Exception("network did not come up, please configure the network" +
225
" prior to running before running the automation framework")
228
self._devicemanager.runCmd(['shell', 'stop', 'b2g'])
231
# relaunch b2g inside b2g instance
232
instance = self.B2GInstance(self._devicemanager)
202
236
# Set up port forwarding again for Marionette, since any that
203
237
# existed previously got wiped out by the reboot.
206
240
'tcp:%s' % self.marionette.port,
207
241
'tcp:%s' % self.marionette.port])
243
if self._is_emulator:
244
self.marionette.emulator.wait_for_port()
209
248
# start a marionette session
210
249
session = self.marionette.start_session()
211
250
if 'b2g' not in session:
212
251
raise Exception("bad session value %s returned by start_session" % session)
214
# start the tests by navigating to the mochitest url
215
self.marionette.execute_script("window.location.href='%s';" % self.testURL)
253
if self.context_chrome:
254
self.marionette.set_context(self.marionette.CONTEXT_CHROME)
257
if hasattr(self, 'testURL'):
258
# Start the tests by navigating to the mochitest url, by setting it
259
# as the 'src' attribute to the homescreen mozbrowser element
260
# provided by B2G's shell.js.
261
self.marionette.execute_script("document.getElementById('homescreen').src='%s';" % self.testURL)
262
# run the script that starts the tests
263
elif self.test_script:
264
if os.path.isfile(self.test_script):
265
script = open(self.test_script, 'r')
266
self.marionette.execute_script(script.read(), script_args=self.test_script_args)
269
# assume test_script is a string
270
self.marionette.execute_script(self.test_script, script_args=self.test_script_args)
272
# assumes the tests are started on startup automatically
226
284
def __init__(self, dm):
228
self.logcat_proc = None
286
self.stdout_proc = None
229
287
self.queue = Queue.Queue()
231
# Launch logcat in a separate thread, and dump all output lines
289
# Launch b2g in a separate thread, and dump all output lines
232
290
# into a queue. The lines in this queue are
233
291
# retrieved and returned by accessing the stdout property of
235
293
cmd = [self.dm.adbPath]
236
294
if self.dm.deviceSerial:
237
295
cmd.extend(['-s', self.dm.deviceSerial])
239
proc = threading.Thread(target=self._save_logcat_proc, args=(cmd, self.queue))
297
cmd.append('/system/bin/b2g.sh')
298
proc = threading.Thread(target=self._save_stdout_proc, args=(cmd, self.queue))
240
299
proc.daemon = True
243
def _save_logcat_proc(self, cmd, queue):
244
self.logcat_proc = LogcatProc(cmd, queue)
245
self.logcat_proc.run()
246
self.logcat_proc.waitForFinish()
247
self.logcat_proc = None
302
def _save_stdout_proc(self, cmd, queue):
303
self.stdout_proc = StdOutProc(cmd, queue)
304
self.stdout_proc.run()
305
if hasattr(self.stdout_proc, 'processOutput'):
306
self.stdout_proc.processOutput()
307
self.stdout_proc.waitForFinish()
308
self.stdout_proc = None