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 _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 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 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 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 _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 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 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")
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()
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()
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)) assert(m.execute_js_script(server.TEST_EXECUTE_SCRIPT)) assert(m.execute_js_script(server.TEST_EXECUTE_SCRIPT, server.TEST_EXECUTE_SCRIPT_ARGS)) assert(m.execute_script(server.TEST_EXECUTE_SCRIPT, server.TEST_EXECUTE_SCRIPT_ARGS)) assert(m.execute_async_script(server.TEST_EXECUTE_SCRIPT)) assert(m.execute_async_script(server.TEST_EXECUTE_SCRIPT, server.TEST_EXECUTE_SCRIPT_ARGS)) assert(str(m.find_element(HTMLElement.CLASS, 'heading')) == server.TEST_FIND_ELEMENT) assert([str(x) for x in m.find_elements(HTMLElement.TAG, 'p')] == server.TEST_FIND_ELEMENTS) assert(str(m.find_element(HTMLElement.CLASS, 'heading').find_element(HTMLElement.TAG, 'h1')) == server.TEST_FIND_ELEMENT)
class B2GMixin(object): profileDir = None userJS = "/data/local/user.js" marionette = None def __init__(self, host=None, marionetteHost=None, marionettePort=2828, **kwargs): # (allowing marionneteHost to be specified seems a bit # counter-intuitive since we normally get it below from the ip # address, however we currently need it to be able to connect # via adb port forwarding and localhost) if marionetteHost: self.marionetteHost = marionetteHost elif host: self.marionetteHost = host self.marionettePort = marionettePort def cleanup(self): """ If a user profile was setup on the device, restore it to the original. """ if self.profileDir: self.restoreProfile() def waitForPort(self, timeout): """Waits for the marionette server to respond, until the timeout specified. :param timeout: Timeout parameter in seconds. """ print "waiting for port" starttime = datetime.datetime.now() while datetime.datetime.now() - starttime < datetime.timedelta(seconds=timeout): try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print "trying %s %s" % (self.marionettePort, self.marionetteHost) sock.connect((self.marionetteHost, self.marionettePort)) data = sock.recv(16) sock.close() if '"from"' in data: return True except socket.error: pass except Exception as e: raise DMError("Could not connect to marionette: %s" % e) time.sleep(1) raise DMError("Could not communicate with Marionette port") def setupMarionette(self, scriptTimeout=60000): """ Starts a marionette session. If no host was given at init, the ip of the device will be retrieved and networking will be established. """ if not self.marionetteHost: self.setupDHCP() self.marionetteHost = self.getIP() if not self.marionette: self.marionette = Marionette(self.marionetteHost, self.marionettePort) if not self.marionette.session: self.waitForPort(30) self.marionette.start_session() self.marionette.set_script_timeout(scriptTimeout) def restartB2G(self): """ Restarts the b2g process on the device. """ #restart b2g so we start with a clean slate if self.marionette and self.marionette.session: self.marionette.delete_session() self.shellCheckOutput(['stop', 'b2g']) # Wait for a bit to make sure B2G has completely shut down. tries = 10 while "b2g" in self.shellCheckOutput(['ps', 'b2g']) and tries > 0: tries -= 1 time.sleep(1) if tries == 0: raise DMError("Could not kill b2g process") self.shellCheckOutput(['start', 'b2g']) def setupProfile(self, prefs=None): """Sets up the user profile on the device. :param prefs: String of user_prefs to add to the profile. Defaults to a standard b2g testing profile. """ # currently we have no custom prefs to set (when bug 800138 is fixed, # we will probably want to enable marionette on an external ip by # default) if not prefs: prefs = "" #remove previous user.js if there is one if not self.profileDir: self.profileDir = tempfile.mkdtemp() our_userJS = os.path.join(self.profileDir, "user.js") mozfile.remove(our_userJS) #copy profile try: self.getFile(self.userJS, our_userJS) except subprocess.CalledProcessError: pass #if we successfully copied the profile, make a backup of the file if os.path.exists(our_userJS): self.shellCheckOutput(['dd', 'if=%s' % self.userJS, 'of=%s.orig' % self.userJS]) with open(our_userJS, 'a') as user_file: user_file.write("%s" % prefs) self.pushFile(our_userJS, self.userJS) self.restartB2G() self.setupMarionette() def setupDHCP(self, interfaces=['eth0', 'wlan0']): """Sets up networking. :param interfaces: Network connection types to try. Defaults to eth0 and wlan0. """ all_interfaces = [line.split()[0] for line in \ self.shellCheckOutput(['netcfg']).splitlines()[1:]] interfaces_to_try = filter(lambda i: i in interfaces, all_interfaces) tries = 5 print "Setting up DHCP..." while tries > 0: print "attempts left: %d" % tries try: for interface in interfaces_to_try: self.shellCheckOutput(['netcfg', interface, 'dhcp'], timeout=10) if self.getIP(interfaces=[interface]): return except DMError: pass time.sleep(1) tries -= 1 raise DMError("Could not set up network connection") def restoreProfile(self): """ Restores the original user profile on the device. """ if not self.profileDir: raise DMError("There is no profile to restore") #if we successfully copied the profile, make a backup of the file our_userJS = os.path.join(self.profileDir, "user.js") if os.path.exists(our_userJS): self.shellCheckOutput(['dd', 'if=%s.orig' % self.userJS, 'of=%s' % self.userJS]) mozfile.remove(self.profileDir) self.profileDir = None def getAppInfo(self): """ Returns the appinfo, with an additional "date" key. :rtype: dictionary """ if not self.marionette or not self.marionette.session: self.setupMarionette() self.marionette.set_context("chrome") appinfo = self.marionette.execute_script(""" var appInfo = Components.classes["@mozilla.org/xre/app-info;1"] .getService(Components.interfaces.nsIXULAppInfo); return appInfo; """) (year, month, day) = (appinfo["appBuildID"][0:4], appinfo["appBuildID"][4:6], appinfo["appBuildID"][6:8]) appinfo['date'] = "%s-%s-%s" % (year, month, day) return appinfo
def uninstall_app(app_name, adb_path="adb", script_timeout=5000, marionette=None, device_serial=None): """ Uninstalls the given app. NOTE: if a marionette session is passed, this function switches to the top-most frame. """ def check_uninstall(marionette): uninstall = marionette.execute_script("return window.wrappedJSObject.uninstall;") return uninstall != 'none' def check_click_uninstall(marionette): button = marionette.find_element('css selector', 'gaia-confirm .confirm') try: button.click() not_displayed = not button.is_displayed() except StaleElementException: not_displayed = True return not_displayed 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") print 'requesting uninstall of app', app_name if not marionette: m = Marionette() m.start_session() else: m = marionette m.switch_to_frame() m.set_context("chrome") m.execute_script(""" Components.utils.import("resource://gre/modules/Services.jsm"); window.wrappedJSObject.uninstall = 'none'; Services.obs.addObserver(function observer(subject, topic) { Services.obs.removeObserver(observer, topic); window.wrappedJSObject.uninstall = 'ask'; }, "webapps-ask-uninstall", false); Services.obs.addObserver(function observer(subject, topic) { Services.obs.removeObserver(observer, topic); window.wrappedJSObject.uninstall = 'uninstall'; }, "webapps-uninstall", false); """) m.set_context("content") 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) result = m.execute_script(uninstall_app % app_name.lower()) if result: m.set_context("chrome") Wait(m, 10).until(check_uninstall) uninstall = m.execute_script("return window.wrappedJSObject.uninstall;") m.set_context("content") if uninstall == 'ask': m.switch_to_frame() Wait(m, 20).until(element_displayed(m.find_element('css selector', 'gaia-confirm .confirm'))) Wait(m, 20).until(check_click_uninstall) if not marionette: m.delete_session()
class B2GMixin(object): profileDir = None userJS = "/data/local/user.js" marionette = None def __init__(self, host=None, marionetteHost=None, marionettePort=2828, **kwargs): # (allowing marionneteHost to be specified seems a bit # counter-intuitive since we normally get it below from the ip # address, however we currently need it to be able to connect # via adb port forwarding and localhost) if marionetteHost: self.marionetteHost = marionetteHost elif host: self.marionetteHost = host self.marionettePort = marionettePort def cleanup(self): """ If a user profile was setup on the device, restore it to the original. """ if self.profileDir: self.restoreProfile() def waitForPort(self, timeout): """Waits for the marionette server to respond, until the timeout specified. :param timeout: Timeout parameter in seconds. """ print "waiting for port" starttime = datetime.datetime.now() while datetime.datetime.now() - starttime < datetime.timedelta( seconds=timeout): try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print "trying %s %s" % (self.marionettePort, self.marionetteHost) sock.connect((self.marionetteHost, self.marionettePort)) data = sock.recv(16) sock.close() if '"from"' in data: return True except socket.error: pass except Exception as e: raise DMError("Could not connect to marionette: %s" % e) time.sleep(1) raise DMError("Could not communicate with Marionette port") def setupMarionette(self, scriptTimeout=60000): """ Starts a marionette session. If no host was given at init, the ip of the device will be retrieved and networking will be established. """ if not self.marionetteHost: self.setupDHCP() self.marionetteHost = self.getIP() if not self.marionette: self.marionette = Marionette(self.marionetteHost, self.marionettePort) if not self.marionette.session: self.waitForPort(30) self.marionette.start_session() self.marionette.set_script_timeout(scriptTimeout) def restartB2G(self): """ Restarts the b2g process on the device. """ #restart b2g so we start with a clean slate if self.marionette and self.marionette.session: self.marionette.delete_session() self.shellCheckOutput(['stop', 'b2g']) # Wait for a bit to make sure B2G has completely shut down. tries = 10 while "b2g" in self.shellCheckOutput(['ps', 'b2g']) and tries > 0: tries -= 1 time.sleep(1) if tries == 0: raise DMError("Could not kill b2g process") self.shellCheckOutput(['start', 'b2g']) def setupProfile(self, prefs=None): """Sets up the user profile on the device. :param prefs: String of user_prefs to add to the profile. Defaults to a standard b2g testing profile. """ # currently we have no custom prefs to set (when bug 800138 is fixed, # we will probably want to enable marionette on an external ip by # default) if not prefs: prefs = "" #remove previous user.js if there is one if not self.profileDir: self.profileDir = tempfile.mkdtemp() our_userJS = os.path.join(self.profileDir, "user.js") if os.path.exists(our_userJS): os.remove(our_userJS) #copy profile try: self.getFile(self.userJS, our_userJS) except subprocess.CalledProcessError: pass #if we successfully copied the profile, make a backup of the file if os.path.exists(our_userJS): self.shellCheckOutput( ['dd', 'if=%s' % self.userJS, 'of=%s.orig' % self.userJS]) with open(our_userJS, 'a') as user_file: user_file.write("%s" % prefs) self.pushFile(our_userJS, self.userJS) self.restartB2G() self.setupMarionette() def setupDHCP(self, interfaces=['eth0', 'wlan0']): """Sets up networking. :param interfaces: Network connection types to try. Defaults to eth0 and wlan0. """ all_interfaces = [line.split()[0] for line in \ self.shellCheckOutput(['netcfg']).splitlines()[1:]] interfaces_to_try = filter(lambda i: i in interfaces, all_interfaces) tries = 5 print "Setting up DHCP..." while tries > 0: print "attempts left: %d" % tries try: for interface in interfaces_to_try: self.shellCheckOutput(['netcfg', interface, 'dhcp'], timeout=10) if self.getIP(interfaces=[interface]): return except DMError: pass time.sleep(1) tries -= 1 raise DMError("Could not set up network connection") def restoreProfile(self): """ Restores the original user profile on the device. """ if not self.profileDir: raise DMError("There is no profile to restore") #if we successfully copied the profile, make a backup of the file our_userJS = os.path.join(self.profileDir, "user.js") if os.path.exists(our_userJS): self.shellCheckOutput( ['dd', 'if=%s.orig' % self.userJS, 'of=%s' % self.userJS]) shutil.rmtree(self.profileDir) self.profileDir = None def getAppInfo(self): """ Returns the appinfo, with an additional "date" key. :rtype: dictionary """ if not self.marionette or not self.marionette.session: self.setupMarionette() self.marionette.set_context("chrome") appinfo = self.marionette.execute_script(""" var appInfo = Components.classes["@mozilla.org/xre/app-info;1"] .getService(Components.interfaces.nsIXULAppInfo); return appInfo; """) (year, month, day) = (appinfo["appBuildID"][0:4], appinfo["appBuildID"][4:6], appinfo["appBuildID"][6:8]) appinfo['date'] = "%s-%s-%s" % (year, month, day) return appinfo