Fri, 16 Jan 2015 04:50:19 +0100
Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32
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 |
michael@0 | 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
michael@0 | 4 | |
michael@0 | 5 | import sys |
michael@0 | 6 | import os |
michael@0 | 7 | import time |
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 | SCRIPT_DIRECTORY = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0]))) |
michael@0 | 13 | |
michael@0 | 14 | from runreftest import RefTest |
michael@0 | 15 | from runreftest import ReftestOptions |
michael@0 | 16 | from automation import Automation |
michael@0 | 17 | import devicemanager |
michael@0 | 18 | import droid |
michael@0 | 19 | import moznetwork |
michael@0 | 20 | from remoteautomation import RemoteAutomation, fennecLogcatFilters |
michael@0 | 21 | |
michael@0 | 22 | class RemoteOptions(ReftestOptions): |
michael@0 | 23 | def __init__(self, automation): |
michael@0 | 24 | ReftestOptions.__init__(self, automation) |
michael@0 | 25 | |
michael@0 | 26 | defaults = {} |
michael@0 | 27 | defaults["logFile"] = "reftest.log" |
michael@0 | 28 | # app, xrePath and utilityPath variables are set in main function |
michael@0 | 29 | defaults["app"] = "" |
michael@0 | 30 | defaults["xrePath"] = "" |
michael@0 | 31 | defaults["utilityPath"] = "" |
michael@0 | 32 | defaults["runTestsInParallel"] = False |
michael@0 | 33 | |
michael@0 | 34 | self.add_option("--remote-app-path", action="store", |
michael@0 | 35 | type = "string", dest = "remoteAppPath", |
michael@0 | 36 | help = "Path to remote executable relative to device root using only forward slashes. Either this or app must be specified, but not both.") |
michael@0 | 37 | defaults["remoteAppPath"] = None |
michael@0 | 38 | |
michael@0 | 39 | self.add_option("--deviceIP", action="store", |
michael@0 | 40 | type = "string", dest = "deviceIP", |
michael@0 | 41 | help = "ip address of remote device to test") |
michael@0 | 42 | defaults["deviceIP"] = None |
michael@0 | 43 | |
michael@0 | 44 | self.add_option("--devicePort", action="store", |
michael@0 | 45 | type = "string", dest = "devicePort", |
michael@0 | 46 | help = "port of remote device to test") |
michael@0 | 47 | defaults["devicePort"] = 20701 |
michael@0 | 48 | |
michael@0 | 49 | self.add_option("--remote-product-name", action="store", |
michael@0 | 50 | type = "string", dest = "remoteProductName", |
michael@0 | 51 | help = "Name of product to test - either fennec or firefox, defaults to fennec") |
michael@0 | 52 | defaults["remoteProductName"] = "fennec" |
michael@0 | 53 | |
michael@0 | 54 | self.add_option("--remote-webserver", action="store", |
michael@0 | 55 | type = "string", dest = "remoteWebServer", |
michael@0 | 56 | help = "IP Address of the webserver hosting the reftest content") |
michael@0 | 57 | defaults["remoteWebServer"] = moznetwork.get_ip() |
michael@0 | 58 | |
michael@0 | 59 | self.add_option("--http-port", action = "store", |
michael@0 | 60 | type = "string", dest = "httpPort", |
michael@0 | 61 | help = "port of the web server for http traffic") |
michael@0 | 62 | defaults["httpPort"] = automation.DEFAULT_HTTP_PORT |
michael@0 | 63 | |
michael@0 | 64 | self.add_option("--ssl-port", action = "store", |
michael@0 | 65 | type = "string", dest = "sslPort", |
michael@0 | 66 | help = "Port for https traffic to the web server") |
michael@0 | 67 | defaults["sslPort"] = automation.DEFAULT_SSL_PORT |
michael@0 | 68 | |
michael@0 | 69 | self.add_option("--remote-logfile", action="store", |
michael@0 | 70 | type = "string", dest = "remoteLogFile", |
michael@0 | 71 | help = "Name of log file on the device relative to device root. PLEASE USE ONLY A FILENAME.") |
michael@0 | 72 | defaults["remoteLogFile"] = None |
michael@0 | 73 | |
michael@0 | 74 | self.add_option("--enable-privilege", action="store_true", dest = "enablePrivilege", |
michael@0 | 75 | help = "add webserver and port to the user.js file for remote script access and universalXPConnect") |
michael@0 | 76 | defaults["enablePrivilege"] = False |
michael@0 | 77 | |
michael@0 | 78 | self.add_option("--pidfile", action = "store", |
michael@0 | 79 | type = "string", dest = "pidFile", |
michael@0 | 80 | help = "name of the pidfile to generate") |
michael@0 | 81 | defaults["pidFile"] = "" |
michael@0 | 82 | |
michael@0 | 83 | self.add_option("--bootstrap", action="store_true", dest = "bootstrap", |
michael@0 | 84 | help = "test with a bootstrap addon required for native Fennec") |
michael@0 | 85 | defaults["bootstrap"] = False |
michael@0 | 86 | |
michael@0 | 87 | self.add_option("--dm_trans", action="store", |
michael@0 | 88 | type = "string", dest = "dm_trans", |
michael@0 | 89 | help = "the transport to use to communicate with device: [adb|sut]; default=sut") |
michael@0 | 90 | defaults["dm_trans"] = "sut" |
michael@0 | 91 | |
michael@0 | 92 | self.add_option("--remoteTestRoot", action = "store", |
michael@0 | 93 | type = "string", dest = "remoteTestRoot", |
michael@0 | 94 | help = "remote directory to use as test root (eg. /mnt/sdcard/tests or /data/local/tests)") |
michael@0 | 95 | defaults["remoteTestRoot"] = None |
michael@0 | 96 | |
michael@0 | 97 | self.add_option("--httpd-path", action = "store", |
michael@0 | 98 | type = "string", dest = "httpdPath", |
michael@0 | 99 | help = "path to the httpd.js file") |
michael@0 | 100 | defaults["httpdPath"] = None |
michael@0 | 101 | |
michael@0 | 102 | defaults["localLogName"] = None |
michael@0 | 103 | |
michael@0 | 104 | self.set_defaults(**defaults) |
michael@0 | 105 | |
michael@0 | 106 | def verifyRemoteOptions(self, options): |
michael@0 | 107 | if options.runTestsInParallel: |
michael@0 | 108 | self.error("Cannot run parallel tests here") |
michael@0 | 109 | |
michael@0 | 110 | # Ensure our defaults are set properly for everything we can infer |
michael@0 | 111 | if not options.remoteTestRoot: |
michael@0 | 112 | options.remoteTestRoot = self.automation._devicemanager.getDeviceRoot() + '/reftest' |
michael@0 | 113 | options.remoteProfile = options.remoteTestRoot + "/profile" |
michael@0 | 114 | |
michael@0 | 115 | # Verify that our remotewebserver is set properly |
michael@0 | 116 | if (options.remoteWebServer == None or |
michael@0 | 117 | options.remoteWebServer == '127.0.0.1'): |
michael@0 | 118 | print "ERROR: Either you specified the loopback for the remote webserver or ", |
michael@0 | 119 | print "your local IP cannot be detected. Please provide the local ip in --remote-webserver" |
michael@0 | 120 | return None |
michael@0 | 121 | |
michael@0 | 122 | # One of remoteAppPath (relative path to application) or the app (executable) must be |
michael@0 | 123 | # set, but not both. If both are set, we destroy the user's selection for app |
michael@0 | 124 | # so instead of silently destroying a user specificied setting, we error. |
michael@0 | 125 | if (options.remoteAppPath and options.app): |
michael@0 | 126 | print "ERROR: You cannot specify both the remoteAppPath and the app" |
michael@0 | 127 | return None |
michael@0 | 128 | elif (options.remoteAppPath): |
michael@0 | 129 | options.app = options.remoteTestRoot + "/" + options.remoteAppPath |
michael@0 | 130 | elif (options.app == None): |
michael@0 | 131 | # Neither remoteAppPath nor app are set -- error |
michael@0 | 132 | print "ERROR: You must specify either appPath or app" |
michael@0 | 133 | return None |
michael@0 | 134 | |
michael@0 | 135 | if (options.xrePath == None): |
michael@0 | 136 | print "ERROR: You must specify the path to the controller xre directory" |
michael@0 | 137 | return None |
michael@0 | 138 | else: |
michael@0 | 139 | # Ensure xrepath is a full path |
michael@0 | 140 | options.xrePath = os.path.abspath(options.xrePath) |
michael@0 | 141 | |
michael@0 | 142 | # Default to <deviceroot>/reftest/reftest.log |
michael@0 | 143 | if (options.remoteLogFile == None): |
michael@0 | 144 | options.remoteLogFile = 'reftest.log' |
michael@0 | 145 | |
michael@0 | 146 | options.localLogName = options.remoteLogFile |
michael@0 | 147 | options.remoteLogFile = options.remoteTestRoot + '/' + options.remoteLogFile |
michael@0 | 148 | |
michael@0 | 149 | # Ensure that the options.logfile (which the base class uses) is set to |
michael@0 | 150 | # the remote setting when running remote. Also, if the user set the |
michael@0 | 151 | # log file name there, use that instead of reusing the remotelogfile as above. |
michael@0 | 152 | if (options.logFile): |
michael@0 | 153 | # If the user specified a local logfile name use that |
michael@0 | 154 | options.localLogName = options.logFile |
michael@0 | 155 | |
michael@0 | 156 | options.logFile = options.remoteLogFile |
michael@0 | 157 | |
michael@0 | 158 | if (options.pidFile != ""): |
michael@0 | 159 | f = open(options.pidFile, 'w') |
michael@0 | 160 | f.write("%s" % os.getpid()) |
michael@0 | 161 | f.close() |
michael@0 | 162 | |
michael@0 | 163 | # httpd-path is specified by standard makefile targets and may be specified |
michael@0 | 164 | # on the command line to select a particular version of httpd.js. If not |
michael@0 | 165 | # specified, try to select the one from hostutils.zip, as required in bug 882932. |
michael@0 | 166 | if not options.httpdPath: |
michael@0 | 167 | options.httpdPath = os.path.join(options.utilityPath, "components") |
michael@0 | 168 | |
michael@0 | 169 | # TODO: Copied from main, but I think these are no longer used in a post xulrunner world |
michael@0 | 170 | #options.xrePath = options.remoteTestRoot + self.automation._product + '/xulrunner' |
michael@0 | 171 | #options.utilityPath = options.testRoot + self.automation._product + '/bin' |
michael@0 | 172 | return options |
michael@0 | 173 | |
michael@0 | 174 | class ReftestServer: |
michael@0 | 175 | """ Web server used to serve Reftests, for closer fidelity to the real web. |
michael@0 | 176 | It is virtually identical to the server used in mochitest and will only |
michael@0 | 177 | be used for running reftests remotely. |
michael@0 | 178 | Bug 581257 has been filed to refactor this wrapper around httpd.js into |
michael@0 | 179 | it's own class and use it in both remote and non-remote testing. """ |
michael@0 | 180 | |
michael@0 | 181 | def __init__(self, automation, options, scriptDir): |
michael@0 | 182 | self.automation = automation |
michael@0 | 183 | self._utilityPath = options.utilityPath |
michael@0 | 184 | self._xrePath = options.xrePath |
michael@0 | 185 | self._profileDir = options.serverProfilePath |
michael@0 | 186 | self.webServer = options.remoteWebServer |
michael@0 | 187 | self.httpPort = options.httpPort |
michael@0 | 188 | self.scriptDir = scriptDir |
michael@0 | 189 | self.pidFile = options.pidFile |
michael@0 | 190 | self._httpdPath = os.path.abspath(options.httpdPath) |
michael@0 | 191 | self.shutdownURL = "http://%(server)s:%(port)s/server/shutdown" % { "server" : self.webServer, "port" : self.httpPort } |
michael@0 | 192 | |
michael@0 | 193 | def start(self): |
michael@0 | 194 | "Run the Refest server, returning the process ID of the server." |
michael@0 | 195 | |
michael@0 | 196 | env = self.automation.environment(xrePath = self._xrePath) |
michael@0 | 197 | env["XPCOM_DEBUG_BREAK"] = "warn" |
michael@0 | 198 | if self.automation.IS_WIN32: |
michael@0 | 199 | env["PATH"] = env["PATH"] + ";" + self._xrePath |
michael@0 | 200 | |
michael@0 | 201 | args = ["-g", self._xrePath, |
michael@0 | 202 | "-v", "170", |
michael@0 | 203 | "-f", os.path.join(self._httpdPath, "httpd.js"), |
michael@0 | 204 | "-e", "const _PROFILE_PATH = '%(profile)s';const _SERVER_PORT = '%(port)s'; const _SERVER_ADDR ='%(server)s';" % |
michael@0 | 205 | {"profile" : self._profileDir.replace('\\', '\\\\'), "port" : self.httpPort, "server" : self.webServer }, |
michael@0 | 206 | "-f", os.path.join(self.scriptDir, "server.js")] |
michael@0 | 207 | |
michael@0 | 208 | xpcshell = os.path.join(self._utilityPath, |
michael@0 | 209 | "xpcshell" + self.automation.BIN_SUFFIX) |
michael@0 | 210 | |
michael@0 | 211 | if not os.access(xpcshell, os.F_OK): |
michael@0 | 212 | raise Exception('xpcshell not found at %s' % xpcshell) |
michael@0 | 213 | if self.automation.elf_arm(xpcshell): |
michael@0 | 214 | raise Exception('xpcshell at %s is an ARM binary; please use ' |
michael@0 | 215 | 'the --utility-path argument to specify the path ' |
michael@0 | 216 | 'to a desktop version.' % xpcshell) |
michael@0 | 217 | |
michael@0 | 218 | self._process = self.automation.Process([xpcshell] + args, env = env) |
michael@0 | 219 | pid = self._process.pid |
michael@0 | 220 | if pid < 0: |
michael@0 | 221 | print "TEST-UNEXPECTED-FAIL | remotereftests.py | Error starting server." |
michael@0 | 222 | return 2 |
michael@0 | 223 | self.automation.log.info("INFO | remotereftests.py | Server pid: %d", pid) |
michael@0 | 224 | |
michael@0 | 225 | if (self.pidFile != ""): |
michael@0 | 226 | f = open(self.pidFile + ".xpcshell.pid", 'w') |
michael@0 | 227 | f.write("%s" % pid) |
michael@0 | 228 | f.close() |
michael@0 | 229 | |
michael@0 | 230 | def ensureReady(self, timeout): |
michael@0 | 231 | assert timeout >= 0 |
michael@0 | 232 | |
michael@0 | 233 | aliveFile = os.path.join(self._profileDir, "server_alive.txt") |
michael@0 | 234 | i = 0 |
michael@0 | 235 | while i < timeout: |
michael@0 | 236 | if os.path.exists(aliveFile): |
michael@0 | 237 | break |
michael@0 | 238 | time.sleep(1) |
michael@0 | 239 | i += 1 |
michael@0 | 240 | else: |
michael@0 | 241 | print "TEST-UNEXPECTED-FAIL | remotereftests.py | Timed out while waiting for server startup." |
michael@0 | 242 | self.stop() |
michael@0 | 243 | return 1 |
michael@0 | 244 | |
michael@0 | 245 | def stop(self): |
michael@0 | 246 | if hasattr(self, '_process'): |
michael@0 | 247 | try: |
michael@0 | 248 | c = urllib2.urlopen(self.shutdownURL) |
michael@0 | 249 | c.read() |
michael@0 | 250 | c.close() |
michael@0 | 251 | |
michael@0 | 252 | rtncode = self._process.poll() |
michael@0 | 253 | if (rtncode == None): |
michael@0 | 254 | self._process.terminate() |
michael@0 | 255 | except: |
michael@0 | 256 | self._process.kill() |
michael@0 | 257 | |
michael@0 | 258 | class RemoteReftest(RefTest): |
michael@0 | 259 | remoteApp = '' |
michael@0 | 260 | |
michael@0 | 261 | def __init__(self, automation, devicemanager, options, scriptDir): |
michael@0 | 262 | RefTest.__init__(self, automation) |
michael@0 | 263 | self._devicemanager = devicemanager |
michael@0 | 264 | self.scriptDir = scriptDir |
michael@0 | 265 | self.remoteApp = options.app |
michael@0 | 266 | self.remoteProfile = options.remoteProfile |
michael@0 | 267 | self.remoteTestRoot = options.remoteTestRoot |
michael@0 | 268 | self.remoteLogFile = options.remoteLogFile |
michael@0 | 269 | self.localLogName = options.localLogName |
michael@0 | 270 | self.pidFile = options.pidFile |
michael@0 | 271 | if self.automation.IS_DEBUG_BUILD: |
michael@0 | 272 | self.SERVER_STARTUP_TIMEOUT = 180 |
michael@0 | 273 | else: |
michael@0 | 274 | self.SERVER_STARTUP_TIMEOUT = 90 |
michael@0 | 275 | self.automation.deleteANRs() |
michael@0 | 276 | |
michael@0 | 277 | def findPath(self, paths, filename = None): |
michael@0 | 278 | for path in paths: |
michael@0 | 279 | p = path |
michael@0 | 280 | if filename: |
michael@0 | 281 | p = os.path.join(p, filename) |
michael@0 | 282 | if os.path.exists(self.getFullPath(p)): |
michael@0 | 283 | return path |
michael@0 | 284 | return None |
michael@0 | 285 | |
michael@0 | 286 | def startWebServer(self, options): |
michael@0 | 287 | """ Create the webserver on the host and start it up """ |
michael@0 | 288 | remoteXrePath = options.xrePath |
michael@0 | 289 | remoteUtilityPath = options.utilityPath |
michael@0 | 290 | localAutomation = Automation() |
michael@0 | 291 | localAutomation.IS_WIN32 = False |
michael@0 | 292 | localAutomation.IS_LINUX = False |
michael@0 | 293 | localAutomation.IS_MAC = False |
michael@0 | 294 | localAutomation.UNIXISH = False |
michael@0 | 295 | hostos = sys.platform |
michael@0 | 296 | if (hostos == 'mac' or hostos == 'darwin'): |
michael@0 | 297 | localAutomation.IS_MAC = True |
michael@0 | 298 | elif (hostos == 'linux' or hostos == 'linux2'): |
michael@0 | 299 | localAutomation.IS_LINUX = True |
michael@0 | 300 | localAutomation.UNIXISH = True |
michael@0 | 301 | elif (hostos == 'win32' or hostos == 'win64'): |
michael@0 | 302 | localAutomation.BIN_SUFFIX = ".exe" |
michael@0 | 303 | localAutomation.IS_WIN32 = True |
michael@0 | 304 | |
michael@0 | 305 | paths = [options.xrePath, localAutomation.DIST_BIN, self.automation._product, os.path.join('..', self.automation._product)] |
michael@0 | 306 | options.xrePath = self.findPath(paths) |
michael@0 | 307 | if options.xrePath == None: |
michael@0 | 308 | print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name) |
michael@0 | 309 | return 1 |
michael@0 | 310 | paths.append("bin") |
michael@0 | 311 | paths.append(os.path.join("..", "bin")) |
michael@0 | 312 | |
michael@0 | 313 | xpcshell = "xpcshell" |
michael@0 | 314 | if (os.name == "nt"): |
michael@0 | 315 | xpcshell += ".exe" |
michael@0 | 316 | |
michael@0 | 317 | if (options.utilityPath): |
michael@0 | 318 | paths.insert(0, options.utilityPath) |
michael@0 | 319 | options.utilityPath = self.findPath(paths, xpcshell) |
michael@0 | 320 | if options.utilityPath == None: |
michael@0 | 321 | print "ERROR: unable to find utility path for %s, please specify with --utility-path" % (os.name) |
michael@0 | 322 | return 1 |
michael@0 | 323 | |
michael@0 | 324 | options.serverProfilePath = tempfile.mkdtemp() |
michael@0 | 325 | self.server = ReftestServer(localAutomation, options, self.scriptDir) |
michael@0 | 326 | retVal = self.server.start() |
michael@0 | 327 | if retVal: |
michael@0 | 328 | return retVal |
michael@0 | 329 | retVal = self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT) |
michael@0 | 330 | if retVal: |
michael@0 | 331 | return retVal |
michael@0 | 332 | |
michael@0 | 333 | options.xrePath = remoteXrePath |
michael@0 | 334 | options.utilityPath = remoteUtilityPath |
michael@0 | 335 | return 0 |
michael@0 | 336 | |
michael@0 | 337 | def stopWebServer(self, options): |
michael@0 | 338 | self.server.stop() |
michael@0 | 339 | |
michael@0 | 340 | def createReftestProfile(self, options, reftestlist): |
michael@0 | 341 | profile = RefTest.createReftestProfile(self, options, reftestlist, server=options.remoteWebServer) |
michael@0 | 342 | profileDir = profile.profile |
michael@0 | 343 | |
michael@0 | 344 | prefs = {} |
michael@0 | 345 | prefs["browser.firstrun.show.localepicker"] = False |
michael@0 | 346 | prefs["font.size.inflation.emPerLine"] = 0 |
michael@0 | 347 | prefs["font.size.inflation.minTwips"] = 0 |
michael@0 | 348 | prefs["reftest.remote"] = True |
michael@0 | 349 | # Set a future policy version to avoid the telemetry prompt. |
michael@0 | 350 | prefs["toolkit.telemetry.prompted"] = 999 |
michael@0 | 351 | prefs["toolkit.telemetry.notifiedOptOut"] = 999 |
michael@0 | 352 | prefs["reftest.uri"] = "%s" % reftestlist |
michael@0 | 353 | prefs["datareporting.policy.dataSubmissionPolicyBypassAcceptance"] = True |
michael@0 | 354 | |
michael@0 | 355 | # Point the url-classifier to the local testing server for fast failures |
michael@0 | 356 | prefs["browser.safebrowsing.gethashURL"] = "http://127.0.0.1:8888/safebrowsing-dummy/gethash" |
michael@0 | 357 | prefs["browser.safebrowsing.updateURL"] = "http://127.0.0.1:8888/safebrowsing-dummy/update" |
michael@0 | 358 | # Point update checks to the local testing server for fast failures |
michael@0 | 359 | prefs["extensions.update.url"] = "http://127.0.0.1:8888/extensions-dummy/updateURL" |
michael@0 | 360 | prefs["extensions.update.background.url"] = "http://127.0.0.1:8888/extensions-dummy/updateBackgroundURL" |
michael@0 | 361 | prefs["extensions.blocklist.url"] = "http://127.0.0.1:8888/extensions-dummy/blocklistURL" |
michael@0 | 362 | prefs["extensions.hotfix.url"] = "http://127.0.0.1:8888/extensions-dummy/hotfixURL" |
michael@0 | 363 | # Turn off extension updates so they don't bother tests |
michael@0 | 364 | prefs["extensions.update.enabled"] = False |
michael@0 | 365 | # Make sure opening about:addons won't hit the network |
michael@0 | 366 | prefs["extensions.webservice.discoverURL"] = "http://127.0.0.1:8888/extensions-dummy/discoveryURL" |
michael@0 | 367 | # Make sure AddonRepository won't hit the network |
michael@0 | 368 | prefs["extensions.getAddons.maxResults"] = 0 |
michael@0 | 369 | prefs["extensions.getAddons.get.url"] = "http://127.0.0.1:8888/extensions-dummy/repositoryGetURL" |
michael@0 | 370 | prefs["extensions.getAddons.getWithPerformance.url"] = "http://127.0.0.1:8888/extensions-dummy/repositoryGetWithPerformanceURL" |
michael@0 | 371 | prefs["extensions.getAddons.search.browseURL"] = "http://127.0.0.1:8888/extensions-dummy/repositoryBrowseURL" |
michael@0 | 372 | prefs["extensions.getAddons.search.url"] = "http://127.0.0.1:8888/extensions-dummy/repositorySearchURL" |
michael@0 | 373 | # Make sure that opening the plugins check page won't hit the network |
michael@0 | 374 | prefs["plugins.update.url"] = "http://127.0.0.1:8888/plugins-dummy/updateCheckURL" |
michael@0 | 375 | prefs["layout.css.devPixelsPerPx"] = "1.0" |
michael@0 | 376 | |
michael@0 | 377 | # Disable skia-gl: see bug 907351 |
michael@0 | 378 | prefs["gfx.canvas.azure.accelerated"] = False |
michael@0 | 379 | |
michael@0 | 380 | # Set the extra prefs. |
michael@0 | 381 | profile.set_preferences(prefs) |
michael@0 | 382 | |
michael@0 | 383 | try: |
michael@0 | 384 | self._devicemanager.pushDir(profileDir, options.remoteProfile) |
michael@0 | 385 | except devicemanager.DMError: |
michael@0 | 386 | print "Automation Error: Failed to copy profiledir to device" |
michael@0 | 387 | raise |
michael@0 | 388 | |
michael@0 | 389 | return profile |
michael@0 | 390 | |
michael@0 | 391 | def copyExtraFilesToProfile(self, options, profile): |
michael@0 | 392 | profileDir = profile.profile |
michael@0 | 393 | RefTest.copyExtraFilesToProfile(self, options, profile) |
michael@0 | 394 | try: |
michael@0 | 395 | self._devicemanager.pushDir(profileDir, options.remoteProfile) |
michael@0 | 396 | except devicemanager.DMError: |
michael@0 | 397 | print "Automation Error: Failed to copy extra files to device" |
michael@0 | 398 | raise |
michael@0 | 399 | |
michael@0 | 400 | def getManifestPath(self, path): |
michael@0 | 401 | return path |
michael@0 | 402 | |
michael@0 | 403 | def printDeviceInfo(self, printLogcat=False): |
michael@0 | 404 | try: |
michael@0 | 405 | if printLogcat: |
michael@0 | 406 | logcat = self._devicemanager.getLogcat(filterOutRegexps=fennecLogcatFilters) |
michael@0 | 407 | print ''.join(logcat) |
michael@0 | 408 | print "Device info: %s" % self._devicemanager.getInfo() |
michael@0 | 409 | print "Test root: %s" % self._devicemanager.getDeviceRoot() |
michael@0 | 410 | except devicemanager.DMError: |
michael@0 | 411 | print "WARNING: Error getting device information" |
michael@0 | 412 | |
michael@0 | 413 | def cleanup(self, profileDir): |
michael@0 | 414 | # Pull results back from device |
michael@0 | 415 | if self.remoteLogFile and \ |
michael@0 | 416 | self._devicemanager.fileExists(self.remoteLogFile): |
michael@0 | 417 | self._devicemanager.getFile(self.remoteLogFile, self.localLogName) |
michael@0 | 418 | else: |
michael@0 | 419 | print "WARNING: Unable to retrieve log file (%s) from remote " \ |
michael@0 | 420 | "device" % self.remoteLogFile |
michael@0 | 421 | self._devicemanager.removeDir(self.remoteProfile) |
michael@0 | 422 | self._devicemanager.removeDir(self.remoteTestRoot) |
michael@0 | 423 | RefTest.cleanup(self, profileDir) |
michael@0 | 424 | if (self.pidFile != ""): |
michael@0 | 425 | try: |
michael@0 | 426 | os.remove(self.pidFile) |
michael@0 | 427 | os.remove(self.pidFile + ".xpcshell.pid") |
michael@0 | 428 | except: |
michael@0 | 429 | print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % self.pidFile |
michael@0 | 430 | |
michael@0 | 431 | def main(args): |
michael@0 | 432 | automation = RemoteAutomation(None) |
michael@0 | 433 | parser = RemoteOptions(automation) |
michael@0 | 434 | options, args = parser.parse_args() |
michael@0 | 435 | |
michael@0 | 436 | if (options.deviceIP == None): |
michael@0 | 437 | print "Error: you must provide a device IP to connect to via the --device option" |
michael@0 | 438 | return 1 |
michael@0 | 439 | |
michael@0 | 440 | try: |
michael@0 | 441 | if (options.dm_trans == "adb"): |
michael@0 | 442 | if (options.deviceIP): |
michael@0 | 443 | dm = droid.DroidADB(options.deviceIP, options.devicePort, deviceRoot=options.remoteTestRoot) |
michael@0 | 444 | else: |
michael@0 | 445 | dm = droid.DroidADB(None, None, deviceRoot=options.remoteTestRoot) |
michael@0 | 446 | else: |
michael@0 | 447 | dm = droid.DroidSUT(options.deviceIP, options.devicePort, deviceRoot=options.remoteTestRoot) |
michael@0 | 448 | except devicemanager.DMError: |
michael@0 | 449 | print "Automation Error: exception while initializing devicemanager. Most likely the device is not in a testable state." |
michael@0 | 450 | return 1 |
michael@0 | 451 | |
michael@0 | 452 | automation.setDeviceManager(dm) |
michael@0 | 453 | |
michael@0 | 454 | if (options.remoteProductName != None): |
michael@0 | 455 | automation.setProduct(options.remoteProductName) |
michael@0 | 456 | |
michael@0 | 457 | # Set up the defaults and ensure options are set |
michael@0 | 458 | options = parser.verifyRemoteOptions(options) |
michael@0 | 459 | if (options == None): |
michael@0 | 460 | print "ERROR: Invalid options specified, use --help for a list of valid options" |
michael@0 | 461 | return 1 |
michael@0 | 462 | |
michael@0 | 463 | if not options.ignoreWindowSize: |
michael@0 | 464 | parts = dm.getInfo('screen')['screen'][0].split() |
michael@0 | 465 | width = int(parts[0].split(':')[1]) |
michael@0 | 466 | height = int(parts[1].split(':')[1]) |
michael@0 | 467 | if (width < 1050 or height < 1050): |
michael@0 | 468 | print "ERROR: Invalid screen resolution %sx%s, please adjust to 1366x1050 or higher" % (width, height) |
michael@0 | 469 | return 1 |
michael@0 | 470 | |
michael@0 | 471 | automation.setAppName(options.app) |
michael@0 | 472 | automation.setRemoteProfile(options.remoteProfile) |
michael@0 | 473 | automation.setRemoteLog(options.remoteLogFile) |
michael@0 | 474 | reftest = RemoteReftest(automation, dm, options, SCRIPT_DIRECTORY) |
michael@0 | 475 | options = parser.verifyCommonOptions(options, reftest) |
michael@0 | 476 | |
michael@0 | 477 | # Hack in a symbolic link for jsreftest |
michael@0 | 478 | os.system("ln -s ../jsreftest " + str(os.path.join(SCRIPT_DIRECTORY, "jsreftest"))) |
michael@0 | 479 | |
michael@0 | 480 | # Dynamically build the reftest URL if possible, beware that args[0] should exist 'inside' the webroot |
michael@0 | 481 | manifest = args[0] |
michael@0 | 482 | if os.path.exists(os.path.join(SCRIPT_DIRECTORY, args[0])): |
michael@0 | 483 | manifest = "http://" + str(options.remoteWebServer) + ":" + str(options.httpPort) + "/" + args[0] |
michael@0 | 484 | elif os.path.exists(args[0]): |
michael@0 | 485 | manifestPath = os.path.abspath(args[0]).split(SCRIPT_DIRECTORY)[1].strip('/') |
michael@0 | 486 | manifest = "http://" + str(options.remoteWebServer) + ":" + str(options.httpPort) + "/" + manifestPath |
michael@0 | 487 | else: |
michael@0 | 488 | print "ERROR: Could not find test manifest '%s'" % manifest |
michael@0 | 489 | return 1 |
michael@0 | 490 | |
michael@0 | 491 | # Start the webserver |
michael@0 | 492 | retVal = reftest.startWebServer(options) |
michael@0 | 493 | if retVal: |
michael@0 | 494 | return retVal |
michael@0 | 495 | |
michael@0 | 496 | procName = options.app.split('/')[-1] |
michael@0 | 497 | if (dm.processExist(procName)): |
michael@0 | 498 | dm.killProcess(procName) |
michael@0 | 499 | |
michael@0 | 500 | reftest.printDeviceInfo() |
michael@0 | 501 | |
michael@0 | 502 | #an example manifest name to use on the cli |
michael@0 | 503 | # manifest = "http://" + options.remoteWebServer + "/reftests/layout/reftests/reftest-sanity/reftest.list" |
michael@0 | 504 | retVal = 0 |
michael@0 | 505 | try: |
michael@0 | 506 | cmdlineArgs = ["-reftest", manifest] |
michael@0 | 507 | if options.bootstrap: |
michael@0 | 508 | cmdlineArgs = [] |
michael@0 | 509 | dm.recordLogcat() |
michael@0 | 510 | retVal = reftest.runTests(manifest, options, cmdlineArgs) |
michael@0 | 511 | except: |
michael@0 | 512 | print "Automation Error: Exception caught while running tests" |
michael@0 | 513 | traceback.print_exc() |
michael@0 | 514 | retVal = 1 |
michael@0 | 515 | |
michael@0 | 516 | reftest.stopWebServer(options) |
michael@0 | 517 | |
michael@0 | 518 | reftest.printDeviceInfo(printLogcat=True) |
michael@0 | 519 | |
michael@0 | 520 | return retVal |
michael@0 | 521 | |
michael@0 | 522 | if __name__ == "__main__": |
michael@0 | 523 | sys.exit(main(sys.argv[1:])) |
michael@0 | 524 |