|
1 #!/usr/bin/env python |
|
2 # |
|
3 # This Source Code Form is subject to the terms of the Mozilla Public |
|
4 # License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
|
6 |
|
7 import sys |
|
8 import os |
|
9 sys.path.insert(0, os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))) |
|
10 |
|
11 import traceback |
|
12 from remotexpcshelltests import RemoteXPCShellTestThread, XPCShellRemote, RemoteXPCShellOptions |
|
13 from mozdevice import devicemanagerADB, DMError |
|
14 |
|
15 DEVICE_TEST_ROOT = '/data/local/tests' |
|
16 |
|
17 |
|
18 from marionette import Marionette |
|
19 |
|
20 class B2GXPCShellTestThread(RemoteXPCShellTestThread): |
|
21 # Overridden |
|
22 def launchProcess(self, cmd, stdout, stderr, env, cwd): |
|
23 try: |
|
24 # This returns 1 even when tests pass - hardcode returncode to 0 (bug 773703) |
|
25 outputFile = RemoteXPCShellTestThread.launchProcess(self, cmd, stdout, stderr, env, cwd) |
|
26 self.shellReturnCode = 0 |
|
27 except DMError: |
|
28 self.shellReturnCode = -1 |
|
29 outputFile = "xpcshelloutput" |
|
30 f = open(outputFile, "a") |
|
31 f.write("\n%s" % traceback.format_exc()) |
|
32 f.close() |
|
33 return outputFile |
|
34 |
|
35 class B2GXPCShellRemote(XPCShellRemote): |
|
36 # Overridden |
|
37 def setLD_LIBRARY_PATH(self): |
|
38 self.env['LD_LIBRARY_PATH'] = '/system/b2g' |
|
39 if not self.options.use_device_libs: |
|
40 # overwrite /system/b2g if necessary |
|
41 XPCShellRemote.setLD_LIBRARY_PATH(self) |
|
42 |
|
43 # Overridden |
|
44 def setupUtilities(self): |
|
45 if self.options.clean: |
|
46 # Ensure a fresh directory structure for our tests |
|
47 self.clean() |
|
48 self.device.mkDir(self.options.remoteTestRoot) |
|
49 |
|
50 XPCShellRemote.setupUtilities(self) |
|
51 |
|
52 def clean(self): |
|
53 print >>sys.stderr, "\nCleaning files from previous run.." |
|
54 self.device.removeDir(self.options.remoteTestRoot) |
|
55 |
|
56 # Overriden |
|
57 def setupTestDir(self): |
|
58 if self.device._useZip: |
|
59 return XPCShellRemote.setupTestDir(self) |
|
60 |
|
61 for root, dirs, files in os.walk(self.xpcDir): |
|
62 for filename in files: |
|
63 rel_path = os.path.relpath(os.path.join(root, filename), self.xpcDir) |
|
64 test_file = os.path.join(self.remoteScriptsDir, rel_path) |
|
65 print 'pushing %s' % test_file |
|
66 self.device.pushFile(os.path.join(root, filename), test_file, retryLimit=10) |
|
67 |
|
68 # Overridden |
|
69 def pushLibs(self): |
|
70 if not self.options.use_device_libs: |
|
71 count = XPCShellRemote.pushLibs(self) |
|
72 if not count: |
|
73 # couldn't find any libs, fallback to device libs |
|
74 self.env['LD_LIBRARY_PATH'] = '/system/b2g' |
|
75 self.options.use_device_libs = True |
|
76 |
|
77 class B2GOptions(RemoteXPCShellOptions): |
|
78 |
|
79 def __init__(self): |
|
80 RemoteXPCShellOptions.__init__(self) |
|
81 defaults = {} |
|
82 |
|
83 self.add_option('--b2gpath', action='store', |
|
84 type='string', dest='b2g_path', |
|
85 help="Path to B2G repo or qemu dir") |
|
86 defaults['b2g_path'] = None |
|
87 |
|
88 self.add_option('--emupath', action='store', |
|
89 type='string', dest='emu_path', |
|
90 help="Path to emulator folder (if different " |
|
91 "from b2gpath") |
|
92 |
|
93 self.add_option('--no-clean', action='store_false', |
|
94 dest='clean', |
|
95 help="Do not clean TESTROOT. Saves [lots of] time") |
|
96 defaults['clean'] = True |
|
97 |
|
98 defaults['emu_path'] = None |
|
99 |
|
100 self.add_option('--emulator', action='store', |
|
101 type='string', dest='emulator', |
|
102 help="Architecture of emulator to use: x86 or arm") |
|
103 defaults['emulator'] = None |
|
104 |
|
105 self.add_option('--no-window', action='store_true', |
|
106 dest='no_window', |
|
107 help="Pass --no-window to the emulator") |
|
108 defaults['no_window'] = False |
|
109 |
|
110 self.add_option('--adbpath', action='store', |
|
111 type='string', dest='adb_path', |
|
112 help="Path to adb") |
|
113 defaults['adb_path'] = 'adb' |
|
114 |
|
115 self.add_option('--address', action='store', |
|
116 type='string', dest='address', |
|
117 help="host:port of running Gecko instance to connect to") |
|
118 defaults['address'] = None |
|
119 |
|
120 self.add_option('--use-device-libs', action='store_true', |
|
121 dest='use_device_libs', |
|
122 help="Don't push .so's") |
|
123 defaults['use_device_libs'] = False |
|
124 self.add_option("--gecko-path", action="store", |
|
125 type="string", dest="geckoPath", |
|
126 help="the path to a gecko distribution that should " |
|
127 "be installed on the emulator prior to test") |
|
128 defaults["geckoPath"] = None |
|
129 self.add_option("--logcat-dir", action="store", |
|
130 type="string", dest="logcat_dir", |
|
131 help="directory to store logcat dump files") |
|
132 defaults["logcat_dir"] = None |
|
133 self.add_option('--busybox', action='store', |
|
134 type='string', dest='busybox', |
|
135 help="Path to busybox binary to install on device") |
|
136 defaults['busybox'] = None |
|
137 |
|
138 defaults["remoteTestRoot"] = DEVICE_TEST_ROOT |
|
139 defaults['dm_trans'] = 'adb' |
|
140 defaults['debugger'] = None |
|
141 defaults['debuggerArgs'] = None |
|
142 |
|
143 self.set_defaults(**defaults) |
|
144 |
|
145 def verifyRemoteOptions(self, options): |
|
146 if options.b2g_path is None: |
|
147 self.error("Need to specify a --b2gpath") |
|
148 |
|
149 if options.geckoPath and not options.emulator: |
|
150 self.error("You must specify --emulator if you specify --gecko-path") |
|
151 |
|
152 if options.logcat_dir and not options.emulator: |
|
153 self.error("You must specify --emulator if you specify --logcat-dir") |
|
154 return RemoteXPCShellOptions.verifyRemoteOptions(self, options) |
|
155 |
|
156 def run_remote_xpcshell(parser, options, args): |
|
157 options = parser.verifyRemoteOptions(options) |
|
158 |
|
159 # Create the Marionette instance |
|
160 kwargs = {} |
|
161 if options.emulator: |
|
162 kwargs['emulator'] = options.emulator |
|
163 if options.no_window: |
|
164 kwargs['noWindow'] = True |
|
165 if options.geckoPath: |
|
166 kwargs['gecko_path'] = options.geckoPath |
|
167 if options.logcat_dir: |
|
168 kwargs['logcat_dir'] = options.logcat_dir |
|
169 if options.busybox: |
|
170 kwargs['busybox'] = options.busybox |
|
171 if options.symbolsPath: |
|
172 kwargs['symbols_path'] = options.symbolsPath |
|
173 if options.b2g_path: |
|
174 kwargs['homedir'] = options.emu_path or options.b2g_path |
|
175 if options.address: |
|
176 host, port = options.address.split(':') |
|
177 kwargs['host'] = host |
|
178 kwargs['port'] = int(port) |
|
179 kwargs['baseurl'] = 'http://%s:%d/' % (host, int(port)) |
|
180 if options.emulator: |
|
181 kwargs['connectToRunningEmulator'] = True |
|
182 marionette = Marionette(**kwargs) |
|
183 |
|
184 if options.emulator: |
|
185 dm = marionette.emulator.dm |
|
186 else: |
|
187 # Create the DeviceManager instance |
|
188 kwargs = {'adbPath': options.adb_path} |
|
189 if options.deviceIP: |
|
190 kwargs['host'] = options.deviceIP |
|
191 kwargs['port'] = options.devicePort |
|
192 kwargs['deviceRoot'] = options.remoteTestRoot |
|
193 dm = devicemanagerADB.DeviceManagerADB(**kwargs) |
|
194 |
|
195 if not options.remoteTestRoot: |
|
196 options.remoteTestRoot = dm.getDeviceRoot() |
|
197 xpcsh = B2GXPCShellRemote(dm, options, args) |
|
198 |
|
199 # we don't run concurrent tests on mobile |
|
200 options.sequential = True |
|
201 |
|
202 try: |
|
203 if not xpcsh.runTests(xpcshell='xpcshell', testdirs=args[0:], |
|
204 testClass=B2GXPCShellTestThread, |
|
205 mobileArgs=xpcsh.mobileArgs, |
|
206 **options.__dict__): |
|
207 sys.exit(1) |
|
208 except: |
|
209 print "Automation Error: Exception caught while running tests" |
|
210 traceback.print_exc() |
|
211 sys.exit(1) |
|
212 |
|
213 def main(): |
|
214 parser = B2GOptions() |
|
215 options, args = parser.parse_args() |
|
216 |
|
217 run_remote_xpcshell(parser, options, args) |
|
218 |
|
219 # You usually run this like : |
|
220 # python runtestsb2g.py --emulator arm --b2gpath $B2GPATH --manifest $MANIFEST [--xre-path $MOZ_HOST_BIN |
|
221 # --adbpath $ADB_PATH |
|
222 # ...] |
|
223 # |
|
224 # For xUnit output you should also pass in --tests-root-dir ..objdir-gecko/_tests |
|
225 # --xunit-file ..objdir_gecko/_tests/results.xml |
|
226 # --xunit-suite-name xpcshell-tests |
|
227 if __name__ == '__main__': |
|
228 main() |