~ubuntu-branches/ubuntu/oneiric/lightning-extension/oneiric-updates

« back to all changes in this revision

Viewing changes to mozilla/build/mobile/b2gautomation.py

  • Committer: Package Import Robot
  • Author(s): Chris Coulson
  • Date: 2012-11-08 10:00:06 UTC
  • mfrom: (1.3.8)
  • Revision ID: package-import@ubuntu.com-20121108100006-xpf89hktfitzuqc3
Tags: 1.9+build1-0ubuntu0.11.10.1
* New upstream stable release to support Thunderbird 17 (CALENDAR_1_9_BUILD1)
  - see LP: #1080212 for USN information

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
from mozprocess import ProcessHandlerMixin
19
19
 
20
20
 
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.
23
23
    """
24
24
 
25
25
    def __init__(self, cmd, queue, **kwargs):
35
35
    _devicemanager = None
36
36
 
37
37
    def __init__(self, deviceManager, appName='', remoteLog=None,
38
 
                 marionette=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
45
48
 
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)
49
55
 
50
56
    def setEmulator(self, is_emulator):
76
82
        env['MOZ_HIDE_RESULTS_TABLE'] = '1'
77
83
        return env
78
84
 
 
85
    def waitForNet(self): 
 
86
        active = False
 
87
        time_out = 0
 
88
        while not active and time_out < 40:
 
89
            data = self._devicemanager.runCmd(['shell', '/system/bin/netcfg']).stdout.readlines()
 
90
            data.pop(0)
 
91
            for line in data:
 
92
                if (re.search(r'UP\s+(?:[0-9]{1,3}\.){3}[0-9]{1,3}', line)):
 
93
                    active = True
 
94
                    break
 
95
            time_out += 1
 
96
            time.sleep(1)
 
97
        return active
 
98
 
79
99
    def checkForCrashes(self, directory, symbolsPath):
80
100
        # XXX: This will have to be updated after crash reporting on b2g
81
101
        # is in place.
106
126
        return nettools.getLanIp()
107
127
 
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
112
132
            output.
113
133
        """
114
134
        timeout = timeout or 120
115
 
 
116
 
        didTimeout = False
117
 
 
118
 
        done = time.time() + timeout
 
135
        responseDueBy = time.time() + timeout
119
136
        while True:
120
137
            currentlog = proc.stdout
121
138
            if currentlog:
122
 
                done = time.time() + timeout
 
139
                responseDueBy = time.time() + timeout
123
140
                print currentlog
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:
125
148
                    return 0
126
149
            else:
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))
148
171
        return (serial, status)
149
172
 
150
173
    def restartB2G(self):
 
174
        # TODO hangs in subprocess.Popen without this delay
 
175
        time.sleep(5)
151
176
        self._devicemanager.checkCmd(['shell', 'stop', 'b2g'])
152
177
        # Wait for a bit to make sure B2G has completely shut down.
153
178
        time.sleep(10)
160
185
        serial, status = self.getDeviceStatus()
161
186
 
162
187
        # reboot!
163
 
        self._devicemanager.checkCmd(['reboot'])
 
188
        self._devicemanager.runCmd(['shell', '/system/bin/reboot'])
 
189
 
 
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.
 
192
        time.sleep(10)
164
193
 
165
194
        # wait for device to come back to previous status
166
195
        print 'waiting for device to come back online after reboot'
176
205
 
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.
185
214
 
186
 
        instance = self.B2GInstance(self._devicemanager)
187
 
 
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:
193
 
            self.restartB2G()
194
 
        else:
 
219
        if not self._is_emulator:
195
220
            self.rebootDevice()
196
 
 
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
200
 
        time.sleep(40)
 
221
            time.sleep(5)
 
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")
 
226
 
 
227
        # stop b2g
 
228
        self._devicemanager.runCmd(['shell', 'stop', 'b2g'])
 
229
        time.sleep(5)
 
230
 
 
231
        # relaunch b2g inside b2g instance
 
232
        instance = self.B2GInstance(self._devicemanager)
 
233
 
 
234
        time.sleep(5)
201
235
 
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])
208
242
 
 
243
        if self._is_emulator:
 
244
            self.marionette.emulator.wait_for_port()
 
245
        else:
 
246
            time.sleep(5)
 
247
 
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)
213
252
 
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)
 
255
 
 
256
        # start the tests
 
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)
 
267
                script.close()
 
268
            else:
 
269
                # assume test_script is a string
 
270
                self.marionette.execute_script(self.test_script, script_args=self.test_script_args)
 
271
        else:
 
272
            # assumes the tests are started on startup automatically
 
273
            pass
216
274
 
217
275
        return instance
218
276
 
225
283
 
226
284
        def __init__(self, dm):
227
285
            self.dm = dm
228
 
            self.logcat_proc = None
 
286
            self.stdout_proc = None
229
287
            self.queue = Queue.Queue()
230
288
 
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
234
292
            # this class.
235
293
            cmd = [self.dm.adbPath]
236
294
            if self.dm.deviceSerial:
237
295
                cmd.extend(['-s', self.dm.deviceSerial])
238
 
            cmd.append('logcat')
239
 
            proc = threading.Thread(target=self._save_logcat_proc, args=(cmd, self.queue))
 
296
            cmd.append('shell')
 
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
241
300
            proc.start()
242
301
 
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
248
309
 
249
310
        @property
250
311
        def pid(self):
254
315
        @property
255
316
        def stdout(self):
256
317
            # Return any lines in the queue used by the
257
 
            # logcat process handler.
 
318
            # b2g process handler.
258
319
            lines = []
259
320
            while True:
260
321
                try:
270
331
        def kill(self):
271
332
            # this should never happen
272
333
            raise Exception("'kill' called on B2GInstance")
273