Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | # This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this file, |
michael@0 | 3 | # You can obtain one at http://mozilla.org/MPL/2.0/. |
michael@0 | 4 | |
michael@0 | 5 | import ConfigParser |
michael@0 | 6 | import os |
michael@0 | 7 | import sys |
michael@0 | 8 | import tempfile |
michael@0 | 9 | import traceback |
michael@0 | 10 | |
michael@0 | 11 | # We need to know our current directory so that we can serve our test files from it. |
michael@0 | 12 | here = os.path.abspath(os.path.dirname(__file__)) |
michael@0 | 13 | |
michael@0 | 14 | from automation import Automation |
michael@0 | 15 | from b2gautomation import B2GRemoteAutomation |
michael@0 | 16 | from b2g_desktop import run_desktop_reftests |
michael@0 | 17 | from runreftest import RefTest |
michael@0 | 18 | from runreftest import ReftestOptions |
michael@0 | 19 | from remotereftest import ReftestServer |
michael@0 | 20 | |
michael@0 | 21 | from mozdevice import DeviceManagerADB, DMError |
michael@0 | 22 | from marionette import Marionette |
michael@0 | 23 | import moznetwork |
michael@0 | 24 | |
michael@0 | 25 | class B2GOptions(ReftestOptions): |
michael@0 | 26 | |
michael@0 | 27 | def __init__(self, automation=None, **kwargs): |
michael@0 | 28 | defaults = {} |
michael@0 | 29 | if not automation: |
michael@0 | 30 | automation = B2GRemoteAutomation(None, "fennec", context_chrome=True) |
michael@0 | 31 | |
michael@0 | 32 | ReftestOptions.__init__(self, automation) |
michael@0 | 33 | |
michael@0 | 34 | self.add_option("--browser-arg", action="store", |
michael@0 | 35 | type = "string", dest = "browser_arg", |
michael@0 | 36 | help = "Optional command-line arg to pass to the browser") |
michael@0 | 37 | defaults["browser_arg"] = None |
michael@0 | 38 | |
michael@0 | 39 | self.add_option("--b2gpath", action="store", |
michael@0 | 40 | type = "string", dest = "b2gPath", |
michael@0 | 41 | help = "path to B2G repo or qemu dir") |
michael@0 | 42 | defaults["b2gPath"] = None |
michael@0 | 43 | |
michael@0 | 44 | self.add_option("--marionette", action="store", |
michael@0 | 45 | type = "string", dest = "marionette", |
michael@0 | 46 | help = "host:port to use when connecting to Marionette") |
michael@0 | 47 | defaults["marionette"] = None |
michael@0 | 48 | |
michael@0 | 49 | self.add_option("--emulator", action="store", |
michael@0 | 50 | type="string", dest = "emulator", |
michael@0 | 51 | help = "Architecture of emulator to use: x86 or arm") |
michael@0 | 52 | defaults["emulator"] = None |
michael@0 | 53 | self.add_option("--emulator-res", action="store", |
michael@0 | 54 | type="string", dest = "emulator_res", |
michael@0 | 55 | help = "Emulator resolution of the format '<width>x<height>'") |
michael@0 | 56 | defaults["emulator_res"] = None |
michael@0 | 57 | |
michael@0 | 58 | self.add_option("--no-window", action="store_true", |
michael@0 | 59 | dest = "noWindow", |
michael@0 | 60 | help = "Pass --no-window to the emulator") |
michael@0 | 61 | defaults["noWindow"] = False |
michael@0 | 62 | |
michael@0 | 63 | self.add_option("--adbpath", action="store", |
michael@0 | 64 | type = "string", dest = "adbPath", |
michael@0 | 65 | help = "path to adb") |
michael@0 | 66 | defaults["adbPath"] = "adb" |
michael@0 | 67 | |
michael@0 | 68 | self.add_option("--deviceIP", action="store", |
michael@0 | 69 | type = "string", dest = "deviceIP", |
michael@0 | 70 | help = "ip address of remote device to test") |
michael@0 | 71 | defaults["deviceIP"] = None |
michael@0 | 72 | |
michael@0 | 73 | self.add_option("--devicePort", action="store", |
michael@0 | 74 | type = "string", dest = "devicePort", |
michael@0 | 75 | help = "port of remote device to test") |
michael@0 | 76 | defaults["devicePort"] = 20701 |
michael@0 | 77 | |
michael@0 | 78 | self.add_option("--remote-logfile", action="store", |
michael@0 | 79 | type = "string", dest = "remoteLogFile", |
michael@0 | 80 | help = "Name of log file on the device relative to the device root. PLEASE ONLY USE A FILENAME.") |
michael@0 | 81 | defaults["remoteLogFile"] = None |
michael@0 | 82 | |
michael@0 | 83 | self.add_option("--remote-webserver", action = "store", |
michael@0 | 84 | type = "string", dest = "remoteWebServer", |
michael@0 | 85 | help = "ip address where the remote web server is hosted at") |
michael@0 | 86 | defaults["remoteWebServer"] = None |
michael@0 | 87 | |
michael@0 | 88 | self.add_option("--http-port", action = "store", |
michael@0 | 89 | type = "string", dest = "httpPort", |
michael@0 | 90 | help = "ip address where the remote web server is hosted at") |
michael@0 | 91 | defaults["httpPort"] = automation.DEFAULT_HTTP_PORT |
michael@0 | 92 | |
michael@0 | 93 | self.add_option("--ssl-port", action = "store", |
michael@0 | 94 | type = "string", dest = "sslPort", |
michael@0 | 95 | help = "ip address where the remote web server is hosted at") |
michael@0 | 96 | defaults["sslPort"] = automation.DEFAULT_SSL_PORT |
michael@0 | 97 | |
michael@0 | 98 | self.add_option("--pidfile", action = "store", |
michael@0 | 99 | type = "string", dest = "pidFile", |
michael@0 | 100 | help = "name of the pidfile to generate") |
michael@0 | 101 | defaults["pidFile"] = "" |
michael@0 | 102 | self.add_option("--gecko-path", action="store", |
michael@0 | 103 | type="string", dest="geckoPath", |
michael@0 | 104 | help="the path to a gecko distribution that should " |
michael@0 | 105 | "be installed on the emulator prior to test") |
michael@0 | 106 | defaults["geckoPath"] = None |
michael@0 | 107 | self.add_option("--logcat-dir", action="store", |
michael@0 | 108 | type="string", dest="logcat_dir", |
michael@0 | 109 | help="directory to store logcat dump files") |
michael@0 | 110 | defaults["logcat_dir"] = None |
michael@0 | 111 | self.add_option('--busybox', action='store', |
michael@0 | 112 | type='string', dest='busybox', |
michael@0 | 113 | help="Path to busybox binary to install on device") |
michael@0 | 114 | defaults['busybox'] = None |
michael@0 | 115 | self.add_option("--httpd-path", action = "store", |
michael@0 | 116 | type = "string", dest = "httpdPath", |
michael@0 | 117 | help = "path to the httpd.js file") |
michael@0 | 118 | defaults["httpdPath"] = None |
michael@0 | 119 | self.add_option("--profile", action="store", |
michael@0 | 120 | type="string", dest="profile", |
michael@0 | 121 | help="for desktop testing, the path to the " |
michael@0 | 122 | "gaia profile to use") |
michael@0 | 123 | defaults["profile"] = None |
michael@0 | 124 | self.add_option("--desktop", action="store_true", |
michael@0 | 125 | dest="desktop", |
michael@0 | 126 | help="Run the tests on a B2G desktop build") |
michael@0 | 127 | defaults["desktop"] = False |
michael@0 | 128 | defaults["remoteTestRoot"] = "/data/local/tests" |
michael@0 | 129 | defaults["logFile"] = "reftest.log" |
michael@0 | 130 | defaults["autorun"] = True |
michael@0 | 131 | defaults["closeWhenDone"] = True |
michael@0 | 132 | defaults["testPath"] = "" |
michael@0 | 133 | defaults["runTestsInParallel"] = False |
michael@0 | 134 | |
michael@0 | 135 | self.set_defaults(**defaults) |
michael@0 | 136 | |
michael@0 | 137 | def verifyRemoteOptions(self, options): |
michael@0 | 138 | if options.runTestsInParallel: |
michael@0 | 139 | self.error("Cannot run parallel tests here") |
michael@0 | 140 | |
michael@0 | 141 | if not options.remoteTestRoot: |
michael@0 | 142 | options.remoteTestRoot = self.automation._devicemanager.getDeviceRoot() + "/reftest" |
michael@0 | 143 | options.remoteProfile = options.remoteTestRoot + "/profile" |
michael@0 | 144 | |
michael@0 | 145 | productRoot = options.remoteTestRoot + "/" + self.automation._product |
michael@0 | 146 | if options.utilityPath == self.automation.DIST_BIN: |
michael@0 | 147 | options.utilityPath = productRoot + "/bin" |
michael@0 | 148 | |
michael@0 | 149 | if options.remoteWebServer == None: |
michael@0 | 150 | if os.name != "nt": |
michael@0 | 151 | options.remoteWebServer = moznetwork.get_ip() |
michael@0 | 152 | else: |
michael@0 | 153 | print "ERROR: you must specify a --remote-webserver=<ip address>\n" |
michael@0 | 154 | return None |
michael@0 | 155 | |
michael@0 | 156 | options.webServer = options.remoteWebServer |
michael@0 | 157 | |
michael@0 | 158 | if options.geckoPath and not options.emulator: |
michael@0 | 159 | self.error("You must specify --emulator if you specify --gecko-path") |
michael@0 | 160 | |
michael@0 | 161 | if options.logcat_dir and not options.emulator: |
michael@0 | 162 | self.error("You must specify --emulator if you specify --logcat-dir") |
michael@0 | 163 | |
michael@0 | 164 | #if not options.emulator and not options.deviceIP: |
michael@0 | 165 | # print "ERROR: you must provide a device IP" |
michael@0 | 166 | # return None |
michael@0 | 167 | |
michael@0 | 168 | if options.remoteLogFile == None: |
michael@0 | 169 | options.remoteLogFile = "reftest.log" |
michael@0 | 170 | |
michael@0 | 171 | options.localLogName = options.remoteLogFile |
michael@0 | 172 | options.remoteLogFile = options.remoteTestRoot + '/' + options.remoteLogFile |
michael@0 | 173 | |
michael@0 | 174 | # Ensure that the options.logfile (which the base class uses) is set to |
michael@0 | 175 | # the remote setting when running remote. Also, if the user set the |
michael@0 | 176 | # log file name there, use that instead of reusing the remotelogfile as above. |
michael@0 | 177 | if (options.logFile): |
michael@0 | 178 | # If the user specified a local logfile name use that |
michael@0 | 179 | options.localLogName = options.logFile |
michael@0 | 180 | options.logFile = options.remoteLogFile |
michael@0 | 181 | |
michael@0 | 182 | # Only reset the xrePath if it wasn't provided |
michael@0 | 183 | if options.xrePath == None: |
michael@0 | 184 | options.xrePath = options.utilityPath |
michael@0 | 185 | options.xrePath = os.path.abspath(options.xrePath) |
michael@0 | 186 | |
michael@0 | 187 | if options.pidFile != "": |
michael@0 | 188 | f = open(options.pidFile, 'w') |
michael@0 | 189 | f.write("%s" % os.getpid()) |
michael@0 | 190 | f.close() |
michael@0 | 191 | |
michael@0 | 192 | # httpd-path is specified by standard makefile targets and may be specified |
michael@0 | 193 | # on the command line to select a particular version of httpd.js. If not |
michael@0 | 194 | # specified, try to select the one from from the xre bundle, as required in bug 882932. |
michael@0 | 195 | if not options.httpdPath: |
michael@0 | 196 | options.httpdPath = os.path.join(options.xrePath, "components") |
michael@0 | 197 | |
michael@0 | 198 | return options |
michael@0 | 199 | |
michael@0 | 200 | |
michael@0 | 201 | class ProfileConfigParser(ConfigParser.RawConfigParser): |
michael@0 | 202 | """Subclass of RawConfigParser that outputs .ini files in the exact |
michael@0 | 203 | format expected for profiles.ini, which is slightly different |
michael@0 | 204 | than the default format. |
michael@0 | 205 | """ |
michael@0 | 206 | |
michael@0 | 207 | def optionxform(self, optionstr): |
michael@0 | 208 | return optionstr |
michael@0 | 209 | |
michael@0 | 210 | def write(self, fp): |
michael@0 | 211 | if self._defaults: |
michael@0 | 212 | fp.write("[%s]\n" % ConfigParser.DEFAULTSECT) |
michael@0 | 213 | for (key, value) in self._defaults.items(): |
michael@0 | 214 | fp.write("%s=%s\n" % (key, str(value).replace('\n', '\n\t'))) |
michael@0 | 215 | fp.write("\n") |
michael@0 | 216 | for section in self._sections: |
michael@0 | 217 | fp.write("[%s]\n" % section) |
michael@0 | 218 | for (key, value) in self._sections[section].items(): |
michael@0 | 219 | if key == "__name__": |
michael@0 | 220 | continue |
michael@0 | 221 | if (value is not None) or (self._optcre == self.OPTCRE): |
michael@0 | 222 | key = "=".join((key, str(value).replace('\n', '\n\t'))) |
michael@0 | 223 | fp.write("%s\n" % (key)) |
michael@0 | 224 | fp.write("\n") |
michael@0 | 225 | |
michael@0 | 226 | class B2GRemoteReftest(RefTest): |
michael@0 | 227 | |
michael@0 | 228 | _devicemanager = None |
michael@0 | 229 | localProfile = None |
michael@0 | 230 | remoteApp = '' |
michael@0 | 231 | profile = None |
michael@0 | 232 | |
michael@0 | 233 | def __init__(self, automation, devicemanager, options, scriptDir): |
michael@0 | 234 | RefTest.__init__(self, automation) |
michael@0 | 235 | self._devicemanager = devicemanager |
michael@0 | 236 | self.runSSLTunnel = False |
michael@0 | 237 | self.remoteTestRoot = options.remoteTestRoot |
michael@0 | 238 | self.remoteProfile = options.remoteProfile |
michael@0 | 239 | self.automation.setRemoteProfile(self.remoteProfile) |
michael@0 | 240 | self.localLogName = options.localLogName |
michael@0 | 241 | self.remoteLogFile = options.remoteLogFile |
michael@0 | 242 | self.bundlesDir = '/system/b2g/distribution/bundles' |
michael@0 | 243 | self.userJS = '/data/local/user.js' |
michael@0 | 244 | self.remoteMozillaPath = '/data/b2g/mozilla' |
michael@0 | 245 | self.remoteProfilesIniPath = os.path.join(self.remoteMozillaPath, 'profiles.ini') |
michael@0 | 246 | self.originalProfilesIni = None |
michael@0 | 247 | self.scriptDir = scriptDir |
michael@0 | 248 | self.SERVER_STARTUP_TIMEOUT = 90 |
michael@0 | 249 | if self.automation.IS_DEBUG_BUILD: |
michael@0 | 250 | self.SERVER_STARTUP_TIMEOUT = 180 |
michael@0 | 251 | |
michael@0 | 252 | def cleanup(self, profileDir): |
michael@0 | 253 | # Pull results back from device |
michael@0 | 254 | if (self.remoteLogFile): |
michael@0 | 255 | try: |
michael@0 | 256 | self._devicemanager.getFile(self.remoteLogFile, self.localLogName) |
michael@0 | 257 | except: |
michael@0 | 258 | print "ERROR: We were not able to retrieve the info from %s" % self.remoteLogFile |
michael@0 | 259 | sys.exit(5) |
michael@0 | 260 | |
michael@0 | 261 | # Delete any bundled extensions |
michael@0 | 262 | if profileDir: |
michael@0 | 263 | extensionDir = os.path.join(profileDir, 'extensions', 'staged') |
michael@0 | 264 | for filename in os.listdir(extensionDir): |
michael@0 | 265 | try: |
michael@0 | 266 | self._devicemanager._checkCmd(['shell', 'rm', '-rf', |
michael@0 | 267 | os.path.join(self.bundlesDir, filename)]) |
michael@0 | 268 | except DMError: |
michael@0 | 269 | pass |
michael@0 | 270 | |
michael@0 | 271 | # Restore the original profiles.ini. |
michael@0 | 272 | if self.originalProfilesIni: |
michael@0 | 273 | try: |
michael@0 | 274 | if not self.automation._is_emulator: |
michael@0 | 275 | self.restoreProfilesIni() |
michael@0 | 276 | os.remove(self.originalProfilesIni) |
michael@0 | 277 | except: |
michael@0 | 278 | pass |
michael@0 | 279 | |
michael@0 | 280 | if not self.automation._is_emulator: |
michael@0 | 281 | self._devicemanager.removeFile(self.remoteLogFile) |
michael@0 | 282 | self._devicemanager.removeDir(self.remoteProfile) |
michael@0 | 283 | self._devicemanager.removeDir(self.remoteTestRoot) |
michael@0 | 284 | |
michael@0 | 285 | # Restore the original user.js. |
michael@0 | 286 | self._devicemanager._checkCmd(['shell', 'rm', '-f', self.userJS]) |
michael@0 | 287 | self._devicemanager._checkCmd(['shell', 'dd', 'if=%s.orig' % self.userJS, 'of=%s' % self.userJS]) |
michael@0 | 288 | |
michael@0 | 289 | # We've restored the original profile, so reboot the device so that |
michael@0 | 290 | # it gets picked up. |
michael@0 | 291 | self.automation.rebootDevice() |
michael@0 | 292 | |
michael@0 | 293 | RefTest.cleanup(self, profileDir) |
michael@0 | 294 | if getattr(self, 'pidFile', '') != '': |
michael@0 | 295 | try: |
michael@0 | 296 | os.remove(self.pidFile) |
michael@0 | 297 | os.remove(self.pidFile + ".xpcshell.pid") |
michael@0 | 298 | except: |
michael@0 | 299 | print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % self.pidFile |
michael@0 | 300 | |
michael@0 | 301 | def findPath(self, paths, filename = None): |
michael@0 | 302 | for path in paths: |
michael@0 | 303 | p = path |
michael@0 | 304 | if filename: |
michael@0 | 305 | p = os.path.join(p, filename) |
michael@0 | 306 | if os.path.exists(self.getFullPath(p)): |
michael@0 | 307 | return path |
michael@0 | 308 | return None |
michael@0 | 309 | |
michael@0 | 310 | def startWebServer(self, options): |
michael@0 | 311 | """ Create the webserver on the host and start it up """ |
michael@0 | 312 | remoteXrePath = options.xrePath |
michael@0 | 313 | remoteProfilePath = self.remoteProfile |
michael@0 | 314 | remoteUtilityPath = options.utilityPath |
michael@0 | 315 | localAutomation = Automation() |
michael@0 | 316 | localAutomation.IS_WIN32 = False |
michael@0 | 317 | localAutomation.IS_LINUX = False |
michael@0 | 318 | localAutomation.IS_MAC = False |
michael@0 | 319 | localAutomation.UNIXISH = False |
michael@0 | 320 | hostos = sys.platform |
michael@0 | 321 | if hostos in ['mac', 'darwin']: |
michael@0 | 322 | localAutomation.IS_MAC = True |
michael@0 | 323 | elif hostos in ['linux', 'linux2']: |
michael@0 | 324 | localAutomation.IS_LINUX = True |
michael@0 | 325 | localAutomation.UNIXISH = True |
michael@0 | 326 | elif hostos in ['win32', 'win64']: |
michael@0 | 327 | localAutomation.BIN_SUFFIX = ".exe" |
michael@0 | 328 | localAutomation.IS_WIN32 = True |
michael@0 | 329 | |
michael@0 | 330 | paths = [options.xrePath, |
michael@0 | 331 | localAutomation.DIST_BIN, |
michael@0 | 332 | self.automation._product, |
michael@0 | 333 | os.path.join('..', self.automation._product)] |
michael@0 | 334 | options.xrePath = self.findPath(paths) |
michael@0 | 335 | if options.xrePath == None: |
michael@0 | 336 | print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name) |
michael@0 | 337 | sys.exit(1) |
michael@0 | 338 | paths.append("bin") |
michael@0 | 339 | paths.append(os.path.join("..", "bin")) |
michael@0 | 340 | |
michael@0 | 341 | xpcshell = "xpcshell" |
michael@0 | 342 | if (os.name == "nt"): |
michael@0 | 343 | xpcshell += ".exe" |
michael@0 | 344 | |
michael@0 | 345 | if (options.utilityPath): |
michael@0 | 346 | paths.insert(0, options.utilityPath) |
michael@0 | 347 | options.utilityPath = self.findPath(paths, xpcshell) |
michael@0 | 348 | if options.utilityPath == None: |
michael@0 | 349 | print "ERROR: unable to find utility path for %s, please specify with --utility-path" % (os.name) |
michael@0 | 350 | sys.exit(1) |
michael@0 | 351 | |
michael@0 | 352 | xpcshell = os.path.join(options.utilityPath, xpcshell) |
michael@0 | 353 | if self.automation.elf_arm(xpcshell): |
michael@0 | 354 | raise Exception('xpcshell at %s is an ARM binary; please use ' |
michael@0 | 355 | 'the --utility-path argument to specify the path ' |
michael@0 | 356 | 'to a desktop version.' % xpcshell) |
michael@0 | 357 | |
michael@0 | 358 | options.serverProfilePath = tempfile.mkdtemp() |
michael@0 | 359 | self.server = ReftestServer(localAutomation, options, self.scriptDir) |
michael@0 | 360 | retVal = self.server.start() |
michael@0 | 361 | if retVal: |
michael@0 | 362 | return retVal |
michael@0 | 363 | |
michael@0 | 364 | if (options.pidFile != ""): |
michael@0 | 365 | f = open(options.pidFile + ".xpcshell.pid", 'w') |
michael@0 | 366 | f.write("%s" % self.server._process.pid) |
michael@0 | 367 | f.close() |
michael@0 | 368 | |
michael@0 | 369 | retVal = self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT) |
michael@0 | 370 | if retVal: |
michael@0 | 371 | return retVal |
michael@0 | 372 | |
michael@0 | 373 | options.xrePath = remoteXrePath |
michael@0 | 374 | options.utilityPath = remoteUtilityPath |
michael@0 | 375 | options.profilePath = remoteProfilePath |
michael@0 | 376 | return 0 |
michael@0 | 377 | |
michael@0 | 378 | def stopWebServer(self, options): |
michael@0 | 379 | if hasattr(self, 'server'): |
michael@0 | 380 | self.server.stop() |
michael@0 | 381 | |
michael@0 | 382 | def restoreProfilesIni(self): |
michael@0 | 383 | # restore profiles.ini on the device to its previous state |
michael@0 | 384 | if not self.originalProfilesIni or not os.access(self.originalProfilesIni, os.F_OK): |
michael@0 | 385 | raise DMError('Unable to install original profiles.ini; file not found: %s', |
michael@0 | 386 | self.originalProfilesIni) |
michael@0 | 387 | |
michael@0 | 388 | self._devicemanager.pushFile(self.originalProfilesIni, self.remoteProfilesIniPath) |
michael@0 | 389 | |
michael@0 | 390 | def updateProfilesIni(self, profilePath): |
michael@0 | 391 | # update profiles.ini on the device to point to the test profile |
michael@0 | 392 | self.originalProfilesIni = tempfile.mktemp() |
michael@0 | 393 | self._devicemanager.getFile(self.remoteProfilesIniPath, self.originalProfilesIni) |
michael@0 | 394 | |
michael@0 | 395 | config = ProfileConfigParser() |
michael@0 | 396 | config.read(self.originalProfilesIni) |
michael@0 | 397 | for section in config.sections(): |
michael@0 | 398 | if 'Profile' in section: |
michael@0 | 399 | config.set(section, 'IsRelative', 0) |
michael@0 | 400 | config.set(section, 'Path', profilePath) |
michael@0 | 401 | |
michael@0 | 402 | newProfilesIni = tempfile.mktemp() |
michael@0 | 403 | with open(newProfilesIni, 'wb') as configfile: |
michael@0 | 404 | config.write(configfile) |
michael@0 | 405 | |
michael@0 | 406 | self._devicemanager.pushFile(newProfilesIni, self.remoteProfilesIniPath) |
michael@0 | 407 | try: |
michael@0 | 408 | os.remove(newProfilesIni) |
michael@0 | 409 | except: |
michael@0 | 410 | pass |
michael@0 | 411 | |
michael@0 | 412 | |
michael@0 | 413 | def createReftestProfile(self, options, reftestlist): |
michael@0 | 414 | profile = RefTest.createReftestProfile(self, options, reftestlist, |
michael@0 | 415 | server=options.remoteWebServer, |
michael@0 | 416 | special_powers=False) |
michael@0 | 417 | profileDir = profile.profile |
michael@0 | 418 | |
michael@0 | 419 | prefs = {} |
michael@0 | 420 | # Turn off the locale picker screen |
michael@0 | 421 | prefs["browser.firstrun.show.localepicker"] = False |
michael@0 | 422 | prefs["browser.homescreenURL"] = "app://test-container.gaiamobile.org/index.html" |
michael@0 | 423 | prefs["browser.manifestURL"] = "app://test-container.gaiamobile.org/manifest.webapp" |
michael@0 | 424 | prefs["browser.tabs.remote"] = False |
michael@0 | 425 | prefs["dom.ipc.tabs.disabled"] = False |
michael@0 | 426 | prefs["dom.mozBrowserFramesEnabled"] = True |
michael@0 | 427 | prefs["font.size.inflation.emPerLine"] = 0 |
michael@0 | 428 | prefs["font.size.inflation.minTwips"] = 0 |
michael@0 | 429 | prefs["network.dns.localDomains"] = "app://test-container.gaiamobile.org" |
michael@0 | 430 | prefs["reftest.browser.iframe.enabled"] = False |
michael@0 | 431 | prefs["reftest.remote"] = True |
michael@0 | 432 | prefs["reftest.uri"] = "%s" % reftestlist |
michael@0 | 433 | # Set a future policy version to avoid the telemetry prompt. |
michael@0 | 434 | prefs["toolkit.telemetry.prompted"] = 999 |
michael@0 | 435 | prefs["toolkit.telemetry.notifiedOptOut"] = 999 |
michael@0 | 436 | |
michael@0 | 437 | # Set the extra prefs. |
michael@0 | 438 | profile.set_preferences(prefs) |
michael@0 | 439 | |
michael@0 | 440 | # Copy the profile to the device. |
michael@0 | 441 | self._devicemanager.removeDir(self.remoteProfile) |
michael@0 | 442 | try: |
michael@0 | 443 | self._devicemanager.pushDir(profileDir, self.remoteProfile) |
michael@0 | 444 | except DMError: |
michael@0 | 445 | print "Automation Error: Unable to copy profile to device." |
michael@0 | 446 | raise |
michael@0 | 447 | |
michael@0 | 448 | # Copy the extensions to the B2G bundles dir. |
michael@0 | 449 | extensionDir = os.path.join(profileDir, 'extensions', 'staged') |
michael@0 | 450 | # need to write to read-only dir |
michael@0 | 451 | self._devicemanager._checkCmd(['remount']) |
michael@0 | 452 | for filename in os.listdir(extensionDir): |
michael@0 | 453 | self._devicemanager._checkCmd(['shell', 'rm', '-rf', |
michael@0 | 454 | os.path.join(self.bundlesDir, filename)]) |
michael@0 | 455 | try: |
michael@0 | 456 | self._devicemanager.pushDir(extensionDir, self.bundlesDir) |
michael@0 | 457 | except DMError: |
michael@0 | 458 | print "Automation Error: Unable to copy extensions to device." |
michael@0 | 459 | raise |
michael@0 | 460 | |
michael@0 | 461 | # In B2G, user.js is always read from /data/local, not the profile |
michael@0 | 462 | # directory. Backup the original user.js first so we can restore it. |
michael@0 | 463 | self._devicemanager._checkCmd(['shell', 'rm', '-f', '%s.orig' % self.userJS]) |
michael@0 | 464 | self._devicemanager._checkCmd(['shell', 'dd', 'if=%s' % self.userJS, 'of=%s.orig' % self.userJS]) |
michael@0 | 465 | self._devicemanager.pushFile(os.path.join(profileDir, "user.js"), self.userJS) |
michael@0 | 466 | |
michael@0 | 467 | self.updateProfilesIni(self.remoteProfile) |
michael@0 | 468 | |
michael@0 | 469 | options.profilePath = self.remoteProfile |
michael@0 | 470 | return profile |
michael@0 | 471 | |
michael@0 | 472 | def copyExtraFilesToProfile(self, options, profile): |
michael@0 | 473 | profileDir = profile.profile |
michael@0 | 474 | RefTest.copyExtraFilesToProfile(self, options, profile) |
michael@0 | 475 | try: |
michael@0 | 476 | self._devicemanager.pushDir(profileDir, options.remoteProfile) |
michael@0 | 477 | except DMError: |
michael@0 | 478 | print "Automation Error: Failed to copy extra files to device" |
michael@0 | 479 | raise |
michael@0 | 480 | |
michael@0 | 481 | def getManifestPath(self, path): |
michael@0 | 482 | return path |
michael@0 | 483 | |
michael@0 | 484 | |
michael@0 | 485 | def run_remote_reftests(parser, options, args): |
michael@0 | 486 | auto = B2GRemoteAutomation(None, "fennec", context_chrome=True) |
michael@0 | 487 | |
michael@0 | 488 | # create our Marionette instance |
michael@0 | 489 | kwargs = {} |
michael@0 | 490 | if options.emulator: |
michael@0 | 491 | kwargs['emulator'] = options.emulator |
michael@0 | 492 | auto.setEmulator(True) |
michael@0 | 493 | if options.noWindow: |
michael@0 | 494 | kwargs['noWindow'] = True |
michael@0 | 495 | if options.geckoPath: |
michael@0 | 496 | kwargs['gecko_path'] = options.geckoPath |
michael@0 | 497 | if options.logcat_dir: |
michael@0 | 498 | kwargs['logcat_dir'] = options.logcat_dir |
michael@0 | 499 | if options.busybox: |
michael@0 | 500 | kwargs['busybox'] = options.busybox |
michael@0 | 501 | if options.symbolsPath: |
michael@0 | 502 | kwargs['symbols_path'] = options.symbolsPath |
michael@0 | 503 | if options.emulator_res: |
michael@0 | 504 | kwargs['emulator_res'] = options.emulator_res |
michael@0 | 505 | if options.b2gPath: |
michael@0 | 506 | kwargs['homedir'] = options.b2gPath |
michael@0 | 507 | if options.marionette: |
michael@0 | 508 | host,port = options.marionette.split(':') |
michael@0 | 509 | kwargs['host'] = host |
michael@0 | 510 | kwargs['port'] = int(port) |
michael@0 | 511 | marionette = Marionette.getMarionetteOrExit(**kwargs) |
michael@0 | 512 | auto.marionette = marionette |
michael@0 | 513 | |
michael@0 | 514 | if options.emulator: |
michael@0 | 515 | dm = marionette.emulator.dm |
michael@0 | 516 | else: |
michael@0 | 517 | # create the DeviceManager |
michael@0 | 518 | kwargs = {'adbPath': options.adbPath, |
michael@0 | 519 | 'deviceRoot': options.remoteTestRoot} |
michael@0 | 520 | if options.deviceIP: |
michael@0 | 521 | kwargs.update({'host': options.deviceIP, |
michael@0 | 522 | 'port': options.devicePort}) |
michael@0 | 523 | dm = DeviagerADB(**kwargs) |
michael@0 | 524 | auto.setDeviceManager(dm) |
michael@0 | 525 | |
michael@0 | 526 | options = parser.verifyRemoteOptions(options) |
michael@0 | 527 | |
michael@0 | 528 | if (options == None): |
michael@0 | 529 | print "ERROR: Invalid options specified, use --help for a list of valid options" |
michael@0 | 530 | sys.exit(1) |
michael@0 | 531 | |
michael@0 | 532 | # TODO fix exception |
michael@0 | 533 | if not options.ignoreWindowSize: |
michael@0 | 534 | parts = dm.getInfo('screen')['screen'][0].split() |
michael@0 | 535 | width = int(parts[0].split(':')[1]) |
michael@0 | 536 | height = int(parts[1].split(':')[1]) |
michael@0 | 537 | if (width < 1366 or height < 1050): |
michael@0 | 538 | print "ERROR: Invalid screen resolution %sx%s, please adjust to 1366x1050 or higher" % (width, height) |
michael@0 | 539 | return 1 |
michael@0 | 540 | |
michael@0 | 541 | auto.setProduct("b2g") |
michael@0 | 542 | auto.test_script = os.path.join(here, 'b2g_start_script.js') |
michael@0 | 543 | auto.test_script_args = [options.remoteWebServer, options.httpPort] |
michael@0 | 544 | auto.logFinish = "REFTEST TEST-START | Shutdown" |
michael@0 | 545 | |
michael@0 | 546 | reftest = B2GRemoteReftest(auto, dm, options, here) |
michael@0 | 547 | options = parser.verifyCommonOptions(options, reftest) |
michael@0 | 548 | |
michael@0 | 549 | logParent = os.path.dirname(options.remoteLogFile) |
michael@0 | 550 | dm.mkDir(logParent); |
michael@0 | 551 | auto.setRemoteLog(options.remoteLogFile) |
michael@0 | 552 | auto.setServerInfo(options.webServer, options.httpPort, options.sslPort) |
michael@0 | 553 | |
michael@0 | 554 | # Hack in a symbolic link for jsreftest |
michael@0 | 555 | os.system("ln -s %s %s" % (os.path.join('..', 'jsreftest'), os.path.join(here, 'jsreftest'))) |
michael@0 | 556 | |
michael@0 | 557 | # Dynamically build the reftest URL if possible, beware that args[0] should exist 'inside' the webroot |
michael@0 | 558 | manifest = args[0] |
michael@0 | 559 | if os.path.exists(os.path.join(here, args[0])): |
michael@0 | 560 | manifest = "http://%s:%s/%s" % (options.remoteWebServer, options.httpPort, args[0]) |
michael@0 | 561 | elif os.path.exists(args[0]): |
michael@0 | 562 | manifestPath = os.path.abspath(args[0]).split(here)[1].strip('/') |
michael@0 | 563 | manifest = "http://%s:%s/%s" % (options.remoteWebServer, options.httpPort, manifestPath) |
michael@0 | 564 | else: |
michael@0 | 565 | print "ERROR: Could not find test manifest '%s'" % manifest |
michael@0 | 566 | return 1 |
michael@0 | 567 | |
michael@0 | 568 | # Start the webserver |
michael@0 | 569 | retVal = 1 |
michael@0 | 570 | try: |
michael@0 | 571 | retVal = reftest.startWebServer(options) |
michael@0 | 572 | if retVal: |
michael@0 | 573 | return retVal |
michael@0 | 574 | procName = options.app.split('/')[-1] |
michael@0 | 575 | if (dm.processExist(procName)): |
michael@0 | 576 | dm.killProcess(procName) |
michael@0 | 577 | |
michael@0 | 578 | cmdlineArgs = ["-reftest", manifest] |
michael@0 | 579 | if getattr(options, 'bootstrap', False): |
michael@0 | 580 | cmdlineArgs = [] |
michael@0 | 581 | |
michael@0 | 582 | retVal = reftest.runTests(manifest, options, cmdlineArgs) |
michael@0 | 583 | except: |
michael@0 | 584 | print "Automation Error: Exception caught while running tests" |
michael@0 | 585 | traceback.print_exc() |
michael@0 | 586 | reftest.stopWebServer(options) |
michael@0 | 587 | try: |
michael@0 | 588 | reftest.cleanup(None) |
michael@0 | 589 | except: |
michael@0 | 590 | pass |
michael@0 | 591 | return 1 |
michael@0 | 592 | |
michael@0 | 593 | reftest.stopWebServer(options) |
michael@0 | 594 | return retVal |
michael@0 | 595 | |
michael@0 | 596 | def main(args=sys.argv[1:]): |
michael@0 | 597 | parser = B2GOptions() |
michael@0 | 598 | options, args = parser.parse_args(args) |
michael@0 | 599 | |
michael@0 | 600 | if options.desktop: |
michael@0 | 601 | return run_desktop_reftests(parser, options, args) |
michael@0 | 602 | return run_remote_reftests(parser, options, args) |
michael@0 | 603 | |
michael@0 | 604 | |
michael@0 | 605 | if __name__ == "__main__": |
michael@0 | 606 | sys.exit(main()) |
michael@0 | 607 |