class B2GMochitest(Mochitest): _automation = None _dm = None localProfile = None testDir = "/data/local/tests" def __init__(self, automation, devmgr, options): self._automation = automation Mochitest.__init__(self, self._automation) self._dm = devmgr self.runSSLTunnel = False self.remoteProfile = options.remoteTestRoot + "/profile" self._automation.setRemoteProfile(self.remoteProfile) self.remoteLog = options.remoteLogFile self.userJS = "/data/local/user.js" self.remoteMozillaPath = "/data/b2g/mozilla" self.remoteProfilesIniPath = os.path.join(self.remoteMozillaPath, "profiles.ini") self.originalProfilesIni = None def cleanup(self, manifest, options): # Restore the original profiles.ini. if self.originalProfilesIni: try: if not options.emulator: self.restoreProfilesIni() os.remove(self.originalProfilesIni) except: pass if not options.emulator: self._dm.getFile(self.remoteLog, self.localLog) self._dm.removeFile(self.remoteLog) self._dm.removeDir(self.remoteProfile) # Restore the original user.js. self._dm.checkCmdAs(["shell", "rm", "-f", self.userJS]) if self._dm.useDDCopy: self._dm.checkCmdAs(["shell", "dd", "if=%s.orig" % self.userJS, "of=%s" % self.userJS]) else: self._dm.checkCmdAs(["shell", "cp", "%s.orig" % self.userJS, self.userJS]) # We've restored the original profile, so reboot the device so that # it gets picked up. self._automation.rebootDevice() if options.pidFile != "": try: os.remove(options.pidFile) os.remove(options.pidFile + ".xpcshell.pid") except: print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % options.pidFile def findPath(self, paths, filename=None): for path in paths: p = path if filename: p = os.path.join(p, filename) if os.path.exists(self.getFullPath(p)): return path return None def startWebServer(self, options): """ Create the webserver on the host and start it up """ remoteXrePath = options.xrePath remoteProfilePath = options.profilePath remoteUtilityPath = options.utilityPath localAutomation = Automation() localAutomation.IS_WIN32 = False localAutomation.IS_LINUX = False localAutomation.IS_MAC = False localAutomation.UNIXISH = False hostos = sys.platform if hostos in ["mac", "darwin"]: localAutomation.IS_MAC = True elif hostos in ["linux", "linux2"]: localAutomation.IS_LINUX = True localAutomation.UNIXISH = True elif hostos in ["win32", "win64"]: localAutomation.BIN_SUFFIX = ".exe" localAutomation.IS_WIN32 = True paths = [ options.xrePath, localAutomation.DIST_BIN, self._automation._product, os.path.join("..", self._automation._product), ] options.xrePath = self.findPath(paths) if options.xrePath == None: print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name) sys.exit(1) paths.append("bin") paths.append(os.path.join("..", "bin")) xpcshell = "xpcshell" if os.name == "nt": xpcshell += ".exe" if options.utilityPath: paths.insert(0, options.utilityPath) options.utilityPath = self.findPath(paths, xpcshell) if options.utilityPath == None: print "ERROR: unable to find utility path for %s, please specify with --utility-path" % (os.name) sys.exit(1) options.profilePath = tempfile.mkdtemp() self.server = MochitestServer(localAutomation, options) self.server.start() if options.pidFile != "": f = open(options.pidFile + ".xpcshell.pid", "w") f.write("%s" % self.server._process.pid) f.close() self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT) options.xrePath = remoteXrePath options.utilityPath = remoteUtilityPath options.profilePath = remoteProfilePath def stopWebServer(self, options): if hasattr(self, "server"): self.server.stop() def buildProfile(self, options): if self.localProfile: options.profilePath = self.localProfile manifest = Mochitest.buildProfile(self, options) self.localProfile = options.profilePath # Profile isn't actually copied to device until # buildURLOptions is called. options.profilePath = self.remoteProfile return manifest def restoreProfilesIni(self): # restore profiles.ini on the device to its previous state if not self.originalProfilesIni or not os.access(self.originalProfilesIni, os.F_OK): raise DMError("Unable to install original profiles.ini; file not found: %s", self.originalProfilesIni) self._dm.pushFile(self.originalProfilesIni, self.remoteProfilesIniPath) def updateProfilesIni(self, profilePath): # update profiles.ini on the device to point to the test profile self.originalProfilesIni = tempfile.mktemp() self._dm.getFile(self.remoteProfilesIniPath, self.originalProfilesIni) config = ProfileConfigParser() config.read(self.originalProfilesIni) for section in config.sections(): if "Profile" in section: config.set(section, "IsRelative", 0) config.set(section, "Path", profilePath) newProfilesIni = tempfile.mktemp() with open(newProfilesIni, "wb") as configfile: config.write(configfile) self._dm.pushFile(newProfilesIni, self.remoteProfilesIniPath) try: os.remove(newProfilesIni) except: pass def buildURLOptions(self, options, env): self.localLog = options.logFile options.logFile = self.remoteLog options.profilePath = self.localProfile retVal = Mochitest.buildURLOptions(self, options, env) # set the testURL testURL = self.buildTestPath(options) if len(self.urlOpts) > 0: testURL += "?" + "&".join(self.urlOpts) self._automation.testURL = testURL # Set extra prefs for B2G. f = open(os.path.join(options.profilePath, "user.js"), "a") f.write( """ user_pref("browser.homescreenURL","app://system.gaiamobile.org");\n user_pref("dom.mozBrowserFramesEnabled", true);\n user_pref("dom.ipc.tabs.disabled", false);\n user_pref("dom.ipc.browser_frames.oop_by_default", true);\n user_pref("browser.manifestURL","app://system.gaiamobile.org/manifest.webapp");\n user_pref("dom.mozBrowserFramesWhitelist","app://system.gaiamobile.org,http://mochi.test:8888");\n user_pref("network.dns.localDomains","app://system.gaiamobile.org");\n """ ) f.close() # Copy the profile to the device. self._dm.removeDir(self.remoteProfile) if self._dm.pushDir(options.profilePath, self.remoteProfile) == None: raise devicemanager.FileError("Unable to copy profile to device.") # In B2G, user.js is always read from /data/local, not the profile # directory. Backup the original user.js first so we can restore it. self._dm.checkCmdAs(["shell", "rm", "-f", "%s.orig" % self.userJS]) if self._dm.useDDCopy: self._dm.checkCmdAs(["shell", "dd", "if=%s" % self.userJS, "of=%s.orig" % self.userJS]) else: self._dm.checkCmdAs(["shell", "cp", self.userJS, "%s.orig" % self.userJS]) self._dm.pushFile(os.path.join(options.profilePath, "user.js"), self.userJS) self.updateProfilesIni(self.remoteProfile) options.profilePath = self.remoteProfile options.logFile = self.localLog return retVal
class MochiRemote(Mochitest): _automation = None _dm = None localProfile = None logLines = [] def __init__(self, automation, devmgr, options): self._automation = automation Mochitest.__init__(self, self._automation) self._dm = devmgr self.runSSLTunnel = False self.remoteProfile = options.remoteTestRoot + "/profile" self._automation.setRemoteProfile(self.remoteProfile) self.remoteLog = options.remoteLogFile def cleanup(self, manifest, options): self._dm.getFile(self.remoteLog, self.localLog) self._dm.removeFile(self.remoteLog) self._dm.removeDir(self.remoteProfile) if (options.pidFile != ""): try: os.remove(options.pidFile) os.remove(options.pidFile + ".xpcshell.pid") except: print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % options.pidFile def findPath(self, paths, filename = None): for path in paths: p = path if filename: p = os.path.join(p, filename) if os.path.exists(self.getFullPath(p)): return path return None def startWebServer(self, options): """ Create the webserver on the host and start it up """ remoteXrePath = options.xrePath remoteProfilePath = options.profilePath remoteUtilityPath = options.utilityPath localAutomation = Automation() localAutomation.IS_WIN32 = False localAutomation.IS_LINUX = False localAutomation.IS_MAC = False localAutomation.UNIXISH = False hostos = sys.platform if (hostos == 'mac' or hostos == 'darwin'): localAutomation.IS_MAC = True elif (hostos == 'linux' or hostos == 'linux2'): localAutomation.IS_LINUX = True localAutomation.UNIXISH = True elif (hostos == 'win32' or hostos == 'win64'): localAutomation.BIN_SUFFIX = ".exe" localAutomation.IS_WIN32 = True paths = [options.xrePath, localAutomation.DIST_BIN, self._automation._product, os.path.join('..', self._automation._product)] options.xrePath = self.findPath(paths) if options.xrePath == None: print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name) sys.exit(1) paths.append("bin") paths.append(os.path.join("..", "bin")) xpcshell = "xpcshell" if (os.name == "nt"): xpcshell += ".exe" if (options.utilityPath): paths.insert(0, options.utilityPath) options.utilityPath = self.findPath(paths, xpcshell) if options.utilityPath == None: print "ERROR: unable to find utility path for %s, please specify with --utility-path" % (os.name) sys.exit(1) options.profilePath = tempfile.mkdtemp() self.server = MochitestServer(localAutomation, options) self.server.start() if (options.pidFile != ""): f = open(options.pidFile + ".xpcshell.pid", 'w') f.write("%s" % self.server._process.pid) f.close() self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT) options.xrePath = remoteXrePath options.utilityPath = remoteUtilityPath options.profilePath = remoteProfilePath def stopWebServer(self, options): self.server.stop() def buildProfile(self, options): if self.localProfile: options.profilePath = self.localProfile manifest = Mochitest.buildProfile(self, options) self.localProfile = options.profilePath self._dm.removeDir(self.remoteProfile) if self._dm.pushDir(options.profilePath, self.remoteProfile) == None: raise devicemanager.FileError("Unable to copy profile to device.") options.profilePath = self.remoteProfile return manifest def buildURLOptions(self, options, env): self.localLog = options.logFile options.logFile = self.remoteLog options.profilePath = self.localProfile retVal = Mochitest.buildURLOptions(self, options, env) #we really need testConfig.js (for browser chrome) if self._dm.pushDir(options.profilePath, self.remoteProfile) == None: raise devicemanager.FileError("Unable to copy profile to device.") options.profilePath = self.remoteProfile options.logFile = self.localLog return retVal def installChromeFile(self, filename, options): parts = options.app.split('/') if (parts[0] == options.app): return "NO_CHROME_ON_DROID" path = '/'.join(parts[:-1]) manifest = path + "/chrome/" + os.path.basename(filename) if self._dm.pushFile(filename, manifest) == False: raise devicemanager.FileError("Unable to install Chrome files on device.") return manifest def getLogFilePath(self, logFile): return logFile # In the future we could use LogParser: http://hg.mozilla.org/automation/logparser/ def addLogData(self): with open(self.localLog) as currentLog: data = currentLog.readlines() restart = re.compile('0 INFO SimpleTest START.*') reend = re.compile('([0-9]+) INFO TEST-START . Shutdown.*') start_found = False end_found = False for line in data: if reend.match(line): end_found = True start_found = False return if start_found and not end_found: # Append the line without the number to increment self.logLines.append(' '.join(line.split(' ')[1:])) if restart.match(line): start_found = True def printLog(self): passed = 0 failed = 0 todo = 0 incr = 1 logFile = [] logFile.append("0 INFO SimpleTest START") for line in self.logLines: if line.startswith("INFO TEST-PASS"): passed += 1 elif line.startswith("INFO TEST-UNEXPECTED"): failed += 1 elif line.startswith("INFO TEST-KNOWN"): todo += 1 incr += 1 logFile.append("%s INFO TEST-START | Shutdown" % incr) incr += 1 logFile.append("%s INFO Passed: %s" % (incr, passed)) incr += 1 logFile.append("%s INFO Failed: %s" % (incr, failed)) incr += 1 logFile.append("%s INFO Todo: %s" % (incr, todo)) incr += 1 logFile.append("%s INFO SimpleTest FINISHED" % incr) # TODO: Consider not printing to stdout because we might be duplicating output print '\n'.join(logFile) with open(self.localLog, 'w') as localLog: localLog.write('\n'.join(logFile)) if failed > 0: return 1 return 0
class B2GMochitest(Mochitest, B2GMochitestMixin): _automation = None _dm = None localProfile = None def __init__(self, automation, devmgr, options): self._automation = automation Mochitest.__init__(self, self._automation) self._dm = devmgr self.runSSLTunnel = False self.remoteProfile = options.remoteTestRoot + '/profile' self._automation.setRemoteProfile(self.remoteProfile) self.remoteLog = options.remoteLogFile self.localLog = None self.userJS = '/data/local/user.js' self.remoteMozillaPath = '/data/b2g/mozilla' self.bundlesDir = '/system/b2g/distribution/bundles' self.remoteProfilesIniPath = os.path.join(self.remoteMozillaPath, 'profiles.ini') self.originalProfilesIni = None def copyRemoteFile(self, src, dest): if self._dm._useDDCopy: self._dm._checkCmdAs(['shell', 'dd', 'if=%s' % src, 'of=%s' % dest]) else: self._dm._checkCmdAs(['shell', 'cp', src, dest]) def origUserJSExists(self): return self._dm.fileExists('/data/local/user.js.orig') def cleanup(self, manifest, options): if self.localLog: self._dm.getFile(self.remoteLog, self.localLog) self._dm.removeFile(self.remoteLog) # Delete any bundled extensions extensionDir = os.path.join(options.profilePath, 'extensions', 'staged') if os.access(extensionDir, os.F_OK): for filename in os.listdir(extensionDir): try: self._dm._checkCmdAs(['shell', 'rm', '-rf', os.path.join(self.bundlesDir, filename)]) except devicemanager.DMError: pass if not options.emulator: # Remove the test profile self._dm._checkCmdAs(['shell', 'rm', '-r', self.remoteProfile]) if self.origUserJSExists(): # Restore the original user.js self._dm.removeFile(self.userJS) self.copyRemoteFile('%s.orig' % self.userJS, self.userJS) self._dm.removeFile("%s.orig" % self.userJS) if self._dm.fileExists('%s.orig' % self.remoteProfilesIniPath): # Restore the original profiles.ini self._dm.removeFile(self.remoteProfilesIniPath) self.copyRemoteFile('%s.orig' % self.remoteProfilesIniPath, self.remoteProfilesIniPath) self._dm.removeFile("%s.orig" % self.remoteProfilesIniPath) # We've restored the original profile, so reboot the device so that # it gets picked up. self._automation.rebootDevice() if options.pidFile != "": try: os.remove(options.pidFile) os.remove(options.pidFile + ".xpcshell.pid") except: print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % options.pidFile def findPath(self, paths, filename=None): for path in paths: p = path if filename: p = os.path.join(p, filename) if os.path.exists(self.getFullPath(p)): return path return None def startWebServer(self, options): """ Create the webserver on the host and start it up """ remoteXrePath = options.xrePath remoteProfilePath = options.profilePath remoteUtilityPath = options.utilityPath localAutomation = Automation() localAutomation.IS_WIN32 = False localAutomation.IS_LINUX = False localAutomation.IS_MAC = False localAutomation.UNIXISH = False hostos = sys.platform if hostos in ['mac', 'darwin']: localAutomation.IS_MAC = True elif hostos in ['linux', 'linux2']: localAutomation.IS_LINUX = True localAutomation.UNIXISH = True elif hostos in ['win32', 'win64']: localAutomation.BIN_SUFFIX = ".exe" localAutomation.IS_WIN32 = True paths = [options.xrePath, localAutomation.DIST_BIN, self._automation._product, os.path.join('..', self._automation._product)] options.xrePath = self.findPath(paths) if options.xrePath == None: print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name) sys.exit(1) paths.append("bin") paths.append(os.path.join("..", "bin")) xpcshell = "xpcshell" if (os.name == "nt"): xpcshell += ".exe" if (options.utilityPath): paths.insert(0, options.utilityPath) options.utilityPath = self.findPath(paths, xpcshell) if options.utilityPath == None: print "ERROR: unable to find utility path for %s, please specify with --utility-path" % (os.name) sys.exit(1) options.profilePath = tempfile.mkdtemp() self.server = MochitestServer(localAutomation, options) self.server.start() if (options.pidFile != ""): f = open(options.pidFile + ".xpcshell.pid", 'w') f.write("%s" % self.server._process.pid) f.close() self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT) options.xrePath = remoteXrePath options.utilityPath = remoteUtilityPath options.profilePath = remoteProfilePath def stopWebServer(self, options): if hasattr(self, 'server'): self.server.stop() def buildProfile(self, options): if self.localProfile: options.profilePath = self.localProfile manifest = Mochitest.buildProfile(self, options) self.localProfile = options.profilePath # Profile isn't actually copied to device until # buildURLOptions is called. options.profilePath = self.remoteProfile return manifest def updateProfilesIni(self, profilePath): # update profiles.ini on the device to point to the test profile self.originalProfilesIni = tempfile.mktemp() self._dm.getFile(self.remoteProfilesIniPath, self.originalProfilesIni) config = ProfileConfigParser() config.read(self.originalProfilesIni) for section in config.sections(): if 'Profile' in section: config.set(section, 'IsRelative', 0) config.set(section, 'Path', profilePath) newProfilesIni = tempfile.mktemp() with open(newProfilesIni, 'wb') as configfile: config.write(configfile) self._dm.pushFile(newProfilesIni, self.remoteProfilesIniPath) self._dm.pushFile(self.originalProfilesIni, '%s.orig' % self.remoteProfilesIniPath) try: os.remove(newProfilesIni) os.remove(self.originalProfilesIni) except: pass def buildURLOptions(self, options, env): self.localLog = options.logFile options.logFile = self.remoteLog options.profilePath = self.localProfile retVal = Mochitest.buildURLOptions(self, options, env) self.setupCommonOptions(options) # Copy the profile to the device. self._dm._checkCmdAs(['shell', 'rm', '-r', self.remoteProfile]) try: self._dm.pushDir(options.profilePath, self.remoteProfile) except devicemanager.DMError: print "Automation Error: Unable to copy profile to device." raise # Copy the extensions to the B2G bundles dir. extensionDir = os.path.join(options.profilePath, 'extensions', 'staged') # need to write to read-only dir self._dm._checkCmdAs(['remount']) for filename in os.listdir(extensionDir): self._dm._checkCmdAs(['shell', 'rm', '-rf', os.path.join(self.bundlesDir, filename)]) try: self._dm.pushDir(extensionDir, self.bundlesDir) except devicemanager.DMError: print "Automation Error: Unable to copy extensions to device." raise # In B2G, user.js is always read from /data/local, not the profile # directory. Backup the original user.js first so we can restore it. if not self._dm.fileExists('%s.orig' % self.userJS): self.copyRemoteFile(self.userJS, '%s.orig' % self.userJS) self._dm.pushFile(os.path.join(options.profilePath, "user.js"), self.userJS) self.updateProfilesIni(self.remoteProfile) options.profilePath = self.remoteProfile options.logFile = self.localLog return retVal
class B2GDeviceMochitest(B2GMochitest): _dm = None def __init__(self, marionette, devicemanager, profile_data_dir, local_binary_dir, remote_test_root=None, remote_log_file=None): B2GMochitest.__init__(self, marionette, out_of_process=True, profile_data_dir=profile_data_dir) self._dm = devicemanager self.remote_test_root = remote_test_root or self._dm.getDeviceRoot() self.remote_profile = posixpath.join(self.remote_test_root, 'profile') self.remote_log = remote_log_file or posixpath.join(self.remote_test_root, 'log', 'mochitest.log') self.local_log = None self.local_binary_dir = local_binary_dir if not self._dm.dirExists(posixpath.dirname(self.remote_log)): self._dm.mkDirs(self.remote_log) def cleanup(self, manifest, options): if self.local_log: self._dm.getFile(self.remote_log, self.local_log) self._dm.removeFile(self.remote_log) if options.pidFile != "": try: os.remove(options.pidFile) os.remove(options.pidFile + ".xpcshell.pid") except: print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % options.pidFile # stop and clean up the runner if getattr(self, 'runner', False): self.runner.cleanup() self.runner = None def startWebServer(self, options): """ Create the webserver on the host and start it up """ d = vars(options).copy() d['xrePath'] = self.local_binary_dir d['utilityPath'] = self.local_binary_dir d['profilePath'] = tempfile.mkdtemp() if d.get('httpdPath') is None: d['httpdPath'] = os.path.abspath(os.path.join(self.local_binary_dir, 'components')) self.server = MochitestServer(d) self.server.start() if (options.pidFile != ""): f = open(options.pidFile + ".xpcshell.pid", 'w') f.write("%s" % self.server._process.pid) f.close() self.server.ensureReady(90) def stopWebServer(self, options): if hasattr(self, 'server'): self.server.stop() def buildURLOptions(self, options, env): self.local_log = options.logFile options.logFile = self.remote_log options.profilePath = self.profile.profile retVal = super(B2GDeviceMochitest, self).buildURLOptions(options, env) self.setup_common_options(options) options.profilePath = self.remote_profile options.logFile = self.local_log return retVal
class MochiRemote(Mochitest): _automation = None _dm = None localProfile = None logLines = [] def __init__(self, automation, devmgr, options): self._automation = automation Mochitest.__init__(self, self._automation) self._dm = devmgr self.runSSLTunnel = False self.remoteProfile = options.remoteTestRoot + "/profile" self._automation.setRemoteProfile(self.remoteProfile) self.remoteLog = options.remoteLogFile self.localLog = options.logFile def cleanup(self, manifest, options): if self._dm.fileExists(self.remoteLog): self._dm.getFile(self.remoteLog, self.localLog) self._dm.removeFile(self.remoteLog) else: print "WARNING: Unable to retrieve log file (%s) from remote " \ "device" % self.remoteLog self._dm.removeDir(self.remoteProfile) if (options.pidFile != ""): try: os.remove(options.pidFile) os.remove(options.pidFile + ".xpcshell.pid") except: print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % options.pidFile def findPath(self, paths, filename = None): for path in paths: p = path if filename: p = os.path.join(p, filename) if os.path.exists(self.getFullPath(p)): return path return None def startWebServer(self, options): """ Create the webserver on the host and start it up """ remoteXrePath = options.xrePath remoteProfilePath = options.profilePath remoteUtilityPath = options.utilityPath localAutomation = Automation() localAutomation.IS_WIN32 = False localAutomation.IS_LINUX = False localAutomation.IS_MAC = False localAutomation.UNIXISH = False hostos = sys.platform if (hostos == 'mac' or hostos == 'darwin'): localAutomation.IS_MAC = True elif (hostos == 'linux' or hostos == 'linux2'): localAutomation.IS_LINUX = True localAutomation.UNIXISH = True elif (hostos == 'win32' or hostos == 'win64'): localAutomation.BIN_SUFFIX = ".exe" localAutomation.IS_WIN32 = True paths = [options.xrePath, localAutomation.DIST_BIN, self._automation._product, os.path.join('..', self._automation._product)] options.xrePath = self.findPath(paths) if options.xrePath == None: print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name) sys.exit(1) paths.append("bin") paths.append(os.path.join("..", "bin")) xpcshell = "xpcshell" if (os.name == "nt"): xpcshell += ".exe" if (options.utilityPath): paths.insert(0, options.utilityPath) options.utilityPath = self.findPath(paths, xpcshell) if options.utilityPath == None: print "ERROR: unable to find utility path for %s, please specify with --utility-path" % (os.name) sys.exit(1) options.profilePath = tempfile.mkdtemp() self.server = MochitestServer(localAutomation, options) self.server.start() if (options.pidFile != ""): f = open(options.pidFile + ".xpcshell.pid", 'w') f.write("%s" % self.server._process.pid) f.close() self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT) options.xrePath = remoteXrePath options.utilityPath = remoteUtilityPath options.profilePath = remoteProfilePath def stopWebServer(self, options): self.server.stop() def buildProfile(self, options): if self.localProfile: options.profilePath = self.localProfile manifest = Mochitest.buildProfile(self, options) self.localProfile = options.profilePath self._dm.removeDir(self.remoteProfile) # we do not need this for robotium based tests, lets save a LOT of time if options.robocop: shutil.rmtree(os.path.join(options.profilePath, 'webapps')) shutil.rmtree(os.path.join(options.profilePath, 'extensions', 'staged', '*****@*****.**')) shutil.rmtree(os.path.join(options.profilePath, 'extensions', 'staged', '*****@*****.**')) shutil.rmtree(os.path.join(options.profilePath, 'extensions', 'staged', '*****@*****.**')) shutil.rmtree(os.path.join(options.profilePath, 'extensions', 'staged', '*****@*****.**')) os.remove(os.path.join(options.profilePath, 'userChrome.css')) if os.path.exists(os.path.join(options.profilePath, 'tests.jar')): os.remove(os.path.join(options.profilePath, 'tests.jar')) if os.path.exists(os.path.join(options.profilePath, 'tests.manifest')): os.remove(os.path.join(options.profilePath, 'tests.manifest')) try: self._dm.pushDir(options.profilePath, self.remoteProfile) except devicemanager.DMError: print "Automation Error: Unable to copy profile to device." raise options.profilePath = self.remoteProfile return manifest def buildURLOptions(self, options, env): self.localLog = options.logFile options.logFile = self.remoteLog options.profilePath = self.localProfile env["MOZ_HIDE_RESULTS_TABLE"] = "1" retVal = Mochitest.buildURLOptions(self, options, env) if not options.robocop: #we really need testConfig.js (for browser chrome) try: self._dm.pushDir(options.profilePath, self.remoteProfile) except devicemanager.DMError: print "Automation Error: Unable to copy profile to device." raise options.profilePath = self.remoteProfile options.logFile = self.localLog return retVal def installChromeFile(self, filename, options): parts = options.app.split('/') if (parts[0] == options.app): return "NO_CHROME_ON_DROID" path = '/'.join(parts[:-1]) manifest = path + "/chrome/" + os.path.basename(filename) try: self._dm.pushFile(filename, manifest) except devicemanager.DMError: print "Automation Error: Unable to install Chrome files on device." raise return manifest def getLogFilePath(self, logFile): return logFile # In the future we could use LogParser: http://hg.mozilla.org/automation/logparser/ def addLogData(self): with open(self.localLog) as currentLog: data = currentLog.readlines() restart = re.compile('0 INFO SimpleTest START.*') reend = re.compile('([0-9]+) INFO TEST-START . Shutdown.*') start_found = False end_found = False for line in data: if reend.match(line): end_found = True start_found = False return if start_found and not end_found: # Append the line without the number to increment self.logLines.append(' '.join(line.split(' ')[1:])) if restart.match(line): start_found = True def printLog(self): passed = 0 failed = 0 todo = 0 incr = 1 logFile = [] logFile.append("0 INFO SimpleTest START") for line in self.logLines: if line.startswith("INFO TEST-PASS"): passed += 1 elif line.startswith("INFO TEST-UNEXPECTED"): failed += 1 elif line.startswith("INFO TEST-KNOWN"): todo += 1 incr += 1 logFile.append("%s INFO TEST-START | Shutdown" % incr) incr += 1 logFile.append("%s INFO Passed: %s" % (incr, passed)) incr += 1 logFile.append("%s INFO Failed: %s" % (incr, failed)) incr += 1 logFile.append("%s INFO Todo: %s" % (incr, todo)) incr += 1 logFile.append("%s INFO SimpleTest FINISHED" % incr) # TODO: Consider not printing to stdout because we might be duplicating output print '\n'.join(logFile) with open(self.localLog, 'w') as localLog: localLog.write('\n'.join(logFile)) if failed > 0: return 1 return 0 def printDeviceInfo(self): try: logcat = self._dm.getLogcat(filterOutRegexps=fennecLogcatFilters) print ''.join(logcat) print self._dm.getInfo() except devicemanager.DMError: print "WARNING: Error getting device information" def buildRobotiumConfig(self, options, browserEnv): deviceRoot = self._dm.getDeviceRoot() fHandle = tempfile.NamedTemporaryFile(suffix='.config', prefix='robotium-', dir=os.getcwd(), delete=False) fHandle.write("profile=%s\n" % (self.remoteProfile)) fHandle.write("logfile=%s\n" % (options.remoteLogFile)) fHandle.write("host=http://mochi.test:8888/tests\n") fHandle.write("rawhost=http://%s:%s/tests\n" % (options.remoteWebServer, options.httpPort)) if browserEnv: envstr = "" delim = "" for key, value in browserEnv.items(): try: value.index(',') print "Found: Error an ',' in our value, unable to process value." except ValueError, e: envstr += "%s%s=%s" % (delim, key, value) delim = "," fHandle.write("envvars=%s\n" % envstr) fHandle.close() self._dm.removeFile(os.path.join(deviceRoot, "robotium.config")) self._dm.pushFile(fHandle.name, os.path.join(deviceRoot, "robotium.config")) os.unlink(fHandle.name)
class MochiRemote(Mochitest): _automation = None _dm = None localProfile = None logLines = [] def __init__(self, automation, devmgr, options): self._automation = automation Mochitest.__init__(self, self._automation) self._dm = devmgr self.runSSLTunnel = False self.remoteProfile = options.remoteTestRoot + "/profile" self._automation.setRemoteProfile(self.remoteProfile) self.remoteLog = options.remoteLogFile def cleanup(self, manifest, options): self._dm.getFile(self.remoteLog, self.localLog) self._dm.removeFile(self.remoteLog) self._dm.removeDir(self.remoteProfile) if (options.pidFile != ""): try: os.remove(options.pidFile) os.remove(options.pidFile + ".xpcshell.pid") except: print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % options.pidFile def findPath(self, paths, filename=None): for path in paths: p = path if filename: p = os.path.join(p, filename) if os.path.exists(self.getFullPath(p)): return path return None def startWebServer(self, options): """ Create the webserver on the host and start it up """ remoteXrePath = options.xrePath remoteProfilePath = options.profilePath remoteUtilityPath = options.utilityPath localAutomation = Automation() localAutomation.IS_WIN32 = False localAutomation.IS_LINUX = False localAutomation.IS_MAC = False localAutomation.UNIXISH = False hostos = sys.platform if (hostos == 'mac' or hostos == 'darwin'): localAutomation.IS_MAC = True elif (hostos == 'linux' or hostos == 'linux2'): localAutomation.IS_LINUX = True localAutomation.UNIXISH = True elif (hostos == 'win32' or hostos == 'win64'): localAutomation.BIN_SUFFIX = ".exe" localAutomation.IS_WIN32 = True paths = [ options.xrePath, localAutomation.DIST_BIN, self._automation._product, os.path.join('..', self._automation._product) ] options.xrePath = self.findPath(paths) if options.xrePath == None: print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % ( os.name) sys.exit(1) paths.append("bin") paths.append(os.path.join("..", "bin")) xpcshell = "xpcshell" if (os.name == "nt"): xpcshell += ".exe" if (options.utilityPath): paths.insert(0, options.utilityPath) options.utilityPath = self.findPath(paths, xpcshell) if options.utilityPath == None: print "ERROR: unable to find utility path for %s, please specify with --utility-path" % ( os.name) sys.exit(1) options.profilePath = tempfile.mkdtemp() self.server = MochitestServer(localAutomation, options) self.server.start() if (options.pidFile != ""): f = open(options.pidFile + ".xpcshell.pid", 'w') f.write("%s" % self.server._process.pid) f.close() self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT) options.xrePath = remoteXrePath options.utilityPath = remoteUtilityPath options.profilePath = remoteProfilePath def stopWebServer(self, options): self.server.stop() def buildProfile(self, options): if self.localProfile: options.profilePath = self.localProfile manifest = Mochitest.buildProfile(self, options) self.localProfile = options.profilePath self._dm.removeDir(self.remoteProfile) if self._dm.pushDir(options.profilePath, self.remoteProfile) == None: raise devicemanager.FileError("Unable to copy profile to device.") options.profilePath = self.remoteProfile return manifest def buildURLOptions(self, options, env): self.localLog = options.logFile options.logFile = self.remoteLog options.profilePath = self.localProfile retVal = Mochitest.buildURLOptions(self, options, env) #we really need testConfig.js (for browser chrome) if self._dm.pushDir(options.profilePath, self.remoteProfile) == None: raise devicemanager.FileError("Unable to copy profile to device.") options.profilePath = self.remoteProfile options.logFile = self.localLog return retVal def installChromeFile(self, filename, options): parts = options.app.split('/') if (parts[0] == options.app): return "NO_CHROME_ON_DROID" path = '/'.join(parts[:-1]) manifest = path + "/chrome/" + os.path.basename(filename) if self._dm.pushFile(filename, manifest) == False: raise devicemanager.FileError( "Unable to install Chrome files on device.") return manifest def getLogFilePath(self, logFile): return logFile # In the future we could use LogParser: http://hg.mozilla.org/automation/logparser/ def addLogData(self): with open(self.localLog) as currentLog: data = currentLog.readlines() restart = re.compile('0 INFO SimpleTest START.*') reend = re.compile('([0-9]+) INFO TEST-START . Shutdown.*') start_found = False end_found = False for line in data: if reend.match(line): end_found = True start_found = False return if start_found and not end_found: # Append the line without the number to increment self.logLines.append(' '.join(line.split(' ')[1:])) if restart.match(line): start_found = True def printLog(self): passed = 0 failed = 0 todo = 0 incr = 1 logFile = [] logFile.append("0 INFO SimpleTest START") for line in self.logLines: if line.startswith("INFO TEST-PASS"): passed += 1 elif line.startswith("INFO TEST-UNEXPECTED"): failed += 1 elif line.startswith("INFO TEST-KNOWN"): todo += 1 incr += 1 logFile.append("%s INFO TEST-START | Shutdown" % incr) incr += 1 logFile.append("%s INFO Passed: %s" % (incr, passed)) incr += 1 logFile.append("%s INFO Failed: %s" % (incr, failed)) incr += 1 logFile.append("%s INFO Todo: %s" % (incr, todo)) incr += 1 logFile.append("%s INFO SimpleTest FINISHED" % incr) # TODO: Consider not printing to stdout because we might be duplicating output print '\n'.join(logFile) with open(self.localLog, 'w') as localLog: localLog.write('\n'.join(logFile)) if failed > 0: return 1 return 0
class B2GMochitest(Mochitest): _automation = None _dm = None localProfile = None def __init__(self, automation, devmgr, options): self._automation = automation Mochitest.__init__(self, self._automation) self._dm = devmgr self.runSSLTunnel = False self.remoteProfile = options.remoteTestRoot + '/profile' self._automation.setRemoteProfile(self.remoteProfile) self.remoteLog = options.remoteLogFile self.remoteProfilesIniPath = '/data/b2g/mozilla/profiles.ini' self.originalProfilesIni = None def cleanup(self, manifest, options): self._dm.getFile(self.remoteLog, self.localLog) self._dm.removeFile(self.remoteLog) self._dm.removeDir(self.remoteProfile) if self.originalProfilesIni: try: self.restoreProfilesIni() os.remove(self.originalProfilesIni) except: pass if options.pidFile != "": try: os.remove(options.pidFile) os.remove(options.pidFile + ".xpcshell.pid") except: print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % options.pidFile # We've restored the original profile, so reboot the device so that # it gets picked up. self._automation.rebootDevice() def findPath(self, paths, filename = None): for path in paths: p = path if filename: p = os.path.join(p, filename) if os.path.exists(self.getFullPath(p)): return path return None def startWebServer(self, options): """ Create the webserver on the host and start it up """ remoteXrePath = options.xrePath remoteProfilePath = options.profilePath remoteUtilityPath = options.utilityPath localAutomation = Automation() localAutomation.IS_WIN32 = False localAutomation.IS_LINUX = False localAutomation.IS_MAC = False localAutomation.UNIXISH = False hostos = sys.platform if hostos in ['mac', 'darwin']: localAutomation.IS_MAC = True elif hostos in ['linux', 'linux2']: localAutomation.IS_LINUX = True localAutomation.UNIXISH = True elif hostos in ['win32', 'win64']: localAutomation.BIN_SUFFIX = ".exe" localAutomation.IS_WIN32 = True paths = [options.xrePath, localAutomation.DIST_BIN, self._automation._product, os.path.join('..', self._automation._product)] options.xrePath = self.findPath(paths) if options.xrePath == None: print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name) sys.exit(1) paths.append("bin") paths.append(os.path.join("..", "bin")) xpcshell = "xpcshell" if (os.name == "nt"): xpcshell += ".exe" if (options.utilityPath): paths.insert(0, options.utilityPath) options.utilityPath = self.findPath(paths, xpcshell) if options.utilityPath == None: print "ERROR: unable to find utility path for %s, please specify with --utility-path" % (os.name) sys.exit(1) options.profilePath = tempfile.mkdtemp() self.server = MochitestServer(localAutomation, options) self.server.start() if (options.pidFile != ""): f = open(options.pidFile + ".xpcshell.pid", 'w') f.write("%s" % self.server._process.pid) f.close() self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT) options.xrePath = remoteXrePath options.utilityPath = remoteUtilityPath options.profilePath = remoteProfilePath def stopWebServer(self, options): self.server.stop() def buildProfile(self, options): if self.localProfile: options.profilePath = self.localProfile print 'buildProfile', repr(options) manifest = Mochitest.buildProfile(self, options) self.localProfile = options.profilePath # Profile isn't actually copied to device until # buildURLOptions is called. options.profilePath = self.remoteProfile return manifest def restoreProfilesIni(self): # restore profiles.ini on the device to its previous state if not self.originalProfilesIni or not os.access(self.originalProfilesIni, os.F_OK): raise DMError('Unable to install original profiles.ini; file not found: %s', self.originalProfilesIni) self._dm.pushFile(self.originalProfilesIni, self.remoteProfilesIniPath) def updateProfilesIni(self, profilePath): # update profiles.ini on the device to point to the test profile self.originalProfilesIni = tempfile.mktemp() self._dm.getFile(self.remoteProfilesIniPath, self.originalProfilesIni) config = ProfileConfigParser() config.read(self.originalProfilesIni) for section in config.sections(): if 'Profile' in section: config.set(section, 'IsRelative', 0) config.set(section, 'Path', profilePath) newProfilesIni = tempfile.mktemp() with open(newProfilesIni, 'wb') as configfile: config.write(configfile) self._dm.pushFile(newProfilesIni, self.remoteProfilesIniPath) def buildURLOptions(self, options, env): self.localLog = options.logFile options.logFile = self.remoteLog options.profilePath = self.localProfile retVal = Mochitest.buildURLOptions(self, options, env) # set the testURL testURL = self.buildTestPath(options) if len(self.urlOpts) > 0: testURL += "?" + "&".join(self.urlOpts) self._automation.testURL = testURL # Set the B2G homepage as a static local page, since wi-fi generally # isn't available as soon as the device boots. f = open(os.path.join(options.profilePath, "user.js"), "a") f.write('user_pref("browser.homescreenURL", "data:text/html,mochitest-plain should start soon");\n') f.close() self._dm.removeDir(self.remoteProfile) if self._dm.pushDir(options.profilePath, self.remoteProfile) == None: raise devicemanager.FileError("Unable to copy profile to device.") self.updateProfilesIni(self.remoteProfile) options.profilePath = self.remoteProfile options.logFile = self.localLog return retVal
class MochiRemote(Mochitest): _automation = None _dm = None localProfile = None logLines = [] def __init__(self, automation, devmgr, options): self._automation = automation Mochitest.__init__(self) self._dm = devmgr self.runSSLTunnel = False self.environment = self._automation.environment self.remoteProfile = options.remoteTestRoot + "/profile" self._automation.setRemoteProfile(self.remoteProfile) self.remoteLog = options.remoteLogFile self.localLog = options.logFile self._automation.deleteANRs() def cleanup(self, manifest, options): if self._dm.fileExists(self.remoteLog): self._dm.getFile(self.remoteLog, self.localLog) self._dm.removeFile(self.remoteLog) else: log.warn("Unable to retrieve log file (%s) from remote device", self.remoteLog) self._dm.removeDir(self.remoteProfile) if options.pidFile != "": try: os.remove(options.pidFile) os.remove(options.pidFile + ".xpcshell.pid") except: log.warn("cleaning up pidfile '%s' was unsuccessful from the test harness", options.pidFile) def findPath(self, paths, filename=None): for path in paths: p = path if filename: p = os.path.join(p, filename) if os.path.exists(self.getFullPath(p)): return path return None def startWebServer(self, options): """ Create the webserver on the host and start it up """ remoteXrePath = options.xrePath remoteProfilePath = options.profilePath remoteUtilityPath = options.utilityPath localAutomation = Automation() localAutomation.IS_WIN32 = False localAutomation.IS_LINUX = False localAutomation.IS_MAC = False localAutomation.UNIXISH = False hostos = sys.platform if hostos == "mac" or hostos == "darwin": localAutomation.IS_MAC = True elif hostos == "linux" or hostos == "linux2": localAutomation.IS_LINUX = True localAutomation.UNIXISH = True elif hostos == "win32" or hostos == "win64": localAutomation.BIN_SUFFIX = ".exe" localAutomation.IS_WIN32 = True paths = [ options.xrePath, localAutomation.DIST_BIN, self._automation._product, os.path.join("..", self._automation._product), ] options.xrePath = self.findPath(paths) if options.xrePath == None: log.error("unable to find xulrunner path for %s, please specify with --xre-path", os.name) sys.exit(1) xpcshell = "xpcshell" if os.name == "nt": xpcshell += ".exe" if options.utilityPath: paths = [options.utilityPath, options.xrePath] else: paths = [options.xrePath] options.utilityPath = self.findPath(paths, xpcshell) if options.utilityPath == None: log.error("unable to find utility path for %s, please specify with --utility-path", os.name) sys.exit(1) # httpd-path is specified by standard makefile targets and may be specified # on the command line to select a particular version of httpd.js. If not # specified, try to select the one from hostutils.zip, as required in bug 882932. if not options.httpdPath: options.httpdPath = os.path.join(options.utilityPath, "components") xpcshell_path = os.path.join(options.utilityPath, xpcshell) if localAutomation.elf_arm(xpcshell_path): log.error( "xpcshell at %s is an ARM binary; please use " "the --utility-path argument to specify the path " "to a desktop version." % xpcshell_path ) sys.exit(1) options.profilePath = tempfile.mkdtemp() self.server = MochitestServer(options) self.server.start() if options.pidFile != "": f = open(options.pidFile + ".xpcshell.pid", "w") f.write("%s" % self.server._process.pid) f.close() self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT) options.xrePath = remoteXrePath options.utilityPath = remoteUtilityPath options.profilePath = remoteProfilePath def stopWebServer(self, options): if hasattr(self, "server"): self.server.stop() def buildProfile(self, options): if self.localProfile: options.profilePath = self.localProfile manifest = Mochitest.buildProfile(self, options) self.localProfile = options.profilePath self._dm.removeDir(self.remoteProfile) # we do not need this for robotium based tests, lets save a LOT of time if options.robocopIni: shutil.rmtree(os.path.join(options.profilePath, "webapps")) shutil.rmtree(os.path.join(options.profilePath, "extensions", "staged", "*****@*****.**")) shutil.rmtree(os.path.join(options.profilePath, "extensions", "staged", "*****@*****.**")) shutil.rmtree(os.path.join(options.profilePath, "extensions", "staged", "*****@*****.**")) os.remove(os.path.join(options.profilePath, "userChrome.css")) if os.path.exists(os.path.join(options.profilePath, "tests.jar")): os.remove(os.path.join(options.profilePath, "tests.jar")) if os.path.exists(os.path.join(options.profilePath, "tests.manifest")): os.remove(os.path.join(options.profilePath, "tests.manifest")) try: self._dm.pushDir(options.profilePath, self.remoteProfile) except devicemanager.DMError: log.error("Automation Error: Unable to copy profile to device.") raise options.profilePath = self.remoteProfile return manifest def buildURLOptions(self, options, env): self.localLog = options.logFile options.logFile = self.remoteLog options.profilePath = self.localProfile env["MOZ_HIDE_RESULTS_TABLE"] = "1" retVal = Mochitest.buildURLOptions(self, options, env) if not options.robocopIni: # we really need testConfig.js (for browser chrome) try: self._dm.pushDir(options.profilePath, self.remoteProfile) except devicemanager.DMError: log.error("Automation Error: Unable to copy profile to device.") raise options.profilePath = self.remoteProfile options.logFile = self.localLog return retVal def installChromeFile(self, filename, options): parts = options.app.split("/") if parts[0] == options.app: return "NO_CHROME_ON_DROID" path = "/".join(parts[:-1]) manifest = path + "/chrome/" + os.path.basename(filename) try: self._dm.pushFile(filename, manifest) except devicemanager.DMError: log.error("Automation Error: Unable to install Chrome files on device.") raise return manifest def getLogFilePath(self, logFile): return logFile # In the future we could use LogParser: http://hg.mozilla.org/automation/logparser/ def addLogData(self): with open(self.localLog) as currentLog: data = currentLog.readlines() restart = re.compile("0 INFO SimpleTest START.*") reend = re.compile("([0-9]+) INFO TEST-START . Shutdown.*") refail = re.compile("([0-9]+) INFO TEST-UNEXPECTED-FAIL.*") start_found = False end_found = False fail_found = False for line in data: if reend.match(line): end_found = True start_found = False break if start_found and not end_found: # Append the line without the number to increment self.logLines.append(" ".join(line.split(" ")[1:])) if restart.match(line): start_found = True if refail.match(line): fail_found = True result = 0 if fail_found: result = 1 if not end_found: log.error("Automation Error: Missing end of test marker (process crashed?)") result = 1 return result def printLog(self): passed = 0 failed = 0 todo = 0 incr = 1 logFile = [] logFile.append("0 INFO SimpleTest START") for line in self.logLines: if line.startswith("INFO TEST-PASS"): passed += 1 elif line.startswith("INFO TEST-UNEXPECTED"): failed += 1 elif line.startswith("INFO TEST-KNOWN"): todo += 1 incr += 1 logFile.append("%s INFO TEST-START | Shutdown" % incr) incr += 1 logFile.append("%s INFO Passed: %s" % (incr, passed)) incr += 1 logFile.append("%s INFO Failed: %s" % (incr, failed)) incr += 1 logFile.append("%s INFO Todo: %s" % (incr, todo)) incr += 1 logFile.append("%s INFO SimpleTest FINISHED" % incr) # TODO: Consider not printing to stdout because we might be duplicating output print "\n".join(logFile) with open(self.localLog, "w") as localLog: localLog.write("\n".join(logFile)) if failed > 0: return 1 return 0 def printScreenshots(self, screenShotDir): # TODO: This can be re-written after completion of bug 749421 if not self._dm.dirExists(screenShotDir): log.info("SCREENSHOT: No ScreenShots directory available: " + screenShotDir) return printed = 0 for name in self._dm.listFiles(screenShotDir): fullName = screenShotDir + "/" + name log.info("SCREENSHOT: FOUND: [%s]", fullName) try: image = self._dm.pullFile(fullName) encoded = base64.b64encode(image) log.info("SCREENSHOT: data:image/jpg;base64,%s", encoded) printed += 1 except: log.info("SCREENSHOT: Could not be parsed") pass log.info("SCREENSHOT: TOTAL PRINTED: [%s]", printed) def printDeviceInfo(self, printLogcat=False): try: if printLogcat: logcat = self._dm.getLogcat(filterOutRegexps=fennecLogcatFilters) log.info("\n" + ("".join(logcat))) log.info("Device info: %s", self._dm.getInfo()) log.info("Test root: %s", self._dm.getDeviceRoot()) except devicemanager.DMError: log.warn("Error getting device information") def buildRobotiumConfig(self, options, browserEnv): deviceRoot = self._dm.getDeviceRoot() fHandle = tempfile.NamedTemporaryFile(suffix=".config", prefix="robotium-", dir=os.getcwd(), delete=False) fHandle.write("profile=%s\n" % (self.remoteProfile)) fHandle.write("logfile=%s\n" % (options.remoteLogFile)) fHandle.write("host=http://mochi.test:8888/tests\n") fHandle.write("rawhost=http://%s:%s/tests\n" % (options.remoteWebServer, options.httpPort)) if browserEnv: envstr = "" delim = "" for key, value in browserEnv.items(): try: value.index(",") log.error( "buildRobotiumConfig: browserEnv - Found a ',' in our value, unable to process value. key=%s,value=%s", key, value, ) log.error("browserEnv=%s", browserEnv) except ValueError, e: envstr += "%s%s=%s" % (delim, key, value) delim = "," fHandle.write("envvars=%s\n" % envstr) fHandle.close() self._dm.removeFile(os.path.join(deviceRoot, "robotium.config")) self._dm.pushFile(fHandle.name, os.path.join(deviceRoot, "robotium.config")) os.unlink(fHandle.name)
class B2GMochitest(Mochitest): _automation = None _dm = None localProfile = None testDir = '/data/local/tests' def __init__(self, automation, devmgr, options): self._automation = automation Mochitest.__init__(self, self._automation) self._dm = devmgr self.runSSLTunnel = False self.remoteProfile = options.remoteTestRoot + '/profile' self._automation.setRemoteProfile(self.remoteProfile) self.remoteLog = options.remoteLogFile self.localLog = None self.userJS = '/data/local/user.js' self.remoteMozillaPath = '/data/b2g/mozilla' self.remoteProfilesIniPath = os.path.join(self.remoteMozillaPath, 'profiles.ini') self.originalProfilesIni = None def copyRemoteFile(self, src, dest): if self._dm.useDDCopy: self._dm._checkCmdAs( ['shell', 'dd', 'if=%s' % src, 'of=%s' % dest]) else: self._dm._checkCmdAs(['shell', 'cp', src, dest]) def origUserJSExists(self): return self._dm.fileExists('/data/local/user.js.orig') def cleanup(self, manifest, options): if self.localLog: self._dm.getFile(self.remoteLog, self.localLog) self._dm.removeFile(self.remoteLog) if not options.emulator: # Remove the test profile self._dm._checkCmdAs(['shell', 'rm', '-r', self.remoteProfile]) if self.origUserJSExists(): # Restore the original user.js self._dm.removeFile(self.userJS) self.copyRemoteFile('%s.orig' % self.userJS, self.userJS) self._dm.removeFile("%s.orig" % self.userJS) if self._dm.fileExists('%s.orig' % self.remoteProfilesIniPath): # Restore the original profiles.ini self._dm.removeFile(self.remoteProfilesIniPath) self.copyRemoteFile('%s.orig' % self.remoteProfilesIniPath, self.remoteProfilesIniPath) self._dm.removeFile("%s.orig" % self.remoteProfilesIniPath) # We've restored the original profile, so reboot the device so that # it gets picked up. self._automation.rebootDevice() if options.pidFile != "": try: os.remove(options.pidFile) os.remove(options.pidFile + ".xpcshell.pid") except: print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % options.pidFile def findPath(self, paths, filename=None): for path in paths: p = path if filename: p = os.path.join(p, filename) if os.path.exists(self.getFullPath(p)): return path return None def startWebServer(self, options): """ Create the webserver on the host and start it up """ remoteXrePath = options.xrePath remoteProfilePath = options.profilePath remoteUtilityPath = options.utilityPath localAutomation = Automation() localAutomation.IS_WIN32 = False localAutomation.IS_LINUX = False localAutomation.IS_MAC = False localAutomation.UNIXISH = False hostos = sys.platform if hostos in ['mac', 'darwin']: localAutomation.IS_MAC = True elif hostos in ['linux', 'linux2']: localAutomation.IS_LINUX = True localAutomation.UNIXISH = True elif hostos in ['win32', 'win64']: localAutomation.BIN_SUFFIX = ".exe" localAutomation.IS_WIN32 = True paths = [ options.xrePath, localAutomation.DIST_BIN, self._automation._product, os.path.join('..', self._automation._product) ] options.xrePath = self.findPath(paths) if options.xrePath == None: print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % ( os.name) sys.exit(1) paths.append("bin") paths.append(os.path.join("..", "bin")) xpcshell = "xpcshell" if (os.name == "nt"): xpcshell += ".exe" if (options.utilityPath): paths.insert(0, options.utilityPath) options.utilityPath = self.findPath(paths, xpcshell) if options.utilityPath == None: print "ERROR: unable to find utility path for %s, please specify with --utility-path" % ( os.name) sys.exit(1) options.profilePath = tempfile.mkdtemp() self.server = MochitestServer(localAutomation, options) self.server.start() if (options.pidFile != ""): f = open(options.pidFile + ".xpcshell.pid", 'w') f.write("%s" % self.server._process.pid) f.close() self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT) options.xrePath = remoteXrePath options.utilityPath = remoteUtilityPath options.profilePath = remoteProfilePath def stopWebServer(self, options): if hasattr(self, 'server'): self.server.stop() def buildProfile(self, options): if self.localProfile: options.profilePath = self.localProfile manifest = Mochitest.buildProfile(self, options) self.localProfile = options.profilePath # Profile isn't actually copied to device until # buildURLOptions is called. options.profilePath = self.remoteProfile return manifest def updateProfilesIni(self, profilePath): # update profiles.ini on the device to point to the test profile self.originalProfilesIni = tempfile.mktemp() self._dm.getFile(self.remoteProfilesIniPath, self.originalProfilesIni) config = ProfileConfigParser() config.read(self.originalProfilesIni) for section in config.sections(): if 'Profile' in section: config.set(section, 'IsRelative', 0) config.set(section, 'Path', profilePath) newProfilesIni = tempfile.mktemp() with open(newProfilesIni, 'wb') as configfile: config.write(configfile) self._dm.pushFile(newProfilesIni, self.remoteProfilesIniPath) self._dm.pushFile(self.originalProfilesIni, '%s.orig' % self.remoteProfilesIniPath) try: os.remove(newProfilesIni) os.remove(self.originalProfilesIni) except: pass def buildURLOptions(self, options, env): self.localLog = options.logFile options.logFile = self.remoteLog options.profilePath = self.localProfile retVal = Mochitest.buildURLOptions(self, options, env) # set the testURL testURL = self.buildTestPath(options) if len(self.urlOpts) > 0: testURL += "?" + "&".join(self.urlOpts) self._automation.testURL = testURL # Set extra prefs for B2G. f = open(os.path.join(options.profilePath, "user.js"), "a") f.write(""" user_pref("browser.homescreenURL","app://system.gaiamobile.org");\n user_pref("dom.mozBrowserFramesEnabled", true);\n user_pref("dom.ipc.tabs.disabled", false);\n user_pref("dom.ipc.browser_frames.oop_by_default", true);\n user_pref("browser.manifestURL","app://system.gaiamobile.org/manifest.webapp");\n user_pref("dom.mozBrowserFramesWhitelist","app://system.gaiamobile.org,http://mochi.test:8888");\n user_pref("network.dns.localDomains","app://system.gaiamobile.org");\n """) f.close() # Copy the profile to the device. self._dm._checkCmdAs(['shell', 'rm', '-r', self.remoteProfile]) if self._dm.pushDir(options.profilePath, self.remoteProfile) == None: raise devicemanager.FileError("Unable to copy profile to device.") # In B2G, user.js is always read from /data/local, not the profile # directory. Backup the original user.js first so we can restore it. if not self._dm.fileExists('%s.orig' % self.userJS): self.copyRemoteFile(self.userJS, '%s.orig' % self.userJS) self._dm.pushFile(os.path.join(options.profilePath, "user.js"), self.userJS) self.updateProfilesIni(self.remoteProfile) options.profilePath = self.remoteProfile options.logFile = self.localLog return retVal
class B2GDeviceMochitest(B2GMochitest): _automation = None _dm = None def __init__(self, automation, devmgr, options): self._automation = automation B2GMochitest.__init__(self, automation, OOP=True, profile_data_dir=options.profile_data_dir) self._dm = devmgr self.runSSLTunnel = False self.remoteProfile = options.remoteTestRoot + '/profile' self._automation.setRemoteProfile(self.remoteProfile) self.remoteLog = options.remoteLogFile self.localLog = None self.userJS = '/data/local/user.js' self.remoteMozillaPath = '/data/b2g/mozilla' self.bundlesDir = '/system/b2g/distribution/bundles' self.remoteProfilesIniPath = os.path.join(self.remoteMozillaPath, 'profiles.ini') self.originalProfilesIni = None def copyRemoteFile(self, src, dest): self._dm._checkCmdAs(['shell', 'dd', 'if=%s' % src, 'of=%s' % dest]) def origUserJSExists(self): return self._dm.fileExists('/data/local/user.js.orig') def cleanup(self, manifest, options): if self.localLog: self._dm.getFile(self.remoteLog, self.localLog) self._dm.removeFile(self.remoteLog) # Delete any bundled extensions extensionDir = os.path.join(options.profilePath, 'extensions', 'staged') if os.access(extensionDir, os.F_OK): for filename in os.listdir(extensionDir): try: self._dm._checkCmdAs([ 'shell', 'rm', '-rf', os.path.join(self.bundlesDir, filename) ]) except DMError: pass if not options.emulator: # Remove the test profile self._dm._checkCmdAs(['shell', 'rm', '-r', self.remoteProfile]) if self.origUserJSExists(): # Restore the original user.js self._dm.removeFile(self.userJS) self.copyRemoteFile('%s.orig' % self.userJS, self.userJS) self._dm.removeFile("%s.orig" % self.userJS) if self._dm.fileExists('%s.orig' % self.remoteProfilesIniPath): # Restore the original profiles.ini self._dm.removeFile(self.remoteProfilesIniPath) self.copyRemoteFile('%s.orig' % self.remoteProfilesIniPath, self.remoteProfilesIniPath) self._dm.removeFile("%s.orig" % self.remoteProfilesIniPath) # We've restored the original profile, so reboot the device so that # it gets picked up. self._automation.rebootDevice() if options.pidFile != "": try: os.remove(options.pidFile) os.remove(options.pidFile + ".xpcshell.pid") except: print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % options.pidFile def findPath(self, paths, filename=None): for path in paths: p = path if filename: p = os.path.join(p, filename) if os.path.exists(self.getFullPath(p)): return path return None def startWebServer(self, options): """ Create the webserver on the host and start it up """ remoteXrePath = options.xrePath remoteProfilePath = options.profilePath remoteUtilityPath = options.utilityPath localAutomation = Automation() localAutomation.IS_WIN32 = False localAutomation.IS_LINUX = False localAutomation.IS_MAC = False localAutomation.UNIXISH = False hostos = sys.platform if hostos in ['mac', 'darwin']: localAutomation.IS_MAC = True elif hostos in ['linux', 'linux2']: localAutomation.IS_LINUX = True localAutomation.UNIXISH = True elif hostos in ['win32', 'win64']: localAutomation.BIN_SUFFIX = ".exe" localAutomation.IS_WIN32 = True paths = [ options.xrePath, localAutomation.DIST_BIN, self._automation._product, os.path.join('..', self._automation._product) ] options.xrePath = self.findPath(paths) if options.xrePath == None: print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % ( os.name) sys.exit(1) paths.append("bin") paths.append(os.path.join("..", "bin")) xpcshell = "xpcshell" if (os.name == "nt"): xpcshell += ".exe" if (options.utilityPath): paths.insert(0, options.utilityPath) options.utilityPath = self.findPath(paths, xpcshell) if options.utilityPath == None: print "ERROR: unable to find utility path for %s, please specify with --utility-path" % ( os.name) sys.exit(1) options.profilePath = tempfile.mkdtemp() self.server = MochitestServer(localAutomation, options) self.server.start() if (options.pidFile != ""): f = open(options.pidFile + ".xpcshell.pid", 'w') f.write("%s" % self.server._process.pid) f.close() self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT) options.xrePath = remoteXrePath options.utilityPath = remoteUtilityPath options.profilePath = remoteProfilePath def stopWebServer(self, options): if hasattr(self, 'server'): self.server.stop() def updateProfilesIni(self, profilePath): # update profiles.ini on the device to point to the test profile self.originalProfilesIni = tempfile.mktemp() self._dm.getFile(self.remoteProfilesIniPath, self.originalProfilesIni) config = ProfileConfigParser() config.read(self.originalProfilesIni) for section in config.sections(): if 'Profile' in section: config.set(section, 'IsRelative', 0) config.set(section, 'Path', profilePath) newProfilesIni = tempfile.mktemp() with open(newProfilesIni, 'wb') as configfile: config.write(configfile) self._dm.pushFile(newProfilesIni, self.remoteProfilesIniPath) self._dm.pushFile(self.originalProfilesIni, '%s.orig' % self.remoteProfilesIniPath) try: os.remove(newProfilesIni) os.remove(self.originalProfilesIni) except: pass def buildURLOptions(self, options, env): self.localLog = options.logFile options.logFile = self.remoteLog options.profilePath = self.profile.profile retVal = Mochitest.buildURLOptions(self, options, env) self.setupCommonOptions(options) # Copy the profile to the device. self._dm._checkCmdAs(['shell', 'rm', '-r', self.remoteProfile]) try: self._dm.pushDir(options.profilePath, self.remoteProfile) except DMError: print "Automation Error: Unable to copy profile to device." raise # Copy the extensions to the B2G bundles dir. extensionDir = os.path.join(options.profilePath, 'extensions', 'staged') # need to write to read-only dir self._dm._checkCmdAs(['remount']) for filename in os.listdir(extensionDir): self._dm._checkCmdAs([ 'shell', 'rm', '-rf', os.path.join(self.bundlesDir, filename) ]) try: self._dm.pushDir(extensionDir, self.bundlesDir) except DMError: print "Automation Error: Unable to copy extensions to device." raise # In B2G, user.js is always read from /data/local, not the profile # directory. Backup the original user.js first so we can restore it. if not self._dm.fileExists('%s.orig' % self.userJS): self.copyRemoteFile(self.userJS, '%s.orig' % self.userJS) self._dm.pushFile(os.path.join(options.profilePath, "user.js"), self.userJS) self.updateProfilesIni(self.remoteProfile) options.profilePath = self.remoteProfile options.logFile = self.localLog return retVal
class MochiRemote(Mochitest): _automation = None _dm = None localProfile = None logLines = [] def __init__(self, automation, devmgr, options): self._automation = automation Mochitest.__init__(self) self._dm = devmgr self.runSSLTunnel = False self.environment = self._automation.environment self.remoteProfile = options.remoteTestRoot + "/profile" self._automation.setRemoteProfile(self.remoteProfile) self.remoteLog = options.remoteLogFile self.localLog = options.logFile self._automation.deleteANRs() def cleanup(self, manifest, options): if self._dm.fileExists(self.remoteLog): self._dm.getFile(self.remoteLog, self.localLog) self._dm.removeFile(self.remoteLog) else: log.warn("Unable to retrieve log file (%s) from remote device", self.remoteLog) self._dm.removeDir(self.remoteProfile) if (options.pidFile != ""): try: os.remove(options.pidFile) os.remove(options.pidFile + ".xpcshell.pid") except: log.warn("cleaning up pidfile '%s' was unsuccessful from the test harness", options.pidFile) def findPath(self, paths, filename = None): for path in paths: p = path if filename: p = os.path.join(p, filename) if os.path.exists(self.getFullPath(p)): return path return None def startWebServer(self, options): """ Create the webserver on the host and start it up """ remoteXrePath = options.xrePath remoteProfilePath = options.profilePath remoteUtilityPath = options.utilityPath localAutomation = Automation() localAutomation.IS_WIN32 = False localAutomation.IS_LINUX = False localAutomation.IS_MAC = False localAutomation.UNIXISH = False hostos = sys.platform if (hostos == 'mac' or hostos == 'darwin'): localAutomation.IS_MAC = True elif (hostos == 'linux' or hostos == 'linux2'): localAutomation.IS_LINUX = True localAutomation.UNIXISH = True elif (hostos == 'win32' or hostos == 'win64'): localAutomation.BIN_SUFFIX = ".exe" localAutomation.IS_WIN32 = True paths = [options.xrePath, localAutomation.DIST_BIN, self._automation._product, os.path.join('..', self._automation._product)] options.xrePath = self.findPath(paths) if options.xrePath == None: log.error("unable to find xulrunner path for %s, please specify with --xre-path", os.name) sys.exit(1) xpcshell = "xpcshell" if (os.name == "nt"): xpcshell += ".exe" if options.utilityPath: paths = [options.utilityPath, options.xrePath] else: paths = [options.xrePath] options.utilityPath = self.findPath(paths, xpcshell) if options.utilityPath == None: log.error("unable to find utility path for %s, please specify with --utility-path", os.name) sys.exit(1) # httpd-path is specified by standard makefile targets and may be specified # on the command line to select a particular version of httpd.js. If not # specified, try to select the one from hostutils.zip, as required in bug 882932. if not options.httpdPath: options.httpdPath = os.path.join(options.utilityPath, "components") xpcshell_path = os.path.join(options.utilityPath, xpcshell) if localAutomation.elf_arm(xpcshell_path): log.error('xpcshell at %s is an ARM binary; please use ' 'the --utility-path argument to specify the path ' 'to a desktop version.' % xpcshell_path) sys.exit(1) options.profilePath = tempfile.mkdtemp() self.server = MochitestServer(options) self.server.start() if (options.pidFile != ""): f = open(options.pidFile + ".xpcshell.pid", 'w') f.write("%s" % self.server._process.pid) f.close() self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT) options.xrePath = remoteXrePath options.utilityPath = remoteUtilityPath options.profilePath = remoteProfilePath def stopWebServer(self, options): if hasattr(self, 'server'): self.server.stop() def buildProfile(self, options): if self.localProfile: options.profilePath = self.localProfile manifest = Mochitest.buildProfile(self, options) self.localProfile = options.profilePath self._dm.removeDir(self.remoteProfile) # we do not need this for robotium based tests, lets save a LOT of time if options.robocopIni: shutil.rmtree(os.path.join(options.profilePath, 'webapps')) shutil.rmtree(os.path.join(options.profilePath, 'extensions', 'staged', '*****@*****.**')) shutil.rmtree(os.path.join(options.profilePath, 'extensions', 'staged', '*****@*****.**')) shutil.rmtree(os.path.join(options.profilePath, 'extensions', 'staged', '*****@*****.**')) os.remove(os.path.join(options.profilePath, 'userChrome.css')) try: self._dm.pushDir(options.profilePath, self.remoteProfile) except devicemanager.DMError: log.error("Automation Error: Unable to copy profile to device.") raise options.profilePath = self.remoteProfile return manifest def buildURLOptions(self, options, env): self.localLog = options.logFile options.logFile = self.remoteLog options.profilePath = self.localProfile env["MOZ_HIDE_RESULTS_TABLE"] = "1" retVal = Mochitest.buildURLOptions(self, options, env) if not options.robocopIni: #we really need testConfig.js (for browser chrome) try: self._dm.pushDir(options.profilePath, self.remoteProfile) except devicemanager.DMError: log.error("Automation Error: Unable to copy profile to device.") raise options.profilePath = self.remoteProfile options.logFile = self.localLog return retVal def installChromeFile(self, filename, options): parts = options.app.split('/') if (parts[0] == options.app): return "NO_CHROME_ON_DROID" path = '/'.join(parts[:-1]) manifest = path + "/chrome/" + os.path.basename(filename) try: self._dm.pushFile(filename, manifest) except devicemanager.DMError: log.error("Automation Error: Unable to install Chrome files on device.") raise return manifest def getLogFilePath(self, logFile): return logFile # In the future we could use LogParser: http://hg.mozilla.org/automation/logparser/ def addLogData(self): with open(self.localLog) as currentLog: data = currentLog.readlines() restart = re.compile('0 INFO SimpleTest START.*') reend = re.compile('([0-9]+) INFO TEST-START . Shutdown.*') refail = re.compile('([0-9]+) INFO TEST-UNEXPECTED-FAIL.*') start_found = False end_found = False fail_found = False for line in data: if reend.match(line): end_found = True start_found = False break if start_found and not end_found: # Append the line without the number to increment self.logLines.append(' '.join(line.split(' ')[1:])) if restart.match(line): start_found = True if refail.match(line): fail_found = True result = 0 if fail_found: result = 1 if not end_found: log.error("Automation Error: Missing end of test marker (process crashed?)") result = 1 return result def printLog(self): passed = 0 failed = 0 todo = 0 incr = 1 logFile = [] logFile.append("0 INFO SimpleTest START") for line in self.logLines: if line.startswith("INFO TEST-PASS"): passed += 1 elif line.startswith("INFO TEST-UNEXPECTED"): failed += 1 elif line.startswith("INFO TEST-KNOWN"): todo += 1 incr += 1 logFile.append("%s INFO TEST-START | Shutdown" % incr) incr += 1 logFile.append("%s INFO Passed: %s" % (incr, passed)) incr += 1 logFile.append("%s INFO Failed: %s" % (incr, failed)) incr += 1 logFile.append("%s INFO Todo: %s" % (incr, todo)) incr += 1 logFile.append("%s INFO SimpleTest FINISHED" % incr) # TODO: Consider not printing to stdout because we might be duplicating output print '\n'.join(logFile) with open(self.localLog, 'w') as localLog: localLog.write('\n'.join(logFile)) if failed > 0: return 1 return 0 def printScreenshots(self, screenShotDir): # TODO: This can be re-written after completion of bug 749421 if not self._dm.dirExists(screenShotDir): log.info("SCREENSHOT: No ScreenShots directory available: " + screenShotDir) return printed = 0 for name in self._dm.listFiles(screenShotDir): fullName = screenShotDir + "/" + name log.info("SCREENSHOT: FOUND: [%s]", fullName) try: image = self._dm.pullFile(fullName) encoded = base64.b64encode(image) log.info("SCREENSHOT: data:image/jpg;base64,%s", encoded) printed += 1 except: log.info("SCREENSHOT: Could not be parsed") pass log.info("SCREENSHOT: TOTAL PRINTED: [%s]", printed) def printDeviceInfo(self, printLogcat=False): try: if printLogcat: logcat = self._dm.getLogcat(filterOutRegexps=fennecLogcatFilters) log.info('\n'+(''.join(logcat))) log.info("Device info: %s", self._dm.getInfo()) log.info("Test root: %s", self._dm.getDeviceRoot()) except devicemanager.DMError: log.warn("Error getting device information") def buildRobotiumConfig(self, options, browserEnv): deviceRoot = self._dm.getDeviceRoot() fHandle = tempfile.NamedTemporaryFile(suffix='.config', prefix='robotium-', dir=os.getcwd(), delete=False) fHandle.write("profile=%s\n" % (self.remoteProfile)) fHandle.write("logfile=%s\n" % (options.remoteLogFile)) fHandle.write("host=http://mochi.test:8888/tests\n") fHandle.write("rawhost=http://%s:%s/tests\n" % (options.remoteWebServer, options.httpPort)) if browserEnv: envstr = "" delim = "" for key, value in browserEnv.items(): try: value.index(',') log.error("buildRobotiumConfig: browserEnv - Found a ',' in our value, unable to process value. key=%s,value=%s", key, value) log.error("browserEnv=%s", browserEnv) except ValueError, e: envstr += "%s%s=%s" % (delim, key, value) delim = "," fHandle.write("envvars=%s\n" % envstr) fHandle.close() self._dm.removeFile(os.path.join(deviceRoot, "robotium.config")) self._dm.pushFile(fHandle.name, os.path.join(deviceRoot, "robotium.config")) os.unlink(fHandle.name)
class MochiRemote(Mochitest): _automation = None _dm = None def __init__(self, automation, devmgr, options): self._automation = automation Mochitest.__init__(self, self._automation) self._dm = devmgr self.runSSLTunnel = False self.remoteProfile = options.remoteTestRoot + "/profile" self.remoteLog = options.remoteLogFile def cleanup(self, manifest, options): self._dm.getFile(self.remoteLog, self.localLog) self._dm.removeFile(self.remoteLog) self._dm.removeDir(self.remoteProfile) def findPath(self, paths, filename = None): for path in paths: p = path if filename: p = os.path.join(p, filename) if os.path.exists(self.getFullPath(p)): return path return None def startWebServer(self, options): """ Create the webserver on the host and start it up """ remoteXrePath = options.xrePath remoteProfilePath = options.profilePath remoteUtilityPath = options.utilityPath localAutomation = Automation() paths = [options.xrePath, localAutomation.DIST_BIN, self._automation._product, os.path.join('..', self._automation._product)] options.xrePath = self.findPath(paths) if options.xrePath == None: print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name) sys.exit(1) paths.append("bin") paths.append(os.path.join("..", "bin")) xpcshell = "xpcshell" if (os.name == "nt"): xpcshell += ".exe" if (options.utilityPath): paths.insert(0, options.utilityPath) options.utilityPath = self.findPath(paths, xpcshell) if options.utilityPath == None: print "ERROR: unable to find utility path for %s, please specify with --utility-path" % (os.name) sys.exit(1) options.profilePath = tempfile.mkdtemp() self.server = MochitestServer(localAutomation, options) self.server.start() self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT) options.xrePath = remoteXrePath options.utilityPath = remoteUtilityPath options.profilePath = remoteProfilePath def stopWebServer(self, options): self.server.stop() def buildProfile(self, options): manifest = Mochitest.buildProfile(self, options) self.localProfile = options.profilePath if self._dm.pushDir(options.profilePath, self.remoteProfile) == None: raise devicemanager.FileError("Unable to copy profile to device.") options.profilePath = self.remoteProfile return manifest def buildURLOptions(self, options): self.localLog = options.logFile options.logFile = self.remoteLog retVal = Mochitest.buildURLOptions(self, options) options.logFile = self.localLog return retVal def installChromeFile(self, filename, options): parts = options.app.split('/') if (parts[0] == options.app): return "NO_CHROME_ON_DROID" path = '/'.join(parts[:-1]) manifest = path + "/chrome/" + os.path.basename(filename) if self._dm.pushFile(filename, manifest) == None: raise devicemanager.FileError("Unable to install Chrome files on device.") return manifest def getLogFilePath(self, logFile): return logFile
class MochiRemote(Mochitest): _automation = None _dm = None localProfile = None logLines = [] def __init__(self, automation, devmgr, options): self._automation = automation Mochitest.__init__(self, self._automation) self._dm = devmgr self.runSSLTunnel = False self.remoteProfile = options.remoteTestRoot + "/profile" self._automation.setRemoteProfile(self.remoteProfile) self.remoteLog = options.remoteLogFile self.localLog = options.logFile def cleanup(self, manifest, options): if self._dm.fileExists(self.remoteLog): self._dm.getFile(self.remoteLog, self.localLog) self._dm.removeFile(self.remoteLog) else: print "WARNING: Unable to retrieve log file (%s) from remote " "device" % self.remoteLog self._dm.removeDir(self.remoteProfile) if options.pidFile != "": try: os.remove(options.pidFile) os.remove(options.pidFile + ".xpcshell.pid") except: print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % options.pidFile def findPath(self, paths, filename=None): for path in paths: p = path if filename: p = os.path.join(p, filename) if os.path.exists(self.getFullPath(p)): return path return None def startWebServer(self, options): """ Create the webserver on the host and start it up """ remoteXrePath = options.xrePath remoteProfilePath = options.profilePath remoteUtilityPath = options.utilityPath localAutomation = Automation() localAutomation.IS_WIN32 = False localAutomation.IS_LINUX = False localAutomation.IS_MAC = False localAutomation.UNIXISH = False hostos = sys.platform if hostos == "mac" or hostos == "darwin": localAutomation.IS_MAC = True elif hostos == "linux" or hostos == "linux2": localAutomation.IS_LINUX = True localAutomation.UNIXISH = True elif hostos == "win32" or hostos == "win64": localAutomation.BIN_SUFFIX = ".exe" localAutomation.IS_WIN32 = True paths = [ options.xrePath, localAutomation.DIST_BIN, self._automation._product, os.path.join("..", self._automation._product), ] options.xrePath = self.findPath(paths) if options.xrePath == None: print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name) sys.exit(1) paths.append("bin") paths.append(os.path.join("..", "bin")) xpcshell = "xpcshell" if os.name == "nt": xpcshell += ".exe" if options.utilityPath: paths.insert(0, options.utilityPath) options.utilityPath = self.findPath(paths, xpcshell) if options.utilityPath == None: print "ERROR: unable to find utility path for %s, please specify with --utility-path" % (os.name) sys.exit(1) options.profilePath = tempfile.mkdtemp() self.server = MochitestServer(localAutomation, options) self.server.start() if options.pidFile != "": f = open(options.pidFile + ".xpcshell.pid", "w") f.write("%s" % self.server._process.pid) f.close() self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT) options.xrePath = remoteXrePath options.utilityPath = remoteUtilityPath options.profilePath = remoteProfilePath def stopWebServer(self, options): self.server.stop() def buildProfile(self, options): if self.localProfile: options.profilePath = self.localProfile manifest = Mochitest.buildProfile(self, options) self.localProfile = options.profilePath self._dm.removeDir(self.remoteProfile) try: self._dm.pushDir(options.profilePath, self.remoteProfile) except devicemanager.DMError: print "Automation Error: Unable to copy profile to device." raise options.profilePath = self.remoteProfile return manifest def buildURLOptions(self, options, env): self.localLog = options.logFile options.logFile = self.remoteLog options.profilePath = self.localProfile retVal = Mochitest.buildURLOptions(self, options, env) # we really need testConfig.js (for browser chrome) try: self._dm.pushDir(options.profilePath, self.remoteProfile) except devicemanager.DMError: print "Automation Error: Unable to copy profile to device." raise options.profilePath = self.remoteProfile options.logFile = self.localLog return retVal def installChromeFile(self, filename, options): parts = options.app.split("/") if parts[0] == options.app: return "NO_CHROME_ON_DROID" path = "/".join(parts[:-1]) manifest = path + "/chrome/" + os.path.basename(filename) try: self._dm.pushFile(filename, manifest) except devicemanager.DMError: print "Automation Error: Unable to install Chrome files on device." raise return manifest def getLogFilePath(self, logFile): return logFile # In the future we could use LogParser: http://hg.mozilla.org/automation/logparser/ def addLogData(self): with open(self.localLog) as currentLog: data = currentLog.readlines() restart = re.compile("0 INFO SimpleTest START.*") reend = re.compile("([0-9]+) INFO TEST-START . Shutdown.*") start_found = False end_found = False for line in data: if reend.match(line): end_found = True start_found = False return if start_found and not end_found: # Append the line without the number to increment self.logLines.append(" ".join(line.split(" ")[1:])) if restart.match(line): start_found = True def printLog(self): passed = 0 failed = 0 todo = 0 incr = 1 logFile = [] logFile.append("0 INFO SimpleTest START") for line in self.logLines: if line.startswith("INFO TEST-PASS"): passed += 1 elif line.startswith("INFO TEST-UNEXPECTED"): failed += 1 elif line.startswith("INFO TEST-KNOWN"): todo += 1 incr += 1 logFile.append("%s INFO TEST-START | Shutdown" % incr) incr += 1 logFile.append("%s INFO Passed: %s" % (incr, passed)) incr += 1 logFile.append("%s INFO Failed: %s" % (incr, failed)) incr += 1 logFile.append("%s INFO Todo: %s" % (incr, todo)) incr += 1 logFile.append("%s INFO SimpleTest FINISHED" % incr) # TODO: Consider not printing to stdout because we might be duplicating output print "\n".join(logFile) with open(self.localLog, "w") as localLog: localLog.write("\n".join(logFile)) if failed > 0: return 1 return 0 def buildRobotiumConfig(self, options, browserEnv): deviceRoot = self._dm.getDeviceRoot() fHandle = tempfile.NamedTemporaryFile(suffix=".config", prefix="robotium-", dir=os.getcwd(), delete=False) fHandle.write("profile=%s\n" % (self.remoteProfile)) fHandle.write("logfile=%s\n" % (options.remoteLogFile)) fHandle.write("host=http://mochi.test:8888/tests\n") fHandle.write("rawhost=http://%s:%s/tests\n" % (options.remoteWebServer, options.httpPort)) if browserEnv: envstr = "" delim = "" for key, value in browserEnv.items(): try: value.index(",") print "Found: Error an ',' in our value, unable to process value." except ValueError, e: envstr += "%s%s=%s" % (delim, key, value) delim = "," fHandle.write("envvars=%s\n" % envstr) fHandle.close() self._dm.removeFile(os.path.join(deviceRoot, "robotium.config")) self._dm.pushFile(fHandle.name, os.path.join(deviceRoot, "robotium.config")) os.unlink(fHandle.name)
class MochiRemote(Mochitest): _automation = None _dm = None localProfile = None logLines = [] def __init__(self, automation, devmgr, options): self._automation = automation Mochitest.__init__(self, self._automation) self._dm = devmgr self.runSSLTunnel = False self.remoteProfile = options.remoteTestRoot + "/profile" self._automation.setRemoteProfile(self.remoteProfile) self.remoteLog = options.remoteLogFile self.localLog = options.logFile def cleanup(self, manifest, options): if self._dm.fileExists(self.remoteLog): self._dm.getFile(self.remoteLog, self.localLog) self._dm.removeFile(self.remoteLog) else: print "WARNING: Unable to retrieve log file (%s) from remote " \ "device" % self.remoteLog self._dm.removeDir(self.remoteProfile) if (options.pidFile != ""): try: os.remove(options.pidFile) os.remove(options.pidFile + ".xpcshell.pid") except: print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % options.pidFile def findPath(self, paths, filename = None): for path in paths: p = path if filename: p = os.path.join(p, filename) if os.path.exists(self.getFullPath(p)): return path return None def startWebServer(self, options): """ Create the webserver on the host and start it up """ remoteXrePath = options.xrePath remoteProfilePath = options.profilePath remoteUtilityPath = options.utilityPath localAutomation = Automation() localAutomation.IS_WIN32 = False localAutomation.IS_LINUX = False localAutomation.IS_MAC = False localAutomation.UNIXISH = False hostos = sys.platform if (hostos == 'mac' or hostos == 'darwin'): localAutomation.IS_MAC = True elif (hostos == 'linux' or hostos == 'linux2'): localAutomation.IS_LINUX = True localAutomation.UNIXISH = True elif (hostos == 'win32' or hostos == 'win64'): localAutomation.BIN_SUFFIX = ".exe" localAutomation.IS_WIN32 = True paths = [options.xrePath, localAutomation.DIST_BIN, self._automation._product, os.path.join('..', self._automation._product)] options.xrePath = self.findPath(paths) if options.xrePath == None: print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name) sys.exit(1) paths.append("bin") paths.append(os.path.join("..", "bin")) xpcshell = "xpcshell" if (os.name == "nt"): xpcshell += ".exe" if (options.utilityPath): paths.insert(0, options.utilityPath) options.utilityPath = self.findPath(paths, xpcshell) if options.utilityPath == None: print "ERROR: unable to find utility path for %s, please specify with --utility-path" % (os.name) sys.exit(1) xpcshell_path = os.path.join(options.utilityPath, xpcshell) if localAutomation.elf_arm(xpcshell_path): self.error('xpcshell at %s is an ARM binary; please use ' 'the --utility-path argument to specify the path ' 'to a desktop version.' % xpcshell) options.profilePath = tempfile.mkdtemp() self.server = MochitestServer(localAutomation, options) self.server.start() if (options.pidFile != ""): f = open(options.pidFile + ".xpcshell.pid", 'w') f.write("%s" % self.server._process.pid) f.close() self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT) options.xrePath = remoteXrePath options.utilityPath = remoteUtilityPath options.profilePath = remoteProfilePath def stopWebServer(self, options): self.server.stop() def buildProfile(self, options): if self.localProfile: options.profilePath = self.localProfile manifest = Mochitest.buildProfile(self, options) self.localProfile = options.profilePath self._dm.removeDir(self.remoteProfile) # we do not need this for robotium based tests, lets save a LOT of time if options.robocop: shutil.rmtree(os.path.join(options.profilePath, 'webapps')) shutil.rmtree(os.path.join(options.profilePath, 'extensions', 'staged', '*****@*****.**')) shutil.rmtree(os.path.join(options.profilePath, 'extensions', 'staged', '*****@*****.**')) shutil.rmtree(os.path.join(options.profilePath, 'extensions', 'staged', '*****@*****.**')) os.remove(os.path.join(options.profilePath, 'userChrome.css')) if os.path.exists(os.path.join(options.profilePath, 'tests.jar')): os.remove(os.path.join(options.profilePath, 'tests.jar')) if os.path.exists(os.path.join(options.profilePath, 'tests.manifest')): os.remove(os.path.join(options.profilePath, 'tests.manifest')) try: self._dm.pushDir(options.profilePath, self.remoteProfile) except devicemanager.DMError: print "Automation Error: Unable to copy profile to device." raise options.profilePath = self.remoteProfile return manifest def buildURLOptions(self, options, env): self.localLog = options.logFile options.logFile = self.remoteLog options.profilePath = self.localProfile env["MOZ_HIDE_RESULTS_TABLE"] = "1" retVal = Mochitest.buildURLOptions(self, options, env) if not options.robocop: #we really need testConfig.js (for browser chrome) try: self._dm.pushDir(options.profilePath, self.remoteProfile) except devicemanager.DMError: print "Automation Error: Unable to copy profile to device." raise options.profilePath = self.remoteProfile options.logFile = self.localLog return retVal def installChromeFile(self, filename, options): parts = options.app.split('/') if (parts[0] == options.app): return "NO_CHROME_ON_DROID" path = '/'.join(parts[:-1]) manifest = path + "/chrome/" + os.path.basename(filename) try: self._dm.pushFile(filename, manifest) except devicemanager.DMError: print "Automation Error: Unable to install Chrome files on device." raise return manifest def getLogFilePath(self, logFile): return logFile # In the future we could use LogParser: http://hg.mozilla.org/automation/logparser/ def addLogData(self): with open(self.localLog) as currentLog: data = currentLog.readlines() restart = re.compile('0 INFO SimpleTest START.*') reend = re.compile('([0-9]+) INFO TEST-START . Shutdown.*') refail = re.compile('([0-9]+) INFO TEST-UNEXPECTED-FAIL.*') start_found = False end_found = False fail_found = False for line in data: if reend.match(line): end_found = True start_found = False break if start_found and not end_found: # Append the line without the number to increment self.logLines.append(' '.join(line.split(' ')[1:])) if restart.match(line): start_found = True if refail.match(line): fail_found = True result = 0 if fail_found: result = 1 if not end_found: print "ERROR: missing end of test marker (process crashed?)" result = 1 return result def printLog(self): passed = 0 failed = 0 todo = 0 incr = 1 logFile = [] logFile.append("0 INFO SimpleTest START") for line in self.logLines: if line.startswith("INFO TEST-PASS"): passed += 1 elif line.startswith("INFO TEST-UNEXPECTED"): failed += 1 elif line.startswith("INFO TEST-KNOWN"): todo += 1 incr += 1 logFile.append("%s INFO TEST-START | Shutdown" % incr) incr += 1 logFile.append("%s INFO Passed: %s" % (incr, passed)) incr += 1 logFile.append("%s INFO Failed: %s" % (incr, failed)) incr += 1 logFile.append("%s INFO Todo: %s" % (incr, todo)) incr += 1 logFile.append("%s INFO SimpleTest FINISHED" % incr) # TODO: Consider not printing to stdout because we might be duplicating output print '\n'.join(logFile) with open(self.localLog, 'w') as localLog: localLog.write('\n'.join(logFile)) if failed > 0: return 1 return 0 def printScreenshot(self): try: image = self._dm.pullFile("/mnt/sdcard/Robotium-Screenshots/robocop-screenshot.jpg") encoded = base64.b64encode(image) print "SCREENSHOT: data:image/jpg;base64,%s" % encoded except: # If the test passes, no screenshot will be generated and # pullFile will fail -- continue silently. pass def printDeviceInfo(self): try: logcat = self._dm.getLogcat(filterOutRegexps=fennecLogcatFilters) print ''.join(logcat) print self._dm.getInfo() except devicemanager.DMError: print "WARNING: Error getting device information" def buildRobotiumConfig(self, options, browserEnv): deviceRoot = self._dm.getDeviceRoot() fHandle = tempfile.NamedTemporaryFile(suffix='.config', prefix='robotium-', dir=os.getcwd(), delete=False) fHandle.write("profile=%s\n" % (self.remoteProfile)) fHandle.write("logfile=%s\n" % (options.remoteLogFile)) fHandle.write("host=http://mochi.test:8888/tests\n") fHandle.write("rawhost=http://%s:%s/tests\n" % (options.remoteWebServer, options.httpPort)) if browserEnv: envstr = "" delim = "" for key, value in browserEnv.items(): try: value.index(',') print "Found: Error an ',' in our value, unable to process value." except ValueError, e: envstr += "%s%s=%s" % (delim, key, value) delim = "," fHandle.write("envvars=%s\n" % envstr) fHandle.close() self._dm.removeFile(os.path.join(deviceRoot, "robotium.config")) self._dm.pushFile(fHandle.name, os.path.join(deviceRoot, "robotium.config")) os.unlink(fHandle.name)
class B2GMochitest(Mochitest): _automation = None _dm = None localProfile = None testDir = '/data/local/tests' def __init__(self, automation, devmgr, options): self._automation = automation Mochitest.__init__(self, self._automation) self._dm = devmgr self.runSSLTunnel = False self.remoteProfile = options.remoteTestRoot + '/profile' self._automation.setRemoteProfile(self.remoteProfile) self.remoteLog = options.remoteLogFile self.localLog = None self.userJS = '/data/local/user.js' self.remoteMozillaPath = '/data/b2g/mozilla' self.bundlesDir = '/system/b2g/distribution/bundles' self.remoteProfilesIniPath = os.path.join(self.remoteMozillaPath, 'profiles.ini') self.originalProfilesIni = None def copyRemoteFile(self, src, dest): if self._dm._useDDCopy: self._dm._checkCmdAs(['shell', 'dd', 'if=%s' % src,'of=%s' % dest]) else: self._dm._checkCmdAs(['shell', 'cp', src, dest]) def origUserJSExists(self): return self._dm.fileExists('/data/local/user.js.orig') def cleanup(self, manifest, options): if self.localLog: self._dm.getFile(self.remoteLog, self.localLog) self._dm.removeFile(self.remoteLog) # Delete any bundled extensions extensionDir = os.path.join(options.profilePath, 'extensions', 'staged') if os.access(extensionDir, os.F_OK): for filename in os.listdir(extensionDir): try: self._dm._checkCmdAs(['shell', 'rm', '-rf', os.path.join(self.bundlesDir, filename)]) except devicemanager.DMError: pass if not options.emulator: # Remove the test profile self._dm._checkCmdAs(['shell', 'rm', '-r', self.remoteProfile]) if self.origUserJSExists(): # Restore the original user.js self._dm.removeFile(self.userJS) self.copyRemoteFile('%s.orig' % self.userJS, self.userJS) self._dm.removeFile("%s.orig" % self.userJS) if self._dm.fileExists('%s.orig' % self.remoteProfilesIniPath): # Restore the original profiles.ini self._dm.removeFile(self.remoteProfilesIniPath) self.copyRemoteFile('%s.orig' % self.remoteProfilesIniPath, self.remoteProfilesIniPath) self._dm.removeFile("%s.orig" % self.remoteProfilesIniPath) # We've restored the original profile, so reboot the device so that # it gets picked up. self._automation.rebootDevice() if options.pidFile != "": try: os.remove(options.pidFile) os.remove(options.pidFile + ".xpcshell.pid") except: print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % options.pidFile def findPath(self, paths, filename = None): for path in paths: p = path if filename: p = os.path.join(p, filename) if os.path.exists(self.getFullPath(p)): return path return None def startWebServer(self, options): """ Create the webserver on the host and start it up """ remoteXrePath = options.xrePath remoteProfilePath = options.profilePath remoteUtilityPath = options.utilityPath localAutomation = Automation() localAutomation.IS_WIN32 = False localAutomation.IS_LINUX = False localAutomation.IS_MAC = False localAutomation.UNIXISH = False hostos = sys.platform if hostos in ['mac', 'darwin']: localAutomation.IS_MAC = True elif hostos in ['linux', 'linux2']: localAutomation.IS_LINUX = True localAutomation.UNIXISH = True elif hostos in ['win32', 'win64']: localAutomation.BIN_SUFFIX = ".exe" localAutomation.IS_WIN32 = True paths = [options.xrePath, localAutomation.DIST_BIN, self._automation._product, os.path.join('..', self._automation._product)] options.xrePath = self.findPath(paths) if options.xrePath == None: print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name) sys.exit(1) paths.append("bin") paths.append(os.path.join("..", "bin")) xpcshell = "xpcshell" if (os.name == "nt"): xpcshell += ".exe" if (options.utilityPath): paths.insert(0, options.utilityPath) options.utilityPath = self.findPath(paths, xpcshell) if options.utilityPath == None: print "ERROR: unable to find utility path for %s, please specify with --utility-path" % (os.name) sys.exit(1) options.profilePath = tempfile.mkdtemp() self.server = MochitestServer(localAutomation, options) self.server.start() if (options.pidFile != ""): f = open(options.pidFile + ".xpcshell.pid", 'w') f.write("%s" % self.server._process.pid) f.close() self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT) options.xrePath = remoteXrePath options.utilityPath = remoteUtilityPath options.profilePath = remoteProfilePath def stopWebServer(self, options): if hasattr(self, 'server'): self.server.stop() def buildProfile(self, options): if self.localProfile: options.profilePath = self.localProfile manifest = Mochitest.buildProfile(self, options) self.localProfile = options.profilePath # Profile isn't actually copied to device until # buildURLOptions is called. options.profilePath = self.remoteProfile return manifest def updateProfilesIni(self, profilePath): # update profiles.ini on the device to point to the test profile self.originalProfilesIni = tempfile.mktemp() self._dm.getFile(self.remoteProfilesIniPath, self.originalProfilesIni) config = ProfileConfigParser() config.read(self.originalProfilesIni) for section in config.sections(): if 'Profile' in section: config.set(section, 'IsRelative', 0) config.set(section, 'Path', profilePath) newProfilesIni = tempfile.mktemp() with open(newProfilesIni, 'wb') as configfile: config.write(configfile) self._dm.pushFile(newProfilesIni, self.remoteProfilesIniPath) self._dm.pushFile(self.originalProfilesIni, '%s.orig' % self.remoteProfilesIniPath) try: os.remove(newProfilesIni) os.remove(self.originalProfilesIni) except: pass def buildURLOptions(self, options, env): self.localLog = options.logFile options.logFile = self.remoteLog options.profilePath = self.localProfile retVal = Mochitest.buildURLOptions(self, options, env) # set the testURL testURL = self.buildTestPath(options) if len(self.urlOpts) > 0: testURL += "?" + "&".join(self.urlOpts) self._automation.testURL = testURL # execute this script on start up. # loads special powers and sets the test-container # apps's iframe to the mochitest URL. self._automation.test_script = """ const CHILD_SCRIPT = "chrome://specialpowers/content/specialpowers.js"; const CHILD_SCRIPT_API = "chrome://specialpowers/content/specialpowersAPI.js"; const CHILD_LOGGER_SCRIPT = "chrome://specialpowers/content/MozillaLogger.js"; let homescreen = document.getElementById('homescreen'); let container = homescreen.contentWindow.document.getElementById('test-container'); let specialpowers = {}; let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader); loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserver.js", specialpowers); let specialPowersObserver = new specialpowers.SpecialPowersObserver(); specialPowersObserver.init(); let mm = container.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.messageManager; mm.addMessageListener("SPPrefService", specialPowersObserver); mm.addMessageListener("SPProcessCrashService", specialPowersObserver); mm.addMessageListener("SPPingService", specialPowersObserver); mm.addMessageListener("SpecialPowers.Quit", specialPowersObserver); mm.addMessageListener("SPPermissionManager", specialPowersObserver); mm.loadFrameScript(CHILD_LOGGER_SCRIPT, true); mm.loadFrameScript(CHILD_SCRIPT_API, true); mm.loadFrameScript(CHILD_SCRIPT, true); specialPowersObserver._isFrameScriptLoaded = true; container.src = '%s'; """ % testURL # Set extra prefs for B2G. f = open(os.path.join(options.profilePath, "user.js"), "a") f.write(""" user_pref("browser.homescreenURL","app://test-container.gaiamobile.org/index.html"); user_pref("browser.manifestURL","app://test-container.gaiamobile.org/manifest.webapp"); user_pref("dom.mozBrowserFramesEnabled", true); user_pref("dom.ipc.tabs.disabled", false); user_pref("dom.ipc.browser_frames.oop_by_default", false); user_pref("dom.mozBrowserFramesWhitelist","app://test-container.gaiamobile.org,http://mochi.test:8888"); user_pref("network.dns.localDomains","app://test-container.gaiamobile.org"); user_pref("marionette.loadearly", true); """) f.close() # Copy the profile to the device. self._dm._checkCmdAs(['shell', 'rm', '-r', self.remoteProfile]) try: self._dm.pushDir(options.profilePath, self.remoteProfile) except devicemanager.DMError: print "Automation Error: Unable to copy profile to device." raise # Copy the extensions to the B2G bundles dir. extensionDir = os.path.join(options.profilePath, 'extensions', 'staged') # need to write to read-only dir self._dm._checkCmdAs(['remount']) for filename in os.listdir(extensionDir): self._dm._checkCmdAs(['shell', 'rm', '-rf', os.path.join(self.bundlesDir, filename)]) try: self._dm.pushDir(extensionDir, self.bundlesDir) except devicemanager.DMError: print "Automation Error: Unable to copy extensions to device." raise # In B2G, user.js is always read from /data/local, not the profile # directory. Backup the original user.js first so we can restore it. if not self._dm.fileExists('%s.orig' % self.userJS): self.copyRemoteFile(self.userJS, '%s.orig' % self.userJS) self._dm.pushFile(os.path.join(options.profilePath, "user.js"), self.userJS) self.updateProfilesIni(self.remoteProfile) options.profilePath = self.remoteProfile options.logFile = self.localLog return retVal
class B2GMochitest(Mochitest): _automation = None _dm = None localProfile = None def __init__(self, automation, devmgr, options): self._automation = automation Mochitest.__init__(self, self._automation) self._dm = devmgr self.runSSLTunnel = False self.remoteProfile = options.remoteTestRoot + '/profile' self._automation.setRemoteProfile(self.remoteProfile) self.remoteLog = options.remoteLogFile self.userJS = '/data/local/user.js' self.testDir = '/data/local/tests' self.remoteMozillaPath = '/data/b2g/mozilla' self.remoteProfilesIniPath = os.path.join(self.remoteMozillaPath, 'profiles.ini') self.originalProfilesIni = None def cleanup(self, manifest, options): # Restore the original profiles.ini. if self.originalProfilesIni: try: if not options.emulator: self.restoreProfilesIni() os.remove(self.originalProfilesIni) except: pass if not options.emulator: self._dm.getFile(self.remoteLog, self.localLog) self._dm.removeFile(self.remoteLog) self._dm.removeDir(self.remoteProfile) # Restore the original user.js. self._dm.checkCmdAs(['shell', 'rm', '-f', self.userJS]) if self._dm.useDDCopy: self._dm.checkCmdAs(['shell', 'dd', 'if=%s.orig' % self.userJS, 'of=%s' % self.userJS]) else: self._dm.checkCmdAs(['shell', 'cp', '%s.orig' % self.userJS, self.userJS]) # We've restored the original profile, so reboot the device so that # it gets picked up. self._automation.rebootDevice() if options.pidFile != "": try: os.remove(options.pidFile) os.remove(options.pidFile + ".xpcshell.pid") except: print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % options.pidFile def findPath(self, paths, filename = None): for path in paths: p = path if filename: p = os.path.join(p, filename) if os.path.exists(self.getFullPath(p)): return path return None def startWebServer(self, options): """ Create the webserver on the host and start it up """ remoteXrePath = options.xrePath remoteProfilePath = options.profilePath remoteUtilityPath = options.utilityPath localAutomation = Automation() localAutomation.IS_WIN32 = False localAutomation.IS_LINUX = False localAutomation.IS_MAC = False localAutomation.UNIXISH = False hostos = sys.platform if hostos in ['mac', 'darwin']: localAutomation.IS_MAC = True elif hostos in ['linux', 'linux2']: localAutomation.IS_LINUX = True localAutomation.UNIXISH = True elif hostos in ['win32', 'win64']: localAutomation.BIN_SUFFIX = ".exe" localAutomation.IS_WIN32 = True paths = [options.xrePath, localAutomation.DIST_BIN, self._automation._product, os.path.join('..', self._automation._product)] options.xrePath = self.findPath(paths) if options.xrePath == None: print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name) sys.exit(1) paths.append("bin") paths.append(os.path.join("..", "bin")) xpcshell = "xpcshell" if (os.name == "nt"): xpcshell += ".exe" if (options.utilityPath): paths.insert(0, options.utilityPath) options.utilityPath = self.findPath(paths, xpcshell) if options.utilityPath == None: print "ERROR: unable to find utility path for %s, please specify with --utility-path" % (os.name) sys.exit(1) options.profilePath = tempfile.mkdtemp() self.server = MochitestServer(localAutomation, options) self.server.start() if (options.pidFile != ""): f = open(options.pidFile + ".xpcshell.pid", 'w') f.write("%s" % self.server._process.pid) f.close() self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT) options.xrePath = remoteXrePath options.utilityPath = remoteUtilityPath options.profilePath = remoteProfilePath def stopWebServer(self, options): self.server.stop() def buildProfile(self, options): if self.localProfile: options.profilePath = self.localProfile manifest = Mochitest.buildProfile(self, options) self.localProfile = options.profilePath # Profile isn't actually copied to device until # buildURLOptions is called. options.profilePath = self.remoteProfile return manifest def restoreProfilesIni(self): # restore profiles.ini on the device to its previous state if not self.originalProfilesIni or not os.access(self.originalProfilesIni, os.F_OK): raise DMError('Unable to install original profiles.ini; file not found: %s', self.originalProfilesIni) self._dm.pushFile(self.originalProfilesIni, self.remoteProfilesIniPath) def updateProfilesIni(self, profilePath): # update profiles.ini on the device to point to the test profile self.originalProfilesIni = tempfile.mktemp() self._dm.getFile(self.remoteProfilesIniPath, self.originalProfilesIni) config = ProfileConfigParser() config.read(self.originalProfilesIni) for section in config.sections(): if 'Profile' in section: config.set(section, 'IsRelative', 0) config.set(section, 'Path', profilePath) newProfilesIni = tempfile.mktemp() with open(newProfilesIni, 'wb') as configfile: config.write(configfile) self._dm.pushFile(newProfilesIni, self.remoteProfilesIniPath) try: os.remove(newProfilesIni) except: pass def buildURLOptions(self, options, env): self.localLog = options.logFile options.logFile = self.remoteLog options.profilePath = self.localProfile retVal = Mochitest.buildURLOptions(self, options, env) # set the testURL testURL = self.buildTestPath(options) if len(self.urlOpts) > 0: testURL += "?" + "&".join(self.urlOpts) self._automation.testURL = testURL # Set the B2G homepage as a static local page, since wi-fi generally # isn't available as soon as the device boots. f = open(os.path.join(options.profilePath, "user.js"), "a") f.write('user_pref("browser.homescreenURL", "data:text/html,<h1>mochitest-plain should start soon</h1>");\n') f.close() # Copy the profile to the device. self._dm.removeDir(self.remoteProfile) if self._dm.pushDir(options.profilePath, self.remoteProfile) == None: raise devicemanager.FileError("Unable to copy profile to device.") # In B2G, user.js is always read from /data/local, not the profile # directory. Backup the original user.js first so we can restore it. self._dm.checkCmdAs(['shell', 'rm', '-f', '%s.orig' % self.userJS]) if self._dm.useDDCopy: self._dm.checkCmdAs(['shell', 'dd', 'if=%s' % self.userJS, 'of=%s.orig' % self.userJS]) else: self._dm.checkCmdAs(['shell', 'cp', self.userJS, '%s.orig' % self.userJS]) self._dm.pushFile(os.path.join(options.profilePath, "user.js"), self.userJS) self.updateProfilesIni(self.remoteProfile) options.profilePath = self.remoteProfile options.logFile = self.localLog return retVal
class MochiRemote(Mochitest): _automation = None _dm = None def __init__(self, automation, devmgr, options): self._automation = automation Mochitest.__init__(self, self._automation) self._dm = devmgr self.runSSLTunnel = False self.remoteProfile = options.remoteTestRoot + "/profile" self.remoteLog = options.remoteLogFile def cleanup(self, manifest, options): self._dm.getFile(self.remoteLog, self.localLog) self._dm.removeFile(self.remoteLog) self._dm.removeDir(self.remoteProfile) if (options.pidFile != ""): try: os.remove(options.pidFile) os.remove(options.pidFile + ".xpcshell.pid") except: print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % options.pidFile def findPath(self, paths, filename = None): for path in paths: p = path if filename: p = os.path.join(p, filename) if os.path.exists(self.getFullPath(p)): return path return None def startWebServer(self, options): """ Create the webserver on the host and start it up """ remoteXrePath = options.xrePath remoteProfilePath = options.profilePath remoteUtilityPath = options.utilityPath localAutomation = Automation() localAutomation.IS_WIN32 = False localAutomation.IS_LINUX = False localAutomation.IS_MAC = False localAutomation.UNIXISH = False hostos = sys.platform if (hostos == 'mac' or hostos == 'darwin'): localAutomation.IS_MAC = True elif (hostos == 'linux' or hostos == 'linux2'): localAutomation.IS_LINUX = True localAutomation.UNIXISH = True elif (hostos == 'win32' or hostos == 'win64'): localAutomation.BIN_SUFFIX = ".exe" localAutomation.IS_WIN32 = True paths = [options.xrePath, localAutomation.DIST_BIN, self._automation._product, os.path.join('..', self._automation._product)] options.xrePath = self.findPath(paths) if options.xrePath == None: print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name) sys.exit(1) paths.append("bin") paths.append(os.path.join("..", "bin")) xpcshell = "xpcshell" if (os.name == "nt"): xpcshell += ".exe" if (options.utilityPath): paths.insert(0, options.utilityPath) options.utilityPath = self.findPath(paths, xpcshell) if options.utilityPath == None: print "ERROR: unable to find utility path for %s, please specify with --utility-path" % (os.name) sys.exit(1) options.profilePath = tempfile.mkdtemp() self.server = MochitestServer(localAutomation, options) self.server.start() if (options.pidFile != ""): f = open(options.pidFile + ".xpcshell.pid", 'w') f.write("%s" % self.server._process.pid) f.close() self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT) options.xrePath = remoteXrePath options.utilityPath = remoteUtilityPath options.profilePath = remoteProfilePath def stopWebServer(self, options): self.server.stop() def buildProfile(self, options): manifest = Mochitest.buildProfile(self, options) self.localProfile = options.profilePath if self._dm.pushDir(options.profilePath, self.remoteProfile) == None: raise devicemanager.FileError("Unable to copy profile to device.") options.profilePath = self.remoteProfile return manifest def buildURLOptions(self, options): self.localLog = options.logFile options.logFile = self.remoteLog options.profilePath = self.localProfile retVal = Mochitest.buildURLOptions(self, options) #we really need testConfig.js (for browser chrome) if self._dm.pushDir(options.profilePath, self.remoteProfile) == None: raise devicemanager.FileError("Unable to copy profile to device.") options.profilePath = self.remoteProfile options.logFile = self.localLog return retVal def installChromeFile(self, filename, options): parts = options.app.split('/') if (parts[0] == options.app): return "NO_CHROME_ON_DROID" path = '/'.join(parts[:-1]) manifest = path + "/chrome/" + os.path.basename(filename) if self._dm.pushFile(filename, manifest) == False: raise devicemanager.FileError("Unable to install Chrome files on device.") return manifest def getLogFilePath(self, logFile): return logFile
class MochiRemote(Mochitest): _automation = None _dm = None def __init__(self, automation, devmgr, options): self._automation = automation Mochitest.__init__(self, self._automation) self._dm = devmgr self.runSSLTunnel = False self.remoteProfile = options.remoteTestRoot + "/profile" self.remoteLog = options.remoteLogFile def cleanup(self, manifest, options): self._dm.getFile(self.remoteLog, self.localLog) self._dm.removeFile(self.remoteLog) self._dm.removeDir(self.remoteProfile) if (options.pidFile != ""): try: os.remove(options.pidFile) os.remove(options.pidFile + ".xpcshell.pid") except: print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % options.pidFile def findPath(self, paths, filename=None): for path in paths: p = path if filename: p = os.path.join(p, filename) if os.path.exists(self.getFullPath(p)): return path return None def startWebServer(self, options): """ Create the webserver on the host and start it up """ remoteXrePath = options.xrePath remoteProfilePath = options.profilePath remoteUtilityPath = options.utilityPath localAutomation = Automation() localAutomation.IS_WIN32 = False localAutomation.IS_LINUX = False localAutomation.IS_MAC = False localAutomation.UNIXISH = False hostos = sys.platform if (hostos == 'mac' or hostos == 'darwin'): localAutomation.IS_MAC = True elif (hostos == 'linux' or hostos == 'linux2'): localAutomation.IS_LINUX = True localAutomation.UNIXISH = True elif (hostos == 'win32' or hostos == 'win64'): localAutomation.BIN_SUFFIX = ".exe" localAutomation.IS_WIN32 = True paths = [ options.xrePath, localAutomation.DIST_BIN, self._automation._product, os.path.join('..', self._automation._product) ] options.xrePath = self.findPath(paths) if options.xrePath == None: print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % ( os.name) sys.exit(1) paths.append("bin") paths.append(os.path.join("..", "bin")) xpcshell = "xpcshell" if (os.name == "nt"): xpcshell += ".exe" if (options.utilityPath): paths.insert(0, options.utilityPath) options.utilityPath = self.findPath(paths, xpcshell) if options.utilityPath == None: print "ERROR: unable to find utility path for %s, please specify with --utility-path" % ( os.name) sys.exit(1) options.profilePath = tempfile.mkdtemp() self.server = MochitestServer(localAutomation, options) self.server.start() if (options.pidFile != ""): f = open(options.pidFile + ".xpcshell.pid", 'w') f.write("%s" % self.server._process.pid) f.close() self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT) options.xrePath = remoteXrePath options.utilityPath = remoteUtilityPath options.profilePath = remoteProfilePath def stopWebServer(self, options): self.server.stop() def buildProfile(self, options): manifest = Mochitest.buildProfile(self, options) self.localProfile = options.profilePath if self._dm.pushDir(options.profilePath, self.remoteProfile) == None: raise devicemanager.FileError("Unable to copy profile to device.") options.profilePath = self.remoteProfile return manifest def buildURLOptions(self, options): self.localLog = options.logFile options.logFile = self.remoteLog options.profilePath = self.localProfile retVal = Mochitest.buildURLOptions(self, options) #we really need testConfig.js (for browser chrome) if self._dm.pushDir(options.profilePath, self.remoteProfile) == None: raise devicemanager.FileError("Unable to copy profile to device.") options.profilePath = self.remoteProfile options.logFile = self.localLog return retVal def installChromeFile(self, filename, options): parts = options.app.split('/') if (parts[0] == options.app): return "NO_CHROME_ON_DROID" path = '/'.join(parts[:-1]) manifest = path + "/chrome/" + os.path.basename(filename) if self._dm.pushFile(filename, manifest) == False: raise devicemanager.FileError( "Unable to install Chrome files on device.") return manifest def getLogFilePath(self, logFile): return logFile
class B2GMochitest(Mochitest): _automation = None _dm = None localProfile = None testDir = '/data/local/tests' def __init__(self, automation, devmgr, options): self._automation = automation Mochitest.__init__(self, self._automation) self._dm = devmgr self.runSSLTunnel = False self.remoteProfile = options.remoteTestRoot + '/profile' self._automation.setRemoteProfile(self.remoteProfile) self.remoteLog = options.remoteLogFile self.localLog = None self.userJS = '/data/local/user.js' self.remoteMozillaPath = '/data/b2g/mozilla' self.bundlesDir = '/system/b2g/distribution/bundles' self.remoteProfilesIniPath = os.path.join(self.remoteMozillaPath, 'profiles.ini') self.originalProfilesIni = None def copyRemoteFile(self, src, dest): if self._dm._useDDCopy: self._dm._checkCmdAs(['shell', 'dd', 'if=%s' % src,'of=%s' % dest]) else: self._dm._checkCmdAs(['shell', 'cp', src, dest]) def origUserJSExists(self): return self._dm.fileExists('/data/local/user.js.orig') def cleanup(self, manifest, options): if self.localLog: self._dm.getFile(self.remoteLog, self.localLog) self._dm.removeFile(self.remoteLog) # Delete any bundled extensions extensionDir = os.path.join(options.profilePath, 'extensions', 'staged') if os.access(extensionDir, os.F_OK): for filename in os.listdir(extensionDir): try: self._dm._checkCmdAs(['shell', 'rm', '-rf', os.path.join(self.bundlesDir, filename)]) except devicemanager.DMError: pass if not options.emulator: # Remove the test profile self._dm._checkCmdAs(['shell', 'rm', '-r', self.remoteProfile]) if self.origUserJSExists(): # Restore the original user.js self._dm.removeFile(self.userJS) self.copyRemoteFile('%s.orig' % self.userJS, self.userJS) self._dm.removeFile("%s.orig" % self.userJS) if self._dm.fileExists('%s.orig' % self.remoteProfilesIniPath): # Restore the original profiles.ini self._dm.removeFile(self.remoteProfilesIniPath) self.copyRemoteFile('%s.orig' % self.remoteProfilesIniPath, self.remoteProfilesIniPath) self._dm.removeFile("%s.orig" % self.remoteProfilesIniPath) # We've restored the original profile, so reboot the device so that # it gets picked up. self._automation.rebootDevice() if options.pidFile != "": try: os.remove(options.pidFile) os.remove(options.pidFile + ".xpcshell.pid") except: print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % options.pidFile def findPath(self, paths, filename = None): for path in paths: p = path if filename: p = os.path.join(p, filename) if os.path.exists(self.getFullPath(p)): return path return None def startWebServer(self, options): """ Create the webserver on the host and start it up """ remoteXrePath = options.xrePath remoteProfilePath = options.profilePath remoteUtilityPath = options.utilityPath localAutomation = Automation() localAutomation.IS_WIN32 = False localAutomation.IS_LINUX = False localAutomation.IS_MAC = False localAutomation.UNIXISH = False hostos = sys.platform if hostos in ['mac', 'darwin']: localAutomation.IS_MAC = True elif hostos in ['linux', 'linux2']: localAutomation.IS_LINUX = True localAutomation.UNIXISH = True elif hostos in ['win32', 'win64']: localAutomation.BIN_SUFFIX = ".exe" localAutomation.IS_WIN32 = True paths = [options.xrePath, localAutomation.DIST_BIN, self._automation._product, os.path.join('..', self._automation._product)] options.xrePath = self.findPath(paths) if options.xrePath == None: print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name) sys.exit(1) paths.append("bin") paths.append(os.path.join("..", "bin")) xpcshell = "xpcshell" if (os.name == "nt"): xpcshell += ".exe" if (options.utilityPath): paths.insert(0, options.utilityPath) options.utilityPath = self.findPath(paths, xpcshell) if options.utilityPath == None: print "ERROR: unable to find utility path for %s, please specify with --utility-path" % (os.name) sys.exit(1) options.profilePath = tempfile.mkdtemp() self.server = MochitestServer(localAutomation, options) self.server.start() if (options.pidFile != ""): f = open(options.pidFile + ".xpcshell.pid", 'w') f.write("%s" % self.server._process.pid) f.close() self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT) options.xrePath = remoteXrePath options.utilityPath = remoteUtilityPath options.profilePath = remoteProfilePath def stopWebServer(self, options): if hasattr(self, 'server'): self.server.stop() def buildProfile(self, options): if self.localProfile: options.profilePath = self.localProfile manifest = Mochitest.buildProfile(self, options) self.localProfile = options.profilePath # Profile isn't actually copied to device until # buildURLOptions is called. options.profilePath = self.remoteProfile return manifest def updateProfilesIni(self, profilePath): # update profiles.ini on the device to point to the test profile self.originalProfilesIni = tempfile.mktemp() self._dm.getFile(self.remoteProfilesIniPath, self.originalProfilesIni) config = ProfileConfigParser() config.read(self.originalProfilesIni) for section in config.sections(): if 'Profile' in section: config.set(section, 'IsRelative', 0) config.set(section, 'Path', profilePath) newProfilesIni = tempfile.mktemp() with open(newProfilesIni, 'wb') as configfile: config.write(configfile) self._dm.pushFile(newProfilesIni, self.remoteProfilesIniPath) self._dm.pushFile(self.originalProfilesIni, '%s.orig' % self.remoteProfilesIniPath) try: os.remove(newProfilesIni) os.remove(self.originalProfilesIni) except: pass def buildURLOptions(self, options, env): self.localLog = options.logFile options.logFile = self.remoteLog options.profilePath = self.localProfile retVal = Mochitest.buildURLOptions(self, options, env) # set the testURL testURL = self.buildTestPath(options) if len(self.urlOpts) > 0: testURL += "?" + "&".join(self.urlOpts) self._automation.testURL = testURL # execute this script on start up. # loads special powers and sets the test-container # apps's iframe to the mochitest URL. self._automation.test_script = """ const CHILD_SCRIPT = "chrome://specialpowers/content/specialpowers.js"; const CHILD_SCRIPT_API = "chrome://specialpowers/content/specialpowersAPI.js"; const CHILD_LOGGER_SCRIPT = "chrome://specialpowers/content/MozillaLogger.js"; let homescreen = document.getElementById('homescreen'); let container = homescreen.contentWindow.document.getElementById('test-container'); let specialpowers = {}; let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader); loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserver.js", specialpowers); let specialPowersObserver = new specialpowers.SpecialPowersObserver(); specialPowersObserver.init(); let mm = container.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.messageManager; mm.addMessageListener("SPPrefService", specialPowersObserver); mm.addMessageListener("SPProcessCrashService", specialPowersObserver); mm.addMessageListener("SPPingService", specialPowersObserver); mm.addMessageListener("SpecialPowers.Quit", specialPowersObserver); mm.addMessageListener("SPPermissionManager", specialPowersObserver); mm.loadFrameScript(CHILD_LOGGER_SCRIPT, true); mm.loadFrameScript(CHILD_SCRIPT_API, true); mm.loadFrameScript(CHILD_SCRIPT, true); specialPowersObserver._isFrameScriptLoaded = true; container.src = '%s'; """ % testURL # Set extra prefs for B2G. f = open(os.path.join(options.profilePath, "user.js"), "a") f.write(""" user_pref("browser.homescreenURL","app://test-container.gaiamobile.org/index.html"); user_pref("browser.manifestURL","app://test-container.gaiamobile.org/manifest.webapp"); user_pref("dom.mozBrowserFramesEnabled", true); user_pref("dom.ipc.tabs.disabled", false); user_pref("dom.ipc.browser_frames.oop_by_default", false); user_pref("dom.mozBrowserFramesWhitelist","app://test-container.gaiamobile.org,http://mochi.test:8888"); user_pref("network.dns.localDomains","app://test-container.gaiamobile.org"); """) f.close() # Copy the profile to the device. self._dm._checkCmdAs(['shell', 'rm', '-r', self.remoteProfile]) try: self._dm.pushDir(options.profilePath, self.remoteProfile) except devicemanager.DMError: print "Automation Error: Unable to copy profile to device." raise # Copy the extensions to the B2G bundles dir. extensionDir = os.path.join(options.profilePath, 'extensions', 'staged') # need to write to read-only dir self._dm._checkCmdAs(['remount']) for filename in os.listdir(extensionDir): self._dm._checkCmdAs(['shell', 'rm', '-rf', os.path.join(self.bundlesDir, filename)]) try: self._dm.pushDir(extensionDir, self.bundlesDir) except devicemanager.DMError: print "Automation Error: Unable to copy extensions to device." raise # In B2G, user.js is always read from /data/local, not the profile # directory. Backup the original user.js first so we can restore it. if not self._dm.fileExists('%s.orig' % self.userJS): self.copyRemoteFile(self.userJS, '%s.orig' % self.userJS) self._dm.pushFile(os.path.join(options.profilePath, "user.js"), self.userJS) self.updateProfilesIni(self.remoteProfile) options.profilePath = self.remoteProfile options.logFile = self.localLog return retVal