def main(options): print "Setting up CertTest app to device" dm = None if options.adb_path: dm = mozdevice.DeviceManagerADB(adbPath=options.adb_path) else: dm = mozdevice.DeviceManagerADB() if dm.dirExists("/data/local/webapps/certtest-app"): print "CertTest app is already installed" return dm.pushFile("certtest_app.zip", "/data/local/certtest_app.zip") # forward the marionette port print "Forwarding marionette port" ret = dm.forward("tcp:2828", "tcp:2828") if ret != 0: #TODO: right thing here is to keep trying local ports and pass that value in our config raise Exception("Can't use localhost:2828 for port forwarding. Is something else using port 2828?") # install the app print "installing the app" f = open("app_install.js", "r") script = f.read() f.close() m = Marionette() m.start_session() m.set_context("chrome") m.set_script_timeout(5000) m.execute_async_script(script) m.delete_session()
def cli(): parser = OptionParser(usage='%prog gaia_atoms_path app_name [app_name] ...') options, args = parser.parse_args() if not args: parser.print_usage() parser.exit() if not os.path.isdir(args[0]): parser.print_usage() print 'must specify valid path for gaia atoms' parser.exit() if len(args) != 2: parser.print_usage() print 'must specify at one app name' parser.exit() marionette = Marionette(host='localhost', port=2828) # TODO command line option for address marionette.start_session() launchApp( marionette, gaia_atoms=args[0], app_name=args[1])
def set_up_device(opt): if not opt.wifi_ssid or not opt.wifi_key or not opt.wifi_pass: raise ValueError('Missing --wifi options') mc = Marionette('localhost', opt.adb_port) for i in range(2): try: mc.start_session() break except socket.error: sh('adb forward tcp:%s tcp:%s' % (opt.adb_port, opt.adb_port)) if opt.shell: from pdb import set_trace set_trace() return # watch out! This is how gaiatest does it. mc.__class__ = type('Marionette', (Marionette, MarionetteTouchMixin), {}) device = GaiaDevice(mc) device.restart_b2g() apps = GaiaApps(mc) data_layer = GaiaData(mc) lockscreen = LockScreen(mc) mc.setup_touch() lockscreen.unlock() apps.kill_all() data_layer.enable_wifi() if opt.wifi_key == 'WPA-PSK': pass_key = 'psk' elif opt.wifi_key == 'WEP': pass_key = 'wep' else: assert 0, 'unknown key management' data = {'ssid': opt.wifi_ssid, 'keyManagement': opt.wifi_key, pass_key: opt.wifi_pass} data_layer.connect_to_wifi(data) mc.switch_to_frame() all_apps = set(a['manifest']['name'] for a in get_installed(apps)) if 'Marketplace Dev' not in all_apps: mc.execute_script( 'navigator.mozApps.install' '("https://marketplace-dev.allizom.org/manifest.webapp");') wait_for_element_displayed(mc, 'id', 'app-install-install-button') yes = mc.find_element('id', 'app-install-install-button') mc.tap(yes) wait_for_element_displayed(mc, 'id', 'system-banner') print 'Pushing payment prefs' sh('adb shell stop b2g') sh('adb push "%s" /data/local/user.js' % ( os.path.join(os.path.dirname(__file__), 'payment-prefs.js'))) sh('adb shell start b2g') print 'When your device reboots, Marketplace Dev will be installed'
def get_new_emulator(self): _qemu = Marionette(emulator=True, homedir=self.marionette.homedir, baseurl=self.marionette.baseurl, noWindow=self.marionette.noWindow) _qemu.start_session() self._qemu.append(_qemu) return _qemu
def _StartProcess(self): if not self.isEmulatorInitialized: print("Starting Emulator ...") self.emulatorProcess = subprocess.Popen( [self.emulatorStartScript], cwd=os.path.dirname(self.emulatorStartScript), shell=True) # adb shell setprop net.dns1 10.0.2.3 self._isBootFinished() self.monitoringProcessId = self.adb.getPID( self.monitoredProcessName) print("Forwarding TCP port %d ..." % self.forwardedPortADB) self.adb.command([ "forward", "tcp:%d" % self.forwardedPortADB, "tcp:%d" % self.forwardedPortADB ]) self.isEmulatorInitialized = True time.sleep(20) if self.crashSuccess: print("Restarting %s ..." % self.monitoredProcessName) self.adb.killProcess(self.monitoredProcessName, True) time.sleep(40) self.monitoringProcessId = self.adb.getPID( self.monitoredProcessName) self.crashSuccess = False self.debugLogData = str() self.adb.checkCmd(["logcat", "-c"]) print("Starting Marionette session ...") marionette = Marionette('localhost', self.forwardedPortADB) print(marionette.status()) marionette.start_session() marionette.set_script_timeout(self.scriptTimeout) marionette.switch_to_frame() lock = gaia.LockScreen(marionette) lock.unlock() apps = gaia.GaiaApps(marionette) print(apps.runningApps()) print("Launching Browser application") apps.launch(self.appName, switch_to_frame=True) print("Navigating to %s ..." % self.publisherURL) marionette.execute_script( "return window.wrappedJSObject.Browser.navigate('%s')" % self.publisherURL) self.isMonitorInitialized = True
def create_marionette(): """Creates a new Marionette session if one does not exist.""" m = TestCase.stored.marionette if not m: m = Marionette() m.start_session() TestCase.stored.marionette = m return TestCase.stored.marionette
def launch_app(app_name, adb_path="adb", script_timeout=5000, marionette=None, device_serial=None): """ Launches the given app NOTE: if a marionette session is passed, this function switches to the top-most frame. """ dm = mozdevice.DeviceManagerADB(adbPath=adb_path, deviceSerial=device_serial) installed_app_name = app_name.lower() installed_app_name = installed_app_name.replace(" ", "-") dm.forward("tcp:2828", "tcp:2828") if not marionette: m = Marionette() m.start_session() else: m = marionette m.switch_to_frame() launch_app = """ var launchWithName = function(name) { let apps = window.wrappedJSObject.applications || window.wrappedJSObject.Applications; let installedApps = apps.installedApps; for (let manifestURL in installedApps) { let app = installedApps[manifestURL]; let origin = null; let entryPoints = app.manifest.entry_points; if (entryPoints) { for (let ep in entryPoints) { let currentEntryPoint = entryPoints[ep]; let appName = currentEntryPoint.name; if (name == appName.toLowerCase()) { app.launch(); return true; } } } else { let appName = app.manifest.name; if (name == appName.toLowerCase()) { app.launch(); return true; } } } return false; }; return launchWithName("%s"); """ m.set_script_timeout(script_timeout) m.execute_script(launch_app % app_name.lower()) if not marionette: m.delete_session()
class TestConsoleLogCapture(): def setup(self): try: self.client = Marionette(host='localhost', port=2828) self.client.start_session() self.client.set_pref('general.warnOnAboutConfig', False) except: sys.exit("Could not find Firefox browser running") def test_push_notification_received(self): self.client.navigate( "https://people.mozilla.org/~ewong2/push-notification-test/") unregister_button = self.client.find_element(By.ID, "unreg_btn") if unregister_button.is_displayed() == True: unregister_button.click() Wait(self.client, timeout=5, interval=1).until( expected.element_not_displayed(By.ID, "unreg_btn")) Wait(self.client).until(expected.element_displayed(By.ID, "reg_btn")) self.client.find_element(By.ID, "reg_btn").click() Wait(self.client).until( expected.element_displayed(By.ID, "subscribe_btn")) self.client.find_element(By.ID, "subscribe_btn").click() Wait(self.client).until(expected.element_displayed(By.ID, "doXhr_btn")) self.client.find_element(By.ID, "doXhr_btn").click() result = self.web_console_filter_for_string("Received a push message") assert result == 1 def web_console_filter_for_string(self, console_string=None): self.client.set_context(self.client.CONTEXT_CHROME) handles = self.client.window_handles chrome_handles = self.client.chrome_window_handles browser_handle = self.client.current_chrome_window_handle notifications = 0 for handle in chrome_handles: if handle != browser_handle: console_handle = handle self.client.switch_to_window(console_handle) time.sleep(1) results = self.client.find_elements(By.CLASS_NAME, "console-string") for result in results: if console_string in result.text: notifications = notifications + 1 self.client.find_element(By.CLASS_NAME, "webconsole-clear-console-button").click() return notifications def tear_down(self): self.client.close()
def get_marionette(args): mc = Marionette('localhost', args.adb_port) for i in range(3): try: mc.start_session() break # Catching SystemExit because tracebacks are suppressed. # This won't be necessary after # https://bugzilla.mozilla.org/show_bug.cgi?id=863377 except (socket.error, SystemExit): sh('adb forward tcp:%s tcp:%s' % (args.adb_port, args.adb_port)) return mc
def get_new_emulator(self): self.extra_emulator_index += 1 if len(self.marionette.extra_emulators) == self.extra_emulator_index: qemu = Marionette(emulator=self.marionette.emulator.arch, homedir=self.marionette.homedir, baseurl=self.marionette.baseurl, noWindow=self.marionette.noWindow) qemu.start_session() self.marionette.extra_emulators.append(qemu) else: qemu = self.marionette.extra_emulators[self.extra_emulator_index] return qemu
def uninstall_app(app_name, adb_path="adb", script_timeout=5000, marionette=None): """ Uninstalls the given app. NOTE: if a marionette session is passed, this function switches to the top-most frame. """ dm = mozdevice.DeviceManagerADB(adbPath=adb_path) installed_app_name = app_name.lower() installed_app_name = installed_app_name.replace(" ", "-") if dm.forward("tcp:2828", "tcp:2828") != 0: raise Exception("Can't use localhost:2828 for port forwarding." \ "Is something else using port 2828?") if not marionette: m = Marionette() m.start_session() else: m = marionette m.switch_to_frame() uninstall_app = """ var uninstallWithName = function(name) { let apps = window.wrappedJSObject.applications || window.wrappedJSObject.Applications; let installedApps = apps.installedApps; for (let manifestURL in installedApps) { let app = installedApps[manifestURL]; let origin = null; let entryPoints = app.manifest.entry_points; if (entryPoints) { for (let ep in entryPoints) { let currentEntryPoint = entryPoints[ep]; let appName = currentEntryPoint.name; if (name == appName.toLowerCase()) { window.wrappedJSObject.navigator.mozApps.mgmt.uninstall(app); return true; } } } else { let appName = app.manifest.name; if (name == appName.toLowerCase()) { window.wrappedJSObject.navigator.mozApps.mgmt.uninstall(app); return true; } } } return false; }; return uninstallWithName("%s"); """ m.set_script_timeout(script_timeout) m.execute_script(uninstall_app % app_name.lower()) if not marionette: m.delete_session()
def startMarionette(): # FW port for ADB via USB return_code = subprocess.call(["adb root"], shell=True) if return_code: raise Exception("Failed to start adb in root mode. Ensure device is attached to USB.") return_code = subprocess.call(["adb forward tcp:2828 tcp:2828"], shell=True) if return_code: raise Exception("Failed to connect to device via ADB; ensure device is attached to USB.") # Start Marionette marionette = Marionette(host='localhost', port=2828) marionette.start_session() marionette.set_script_timeout(60000) return marionette
def ftu_toggler(skip_ftu=True): dm = mozdevice.DeviceManagerADB(runAdbAsRoot=True) dm.forward("tcp:2828", "tcp:2828") m = Marionette() m.start_session() data_layer = GaiaData(m) url = "null" if skip_ftu else "app://ftu.gaiamobile.org/manifest.webapp" data_layer.set_setting('ftu.manifestURL', url) m.close() # restart b2g to enable dm.reboot()
def get_new_emulator(self): self.extra_emulator_index += 1 if len(self.marionette.extra_emulators) == self.extra_emulator_index: qemu = Marionette(emulator=self.marionette.emulator.arch, emulatorBinary=self.marionette.emulator.binary, homedir=self.marionette.homedir, baseurl=self.marionette.baseurl, noWindow=self.marionette.noWindow) qemu.start_session() self.marionette.extra_emulators.append(qemu) else: qemu = self.marionette.extra_emulators[self.extra_emulator_index] return qemu
def dual_driving(): mm = Marionette(host='localhost', port=2829) mm.start_session() md = Marionette(host='localhost', port=2828) md.start_session() md.set_search_timeout(1000) # especially required for webcompat.com JS-driven loading ignored_bugs = [] buglist = [] for line in open(ignore_file, 'r'): if line[0] == '#': continue ignored_bugs.append(line.strip()) if start_url: print 'Starting from bug search %s' % start_url md.navigate(start_url) buglist = extract_buglist(md) else: buglist = extract_buglist_from_file(filename) i = 1 for item in buglist: if len(item) <= 1: print 'Warning: we expect data format ID Summary URL, something is missing' continue if '://' not in item[0]: # assuming this is Bugzilla data from a tab-separated file - in other words a plain bug number md.navigate('https://bugzilla.mozilla.org/show_bug.cgi?id=%s' % item[0]) else: # we've got a bug tracker URL (right?) md.navigate(item[0]) if len(item) == 2: # URL is not in the data - let's load the bug first and try to get it from there url = get_url_from_bugpage(md) else: url = item[2] if not url: i+=1 continue if i<start_at or url.strip() == '': i+=1 continue if '://' not in url: url = 'http://%s' % url url = url.strip().rstrip('\r\n') location = urlparse.urlparse(url) hostname = location.hostname.rstrip('\r\n') print str(i) + ' : ' + url reset_spoof(mm) mm.navigate(url) print 'READY to analyze %s, \n%s' % (item[0], item[1]) options_menu(mm, url, md) mm.delete_session() md.delete_session()
def create_marionette(): """Returns current Marionette session, or creates one if one does not exist. """ m = TestCase.stored.marionette if m is None: m = Marionette() m.wait_for_port() m.start_session() TestCase.stored.marionette = m return TestCase.stored.marionette
class TestConsoleLogCapture(): def setup(self): try: self.client = Marionette(host='localhost', port=2828) self.client.start_session() self.client.set_pref('general.warnOnAboutConfig', False) except: sys.exit("Could not find Firefox browser running") def test_push_notification_received(self): self.client.navigate("https://people.mozilla.org/~ewong2/push-notification-test/") unregister_button = self.client.find_element(By.ID, "unreg_btn") if unregister_button.is_displayed() == True: unregister_button.click() Wait(self.client, timeout=5, interval=1).until(expected.element_not_displayed(By.ID, "unreg_btn")) Wait(self.client).until(expected.element_displayed(By.ID, "reg_btn")) self.client.find_element(By.ID, "reg_btn").click() Wait(self.client).until(expected.element_displayed(By.ID, "subscribe_btn")) self.client.find_element(By.ID, "subscribe_btn").click() Wait(self.client).until(expected.element_displayed(By.ID, "doXhr_btn")) self.client.find_element(By.ID, "doXhr_btn").click() result = self.web_console_filter_for_string("Received a push message") assert result == 1 def web_console_filter_for_string(self, console_string=None): self.client.set_context(self.client.CONTEXT_CHROME) handles = self.client.window_handles chrome_handles = self.client.chrome_window_handles browser_handle = self.client.current_chrome_window_handle notifications = 0 for handle in chrome_handles: if handle != browser_handle: console_handle = handle self.client.switch_to_window(console_handle) time.sleep(1) results = self.client.find_elements(By.CLASS_NAME, "console-string") for result in results: if console_string in result.text: notifications = notifications + 1 self.client.find_element(By.CLASS_NAME, "webconsole-clear-console-button").click() return notifications def tear_down(self): self.client.close()
def launch_app(app_name, adb_path="adb", script_timeout=5000, marionette=None, device_serial=None): """ Launches the given app NOTE: if a marionette session is passed, this function switches to the top-most frame. """ dm = mozdevice.DeviceManagerADB(adbPath=adb_path,deviceSerial=device_serial) installed_app_name = app_name.lower() installed_app_name = installed_app_name.replace(" ", "-") dm.forward("tcp:2828", "tcp:2828") if not marionette: m = Marionette() m.start_session() else: m = marionette m.switch_to_frame() launch_app = """ var launchWithName = function(name) { let apps = window.wrappedJSObject.applications || window.wrappedJSObject.Applications; let installedApps = apps.installedApps; for (let manifestURL in installedApps) { let app = installedApps[manifestURL]; let origin = null; let entryPoints = app.manifest.entry_points; if (entryPoints) { for (let ep in entryPoints) { let currentEntryPoint = entryPoints[ep]; let appName = currentEntryPoint.name; if (name == appName.toLowerCase()) { app.launch(); return true; } } } else { let appName = app.manifest.name; if (name == appName.toLowerCase()) { app.launch(); return true; } } } return false; }; return launchWithName("%s"); """ m.set_script_timeout(script_timeout) m.execute_script(launch_app % app_name.lower()) if not marionette: m.delete_session()
def _StartProcess(self): if not self.isDeviceInitialized: print("Starting ...") self.monitoringProcessId = self.adb.getPID( self.monitoredProcessName) print("Forwarding TCP port %d ..." % self.forwardedPortADB) self.adb.command([ "forward", "tcp:%d" % self.forwardedPortADB, "tcp:%d" % self.forwardedPortADB ]) self.isDeviceInitialized = True print("Sleeping ...") time.sleep(20) if self.crashSuccess: print("Restarting %s" % self.monitoredProcessName) self.adb.killProcess(self.monitoredProcessName, True) time.sleep(40) self.monitoringProcessId = self.adb.getPID( self.monitoredProcessName) self.crashSuccess = False self.debugLogData = str() self.adb.checkCmd(["logcat", "-c"]) print("Starting Marionette session") marionette = Marionette('localhost', self.forwardedPortADB) print(marionette.status()) marionette.start_session() marionette.set_script_timeout(self.scriptTimeout) marionette.switch_to_frame() lock = gaia.LockScreen(marionette) assert (lock.unlock()) apps = gaia.GaiaApps(marionette) print(apps.runningApps()) print("Launching Browser application") apps.launch(self.appName, switch_to_frame=True) print("Navigating to %s ..." % self.publisherURL) marionette.execute_script( "return window.wrappedJSObject.Browser.navigate('%s')" % self.publisherURL) self.isMonitorInitialized = True
def runemulator(homedir=None, url=None, pidfile=None, arch='x86'): qemu = Emulator(homedir=homedir, arch=arch) qemu.start() port = qemu.setup_port_forwarding(2828) assert (qemu.wait_for_port()) if pidfile: f = open(pidfile, 'w') f.write("%d" % qemu.proc.pid) f.close() print 'emulator launched, pid:', qemu.proc.pid if url: marionette = Marionette(port=port) marionette.start_session() marionette.navigate(url) marionette.delete_session()
def runemulator(homedir=None, url=None, pidfile=None, arch='x86'): qemu = Emulator(homedir=homedir, arch=arch) qemu.start() port = qemu.setup_port_forwarding(2828) assert(qemu.wait_for_port()) if pidfile: f = open(pidfile, 'w') f.write("%d" % qemu.proc.pid) f.close() print 'emulator launched, pid:', qemu.proc.pid if url: marionette = Marionette(port=port) marionette.start_session() marionette.navigate(url) marionette.delete_session()
def _StartProcess(self): if not self.isEmulatorInitialized: print("Starting Emulator ...") self.emulatorProcess = subprocess.Popen( [self.emulatorStartScript], cwd=os.path.dirname(self.emulatorStartScript), shell=True) # adb shell setprop net.dns1 10.0.2.3 self._isBootFinished() self.monitoringProcessId = self.adb.getPID(self.monitoredProcessName) print("Forwarding TCP port %d ..." % self.forwardedPortADB) self.adb.command(["forward", "tcp:%d" % self.forwardedPortADB, "tcp:%d" % self.forwardedPortADB]) self.isEmulatorInitialized = True time.sleep(20) if self.crashSuccess: print("Restarting %s ..." % self.monitoredProcessName) self.adb.killProcess(self.monitoredProcessName, True) time.sleep(40) self.monitoringProcessId = self.adb.getPID(self.monitoredProcessName) self.crashSuccess = False self.debugLogData = str() self.adb.checkCmd(["logcat", "-c"]) print("Starting Marionette session ...") marionette = Marionette('localhost', self.forwardedPortADB) print(marionette.status()) marionette.start_session() marionette.set_script_timeout(self.scriptTimeout) marionette.switch_to_frame() lock = gaia.LockScreen(marionette) lock.unlock() apps = gaia.GaiaApps(marionette) print(apps.runningApps()) print("Launching Browser application") apps.launch(self.appName, switch_to_frame=True) print("Navigating to %s ..." % self.publisherURL) marionette.execute_script("return window.wrappedJSObject.Browser.navigate('%s')" % self.publisherURL) self.isMonitorInitialized = True
def getTextContentViaMarionette(url): if Marionette is None: raise Exception("sorry this method is not supported because marionette driver couldn't be installed") client = Marionette("localhost", port=2828) print("client:", client) client.start_session() print("started session") client.set_script_timeout(30000) # not sure if one script ran after another return client.execute_async_script(""" var win = window.open('""" + url + """'); setTimeout(function(){ textContent = win.document.body.textContent; win.close(); marionetteScriptFinished(textContent); }, 15000); """)
def init(): ret = subprocess.check_output("adb devices", shell=True) print(ret) ## TODO: find more error handling if available import socket s = socket.socket() try: s.bind(("localhost", 2828)) s.close() ret = subprocess.check_output("adb forward tcp:2828 tcp:2828", shell=True) except socket.error: print("address already in use") mar = Marionette() mar.start_session() return mar
def run_marionette(self, dir): self.logger.info("Starting test run") # Start up marionette m = Marionette(emulator=True, homedir=dir) assert m.start_session() for test in self.testlist: run_test(test, m) m.delete_session()
def install_app(app_name, app_path, adb_path="adb", script_timeout=5000, marionette=None, device_serial=None): """ This installs the given application. NOTE: if a marionette session is passed, this function switches to 'content' context and will be at the top-most frame. """ if is_installed(app_name, adb_path=adb_path, device_serial=device_serial): raise Exception("%s is already installed" % app_name) sys.exit(1) app_zip = os.path.basename(app_path) dm = mozdevice.DeviceManagerADB(adbPath=adb_path, deviceSerial=device_serial) dm.pushFile("%s" % app_path, "/data/local/%s" % app_zip) # forward the marionette port dm.forward("tcp:2828", "tcp:2828") # install the app install_js = pkg_resources.resource_filename( __name__, os.path.sep.join(['app_install.js'])) with open(install_js, "r") as f: script = f.read() installed_app_name = app_name.lower().replace(" ", "-") script = script.replace("YOURAPPID", installed_app_name) script = script.replace("YOURAPPZIP", app_zip) if not marionette: m = Marionette() m.start_session() else: m = marionette m.switch_to_frame() m.set_context("chrome") m.set_script_timeout(script_timeout) m.execute_async_script(script) if not marionette: m.delete_session() else: m.set_context("content")
def init(): ret = subprocess.check_output("adb devices", shell=True) if("unagi" in ret): print(ret) else: print("No unagi connected") sys.exit(1) import socket s = socket.socket() try: s.bind(("localhost", 2828)) s.close() ret = subprocess.check_output("adb forward tcp:2828 tcp:2828", shell=True) except socket.error: print("address already in use") mar = Marionette() mar.start_session() return mar
def init(): ret = subprocess.check_output("adb devices", shell=True) # if("unagi" in ret): # print(ret) # else: # print("No unagi connected") # sys.exit(1) import socket s = socket.socket() try: s.bind(("localhost", 2828)) s.close() ret = subprocess.check_output("adb forward tcp:2828 tcp:2828", shell=True) except socket.error: print("address already in use") mar = Marionette() mar.start_session() return mar
def init(): ret = subprocess.check_output("adb devices", shell=True) print(ret) ## TODO: find more error handling if available import socket s = socket.socket() try: s.bind(("localhost", 2828)) s.close() ret = subprocess.check_output( "adb forward tcp:2828 tcp:2828", shell=True ) except socket.error: print("address already in use") mar = Marionette() mar.start_session() return mar
def getTextContentViaMarionette(url): if Marionette is None: raise Exception( "sorry this method is not supported because marionette driver couldn't be installed" ) client = Marionette("localhost", port=2828) print("client:", client) client.start_session() print("started session") client.set_script_timeout(30000) # not sure if one script ran after another return client.execute_async_script(""" var win = window.open('""" + url + """'); setTimeout(function(){ textContent = win.document.body.textContent; win.close(); marionetteScriptFinished(textContent); }, 15000); """)
def install_app(app_name, app_path, adb_path="adb", script_timeout=5000, marionette=None): """ This installs the given application. NOTE: if a marionette session is passed, this function switches to 'content' context and will be at the top-most frame. """ if is_installed(app_name, adb_path=adb_path): raise Exception("%s is already installed" % app_name) sys.exit(1) app_zip = os.path.basename(app_path) dm = mozdevice.DeviceManagerADB(adbPath=adb_path) dm.pushFile("%s" % app_path, "/data/local/%s" % app_zip) # forward the marionette port if dm.forward("tcp:2828", "tcp:2828") != 0: raise Exception("Can't use localhost:2828 for port forwarding." \ "Is something else using port 2828?") # install the app install_js = pkg_resources.resource_filename(__name__, os.path.sep.join([ 'app_install.js'])) with open(install_js, "r") as f: script = f.read() installed_app_name = app_name.lower().replace(" ", "-") script = script.replace("YOURAPPID", installed_app_name) script = script.replace("YOURAPPZIP", app_zip) if not marionette: m = Marionette() m.start_session() else: m = marionette m.switch_to_frame() m.set_context("chrome") m.set_script_timeout(script_timeout) m.execute_async_script(script) if not marionette: m.delete_session() else: m.set_context("content")
class current_frame(): def main(self, p_snippet, p_frame_array=False): # # p_el is an array for the element. # p_frame_array is a list of iframes to iterate through (optional). # self.marionette = Marionette(host='localhost', port=2828) self.marionette.start_session() self.marionette.set_search_timeout(1000) self.actions = Actions(self.marionette) # # Switch to the correct iframe (unless it's "()"). # self.marionette.switch_to_frame() first_iframe = True for x in p_frame_array: # (just to make it look nice ;) typ_str = "'" + x[0] + "'" if first_iframe: first_iframe = False print "" print "Switching to iframe with " + typ_str.rjust(10) + " = '" + x[1] + "'" else: print "... then to iframe with " + typ_str.rjust(10) + " = '" + x[1] + "'" my_iframe = self.marionette.find_element("xpath", "//iframe[@" + x[0] + "='" + x[1] + "']") self.marionette.switch_to_frame(my_iframe) if first_iframe: print "" print "Using 'top level' iframe () ..." # Run the code snippet. print "" print "Running code snippet from this location ..." print "" execfile(p_snippet)
def listapps(): marionette = Marionette(host='localhost', port=2828) marionette.start_session() marionette.set_context(marionette.CONTEXT_CONTENT) marionette.set_script_timeout(1000) apps = marionette.execute_async_script(""" let req = navigator.mozApps.mgmt.getAll(); req.onsuccess = function() { let apps = req.result; let l = [] for (let a of apps) { let data = {origin: a.origin, name: a.manifest.name}; if (a.manifest.entry_points) data.entry_points = a.manifest.entry_points; l.push(data); } marionetteScriptFinished(l); }; """) for a in apps: print a["name"]
def _StartProcess(self): if not self.isDeviceInitialized: print("Starting ...") self.monitoringProcessId = self.adb.getPID(self.monitoredProcessName) print("Forwarding TCP port %d ..." % self.forwardedPortADB) self.adb.command(["forward", "tcp:%d" % self.forwardedPortADB, "tcp:%d" % self.forwardedPortADB]) self.isDeviceInitialized = True print("Sleeping ...") time.sleep(20) if self.crashSuccess: print("Restarting %s" % self.monitoredProcessName) self.adb.killProcess(self.monitoredProcessName, True) time.sleep(40) self.monitoringProcessId = self.adb.getPID(self.monitoredProcessName) self.crashSuccess = False self.debugLogData = str() self.adb.checkCmd(["logcat", "-c"]) print("Starting Marionette session") marionette = Marionette('localhost', self.forwardedPortADB) print(marionette.status()) marionette.start_session() marionette.set_script_timeout(self.scriptTimeout) marionette.switch_to_frame() lock = gaia.LockScreen(marionette) assert(lock.unlock()) apps = gaia.GaiaApps(marionette) print(apps.runningApps()) print("Launching Browser application") apps.launch(self.appName, switch_to_frame=True) print("Navigating to %s ..." % self.publisherURL) marionette.execute_script("return window.wrappedJSObject.Browser.navigate('%s')" % self.publisherURL) self.isMonitorInitialized = True
def install_app(app_name, app_path, adb_path=None): dm = None if adb_path: dm = mozdevice.DeviceManagerADB(adbPath=adb_path) else: dm = mozdevice.DeviceManagerADB() #TODO: replace with app name installed_app_name = app_name.lower() installed_app_name = installed_app_name.replace(" ", "-") if dm.dirExists("/data/local/webapps/%s" % installed_app_name): raise Exception("%s is already installed" % app_name) sys.exit(1) app_zip = os.path.basename(app_path) dm.pushFile("%s" % app_path, "/data/local/%s" % app_zip) # forward the marionette port ret = dm.forward("tcp:2828", "tcp:2828") if ret != 0: raise Exception("Can't use localhost:2828 for port forwarding." \ "Is something else using port 2828?") # install the app install_js = pkg_resources.resource_filename(__name__, os.path.sep.join([ 'app_install.js'])) f = open(install_js, "r") script = f.read() f.close() script = script.replace("YOURAPPID", installed_app_name) script = script.replace("YOURAPPZIP", app_zip) m = Marionette() m.start_session() m.set_context("chrome") m.set_script_timeout(5000) m.execute_async_script(script) m.delete_session()
def cli(): parser = dzOptionParser(usage='%prog [options] result_file') parser.add_option('--address', action='store', dest='address', default='localhost:2828', metavar='str', help='address of marionette server (default: %default)') parser.add_option('--device-serial', action='store', dest='device_serial', metavar='str', help='serial identifier of device to target') options, args = parser.parse_args() if not args: parser.print_usage() parser.exit() if len(args) != 1: parser.exit("You can only specify one result file") datazilla_config = parser.datazilla_config(options) try: host, port = options.address.split(':') except ValueError: raise B2GPerfError('--address must be in the format host:port') marionette = Marionette(host=host, port=int(port)) marionette.start_session() handler = MozPerfHandler(marionette, datazilla_config=datazilla_config, sources=options.sources, device_serial=options.device_serial) handler.process_results(args[0])
def ftu(locale, device_flags, hashes): db = get_db(locale) app = 'ftu' app_categ = 'communications' app_type = 'apps' gaia_hash = hashes[0] hg_hash = hashes[1] screenshot_path = app_type + '/' + app_categ + '/' + app create_screenshot_dir(locale, screenshot_path) client = Marionette('localhost', 2828) client.start_session() change_screen_timeout(client) ftu_iframe = client.find_element( 'css selector', "iframe[src='app://communications.gaiamobile.org/ftu/index.html']") if client.switch_to_frame(ftu_iframe): time.sleep(short_time) # app://communications.gaiamobile.org/ftu/index.html#languages file_name = 'languages' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry, '#activation-screen') # switch to app://communications.gaiamobile.org/ftu/index.html#data_3g (unlock-sim-screen screen) next = client.find_element('css selector', '#forward') next.tap() time.sleep(short_time) # app://communications.gaiamobile.org/ftu/index.html#data_3g (sim pin screen - unlock-sim-screen - 1st attempt) file_name = 'data_3g-unlock_sim_screen-pin_screen' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {"sim": True, "no-sim": False} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry, '#unlock-sim-screen') # invalid pin -> error about pin characters # stay at app://communications.gaiamobile.org/ftu/index.html#data_3g (unlock-sim-screen screen) next = client.find_element('css selector', '#unlock-sim-button') next.tap() time.sleep(short_time) # app://communications.gaiamobile.org/ftu/index.html#data_3g (sim pin screen - unlock-sim-screen - pin error) file_name = 'data_3g-unlock_sim_screen-pin_screen-invalid_pin' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {"sim": True, "no-sim": False} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry, '#unlock-sim-screen') # insert wrong pin (attempt 1 of 3) pin_input = client.find_element('css selector', '#pin-input') pin_input.send_keys(wrong_sim_pin) # stay at app://communications.gaiamobile.org/ftu/index.html#data_3g (unlock-sim-screen screen) next = client.find_element('css selector', '#unlock-sim-button') next.tap() time.sleep(short_time) # app://communications.gaiamobile.org/ftu/index.html#data_3g (sim pin screen - unlock-sim-screen - 2nd attempt) file_name = 'data_3g-unlock_sim_screen-pin_screen-wrong_pin-1st_time' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {"sim": True, "no-sim": False} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry, '#unlock-sim-screen') # insert wrong pin (attempt 2 of 3) pin_input = client.find_element('css selector', '#pin-input') pin_input.send_keys(wrong_sim_pin) # stay at app://communications.gaiamobile.org/ftu/index.html#data_3g (unlock-sim-screen screen) next = client.find_element('css selector', '#unlock-sim-button') next.tap() time.sleep(short_time) # app://communications.gaiamobile.org/ftu/index.html#data_3g (sim pin screen - unlock-sim-screen - 3rd attempt) file_name = 'data_3g-unlock_sim_screen-pin_screen-wrong_pin-2nd_time' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {"sim": True, "no-sim": False} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry, '#unlock-sim-screen') # insert wrong pin (atempt 3 of 3) - continues to puk screen pin_input = client.find_element('css selector', '#pin-input') pin_input.send_keys(wrong_sim_pin) # switch to app://communications.gaiamobile.org/ftu/index.html#data_3g (sim puk screen - unlock-sim-screen) next = client.find_element('css selector', '#unlock-sim-button') next.tap() time.sleep(short_time) # tap the header in order to hide keyboard and get full screenshot of the puk screen header = client.find_element('css selector', '#unlock-sim-header') header.tap() # app://communications.gaiamobile.org/ftu/index.html#data_3g (sim puk screen - unlock-sim-screen - 1st attempt) file_name = 'data_3g-unlock_sim_screen-puk_screen' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {"sim": True, "no-sim": False} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry, '#unlock-sim-screen') # invalid puk -> error about puk characters # stay at app://communications.gaiamobile.org/ftu/index.html#data_3g (sim puk screen - unlock-sim-screen) next = client.find_element('css selector', '#unlock-sim-button') next.tap() time.sleep(short_time) # app://communications.gaiamobile.org/ftu/index.html#data_3g (sim puk screen - unlock-sim-screen - puk error) file_name = 'data_3g-unlock_sim_screen-puk_screen-invalid_puk' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {"sim": True, "no-sim": False} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry, '#unlock-sim-screen') # insert wrong puk - invalid new pin -> error about pin characters puk_input = client.find_element('css selector', '#puk-input') puk_input.send_keys(wrong_sim_puk) # stay at app://communications.gaiamobile.org/ftu/index.html#data_3g (sim puk screen - unlock-sim-screen) next = client.find_element('css selector', '#unlock-sim-button') next.tap() time.sleep(short_time) # app://communications.gaiamobile.org/ftu/index.html#data_3g (sim puk screen - unlock-sim-screen - pin error) file_name = 'data_3g-unlock_sim_screen-puk_screen-invalid_new_pin' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {"sim": True, "no-sim": False} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry, '#unlock-sim-screen') # insert new pin without confirmed it -> error about pin confirmation (wrong puk is preserved at its input) newpin_input = client.find_element('css selector', '#newpin-input') newpin_input.send_keys(sim_pin) # stay at app://communications.gaiamobile.org/ftu/index.html#data_3g (sim puk screen - unlock-sim-screen) next = client.find_element('css selector', '#unlock-sim-button') next.tap() time.sleep(short_time) # app://communications.gaiamobile.org/ftu/index.html#data_3g (sim puk screen - unlock-sim-screen - pin error) file_name = 'data_3g-unlock_sim_screen-puk_screen-invalid_new_pin_confirmation' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {"sim": True, "no-sim": False} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry, '#unlock-sim-screen') # insert confirmation of the new pin (wrong puk and new pin are preserved at their inputs) newpin_input = client.find_element('css selector', '#confirm-newpin-input') newpin_input.send_keys(sim_pin) # wrong puk (attempt 1 of 9) # stay at app://communications.gaiamobile.org/ftu/index.html#data_3g (sim puk screen - unlock-sim-screen) next = client.find_element('css selector', '#unlock-sim-button') next.tap() time.sleep(short_time) # app://communications.gaiamobile.org/ftu/index.html#data_3g (sim puk screen - unlock-sim-screen - puk error) file_name = 'data_3g-unlock_sim_screen-puk_screen-wrong_puk-1st_time' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {"sim": True, "no-sim": False} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry, '#unlock-sim-screen') # insert wrong puk (attempt 2 of 9) (new pin and its confirmation are preserved at their inputs) puk_input = client.find_element('css selector', '#puk-input') puk_input.send_keys(wrong_sim_puk) # stay at app://communications.gaiamobile.org/ftu/index.html#data_3g (sim puk screen - unlock-sim-screen) next = client.find_element('css selector', '#unlock-sim-button') next.tap() time.sleep(short_time) # app://communications.gaiamobile.org/ftu/index.html#data_3g (sim puk screen - unlock-sim-screen - 2nd attempt) file_name = 'data_3g-unlock_sim_screen-puk_screen-wrong_puk-2nd_time' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {"sim": True, "no-sim": False} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry, '#unlock-sim-screen') # insert right puk (attempt 2 of 9) (new pin and its confirmation are preserved at their inputs) puk_input = client.find_element('css selector', '#puk-input') puk_input.send_keys(sim_puk) # switch to app://communications.gaiamobile.org/ftu/index.html#data_3g next = client.find_element('css selector', '#unlock-sim-button') next.tap() time.sleep(short_time) # app://communications.gaiamobile.org/ftu/index.html#data_3g file_name = 'data_3g' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {"sim": True, "no-sim": False} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry, '#activation-screen') # switch to app://communications.gaiamobile.org/ftu/index.html#wifi next = client.find_element('css selector', '#forward') next.tap() time.sleep(long_time) # enable overlay "scanningNetworks" spinner screen (loading-overlay) client.execute_script( "window.wrappedJSObject.utils.overlay.show('scanningNetworks', 'spinner');" ) time.sleep(middle_time) # overlay "scanningNetworks" spinner screen file_name = 'wifi-loading_overlay-scanning_networks' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry, '#loading-overlay') # disable overlay "scanningNetworks" spinner screen client.execute_script( "window.wrappedJSObject.utils.overlay.hide('scanningNetworks', 'spinner');" ) time.sleep(middle_time) # app://communications.gaiamobile.org/ftu/index.html#wifi file_name = 'wifi' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry, '#wifi') # switch to app://communications.gaiamobile.org/ftu/index.html#date_and_time next = client.find_element('css selector', '#forward') next.tap() time.sleep(short_time) # Set time in order to be the same at every screenshot set_time(client) # app://communications.gaiamobile.org/ftu/index.html#date_and_time file_name = 'date_and_time' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry, '#date_and_time') # switch to app://communications.gaiamobile.org/ftu/index.html#geolocation next = client.find_element('css selector', '#forward') next.tap() time.sleep(short_time) # app://communications.gaiamobile.org/ftu/index.html#geolocation file_name = 'geolocation' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry, '#geolocation') # switch to app://communications.gaiamobile.org/ftu/index.html#import_contacts next = client.find_element('css selector', '#forward') next.tap() time.sleep(middle_time) # app://communications.gaiamobile.org/ftu/index.html#import_contacts file_name = 'import_contacts' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry, '#import_contacts') # switch to app://communications.gaiamobile.org/ftu/index.html#welcome_browser next = client.find_element('css selector', '#forward') next.tap() time.sleep(short_time) # app://communications.gaiamobile.org/ftu/index.html#welcome_browser file_name = 'welcome_browser' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry) # switch to app://communications.gaiamobile.org/ftu/index.html#browser_privacy next = client.find_element('css selector', '#forward') next.tap() time.sleep(short_time) # app://communications.gaiamobile.org/ftu/index.html#browser_privacy file_name = 'browser_privacy' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry) # switch to app://communications.gaiamobile.org/ftu/index.html#step1 (first tutorial screen) next = client.find_element('css selector', '#forward') next.tap() time.sleep(long_time) # app://communications.gaiamobile.org/ftu/index.html#step1 (first tutorial screen) file_name = 'step1-first_tutorial_screen' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry) # switch to app://communications.gaiamobile.org/ftu/index.html#step1 next = client.find_element('css selector', '#lets-go-button') next.tap() time.sleep(long_time) # app://communications.gaiamobile.org/ftu/index.html#step1 file_name = 'step1' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry) # switch to app://communications.gaiamobile.org/ftu/index.html#step2 next = client.find_element('css selector', '#forwardTutorial') next.tap() time.sleep(short_time) # app://communications.gaiamobile.org/ftu/index.html#step2 file_name = 'step2' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry) # switch to app://communications.gaiamobile.org/ftu/index.html#step3 next = client.find_element('css selector', '#forwardTutorial') next.tap() time.sleep(short_time) # app://communications.gaiamobile.org/ftu/index.html#step3 file_name = 'step3' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry) # switch to app://communications.gaiamobile.org/ftu/index.html#step4 next = client.find_element('css selector', '#forwardTutorial') next.tap() time.sleep(short_time) # app://communications.gaiamobile.org/ftu/index.html#step4 file_name = 'step4' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry) # switch to app://communications.gaiamobile.org/ftu/index.html#step4 (last tutorial screen) next = client.find_element('css selector', '#forwardTutorial') next.tap() time.sleep(long_time) # app://communications.gaiamobile.org/ftu/index.html#step4 (last tutorial screen) file_name = 'step4-last_tutorial_screen' screenshot_entry = { "id": file_name, "script": app, "gaia": gaia_hash, "hg": hg_hash, "changed": False, "path": screenshot_path } test_flags = {} if check_flags(test_flags, device_flags): screenshot_entry.update(test_flags) if take_screenshot(locale, screenshot_path, client, file_name): screenshot_entry['changed'] = True log_displayed_l10n_strings(client, db, app, app_categ, screenshot_entry) # Close ftu frame next = client.find_element('css selector', '#tutorialFinished') next.tap() time.sleep(short_time) set_db(locale, db) else: #TO DO raise proper error print "switch to ftu frame failed"
class B2GMochitest(MochitestUtilsMixin): marionette = None def __init__(self, marionette_args, logger_options, out_of_process=True, profile_data_dir=None, locations=os.path.join(here, 'server-locations.txt')): super(B2GMochitest, self).__init__(logger_options) self.marionette_args = marionette_args self.out_of_process = out_of_process self.locations_file = locations self.preferences = [] self.webapps = None self.test_script = os.path.join(here, 'b2g_start_script.js') self.test_script_args = [self.out_of_process] self.product = 'b2g' self.remote_chrome_test_dir = None if profile_data_dir: self.preferences = [ os.path.join(profile_data_dir, f) for f in os.listdir(profile_data_dir) if f.startswith('pref') ] self.webapps = [ os.path.join(profile_data_dir, f) for f in os.listdir(profile_data_dir) if f.startswith('webapp') ] # mozinfo is populated by the parent class if mozinfo.info['debug']: self.SERVER_STARTUP_TIMEOUT = 180 else: self.SERVER_STARTUP_TIMEOUT = 90 def setup_common_options(self, options): test_url = self.buildTestPath(options) # For B2G emulators buildURLOptions has been called # without calling buildTestPath first and that # causes manifestFile not to be set if not "manifestFile=tests.json" in self.urlOpts: self.urlOpts.append("manifestFile=%s" % options.manifestFile) if len(self.urlOpts) > 0: test_url += "?" + "&".join(self.urlOpts) self.test_script_args.append(test_url) def buildTestPath(self, options, testsToFilter=None): if options.manifestFile != 'tests.json': super(B2GMochitest, self).buildTestPath(options, testsToFilter, disabled=False) return self.buildTestURL(options) def build_profile(self, options): # preferences prefs = {} for path in self.preferences: prefs.update(Preferences.read_prefs(path)) for v in options.extraPrefs: thispref = v.split("=", 1) if len(thispref) < 2: print "Error: syntax error in --setpref=" + v sys.exit(1) prefs[thispref[0]] = thispref[1] # interpolate the preferences interpolation = { "server": "%s:%s" % (options.webServer, options.httpPort), "OOP": "true" if self.out_of_process else "false" } prefs = json.loads(json.dumps(prefs) % interpolation) for pref in prefs: prefs[pref] = Preferences.cast(prefs[pref]) kwargs = { 'addons': self.getExtensionsToInstall(options), 'apps': self.webapps, 'locations': self.locations_file, 'preferences': prefs, 'proxy': { "remote": options.webServer } } if options.profile: self.profile = Profile.clone(options.profile, **kwargs) else: self.profile = Profile(**kwargs) options.profilePath = self.profile.profile # TODO bug 839108 - mozprofile should probably handle this manifest = self.addChromeToProfile(options) self.copyExtraFilesToProfile(options) return manifest def run_tests(self, options): """ Prepare, configure, run tests and cleanup """ manifest = self.build_profile(options) self.logPreamble(self.getActiveTests(options)) # configuring the message logger's buffering self.message_logger.buffering = options.quiet if options.debugger or not options.autorun: timeout = None else: if not options.timeout: if mozinfo.info['debug']: options.timeout = 420 else: options.timeout = 300 timeout = options.timeout + 30.0 self.log.info("runtestsb2g.py | Running tests: start.") status = 0 try: def on_output(line): messages = self.message_logger.write(line) for message in messages: if message['action'] == 'test_start': self.runner.last_test = message['test'] # The logging will be handled by on_output, so we set the stream to None process_args = {'processOutputLine': on_output, 'stream': None} self.marionette_args['process_args'] = process_args self.marionette_args['profile'] = self.profile self.marionette = Marionette(**self.marionette_args) self.runner = self.marionette.runner self.app_ctx = self.runner.app_ctx self.remote_log = posixpath.join(self.app_ctx.remote_test_root, 'log', 'mochitest.log') if not self.app_ctx.dm.dirExists(posixpath.dirname( self.remote_log)): self.app_ctx.dm.mkDirs(self.remote_log) if options.chrome: # Update chrome manifest file in profile with correct path. self.writeChromeManifest(options) self.leak_report_file = posixpath.join( self.app_ctx.remote_test_root, 'log', 'runtests_leaks.log') # We don't want to copy the host env onto the device, so pass in an # empty env. self.browserEnv = self.buildBrowserEnv(options, env={}) # B2G emulator debug tests still make external connections, so don't # pass MOZ_DISABLE_NONLOCAL_CONNECTIONS to them for now (bug 1039019). if mozinfo.info[ 'debug'] and 'MOZ_DISABLE_NONLOCAL_CONNECTIONS' in self.browserEnv: del self.browserEnv['MOZ_DISABLE_NONLOCAL_CONNECTIONS'] self.runner.env.update(self.browserEnv) self.startServers(options, None) self.buildURLOptions(options, {'MOZ_HIDE_RESULTS_TABLE': '1'}) self.test_script_args.append(not options.emulator) self.test_script_args.append(options.wifi) self.test_script_args.append(options.chrome) self.runner.start(outputTimeout=timeout) self.marionette.wait_for_port() self.marionette.start_session() self.marionette.set_context(self.marionette.CONTEXT_CHROME) # Disable offline status management (bug 777145), otherwise the network # will be 'offline' when the mochitests start. Presumably, the network # won't be offline on a real device, so we only do this for emulators. self.marionette.execute_script(""" Components.utils.import("resource://gre/modules/Services.jsm"); Services.io.manageOfflineStatus = false; Services.io.offline = false; """) if options.chrome: self.app_ctx.dm.removeDir(self.remote_chrome_test_dir) self.app_ctx.dm.mkDir(self.remote_chrome_test_dir) local = super(B2GMochitest, self).getChromeTestDir(options) local = os.path.join(local, "chrome") remote = self.remote_chrome_test_dir self.log.info("pushing %s to %s on device..." % (local, remote)) self.app_ctx.dm.pushDir(local, remote) if os.path.isfile(self.test_script): with open(self.test_script, 'r') as script: self.marionette.execute_script( script.read(), script_args=self.test_script_args) else: self.marionette.execute_script( self.test_script, script_args=self.test_script_args) status = self.runner.wait() if status is None: # the runner has timed out status = 124 local_leak_file = tempfile.NamedTemporaryFile() self.app_ctx.dm.getFile(self.leak_report_file, local_leak_file.name) self.app_ctx.dm.removeFile(self.leak_report_file) processLeakLog(local_leak_file.name, options) except KeyboardInterrupt: self.log.info("runtests.py | Received keyboard interrupt.\n") status = -1 except: traceback.print_exc() self.log.error( "Automation Error: Received unexpected exception while running application\n" ) if hasattr(self, 'runner'): self.runner.check_for_crashes() status = 1 self.stopServers() self.log.info("runtestsb2g.py | Running tests: end.") if manifest is not None: self.cleanup(manifest, options) return status def getGMPPluginPath(self, options): # TODO: bug 1043403 return None def getChromeTestDir(self, options): # The chrome test directory returned here is the remote location # of chrome test files. A reference to this directory is requested # when building the profile locally, before self.app_ctx is defined. # To get around this, return a dummy directory until self.app_ctx # is defined; the correct directory will be returned later, over- # writing the dummy. if hasattr(self, 'app_ctx'): self.remote_chrome_test_dir = posixpath.join( self.app_ctx.remote_test_root, 'chrome') return self.remote_chrome_test_dir return 'dummy-chrome-test-dir'
def kill(origin): marionette = Marionette(host='localhost', port=2828) marionette.start_session() marionette.set_context(marionette.CONTEXT_CONTENT) marionette.execute_script( "window.wrappedJSObject.WindowManager.kill('%s')" % origin)
class GCli(object): def __init__(self): self.commands = { 'connectwifi': { 'function': self.connect_to_wifi, 'args': [ {'name': 'ssid', 'help': 'SSID of the network to connect to'}, {'name': '--security', 'choices': ['WPA-PSK', 'WEP'], 'help': 'Security model of the network'}, {'name': '--password', 'help': 'Password to access the network'}], 'help': 'Connect to a WiFi network'}, 'disablewifi': { 'function': self.disable_wifi, 'help': 'Disable WiFi'}, 'enablewifi': { 'function': self.enable_wifi, 'help': 'Enable WiFi'}, 'forgetallwifi': { 'function': self.forget_all_wifi_networks, 'help': 'Forget all WiFi networks'}, 'getknownwifi': { 'function': self.known_wifi_networks, 'help': 'Show known WiFi networks'}, 'getsetting': { 'function': self.get_setting, 'args': [{ 'name': 'name', 'help': 'Name of the setting to retrieve'}], 'help': 'Show the current value of a setting'}, 'holdhome': { 'function': self.hold_home, 'help': 'Simulate holding the home button'}, 'holdsleep': { 'function': self.hold_sleep, 'help': 'Simulate holding the sleep button'}, 'home': { 'function': self.home, 'help': 'Simulate pressing the home button'}, 'killapps': { 'function': self.kill_all_apps, 'help': 'Kill all running apps'}, 'launchapp': { 'function': self.launch_app, 'args': [ {'name': 'name', 'nargs': argparse.REMAINDER, 'help': 'Name of app to launch'}], 'help': 'Launch an application'}, 'lock': { 'function': self.lock, 'help': 'Lock screen'}, 'screenshot': { 'function': self.screenshot, 'help': 'Take a screenshot'}, 'sendsms': { 'function': self.send_sms, 'args': [ {'name': 'number', 'help': 'Phone number of recipient'}, {'name': 'message', 'help': 'Message content'}], 'help': 'Send an SMS'}, 'setsetting': { 'function': self.set_setting, 'args': [ {'name': 'name', 'help': 'Name of setting to change'}, {'name': 'value', 'help': 'New value for setting'}], 'help': 'Change the value of a setting'}, 'sleep': { 'function': self.sleep, 'help': 'Enter sleep mode'}, 'unlock': { 'function': self.unlock, 'help': 'Unlock screen'}, 'volume': { 'function': self.volume, 'args': [ {'name': 'direction', 'choices': ['down', 'up'], 'help': 'Direction to change the volume'}], 'help': 'Change the volume'}, 'wake': { 'function': self.wake, 'help': 'Wake from sleep mode'}} self.parser = argparse.ArgumentParser() self.add_options(self.parser) self.add_commands(self.parser) def run(self, args=sys.argv[1:]): args = self.parser.parse_args() host, port = args.address.split(':') self.marionette = Marionette(host=host, port=int(port)) self.marionette.start_session() self.apps = gaiatest.GaiaApps(self.marionette) self.data_layer = gaiatest.GaiaData(self.marionette) self.lock_screen = gaiatest.LockScreen(self.marionette) ret = args.func(args) if ret is None: ret = 0 self.marionette.delete_session() sys.exit(ret) def add_options(self, parser): parser.add_argument( '--address', default='localhost:2828', help='Address (host:port) of running Gecko instance to connect to ' '(default: %(default)s)') def add_commands(self, parser): subparsers = parser.add_subparsers( title='Commands', metavar='<command>') for (name, props) in sorted(self.commands.iteritems()): subparser = subparsers.add_parser(name, help=props['help']) if props.get('args'): for arg in props['args']: kwargs = {k: v for k, v in arg.items() if k is not 'name'} subparser.add_argument(arg['name'], **kwargs) subparser.set_defaults(func=props['function']) def connect_to_wifi(self, args): network = { 'ssid': args.ssid, 'keyManagement': args.security or 'NONE'} if args.security == 'WEP': network['wep'] = args.password elif args.security == 'WPA-PSK': network['psk'] = args.password self.data_layer.connect_to_wifi(network) def disable_wifi(self, args): self.data_layer.disable_wifi() def enable_wifi(self, args): self.data_layer.enable_wifi() def forget_all_wifi_networks(self, args): self.data_layer.forget_all_networks() def get_setting(self, args): print '%s: %s' % ( args.name, self.data_layer.get_setting(args.name)) def home(self, args): self.marionette.execute_script( "window.wrappedJSObject.dispatchEvent(new Event('home'));") def hold_home(self, args): self.marionette.execute_script( "window.wrappedJSObject.dispatchEvent(new Event('holdhome'));") def hold_sleep(self, args): self.marionette.execute_script( "window.wrappedJSObject.dispatchEvent(new Event('holdsleep'));") def kill_all_apps(self, args): self.apps.kill_all() def known_wifi_networks(self, args): networks = [n for n in self.data_layer.known_networks if 'ssid' in n] if len(networks) > 0: for i, network in enumerate(networks): print '%s: %s' % (i + 1, network['ssid']) else: print 'No known networks.' def launch_app(self, args): for name in args.name: self.apps.launch(name) def lock(self, args): self.lock_screen.lock() def screenshot(self, args): self.marionette.execute_script( "window.wrappedJSObject.dispatchEvent(new Event('home+sleep'));") def send_sms(self, args): self.data_layer.send_sms(args.number, args.message) def set_setting(self, args): self.data_layer.set_setting(args.name, args.value) def sleep(self, args): self.marionette.execute_script( "window.wrappedJSObject.dispatchEvent(new Event('sleep'));") def unlock(self, args): self.lock_screen.unlock() def volume(self, args): self.marionette.execute_script( "window.wrappedJSObject.dispatchEvent(new Event('volume%s'));" % args.direction) def wake(self, args): self.marionette.execute_script( "window.wrappedJSObject.dispatchEvent(new Event('wake'));")
def runApp(self, profile, binary, cmdargs, env, timeout=None, debuggerInfo=None, symbolsPath=None, options=None, valgrindPath=None, valgrindArgs=None, valgrindSuppFiles=None): def timeoutHandler(): self.handleTimeout(timeout, proc, options.utilityPath, debuggerInfo) interactive = False debug_args = None if debuggerInfo: interactive = debuggerInfo.interactive debug_args = [debuggerInfo.path] + debuggerInfo.args def record_last_test(message): """Records the last test seen by this harness for the benefit of crash logging.""" if message['action'] == 'test_start': if isinstance(message['test'], tuple): self.lastTestSeen = message['test'][0] else: self.lastTestSeen = message['test'] self.log.add_handler(record_last_test) outputHandler = OutputHandler(self.log, options.utilityPath, symbolsPath=symbolsPath) kp_kwargs = { 'kill_on_timeout': False, 'cwd': SCRIPT_DIRECTORY, 'onTimeout': [timeoutHandler], 'processOutputLine': [outputHandler], } if interactive: # If an interactive debugger is attached, # don't use timeouts, and don't capture ctrl-c. timeout = None signal.signal(signal.SIGINT, lambda sigid, frame: None) if mozinfo.info.get( 'appname') == 'b2g' and mozinfo.info.get('toolkit') != 'gonk': runner_cls = mozrunner.Runner else: runner_cls = mozrunner.runners.get( mozinfo.info.get('appname', 'firefox'), mozrunner.Runner) runner = runner_cls(profile=profile, binary=binary, process_class=mozprocess.ProcessHandlerMixin, cmdargs=cmdargs, env=env, process_args=kp_kwargs) runner.start(debug_args=debug_args, interactive=interactive, outputTimeout=timeout) proc = runner.process_handler if self.use_marionette: marionette_args = {'symbols_path': options.symbolsPath} if options.marionette: host, port = options.marionette.split(':') marionette_args['host'] = host marionette_args['port'] = int(port) marionette = Marionette(**marionette_args) marionette.start_session() addons = Addons(marionette) if options.specialPowersExtensionPath: addons.install(options.specialPowersExtensionPath, temp=True) addons.install(options.reftestExtensionPath, temp=True) marionette.delete_session() status = runner.wait() runner.process_handler = None if status: msg = "TEST-UNEXPECTED-FAIL | %s | application terminated with exit code %s" % \ (self.lastTestSeen, status) # use process_output so message is logged verbatim self.log.process_output(None, msg) else: self.lastTestSeen = 'Main app process exited normally' crashed = mozcrash.log_crashes(self.log, os.path.join(profile.profile, 'minidumps'), symbolsPath, test=self.lastTestSeen) runner.cleanup() if not status and crashed: status = 1 return status
class B2GDesktopReftest(RefTest): marionette = None def __init__(self, marionette_args): RefTest.__init__(self) self.last_test = os.path.basename(__file__) self.marionette_args = marionette_args self.profile = None self.runner = None self.test_script = os.path.join(here, 'b2g_start_script.js') self.timeout = None def run_marionette_script(self): self.marionette = Marionette(**self.marionette_args) assert (self.marionette.wait_for_port()) self.marionette.start_session() self.marionette.set_context(self.marionette.CONTEXT_CHROME) if os.path.isfile(self.test_script): f = open(self.test_script, 'r') self.test_script = f.read() f.close() self.marionette.execute_script(self.test_script) def run_tests(self, test_path, options): reftestlist = self.getManifestPath(test_path) if not reftestlist.startswith('file://'): reftestlist = 'file://%s' % reftestlist self.profile = self.create_profile(options, reftestlist, profile_to_clone=options.profile) env = self.buildBrowserEnv(options, self.profile.profile) kp_kwargs = { 'processOutputLine': [self._on_output], 'onTimeout': [self._on_timeout], 'kill_on_timeout': False } if not options.debugger: if not options.timeout: if mozinfo.info['debug']: options.timeout = 420 else: options.timeout = 300 self.timeout = options.timeout + 30.0 log.info("%s | Running tests: start.", os.path.basename(__file__)) cmd, args = self.build_command_line( options.app, ignore_window_size=options.ignoreWindowSize, browser_arg=options.browser_arg) self.runner = FirefoxRunner(profile=self.profile, binary=cmd, cmdargs=args, env=env, process_class=ProcessHandler, process_args=kp_kwargs, symbols_path=options.symbolsPath) status = 0 try: self.runner.start(outputTimeout=self.timeout) log.info("%s | Application pid: %d", os.path.basename(__file__), self.runner.process_handler.pid) # kick starts the reftest harness self.run_marionette_script() status = self.runner.wait() finally: self.runner.check_for_crashes(test_name=self.last_test) self.runner.cleanup() if status > 0: log.testFail("%s | application terminated with exit code %s", self.last_test, status) elif status < 0: log.info("%s | application killed with signal %s", self.last_test, -status) log.info("%s | Running tests: end.", os.path.basename(__file__)) return status def create_profile(self, options, reftestlist, profile_to_clone=None): profile = RefTest.createReftestProfile( self, options, reftestlist, profile_to_clone=profile_to_clone) prefs = {} # Turn off the locale picker screen prefs["browser.firstrun.show.localepicker"] = False prefs[ "b2g.system_startup_url"] = "app://test-container.gaiamobile.org/index.html" prefs[ "b2g.system_manifest_url"] = "app://test-container.gaiamobile.org/manifest.webapp" prefs["browser.tabs.remote"] = False prefs["dom.ipc.tabs.disabled"] = False prefs["dom.mozBrowserFramesEnabled"] = True prefs["font.size.inflation.emPerLine"] = 0 prefs["font.size.inflation.minTwips"] = 0 prefs[ "network.dns.localDomains"] = "app://test-container.gaiamobile.org" prefs["reftest.browser.iframe.enabled"] = False prefs["reftest.remote"] = False prefs["reftest.uri"] = "%s" % reftestlist # Set a future policy version to avoid the telemetry prompt. prefs["toolkit.telemetry.prompted"] = 999 prefs["toolkit.telemetry.notifiedOptOut"] = 999 # Set the extra prefs. profile.set_preferences(prefs) return profile def build_command_line(self, app, ignore_window_size=False, browser_arg=None): cmd = os.path.abspath(app) args = ['-marionette'] if browser_arg: args += [browser_arg] if not ignore_window_size: args.extend(['--screen', '800x1000']) return cmd, args def _on_output(self, line): print(line) # TODO use structured logging if "TEST-START" in line and "|" in line: self.last_test = line.split("|")[1].strip() def _on_timeout(self): msg = "%s | application timed out after %s seconds with no output" log.testFail(msg % (self.last_test, self.timeout)) # kill process to get a stack self.runner.stop(sig=signal.SIGABRT)
def cli(): parser = dzOptionParser(usage='%prog [options] app_name [app_name] ...') parser.add_option( '--delay', action='store', type='float', dest='delay', default=1, # TODO default is needed due to bug 821766 # (and perhaps also to prevent panda board overheating...) metavar='float', help= 'duration (in seconds) to wait before each iteration (default: %default)' ) parser.add_option( '--iterations', action='store', type=int, dest='iterations', default=30, metavar='int', help='number of times to launch each app (default: %default)') parser.add_option('--no-restart', action='store_false', dest='restart', default=True, help='do not restart B2G between tests') parser.add_option( '--settle-time', action='store', type='float', dest='settle_time', default=60, metavar='float', help='time to wait before initial launch (default: %default)') parser.add_option( '--test-type', action='store', type='str', dest='test_type', default='startup', metavar='str', help='type of test to run, valid types are: %s (default: startup)' % TEST_TYPES), parser.add_option('--testvars', action='store', dest='testvars', metavar='str', help='path to a json file with any test data required') options, args = parser.parse_args() if not args: parser.print_usage() parser.exit() if len(args) < 1: parser.print_usage() print 'must specify at least one app name' parser.exit() if options.test_type not in TEST_TYPES: print 'Invalid test type. Test type must be one of %s' % TEST_TYPES parser.exit() testvars = {} if options.testvars: if not os.path.exists(options.testvars): raise Exception('--testvars file does not exist') import json with open(options.testvars) as f: testvars = json.loads(f.read()) datazilla_config = parser.datazilla_config(options) marionette = Marionette(host='localhost', port=2828) # TODO command line option for address marionette.start_session() b2gperf = B2GPerfRunner(marionette, datazilla_config=datazilla_config, sources=options.sources) b2gperf.measure_app_perf(app_names=args, delay=options.delay, iterations=options.iterations, restart=options.restart, settle_time=options.settle_time, test_type=options.test_type, testvars=testvars)
import threading from testserver import TestServer from marionette import Marionette, HTMLElement if __name__ == '__main__': # start the test server server = TestServer(2626) thread = threading.Thread(target=server.run) thread.daemon = True thread.start() # run some trivial unit tests which just verify the protocol m = Marionette(host='localhost', port=2626) assert(m.status()['os']['arch'] == 'x86') assert(m.start_session()) assert(m.get_session_capabilities()['javascriptEnabled'] == True) assert(m.get_window() == server.TEST_CURRENT_WINDOW) assert(m.window == server.TEST_CURRENT_WINDOW) assert(m.get_windows() == server.TEST_WINDOW_LIST) assert(m.switch_to_window('window2')) assert(m.window == 'window2') assert(m.close_window('window2')) assert(m.set_script_timeout(1000)) assert(m.set_search_timeout(500)) assert(m.get_url() == server.TEST_URL) assert(m.navigate(server.TEST_URL)) assert(m.go_back()) assert(m.go_forward()) assert(m.refresh()) assert(m.execute_script(server.TEST_EXECUTE_SCRIPT))
def cli(): parser = dzOptionParser(usage='%prog file [options]') options, args = parser.parse_args() # Ensure have all required options if (not options.datazilla_project or not options.datazilla_branch or not options.datazilla_key or not options.datazilla_secret): parser.print_help() parser.exit() # Either a single file or option to process all in given folder if (not options.results_file) and (not options.process_dir): parser.print_help() parser.exit() if options.results_file and options.process_dir: parser.print_help() parser.exit() # Ensure results file actually exists if options.results_file: if not os.path.exists(options.results_file): raise Exception('%s file does not exist' %options.results_file) if options.process_dir: if not os.path.exists(options.process_dir): raise Exception("Process all path '%s' does not exist" %options.process_dir) # Parse config options datazilla_config = parser.datazilla_config(options) # Start marionette session marionette = Marionette(host='localhost', port=2828) # TODO command line option for address marionette.start_session() # Create datazilla post object poster = DatazillaPerfPoster(marionette, datazilla_config=datazilla_config, sources=options.sources) # If was an error getting required values then poster.submit_report will be false; # if it is true then ok to submit if user wants to if poster.submit_report: if not options.send_to_datazilla: poster.submit_report = False # Parse checkpoint results from provided summary log file checkpoint_summary = {} results = {} summary_file_list = [] if options.process_dir: # All files in the given path file_path = options.process_dir print "\nSearching for *_summary.log files in %s\n" % options.process_dir entire_file_list = os.listdir(file_path) if len(entire_file_list) == 0: raise Exception("No checkpoint *_summary.log files were found in the given path") for found_file in entire_file_list: if found_file.endswith("summary.log") and found_file != "avg_b2g_rss_suite_summary.log": summary_file_list.append("%s/%s" % (file_path, found_file)) if len(summary_file_list) == 0: raise Exception("No checkpoint *_summary.log files were found in the given path") print "Found the following checkpoint summary files to process:\n" for x in summary_file_list: print "%s" % x print "\n" + "-" * 50 else: # Just one file summary_file_list = [options.results_file] for next_file in summary_file_list: # Clear results as only want results for current file being processed results = {} print "\nProcessing results in '%s'\n" % next_file summary_file = open(next_file, 'r') read_in = summary_file.read().split("\n") summary_file.close() for x in read_in: try: if x.find(':') != -1: # Ignore empty lines ie. last line of file which is empty k, v = x.split(': ') if k in "average": checkpoint_summary[k] = int(v) elif k in "test_name": # Prefix test name so all tests are grouped together in datazilla checkpoint_summary[k] = "power_" + v else: checkpoint_summary[k] = v except: raise Exception("Value missing from '%s', cannot proceed." % options.results_file) # Results dictionary required format example # {'test_name': [180892, 180892, 181980, 181852, 180828, 182012, 183652, 182972, 183052, 183052]} results[checkpoint_summary['test_name']] = checkpoint_summary['average'] # Display the Datazilla configuration print 'Datazilla configuration:' for key, value in poster.required.items(): print key + ":", value # Submit or print the results if poster.submit_report: #poster.post_to_datazilla(results, checkpoint_summary['test_name']) poster.post_to_datazilla(results, checkpoint_summary['app_under_test']) else: print "\nCheckpoint summary for test '%s':\n" % checkpoint_summary['test_name'] print checkpoint_summary print '\Power test results data:\n' print results print "\nTo submit results, fix any missing fields and use the '--submit' option.\n" if options.process_dir: # Sleep between submissions print "Pausing...\n" time.sleep(30) print "-" * 50 if options.process_dir: print "\nFinished processing all files.\n"
def cli(): parser = dzOptionParser(usage='%prog [options] app_name [app_name] ...') parser.add_option('--delay', action='store', type='float', dest='delay', default=1, # TODO default is needed due to bug 821766 # (and perhaps also to prevent panda board overheating...) metavar='float', help='duration (in seconds) to wait before each iteration (default: %default)') parser.add_option('--iterations', action='store', type=int, dest='iterations', default=30, metavar='int', help='number of times to launch each app (default: %default)') parser.add_option('--log-level', action='store', dest='log_level', default='INFO', metavar='str', help='threshold for log output (default: %default)') parser.add_option('--no-restart', action='store_false', dest='restart', default=True, help='do not restart B2G between tests') parser.add_option('--settle-time', action='store', type='float', dest='settle_time', default=60, metavar='float', help='time to wait before initial launch (default: %default)') parser.add_option('--test-type', action='store', type='str', dest='test_type', default='startup', metavar='str', help='type of test to run, valid types are: %s (default: startup)' % TEST_TYPES), parser.add_option('--testvars', action='store', dest='testvars', metavar='str', help='path to a json file with any test data required') options, args = parser.parse_args() if not args: parser.print_usage() parser.exit() if len(args) < 1: parser.print_usage() print 'must specify at least one app name' parser.exit() if options.test_type not in TEST_TYPES: print 'Invalid test type. Test type must be one of %s' % TEST_TYPES parser.exit() testvars = {} if options.testvars: if not os.path.exists(options.testvars): raise Exception('--testvars file does not exist') import json with open(options.testvars) as f: testvars = json.loads(f.read()) datazilla_config = parser.datazilla_config(options) marionette = Marionette(host='localhost', port=2828) # TODO command line option for address marionette.start_session() b2gperf = B2GPerfRunner(marionette, datazilla_config=datazilla_config, sources=options.sources, log_level=options.log_level) b2gperf.measure_app_perf( app_names=args, delay=options.delay, iterations=options.iterations, restart=options.restart, settle_time=options.settle_time, test_type=options.test_type, testvars=testvars)
waitFor( function() { window.wrappedJSObject.LockScreen.unlock(); waitFor( function() { finish(window.wrappedJSObject.LockScreen.locked); }, function() { return !window.wrappedJSObject.LockScreen.locked; } ); }, function() { return !!window.wrappedJSObject.LockScreen; } ); """ from marionette import Marionette marionette = Marionette('localhost', 2828) marionette.start_session() marionette.import_script('gaia_apps.js') marionette.set_script_timeout(60000) marionette.execute_script(unlock) result = marionette.execute_async_script("GaiaApps.launchWithName('%s')" % "MozCampAsia-QualityApps") marionette.switch_to_frame(result.get("frame")) pdb.set_trace()
# https://wiki.mozilla.org/Auto-tools/Projects/Marionette/DevNotes#Running_B2G_on_an_emulator # # You should also set your B2G_HOME environment variable to point to the # directory where the B2G code lives. # if __name__ == '__main__': # launch two instance of Marionette, each with their own emulator driver1 = Marionette(emulator=True, port=2828) assert(driver1.emulator.is_running) assert(driver1.emulator.port) print 'emulator1 is running on port', driver1.emulator.port assert(driver1.port != 2828) print 'emulator1 port forwarding configured from port', driver1.port print 'on localhost to port 2828 on the device' assert(driver1.start_session()) driver2 = Marionette(emulator=True, port=2828) assert(driver2.emulator.is_running) assert(driver2.emulator.port) print 'emulator2 is running on port', driver2.emulator.port assert(driver2.port != 2828) print 'emulator1 port forwarding configured from port', driver2.port print 'on localhost to port 2828 on the device' assert(driver2.start_session()) # shutdown both emulators assert(driver2.emulator.close() == 0) assert(not driver2.emulator.is_running) assert(driver1.emulator.close() == 0) assert(not driver1.emulator.is_running)
class B2GMochitest(MochitestUtilsMixin): marionette = None def __init__(self, marionette_args, logger_options, out_of_process=True, profile_data_dir=None, locations=os.path.join(here, 'server-locations.txt')): super(B2GMochitest, self).__init__(logger_options) self.marionette_args = marionette_args self.out_of_process = out_of_process self.locations_file = locations self.preferences = [] self.webapps = None self.test_script = os.path.join(here, 'b2g_start_script.js') self.test_script_args = [self.out_of_process] self.product = 'b2g' self.remote_chrome_test_dir = None if profile_data_dir: self.preferences = [ os.path.join(profile_data_dir, f) for f in os.listdir(profile_data_dir) if f.startswith('pref') ] self.webapps = [ os.path.join(profile_data_dir, f) for f in os.listdir(profile_data_dir) if f.startswith('webapp') ] # mozinfo is populated by the parent class if mozinfo.info['debug']: self.SERVER_STARTUP_TIMEOUT = 180 else: self.SERVER_STARTUP_TIMEOUT = 90 def setup_common_options(self, options): test_url = self.buildTestPath(options) # For B2G emulators buildURLOptions has been called # without calling buildTestPath first and that # causes manifestFile not to be set if not "manifestFile=tests.json" in self.urlOpts: self.urlOpts.append("manifestFile=%s" % options.manifestFile) if len(self.urlOpts) > 0: test_url += "?" + "&".join(self.urlOpts) self.test_script_args.append(test_url) def buildTestPath(self, options, testsToFilter=None): if options.manifestFile != 'tests.json': super(B2GMochitest, self).buildTestPath(options, testsToFilter, disabled=False) return self.buildTestURL(options) def build_profile(self, options): # preferences prefs = {} for path in self.preferences: prefs.update(Preferences.read_prefs(path)) for v in options.extraPrefs: thispref = v.split("=", 1) if len(thispref) < 2: print "Error: syntax error in --setpref=" + v sys.exit(1) prefs[thispref[0]] = thispref[1] # interpolate the preferences interpolation = { "server": "%s:%s" % (options.webServer, options.httpPort), "OOP": "true" if self.out_of_process else "false" } prefs = json.loads(json.dumps(prefs) % interpolation) for pref in prefs: prefs[pref] = Preferences.cast(prefs[pref]) kwargs = { 'addons': self.getExtensionsToInstall(options), 'apps': self.webapps, 'locations': self.locations_file, 'preferences': prefs, 'proxy': { "remote": options.webServer } } if options.profile: self.profile = Profile.clone(options.profile, **kwargs) else: self.profile = Profile(**kwargs) options.profilePath = self.profile.profile # TODO bug 839108 - mozprofile should probably handle this manifest = self.addChromeToProfile(options) self.copyExtraFilesToProfile(options) return manifest def run_tests(self, options): """ Prepare, configure, run tests and cleanup """ self.setTestRoot(options) manifest = self.build_profile(options) self.logPreamble(self.getActiveTests(options)) # configuring the message logger's buffering self.message_logger.buffering = options.quiet if options.debugger or not options.autorun: timeout = None else: if not options.timeout: if mozinfo.info['debug']: options.timeout = 420 else: options.timeout = 300 timeout = options.timeout + 30.0 self.log.info("runtestsb2g.py | Running tests: start.") status = 0 try: def on_output(line): messages = self.message_logger.write(line) for message in messages: if message['action'] == 'test_start': self.runner.last_test = message['test'] # The logging will be handled by on_output, so we set the stream to # None process_args = {'processOutputLine': on_output, 'stream': None} self.marionette_args['process_args'] = process_args self.marionette_args['profile'] = self.profile self.marionette = Marionette(**self.marionette_args) self.runner = self.marionette.runner self.app_ctx = self.runner.app_ctx self.remote_log = posixpath.join(self.app_ctx.remote_test_root, 'log', 'mochitest.log') if not self.app_ctx.dm.dirExists(posixpath.dirname( self.remote_log)): self.app_ctx.dm.mkDirs(self.remote_log) if options.chrome: # Update chrome manifest file in profile with correct path. self.writeChromeManifest(options) self.leak_report_file = posixpath.join( self.app_ctx.remote_test_root, 'log', 'runtests_leaks.log') # We don't want to copy the host env onto the device, so pass in an # empty env. self.browserEnv = self.buildBrowserEnv(options, env={}) # B2G emulator debug tests still make external connections, so don't # pass MOZ_DISABLE_NONLOCAL_CONNECTIONS to them for now (bug # 1039019). if mozinfo.info[ 'debug'] and 'MOZ_DISABLE_NONLOCAL_CONNECTIONS' in self.browserEnv: del self.browserEnv['MOZ_DISABLE_NONLOCAL_CONNECTIONS'] self.runner.env.update(self.browserEnv) # Despite our efforts to clean up servers started by this script, in practice # we still see infrequent cases where a process is orphaned and interferes # with future tests, typically because the old server is keeping the port in use. # Try to avoid those failures by checking for and killing orphan servers before # trying to start new ones. self.killNamedOrphans('ssltunnel') self.killNamedOrphans('xpcshell') self.startServers(options, None) # In desktop mochitests buildTestPath is called before buildURLOptions. This # means options.manifestFile has already been converted to the proper json # style manifest. Not so with B2G, that conversion along with updating the URL # option will happen later. So backup and restore options.manifestFile to # prevent us from trying to pass in an instance of TestManifest via url param. manifestFile = options.manifestFile options.manifestFile = None self.buildURLOptions(options, {'MOZ_HIDE_RESULTS_TABLE': '1'}) options.manifestFile = manifestFile self.test_script_args.append(not options.emulator) self.test_script_args.append(options.wifi) self.test_script_args.append(options.chrome) self.runner.start(outputTimeout=timeout) self.marionette.wait_for_port() self.marionette.start_session() self.marionette.set_context(self.marionette.CONTEXT_CHROME) # Disable offline status management (bug 777145), otherwise the network # will be 'offline' when the mochitests start. Presumably, the network # won't be offline on a real device, so we only do this for # emulators. self.marionette.execute_script(""" Components.utils.import("resource://gre/modules/Services.jsm"); Services.io.manageOfflineStatus = false; Services.io.offline = false; """) self.marionette.execute_script(""" let SECURITY_PREF = "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer"; Services.prefs.setBoolPref(SECURITY_PREF, true); if (!testUtils.hasOwnProperty("specialPowersObserver")) { let loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"] .getService(Components.interfaces.mozIJSSubScriptLoader); loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserver.js", testUtils); testUtils.specialPowersObserver = new testUtils.SpecialPowersObserver(); testUtils.specialPowersObserver.init(); testUtils.specialPowersObserver._loadFrameScript(); } """) if options.chrome: self.app_ctx.dm.removeDir(self.remote_chrome_test_dir) self.app_ctx.dm.mkDir(self.remote_chrome_test_dir) local = super(B2GMochitest, self).getChromeTestDir(options) local = os.path.join(local, "chrome") remote = self.remote_chrome_test_dir self.log.info("pushing %s to %s on device..." % (local, remote)) self.app_ctx.dm.pushDir(local, remote) if os.path.isfile(self.test_script): with open(self.test_script, 'r') as script: self.marionette.execute_script( script.read(), script_args=self.test_script_args) else: self.marionette.execute_script( self.test_script, script_args=self.test_script_args) status = self.runner.wait() if status is None: # the runner has timed out status = 124 local_leak_file = tempfile.NamedTemporaryFile() self.app_ctx.dm.getFile(self.leak_report_file, local_leak_file.name) self.app_ctx.dm.removeFile(self.leak_report_file) mozleak.process_leak_log( local_leak_file.name, leak_thresholds=options.leakThresholds, ignore_missing_leaks=options.ignoreMissingLeaks, log=self.log, ) except KeyboardInterrupt: self.log.info("runtests.py | Received keyboard interrupt.\n") status = -1 except: traceback.print_exc() self.log.error( "Automation Error: Received unexpected exception while running application\n" ) if hasattr(self, 'runner'): self.runner.check_for_crashes() status = 1 self.stopServers() self.log.info("runtestsb2g.py | Running tests: end.") if manifest is not None: self.cleanup(manifest, options) return status def getGMPPluginPath(self, options): if options.gmp_path: return options.gmp_path return '/system/b2g/gmp-clearkey/0.1' def getChromeTestDir(self, options): # The chrome test directory returned here is the remote location # of chrome test files. A reference to this directory is requested # when building the profile locally, before self.app_ctx is defined. # To get around this, return a dummy directory until self.app_ctx # is defined; the correct directory will be returned later, over- # writing the dummy. if hasattr(self, 'app_ctx'): self.remote_chrome_test_dir = posixpath.join( self.app_ctx.remote_test_root, 'chrome') return self.remote_chrome_test_dir return 'dummy-chrome-test-dir'
metric = result['title'].strip().replace(' ', '_') results.setdefault(metric, []).extend(result.get('mozPerfDurations')) if self.submit_report: self.post_to_datazilla(results, app_name) else: print 'results for %s' % app_name print json.dumps(results) if __name__ == "__main__": parser = dzOptionParser(usage='%prog [options] result_file') options, args = parser.parse_args() if not args: parser.print_usage() parser.exit() if len(args) != 1: parser.exit("You can only specify one result file") datazilla_config = parser.datazilla_config(options) marionette = Marionette(host='localhost', port=2828) marionette.start_session() handler = MozPerfHandler(marionette, datazilla_config=datazilla_config, sources=options.sources) handler.process_results(args[0])
class current_frame(): def main(self, LOGDIR, p_el, p_frame_array=False): # # p_el is an array for the element. # p_frame_array is a list of iframes to iterate through (optional). # self.marionette = Marionette(host='localhost', port=2828) self.marionette.start_session() self.marionette.set_search_timeout(1000) # # Switch to the correct iframe (unless it's "()"). # self.marionette.switch_to_frame() first_iframe = True for x in p_frame_array: # (just to make it look nice ;) typ_str = "'" + x[0] + "'" if first_iframe: first_iframe = False print "" print "Switching to iframe with " + typ_str.rjust(10) + " = '" + x[1] + "'" else: print "... then to iframe with " + typ_str.rjust(10) + " = '" + x[1] + "'" my_iframe = self.marionette.find_element("xpath", "//iframe[@" + x[0] + "='" + x[1] + "']") self.marionette.switch_to_frame(my_iframe) if first_iframe: print "" print "Using 'top level' iframe () ..." # # Grab a screenshot and html dump of this frame. # p_sfnam = LOGDIR + "screenshot.png" p_hfnam = LOGDIR + "html_dump.html" print "" print "Screenshot of this frame saved to: " + p_sfnam screenshot = self.marionette.screenshot()[22:] with open(p_sfnam, 'w') as f: f.write(base64.decodestring(screenshot)) f.close() print "HTML dump of this frame saved to : " + p_hfnam f = open(p_hfnam, 'w') f.write(self.marionette.page_source.encode('ascii', 'ignore') ) f.close() # # Test to see if the element is present / displayed / etc... # print "" print "Checking for element: " + str(p_el) b_present = False b_displayed = False b_enabled = False try: x = self.marionette.find_element(*p_el) if x: b_present = True if x.is_displayed(): b_displayed = True if x.is_enabled(): b_enabled = True except: pass print "" print "Present : " + str(b_present) print "Displayed: " + str(b_displayed) print "Enabled : " + str(b_enabled) print ""
def cli(): parser = dzOptionParser(usage='%prog [options] app_name [app_name] ...') parser.add_option('--address', action='store', dest='address', default='localhost:2828', metavar='str', help='address of marionette server (default: %default)') parser.add_option('--device-serial', action='store', dest='device_serial', metavar='str', help='serial identifier of device to target') parser.add_option('--delay', action='store', type='float', dest='delay', default=1, metavar='float', help='duration (in seconds) to wait before each ' 'iteration (default: %default)') parser.add_option('--iterations', action='store', type=int, dest='iterations', default=30, metavar='int', help='number of times to launch each app ' '(default: %default)') parser.add_option('--log-level', action='store', dest='log_level', default='INFO', metavar='str', help='threshold for log output (default: %default)') parser.add_option('--no-restart', action='store_false', dest='restart', default=True, help='do not restart B2G between tests') parser.add_option('--settle-time', action='store', type='float', dest='settle_time', default=60, metavar='float', help='time to wait before initial launch ' '(default: %default)') parser.add_option('--start-timeout', action='store', type=int, dest='start_timeout', default=60, metavar='int', help='b2g start timeout in seconds (default: %default)') parser.add_option('--testvars', action='store', dest='testvars', metavar='str', help='path to a json file with any test data required'), parser.add_option('--reset', action='store_true', dest='reset', default=False, help='reset the target to a clean state between tests ' '(requires restart). WARNING: any personal data ' 'will be removed!') options, args = parser.parse_args() if not args: parser.print_usage() parser.exit() if len(args) < 1: parser.print_usage() print 'must specify at least one app name' parser.exit() testvars = {} if options.testvars: if not os.path.exists(options.testvars): raise B2GPerfError('--testvars file does not exist') import json with open(options.testvars) as f: testvars = json.loads(f.read()) if options.reset and not options.restart: raise B2GPerfError('--reset requires restart') datazilla_config = parser.datazilla_config(options) try: host, port = options.address.split(':') except ValueError: raise B2GPerfError('--address must be in the format host:port') marionette = Marionette(host=host, port=int(port)) marionette.start_session() b2gperf = B2GPerfRunner(marionette, datazilla_config=datazilla_config, sources=options.sources, log_level=options.log_level, delay=options.delay, iterations=options.iterations, restart=options.restart, settle_time=options.settle_time, testvars=testvars, reset=options.reset, start_timeout=options.start_timeout, device_serial=options.device_serial) b2gperf.measure_app_perf(args)
class MtbfJobRunner(BaseActionRunner): serial = None marionette = None flash_params = { 'branch': 'mozilla-b2g34_v2_1-flame-kk-eng', 'build': '', 'build_id': '' } flashed = False def __init__(self, **kwargs): self.logger = logger BaseActionRunner.__init__(self) def setup(self): if not self.serial or not self.port: logger.error("Fail to get device") raise DMError self.config_raptor() self.marionette and self.marionette.session and self.marionette.cleanup( ) self.dm = mozdevice.DeviceManagerADB(deviceSerial=self.serial, port=self.port) self.marionette = Marionette(device_serial=self.serial, port=self.port) self.marionette.wait_for_port() self.marionette.start_session() self.device = GaiaDevice(marionette=self.marionette, manager=self.dm) self.apps = GaiaApps(self.marionette) self.data_layer = GaiaData(self.marionette) if self.flashed: self.device.wait_for_b2g_ready() def adb_test(self): if not hasattr(self, 'serial') or os.system("ANDROID_SERIAL=" + self.serial + " adb shell ls") != 0: logger.error("Device not found or can't be controlled") return False return True @action(enabled=False) def add_7mobile_action(self): # workaround for waiting for boot self.marionette.wait_for_port() self.marionette.start_session() self.data_layer = GaiaData(self.marionette) self.data_layer.set_setting('ril.data.apnSettings', [[{ "carrier": "(7-Mobile) (MMS)", "apn": "opentalk", "mmsc": "http://mms", "mmsproxy": "210.241.199.199", "mmsport": "9201", "types": ["mms"] }, { "carrier": "(7-Mobile) (Internet)", "apn": "opentalk", "types": ["default", "supl"] }]]) return True @action(enabled=False) def change_memory(self): # This function only work in flame # TODO: use native adb/fastboot command to change memory? # Make sure it's in fastboot mode, TODO: leverage all fastboot command in one task function memory = 512 # default set 512 if 'MEM' in os.environ: memory = os.environ['MEM'] elif self.settings['change_memory'][ 'enabled'] and 'memory' in self.settings['change_memory']: memory = self.settings['change_memory']['memory'] if self.adb_test(): os.system("adb reboot bootloader") memory = 512 mem_str = str(memory) os.system("fastboot oem mem " + mem_str) # Preventing from async timing of fastboot os.system("fastboot reboot") self.device_obj.create_adb_forward(self.port) return True logger.error("Can't find device") self.marionette.wait_for_port() self.device_obj.create_adb_forward(self.port) return False @action(enabled=False) def config_raptor(self): settings = self.settings if 'config_raptor' in settings and settings['config_raptor']['config']: with open(os.path.expandvars( settings['config_raptor']['config'])) as conf: self.raptor = json.load(conf) self.raptor['path'] = settings['config_raptor']['config'] self.raptor['monitorJobFolder'] = settings['config_raptor'][ 'monitorJobFolder'] @action(enabled=True) def collect_memory_report(self): zip_utils.collect_about_memory( "mtbf_driver") # TODO: give a correct path for about memory folder def get_free_device(self): do = device_pool.get_device(self.serial) if do: # Record device serial and store dp instance self.serial = do.serial self.device_obj = do if do.create_adb_forward(): self.port = do.adb_forwarded_port logger.info("Device found, ANDROID_SERIAL= " + self.serial) return do logger.error("Port forwarding failed") raise DMError logger.warning( "No available device. Please retry after device released") # TODO: more handling for no available device def validate_flash_params(self): ## Using system environment variable as temporary solution TODO: use other way for input params ## Check if package(files)/folder exists and return, else raise exception if not 'FLASH_BASEDIR' in os.environ: raise AttributeError("No FLASH_BASEDIR set") basedir = os.environ['FLASH_BASEDIR'] if not 'FLASH_BUILDID' in os.environ: ## TODO: if latest/ exists, use latest as default logging.info("No build id set. search in base dir") buildid = "" flash_dir = basedir else: buildid = os.environ['FLASH_BUILDID'] # re-format build id based on pvt folder structure if '-' in buildid: buildid = buildid.replace("-", "") year = buildid[:4] month = buildid[4:6] datetime = '-'.join( [year, month] + [buildid[i + 6:i + 8] for i in range(0, len(buildid[6:]), 2)]) flash_dir = os.path.join(basedir, year, month, datetime) if not os.path.isdir(flash_dir): raise AttributeError("Flash directory " + flash_dir + " not exist") flash_files = glob.glob(os.path.join(flash_dir, '*')) flash_src = {} for flash_file in flash_files: logger.debug("Flash source found: [" + flash_file + "]") if os.path.isdir(flash_file): continue elif re.match("^b2g-[0-9]*.*\.tar\.gz$", flash_file): flash_src['gecko'] = flash_file elif "gaia.zip" == flash_file: flash_src['gaia'] = flash_file elif "symbol" in flash_file: flash_src['symbol'] = flash_file elif "zip" in flash_file and not ("gaia.zip" in flash_file): flash_src['image'] = flash_file return flash_src @action(enabled=True) def full_flash(self): flash_src = self.validate_flash_params() if self.flashed: logger.warning("Flash performed; skip flashing") return True if not flash_src: logger.warning("Invalid build folder/build_id, skip flashing") return False if not 'image' in flash_src: logger.warning("No available image for flash, skip flashing") return False try: self.temp_dir = tempfile.mkdtemp() logger.info('Create temporary folder:' + self.temp_dir) Decompressor().unzip(flash_src['image'], self.temp_dir) # set the permissions to rwxrwxr-x (509 in python's os.chmod) os.chmod( self.temp_dir + '/b2g-distro/flash.sh', stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH) os.chmod( self.temp_dir + '/b2g-distro/load-config.sh', stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH) os.system('cd ' + self.temp_dir + '/b2g-distro; ./flash.sh -f') # support NO_FTU environment for skipping FTU (e.g. monkey test) if 'NO_FTU' in os.environ and os.environ['NO_FTU'] == 'true': logger.log('The [NO_FTU] is [true].') os.system( "ANDROID_SERIAL=" + self.serial + 'adb wait-for-device && adb shell stop b2g; (RET=$(adb root); if ! case ${RET} in *"cannot"*) true;; *) false;; esac; then adb remount && sleep 5; else exit 1; fi; ./disable_ftu.py) || (echo "No root permission, cannot setup NO_FTU."); adb reboot;' ) finally: try: shutil.rmtree(self.temp_dir) # delete directory except OSError: logger.error('Can not remove temporary folder:' + self.temp_dir, level=Logger._LEVEL_WARNING) self.flashed = True @action(enabled=False) def shallow_flash(self): flash_src = self.validate_flash_params() if self.flashed: logger.warning("Flash performed; skip flashing") return True if not flash_src: logger.warning("Invalid build folder/build_id, skip flashing") return False if not 'gaia' in flash_src or not 'gecko' in flash_src: logger.warning("No gaia or gecko archive, skip flashing") return False cmd = 'flash_tool/shallow_flash.sh -y --gecko="' + flash_src[ 'gecko'] + '" --gaia="' + flash_src['gaia'] + '"' if _platform == 'darwin': cmd = cmd.replace('=', ' ') ret = os.system(cmd) if ret != 0: logger.info("Shallow flash ended abnormally") return False self.flashed = True os.system("ANDROID_SERIAL=" + self.serial + " adb wait-for-device") @action(enabled=True) def enable_certified_apps_debug(self): if self.serial: os.system( "ANDROID_SERIAL=" + self.serial + " flash_tool/enable_certified_apps_for_devtools.sh && adb wait-for-device" ) logger.debug("Successfully enabling certified apps for debugging") return True return False def release(self): device_pool.release() def start_monitoring(self): job = { 'name': 'mtbf', 'type': 'moz_minions.kevin.MtbfToRaptorMinion', 'serial': self.serial, 'job_info': { 'pid': os.getpid(), 'program': sys.argv[0], } } if hasattr(self, 'raptor'): raptor = self.raptor job['job_info'].update(self.raptor) if "monitorJobFolder" in self.raptor: dirpath = os.path.expandvars(self.raptor['monitorJobFolder']) else: dirpath = "/tmp/mtbf" if not os.path.isdir(dirpath): os.makedirs(dirpath) timestamp = time.strftime('%Y-%m-%d-%H-%M-%S+0000', time.gmtime()) filename = job['name'] + "_" + timestamp + ".json" self.monitor_conf = os.path.join(dirpath, filename) job['job_info']['conf'] = self.monitor_conf with open(self.monitor_conf, 'w') as fh: fh.write(json.dumps(job, indent=2, sort_keys=True)) def stop_monitoring(self): if hasattr(self, 'raptor'): os.remove(self.monitor_conf) self.monitor_conf = None def check_version(self): # FIXME: fix check version to use package import cmd = "cd flash_tool/ && NO_COLOR=TRUE ./check_versions.py | sed -e 's| \{2,\}||g' -e 's|\[0m||g'" if self.serial: cmd = "ANDROID_SERIAL=" + self.serial + " " + cmd os.system(cmd) @action(enabled=False) def patch_marionette(self): os.system( "M_PATH=/mnt/mtbf_shared/paul/ /mnt/mtbf_shared/paul/marionette_update.sh" ) import time time.sleep(10) self.device_obj.create_adb_forward(self.port) def mtbf_options(self): ## load mtbf parameters if not 'MTBF_TIME' in os.environ: logger.warning("MTBF_TIME is not set") if not 'MTBF_CONF' in os.environ: logger.warning("MTBF_CONF is not set") parser = self.parser.parser parser.add_argument("--testvars", help="Test variables for b2g") self.parse_options() # FIXME: make rootdir of testvars could be customized mtbf_testvars_dir = "/mnt/mtbf_shared/testvars" if not hasattr(self.options, 'testvars') or not self.options.testvars: testvars = os.path.join(mtbf_testvars_dir, "testvars_" + self.serial + ".json") logger.info("testvar is [" + testvars + "]") if os.path.exists(testvars): self.options.testvars = parser.testvars = testvars logger.info("testvar [" + testvars + "] found") else: raise AttributeError("testvars[" + testvars + "] doesn't exist") def remove_settings_opt(self): for e in sys.argv[1:]: if '--settings' in e: idx = sys.argv.index(e) sys.argv.remove(e) if len(sys.argv) > idx and not '--' in sys.argv[idx]: del sys.argv[idx] break @action(enabled=False) def mtbf_daily(self): parser = GaiaTestArguments() opts = [] for k, v in self.kwargs.iteritems(): opts.append("--" + k) opts.append(v) options, tests = parser.parse_args(sys.argv[1:] + opts) structured.commandline.add_logging_group(parser) logger = structured.commandline.setup_logging(options.logger_name, options, {"tbpl": sys.stdout}) options.logger = logger options.testvars = [self.options.testvars] runner = GaiaTestRunner(**vars(options)) runner.run_tests(["tests"]) @action(enabled=True) def run_mtbf(self): mtbf.main(testvars=self.options.testvars, **self.kwargs) def execute(self): self.marionette.cleanup() self.marionette = Marionette(device_serial=self.serial, port=self.port) self.marionette.wait_for_port() # run test runner here self.remove_settings_opt() self.kwargs = {} if self.port: self.kwargs['address'] = "localhost:" + str(self.port) logger.info("Using address[localhost:" + str(self.port) + "]") self.start_monitoring() self.mtbf_daily() self.run_mtbf() self.stop_monitoring() def pre_flash(self): pass def flash(self): self.shallow_flash() self.full_flash() # workaround for waiting for boot def post_flash(self): self.setup() self.check_version() self.change_memory() self.add_7mobile_action() self.enable_certified_apps_debug() self.patch_marionette() def output_crash_report_no_to_log(self, serial): if serial in CrashScan.get_current_all_dev_serials(): crash_result = CrashScan.get_crash_no_by_serial(serial) if crash_result['crashNo'] > 0: logger.error("CrashReportFound: device " + serial + " has " + str(crash_result['crashNo']) + " crashes.") else: logger.info( "CrashReportNotFound: No crash report found in device " + serial) else: logger.error("CrashReportAdbError: Can't find device in ADB list") def collect_report(self, serial): self.output_crash_report_no_to_log(serial) def run(self): try: if self.get_free_device(): self.mtbf_options() self.pre_flash() self.flash() self.device_obj.create_adb_forward() self.port = self.device_obj.adb_forwarded_port self.post_flash() self.execute() self.collect_report(self.serial) finally: self.release()